diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm
index bc0dd8fc2b4..31b91c7cd1e 100644
--- a/code/__DEFINES/preferences.dm
+++ b/code/__DEFINES/preferences.dm
@@ -9,8 +9,9 @@
#define MIDROUND_ANTAG 64
#define SOUND_INSTRUMENTS 128
#define SOUND_SHIP_AMBIENCE 256
+#define SOUND_PRAYERS 512
-#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|MEMBER_PUBLIC|INTENT_STYLE|MIDROUND_ANTAG|SOUND_INSTRUMENTS|SOUND_SHIP_AMBIENCE)
+#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|MEMBER_PUBLIC|INTENT_STYLE|MIDROUND_ANTAG|SOUND_INSTRUMENTS|SOUND_SHIP_AMBIENCE|SOUND_PRAYERS)
//Chat toggles
#define CHAT_OOC 1
diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm
index 9945a13fcad..33b781ad4f8 100644
--- a/code/__HELPERS/text.dm
+++ b/code/__HELPERS/text.dm
@@ -76,12 +76,12 @@
// Used to get a properly sanitized input, of max_length
/proc/stripped_input(var/mob/user, var/message = "", var/title = "", var/default = "", var/max_length=MAX_MESSAGE_LEN)
var/name = input(user, message, title, default) as text|null
- return strip_html_properly(name, max_length)
+ return html_encode(trim(name, max_length)) //trim is "inside" because html_encode can expand single symbols into multiple symbols (such as turning < into <)
// Used to get a properly sanitized multiline input, of max_length
/proc/stripped_multiline_input(var/mob/user, var/message = "", var/title = "", var/default = "", var/max_length=MAX_MESSAGE_LEN)
var/name = input(user, message, title, default) as message|null
- return strip_html_properly(name, max_length)
+ return html_encode(trim(name, max_length))
//Filters out undesirable characters from names
/proc/reject_bad_name(var/t_in, var/allow_numbers=0, var/max_length=MAX_NAME_LEN)
@@ -147,56 +147,7 @@
return t_out
-//this proc strips html properly, this means that it removes everything between < and >, and between "http" and "://"
-//also limit the size of the input, if specified to
-/proc/strip_html_properly(var/input,var/max_length=MAX_MESSAGE_LEN)
- if(!input)
- return
-
- if(max_length)
- input = copytext(input,1,max_length)
-
- var/sanitized_output
- var/next_html_tag = findtext(input, "<")
- var/next_http = findtext(input, "http", 1, next_html_tag)
-
- //the opening and closing of the expression to skip, e.g '<' and '>'
- var/opening = non_zero_min(next_html_tag, next_http)
- var/closing
-
- sanitized_output = copytext(input, 1, opening)
-
- while(next_html_tag || next_http)
-
- //we treat < ... >
- if(opening == next_html_tag)
- closing = findtext(input, ">", opening + 1)
- if(closing)
- next_html_tag = findtext(input, "<", closing)
- next_http = findtext(input, "http", closing, next_html_tag)
- else //no matching ">"
- next_html_tag = 0
-
- //we treat "http(s)://"
- else
- closing = findtext(input, "://", opening + 1)
- if(closing)
- closing += 2 //skip these extra //
- next_http = findtext(input, "http", closing)
- next_html_tag = findtext(input, "<", closing, next_http)
- else //no matching "://"
- next_http = 0
-
- //check if we've something to skip
- if(closing)
- opening = non_zero_min(next_html_tag, next_http)
- sanitized_output += copytext(input, closing + 1, opening)
-
- sanitized_output += copytext(input, opening) //don't forget the remaining text
-
- return sanitized_output
-
-//strip_html_properly helper proc that returns the smallest non null of two numbers
+//html_encode helper proc that returns the smallest non null of two numbers
//or 0 if they're both null (needed because of findtext returning 0 when a value is not present)
/proc/non_zero_min(var/a, var/b)
if(!a)
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index adb3b60c80b..fb75fed9b60 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -987,25 +987,8 @@ Turf and target are seperate in case you want to teleport some distance from a t
/proc/get_turf(atom/A)
if (!istype(A))
return
- if (isturf(A))
- return A
-
- var/list/atom/checked_turf_candidates = list() //prevent recursion from badmins being dumbasses
- var/atom/turf_candidate = A.loc
-
- while (!isturf(turf_candidate))
- if (!turf_candidate || turf_candidate in checked_turf_candidates)
- return
- checked_turf_candidates += turf_candidate
-
- //SO I BET YOU MIGHT BE WONDERING WHY I'M CHECKING THIS AGAIN.
- //I'LL FUCKING TELL YOU WAY, ITS BECAUSE FOR SOME GOD DAMN REASON, WHEN THIS IS CALLED
- //IN AN OBJECT'S NEW() PROC, THE FIRST CHECK WILL FUCKING PASS, BUT FUCKING RUNTIME HERE
- //BITCHING ABOUT HOW IT CAN'T READ NULL.LOC, SO FUCK IT, WE CHECK THIS TWICE.
- if (!turf_candidate)
- return
- turf_candidate = turf_candidate.loc
- return turf_candidate
+ for(A, A && !isturf(A), A=A.loc); //semicolon is for the empty statement
+ return A
//Gets the turf this atom's *ICON* appears to inhabit
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index c250dc1d2d9..e442f74d14f 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -160,6 +160,8 @@
var/aggressive_changelog = 0
+ var/reactionary_explosions = 0 //If we use reactionary explosions, explosions that react to walls and doors
+
/datum/configuration/New()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode
for(var/T in L)
@@ -485,6 +487,8 @@
config.no_summon_magic = 1
if("no_summon_events")
config.no_summon_events = 1
+ if("reactionary_explosions")
+ config.reactionary_explosions = 1
else
diary << "Unknown setting in configuration: '[name]'"
diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm
index 5cff548b620..838bcde4e26 100644
--- a/code/controllers/master_controller.dm
+++ b/code/controllers/master_controller.dm
@@ -9,6 +9,7 @@ var/global/datum/controller/game_controller/master_controller = new()
var/processing_interval = 1 //The minimum length of time between MC ticks (in deciseconds). The highest this can be without affecting schedules, is the GCD of all subsystem var/wait. Set to 0 to disable all processing.
var/iteration = 0
var/cost = 0
+ var/SSCostPerSecond = 0
var/last_thing_processed
var/list/subsystems = list()
@@ -60,7 +61,8 @@ calculate the longest number of ticks the MC can wait between each cycle without
for(var/datum/subsystem/S in subsystems)
S.Initialize(world.timeofday, zlevel)
sleep(-1)
-
+ for(var/datum/subsystem/S in subsystems)
+ S.AfterInitialize(zlevel)
world << "Initializations complete"
world.log << "Initializations complete"
@@ -89,10 +91,11 @@ calculate the longest number of ticks the MC can wait between each cycle without
++iteration
start_time = world.timeofday
-
+ var/SubSystemRan = 0
for(var/datum/subsystem/SS in subsystems)
if(SS.can_fire > 0)
if(SS.next_fire <= world.time)
+ SubSystemRan = 1
timer = world.timeofday
last_thing_processed = SS.type
SS.last_fire = world.time
@@ -100,7 +103,9 @@ calculate the longest number of ticks the MC can wait between each cycle without
SS.cost = MC_AVERAGE(SS.cost, world.timeofday - timer)
if (SS.dynamic_wait)
var/oldwait = SS.wait
- SS.wait = min(max(round(SS.cost*SS.dwait_delta, 0.1),SS.dwait_lower),SS.dwait_upper)
+ var/GlobalCostDelta = (SSCostPerSecond-(SS.cost/SS.wait))/(SS.wait/10)-1
+ var/NewWait = MC_AVERAGE(oldwait,(SS.cost-1.5+GlobalCostDelta)*SS.dwait_delta)
+ SS.wait = Clamp(round(NewWait,0.1),SS.dwait_lower,SS.dwait_upper)
if (oldwait != SS.wait)
calculateGCD()
SS.next_fire += SS.wait
@@ -109,11 +114,20 @@ calculate the longest number of ticks the MC can wait between each cycle without
sleep(-1)
cost = MC_AVERAGE(cost, world.timeofday - start_time)
-
+ if (SubSystemRan)
+ calculateSScost()
sleep(processing_interval)
else
sleep(50)
+/datum/controller/game_controller/proc/calculateSScost()
+ var/newcost = 0
+ for(var/datum/subsystem/SS in subsystems)
+ if (!SS.can_fire)
+ continue
+ newcost += SS.cost/(SS.wait/10)
+ SSCostPerSecond = MC_AVERAGE(SSCostPerSecond,newcost)
+
#undef MC_AVERAGE
/datum/controller/game_controller/proc/roundHasStarted()
diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm
index 5c74da6d84d..969e2fa6d97 100644
--- a/code/controllers/subsystem/air.dm
+++ b/code/controllers/subsystem/air.dm
@@ -3,7 +3,6 @@ var/datum/subsystem/air/SSair
/datum/subsystem/air
name = "Air"
priority = 20
- cost = 5
wait = 5
dynamic_wait = 1
dwait_lower = 5
@@ -56,10 +55,12 @@ var/datum/subsystem/air/SSair
/datum/subsystem/air/Initialize(timeofday, zlevel)
- setup_allturfs(zlevel)
setup_atmos_machinery(zlevel)
..()
+/datum/subsystem/air/AfterInitialize(zlevel)
+ setup_allturfs(zlevel)
+
#define MC_AVERAGE(average, current) (0.8*(average) + 0.2*(current))
/datum/subsystem/air/fire()
var/timer = world.timeofday
@@ -167,15 +168,14 @@ var/datum/subsystem/air/SSair
EG.dismantle()
/datum/subsystem/air/proc/setup_allturfs(z_level)
+ active_turfs.Cut()
var/z_start = 1
var/z_finish = world.maxz
if(1 <= z_level && z_level <= world.maxz)
z_level = round(z_level)
z_start = z_level
z_finish = z_level
-
var/list/turfs_to_init = block(locate(1, 1, z_start), locate(world.maxx, world.maxy, z_finish))
-
for(var/turf/simulated/T in turfs_to_init)
T.CalculateAdjacentTurfs()
if(!T.blocks_air)
@@ -195,6 +195,8 @@ var/datum/subsystem/air/SSair
if(!T.air.check_turf_total(enemy_tile))
T.excited = 1
active_turfs |= T
+ if(active_turfs.len)
+ warning("There are [active_turfs.len] active turfs at roundstart, this is a mapping error caused by a difference of the air between the adjacent turfs.")
/datum/subsystem/air/proc/setup_atmos_machinery(z_level)
for (var/obj/machinery/atmospherics/AM in atmos_machinery)
diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm
index a99ac70899f..352caeb6195 100644
--- a/code/controllers/subsystem/garbage.dm
+++ b/code/controllers/subsystem/garbage.dm
@@ -5,9 +5,11 @@ var/datum/subsystem/garbage_collector/SSgarbage
can_fire = 1
wait = 5
priority = -1
+ dynamic_wait = 1
+ dwait_delta = 5
var/collection_timeout = 300// deciseconds to wait to let running procs finish before we just say fuck it and force del() the object
- var/max_run_time = 2 // how long, in deciseconds, can we run before waiting for the next tick
+ var/max_run_time = 1 // how long, in deciseconds, can we run before waiting for the next tick
var/delslasttick = 0 // number of del()'s we've done this tick
var/gcedlasttick = 0 // number of things that gc'ed last tick
var/totaldels = 0
diff --git a/code/controllers/subsystem/lighting.dm b/code/controllers/subsystem/lighting.dm
index c2a0c3df334..cd74bb16b84 100644
--- a/code/controllers/subsystem/lighting.dm
+++ b/code/controllers/subsystem/lighting.dm
@@ -7,6 +7,7 @@ var/datum/subsystem/lighting/SSlighting
wait = 5
priority = 1
dynamic_wait = 1
+ dwait_delta = 1
var/list/changed_lights = list() //list of all datum/light_source that need updating
var/changed_lights_workload = 0 //stats on the largest number of lights (max changed_lights.len)
diff --git a/code/controllers/subsystem/shuttles.dm b/code/controllers/subsystem/shuttles.dm
index 7392c98ec88..f2598097565 100644
--- a/code/controllers/subsystem/shuttles.dm
+++ b/code/controllers/subsystem/shuttles.dm
@@ -109,7 +109,7 @@ var/datum/subsystem/shuttle/SSshuttle
user << "The emergency shuttle has been disabled by Centcom."
return
- call_reason = strip_html_properly(trim(call_reason))
+ call_reason = html_encode(trim(call_reason))
if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH)
user << "You must provide a reason."
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 4d80d74daae..fa6db81352b 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -417,5 +417,5 @@ var/datum/subsystem/ticker/ticker
/datum/subsystem/ticker/proc/send_random_tip()
var/list/randomtips = file2list("config/tips.txt")
if(randomtips.len)
- world << "Tip of the round: [strip_html_properly(pick(randomtips))]"
+ world << "Tip of the round: [html_encode(pick(randomtips))]"
diff --git a/code/controllers/subsystems.dm b/code/controllers/subsystems.dm
index 5e10dcbcfd6..777bc2e5a1e 100644
--- a/code/controllers/subsystems.dm
+++ b/code/controllers/subsystems.dm
@@ -37,6 +37,9 @@
world << "[msg]"
world.log << msg
+/datum/subsystem/proc/AfterInitialize()
+ return
+
//hook for printing stats to the "MC" statuspanel for admins to see performance and related stats etc.
/datum/subsystem/proc/stat_entry(msg)
var/dwait = ""
diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm
index 4a7c4765b00..f40b58dca57 100644
--- a/code/datums/helper_datums/getrev.dm
+++ b/code/datums/helper_datums/getrev.dm
@@ -38,7 +38,15 @@ var/global/datum/getrev/revdata = new()
src << "Protect Assistant Role From Traitor: [config.protect_assistant_from_antagonist]"
src << "Enforce Human Authority: [config.enforce_human_authority]"
src << "Allow Latejoin Antagonists: [config.allow_latejoin_antagonists]"
- src << "Protect Assistant From Antagonist: [config.protect_assistant_from_antagonist]"
src << "Enforce Continuous Rounds: [config.continuous.len] of [config.modes.len] roundtypes"
src << "Allow Midround Antagonists: [config.midround_antag.len] of [config.modes.len] roundtypes"
+ if(config.show_game_type_odds)
+ src <<"Game Mode Odds:"
+ var/sum = 0
+ for(var/i=1,i<=config.probabilities.len,i++)
+ sum += config.probabilities[config.probabilities[i]]
+ for(var/i=1,i<=config.probabilities.len,i++)
+ if(config.probabilities[config.probabilities[i]] > 0)
+ var/percentage = round(config.probabilities[config.probabilities[i]] / sum * 100, 0.1)
+ src << "[config.probabilities[i]] [percentage]%"
return
diff --git a/code/datums/spells/lichdom.dm b/code/datums/spells/lichdom.dm
new file mode 100644
index 00000000000..a6ace565803
--- /dev/null
+++ b/code/datums/spells/lichdom.dm
@@ -0,0 +1,108 @@
+/obj/effect/proc_holder/spell/targeted/lichdom
+ name = "Bind Soul"
+ desc = "A dark necromantic pact that can forever bind your soul to an item of your choosing. So long as both your body and the item remain intact you can revive from death, though the time between reincarnations grows steadily with use."
+ school = "necromancy"
+ charge_max = 10
+ clothes_req = 0
+ centcom_cancast = 0
+ invocation = "NECREM IMORTIUM!"
+ invocation_type = "shout"
+ range = -1
+ level_max = 0 //cannot be improved
+ cooldown_min = 10
+ include_user = 1
+
+ var/obj/marked_item
+ var/mob/living/current_body
+
+ action_icon_state = "skeleton"
+
+/obj/effect/proc_holder/spell/targeted/lichdom/New()
+ if(ticker.mode.round_ends_with_antag_death)
+ ticker.mode.round_ends_with_antag_death = 0
+
+ ..()
+/obj/effect/proc_holder/spell/targeted/lichdom/cast(list/targets)
+ for(var/mob/user in targets)
+ var/list/hand_items = list()
+ if(iscarbon(user))
+ hand_items = list(user.get_active_hand(),user.get_inactive_hand())
+
+ if(marked_item && !stat_allowed) //sanity, shouldn't happen without badminry
+ marked_item = null
+ return
+
+ if(stat_allowed) //Death is not my end!
+ if(user.stat == CONSCIOUS && iscarbon(user))
+ user << "You aren't dead enough to revive!" //Usually a good problem to have
+ charge_counter = charge_max
+ return
+
+ if(!marked_item.loc) //Wait nevermind
+ user << "Your phylactery is gone!"
+ return
+
+ if(isobserver(user))
+ var/mob/dead/observer/O = user
+ O.reenter_corpse()
+
+ var/mob/living/carbon/human/lich = new /mob/living/carbon/human(get_turf(marked_item))
+
+ lich.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(lich), slot_shoes)
+ lich.equip_to_slot_or_del(new /obj/item/clothing/under/color/black(lich), slot_w_uniform)
+ lich.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/black(lich), slot_wear_suit)
+ lich.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/black(lich), slot_head)
+
+ lich.real_name = user.mind.name
+ user.mind.transfer_to(lich)
+ hardset_dna(lich,null,null,lich.real_name,null,/datum/species/skeleton)
+ lich << "Your bones clatter and shutter as they're pulled back into this world!"
+ charge_max += 600
+ var/mob/old_body = current_body
+ current_body = lich
+ lich.Weaken(10)
+
+ if(old_body && old_body.loc)
+ if(iscarbon(old_body))
+ var/mob/living/carbon/C = old_body
+ for(var/obj/item/W in C)
+ C.unEquip(W)
+ var/wheres_wizdo = dir2text(get_dir(get_turf(old_body), get_turf(marked_item)))
+ if(wheres_wizdo)
+ old_body.visible_message("Suddenly [old_body.name]'s corpse falls to pieces! You see a strange energy rise from the remains, and speed off towards the [wheres_wizdo]!")
+ old_body.dust()
+
+ if(!marked_item) //linking item to the spell
+ message = ""
+ for(var/obj/item in hand_items)
+ if(ABSTRACT in item.flags || NODROP in item.flags)
+ continue
+ marked_item = item
+ user << "You begin to focus your very being into the [item.name]..."
+ break
+
+ if(!marked_item)
+ user << "You must hold an item you wish to make your phylactery..."
+
+ spawn(50)
+ if(marked_item.loc != user) //I changed my mind I don't want to put my soul in a cheeseburger!
+ user << "Your soul snaps back to your body as you drop the [marked_item.name]!"
+ marked_item = null
+ return
+ name = "RISE!"
+ desc = "Rise from the dead! You will reform at the location of your phylactery and your old body will crumble away."
+ charge_max = 1800 //3 minute cooldown, if you rise in sight of someone and killed again, you're probably screwed.
+ charge_counter = 1800
+ stat_allowed = 1
+ marked_item.name = "Ensouled [marked_item.name]"
+ marked_item.desc = "A terrible aura surrounds this item, its very existence is offensive to life itself..."
+ marked_item.color = "#003300"
+ user << "With a hideous feeling of emptiness you watch in horrified fascination as skin sloughs off bone! Blood boils, nerves disintegrate, eyes boil in their sockets! As your organs crumble to dust in your fleshless chest you come to terms with your choice. You're a lich!"
+ hardset_dna(user, null, null, null, null, /datum/species/skeleton)
+ current_body = user.mind.current
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.unEquip(H.wear_suit)
+ H.unEquip(H.head)
+ H.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/black(H), slot_wear_suit)
+ H.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/black(H), slot_head)
\ No newline at end of file
diff --git a/code/datums/spells/summonitem.dm b/code/datums/spells/summonitem.dm
index e74ce4a92c6..7b29e448844 100644
--- a/code/datums/spells/summonitem.dm
+++ b/code/datums/spells/summonitem.dm
@@ -7,7 +7,7 @@
invocation = "GAR YOK"
invocation_type = "whisper"
range = -1
- level_max = 1 //cannot be improved
+ level_max = 0 //cannot be improved
cooldown_min = 100
include_user = 1
diff --git a/code/datums/wires/camera.dm b/code/datums/wires/camera.dm
deleted file mode 100644
index 33f8c1421a5..00000000000
--- a/code/datums/wires/camera.dm
+++ /dev/null
@@ -1,76 +0,0 @@
-// Wires for cameras.
-
-/datum/wires/camera
- random = 0
- holder_type = /obj/machinery/camera
- wire_count = 6
-
-/datum/wires/camera/GetInteractWindow()
-
- . = ..()
- var/obj/machinery/camera/C = holder
- . += " According to \the [src], you are now in \"[strip_html_properly(A.name)]\". According to \the [src], you are now in \"[html_encode(A.name)]\". According to \the [src], you are now in \"[strip_html_properly(A.name)]\". According to \the [src], you are now in \"[html_encode(A.name)]\". You may move an amendment to the drawing.
\n[(C.view_range == initial(C.view_range) ? "The focus light is on." : "The focus light is off.")]"
- . += "
\n[(C.can_use() ? "The power link light is on." : "The power link light is off.")]"
- . += "
\n[(C.light_disabled ? "The camera light is off." : "The camera light is on.")]"
- . += "
\n[(C.alarm_on ? "The alarm light is on." : "The alarm light is off.")]"
- return .
-
-/datum/wires/camera/CanUse(var/mob/living/L)
- var/obj/machinery/camera/C = holder
- if(!C.panel_open)
- return 0
- return 1
-
-var/const/CAMERA_WIRE_FOCUS = 1
-var/const/CAMERA_WIRE_POWER = 2
-var/const/CAMERA_WIRE_LIGHT = 4
-var/const/CAMERA_WIRE_ALARM = 8
-var/const/CAMERA_WIRE_NOTHING1 = 16
-var/const/CAMERA_WIRE_NOTHING2 = 32
-
-/datum/wires/camera/UpdateCut(var/index, var/mended)
- var/obj/machinery/camera/C = holder
-
- switch(index)
- if(CAMERA_WIRE_FOCUS)
- var/range = (mended ? initial(C.view_range) : C.short_range)
- C.setViewRange(range)
-
- if(CAMERA_WIRE_POWER)
- if(C.status && !mended || !C.status && mended)
- C.deactivate(usr, 1)
-
- if(CAMERA_WIRE_LIGHT)
- C.light_disabled = !mended
-
- if(CAMERA_WIRE_ALARM)
- if(!mended)
- C.triggerCameraAlarm()
- else
- C.cancelCameraAlarm()
- return
-
-/datum/wires/camera/UpdatePulsed(var/index)
- var/obj/machinery/camera/C = holder
- if(IsIndexCut(index))
- return
- switch(index)
- if(CAMERA_WIRE_FOCUS)
- var/new_range = (C.view_range == initial(C.view_range) ? C.short_range : initial(C.view_range))
- C.setViewRange(new_range)
-
- if(CAMERA_WIRE_POWER)
- C.deactivate(null) // Deactivate the camera
-
- if(CAMERA_WIRE_LIGHT)
- C.light_disabled = !C.light_disabled
-
- if(CAMERA_WIRE_ALARM)
- C.visible_message("\icon[C] *beep*", "\icon[C] *beep*")
- return
-
-/datum/wires/camera/proc/CanDeconstruct()
- if(IsIndexCut(CAMERA_WIRE_POWER) && IsIndexCut(CAMERA_WIRE_FOCUS) && IsIndexCut(CAMERA_WIRE_LIGHT) && IsIndexCut(CAMERA_WIRE_NOTHING1) && IsIndexCut(CAMERA_WIRE_NOTHING2))
- return 1
- else
- return 0
\ No newline at end of file
diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm
index ba6f252724a..e483513c40a 100644
--- a/code/datums/wires/wires.dm
+++ b/code/datums/wires/wires.dm
@@ -102,8 +102,7 @@ var/list/wireColours = list("red", "blue", "green", "black", "orange", "brown",
/datum/wires/Topic(href, href_list)
..()
- if(in_range(holder, usr) && isliving(usr))
-
+ if(usr.Adjacent(holder) && isliving(usr))
var/mob/living/L = usr
if(CanUse(L) && href_list["action"])
var/obj/item/I = L.get_active_hand()
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 8afadbc4ce8..cb638aa6f31 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -21,6 +21,10 @@
// replaced by OPENCONTAINER flags and atom/proc/is_open_container()
///Chemistry.
var/allow_spin = 1
+
+ //Value used to increment ex_act() if reactionary_explosions is on
+ var/explosion_block = 0
+
/atom/proc/onCentcom()
var/turf/T = get_turf(src)
if(!T)
diff --git a/code/game/communications.dm b/code/game/communications.dm
index 75155dff914..9f7d515a300 100644
--- a/code/game/communications.dm
+++ b/code/game/communications.dm
@@ -299,4 +299,4 @@ var/list/pointers = list()
for(var/d in data)
var/val = data[d]
if(istext(val))
- data[d] = strip_html_properly(val)
+ data[d] = html_encode(val)
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 4bfeecb2247..eddb0216d76 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -188,7 +188,7 @@
return 0
- if(living_antag_player && living_antag_player.mind && living_antag_player.stat != DEAD && !isnewplayer(living_antag_player) &&!isbrain(living_antag_player))
+ if(living_antag_player && living_antag_player.mind && isliving(living_antag_player) && living_antag_player.stat != DEAD && !isnewplayer(living_antag_player) &&!isbrain(living_antag_player))
return 0 //A resource saver: once we find someone who has to die for all antags to be dead, we can just keep checking them, cycling over everyone only when we lose our mark.
for(var/mob/Player in living_mob_list)
diff --git a/code/game/gamemodes/gang/dominator.dm b/code/game/gamemodes/gang/dominator.dm
new file mode 100644
index 00000000000..4fbae44af79
--- /dev/null
+++ b/code/game/gamemodes/gang/dominator.dm
@@ -0,0 +1,209 @@
+/obj/machinery/dominator
+ name = "dominator"
+ desc = "A visibly sinister device. Looks like you can break it if you hit it enough."
+ icon = 'icons/obj/machines/dominator.dmi'
+ icon_state = "dominator"
+ density = 1
+ anchored = 1.0
+ layer = 3.6
+ var/health = 200
+ var/gang
+ var/operating = 0
+ var/broken = 0
+
+/obj/machinery/dominator/New()
+ if(!istype(ticker.mode, /datum/game_mode/gang))
+ qdel(src)
+ return
+ SetLuminosity(2)
+
+/obj/machinery/dominator/examine(mob/user)
+ ..()
+ if(broken)
+ user << "It looks completely busted."
+ return
+
+ var/datum/game_mode/gang/mode = ticker.mode
+ var/time = null
+ if(isnum(mode.A_timer))
+ time = max(mode.A_timer, 0)
+ if(isnum(mode.B_timer))
+ time = max(mode.B_timer, 0)
+ if(isnum(time))
+ if(time > 0)
+ user << "Hostile Takeover in progress. Estimated [time] seconds remain."
+ else
+ user << "Hostile Takeover of [station_name()] successful. Have a great day."
+ else
+ user << "System on standby."
+ user << "System Integrity: [health/2]%"
+
+
+/obj/machinery/dominator/proc/healthcheck(var/damage)
+ var/iconname = "dominator"
+ if(gang)
+ iconname += "-[gang]"
+ SetLuminosity(3)
+
+ var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread
+
+ health -= damage
+
+ switch(health)
+ if(101 to INFINITY)
+ if(prob(damage*2))
+ sparks.set_up(5, 1, src)
+ sparks.start()
+ if(1 to 100)
+ sparks.set_up(5, 1, src)
+ sparks.start()
+ iconname += "-damaged"
+
+ if(!broken)
+ if(health <= 0)
+ set_broken()
+ else
+ icon_state = iconname
+
+ if(health <= -50)
+ new /obj/item/stack/sheet/plasteel(src.loc)
+ qdel(src)
+
+/obj/machinery/dominator/proc/set_broken()
+ if(!gang)
+ return
+ var/datum/game_mode/gang/mode = ticker.mode
+ if(gang == "A")
+ mode.A_timer = "OFFLINE"
+ if(gang == "B")
+ mode.B_timer = "OFFLINE"
+ if(!isnum(mode.A_timer) && !isnum(mode.B_timer))
+ SSshuttle.emergencyNoEscape = 0
+ if(SSshuttle.emergency.mode == SHUTTLE_STRANDED)
+ SSshuttle.emergency.mode = SHUTTLE_DOCKED
+ SSshuttle.emergency.timer = world.time
+ priority_announce("Hostile enviroment resolved. You have 3 minutes to board the Emergency Shuttle.", null, 'sound/AI/shuttledock.ogg', "Priority")
+ else
+ priority_announce("All hostile activity within station systems have ceased.","Network Alert")
+ SetLuminosity(0)
+ icon_state = "dominator-broken"
+ broken = 1
+
+/obj/machinery/dominator/Destroy()
+ if(!broken)
+ set_broken()
+ ..()
+
+/obj/machinery/dominator/emp_act(severity)
+ healthcheck(100)
+ ..()
+
+/obj/machinery/dominator/ex_act(severity, target)
+ if(target == src)
+ qdel(src)
+ return
+ switch(severity)
+ if(1.0)
+ qdel(src)
+ if(2.0)
+ healthcheck(120)
+ if(3.0)
+ healthcheck(30)
+ return
+
+/obj/machinery/dominator/bullet_act(var/obj/item/projectile/Proj)
+ if(Proj.damage)
+ if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
+ playsound(src, 'sound/effects/bang.ogg', 50, 1)
+ visible_message("[src] was hit by [Proj].")
+ healthcheck(Proj.damage)
+ ..()
+
+/obj/machinery/dominator/blob_act()
+ healthcheck(110)
+
+/obj/machinery/dominator/attackby(I as obj, user as mob, params)
+
+ return
+
+/obj/machinery/dominator/attack_hand(mob/user)
+ if(operating||broken)
+ examine(user)
+ return
+
+ var/datum/game_mode/gang/mode = ticker.mode
+ var/gang_territory
+ var/timer
+
+ var/tempgang
+ if(user.mind in (ticker.mode.A_gang|ticker.mode.A_bosses))
+ tempgang = "A"
+ gang_territory = ticker.mode.A_territory.len
+ timer = mode.A_timer
+ else if(user.mind in (ticker.mode.B_gang|ticker.mode.B_bosses))
+ tempgang = "B"
+ gang_territory = ticker.mode.B_territory.len
+ timer = mode.B_timer
+
+ if(!tempgang)
+ examine(user)
+ return
+
+ if(isnum(timer)) //In theory, this shouldn't happen. But if it does, they get this meme
+ user << "Error: Hostile Takeover is already in progress."
+ return
+
+ var/time = max(180,900 - ((round((gang_territory/start_state.num_territories)*200, 1) - 60) * 15))
+ if(alert(user,"With [round((gang_territory/start_state.num_territories)*100, 1)]% station control, a takeover will require [time] seconds.\nThe entire station will likely be alerted once it starts.\nYour gang must be prepared to defend this device throughout the duration.\nAre you ready?","Confirmation","Yes","No") == "Yes")
+ if ((!in_range(src, user) || !istype(src.loc, /turf)))
+ return 0
+ var/area/srcloc = get_area(src.loc)
+ gang = tempgang
+ mode.domination(gang,1,srcloc.name)
+ src.name = "[gang_name(gang)] Gang [src.name]"
+ healthcheck(0)
+ operating = 1
+
+/obj/machinery/dominator/attack_alien(mob/living/user)
+ user.do_attack_animation(src)
+ playsound(src, 'sound/effects/bang.ogg', 50, 1)
+ user.visible_message("[user] smashes against [src] with its claws.",\
+ "You smash against [src] with your claws.",\
+ "You hear metal scraping.")
+ healthcheck(15)
+
+/obj/machinery/dominator/attack_animal(mob/living/user as mob)
+ if(!isanimal(user))
+ return
+ var/mob/living/simple_animal/M = user
+ M.do_attack_animation(src)
+ if(M.melee_damage_upper <= 0)
+ return
+ healthcheck(M.melee_damage_upper)
+
+/obj/machinery/dominator/mech_melee_attack(obj/mecha/M)
+ if(M.damtype == "brute")
+ playsound(src, 'sound/effects/bang.ogg', 50, 1)
+ visible_message("[M.name] has hit [src].")
+ healthcheck(M.force)
+ return
+
+/obj/machinery/dominator/attack_hulk(mob/user)
+ playsound(src, 'sound/effects/bang.ogg', 50, 1)
+ user.visible_message("[user] smashes [src].",\
+ "You punch [src].",\
+ "You hear metal being slammed.")
+ healthcheck(5)
+
+/obj/machinery/dominator/attackby(obj/item/weapon/I as obj, mob/living/user as mob, params)
+ if(istype(I, /obj/item/weapon))
+ add_fingerprint(user)
+ user.changeNext_move(CLICK_CD_MELEE)
+ user.do_attack_animation(src)
+ if( (I.flags&NOBLUDGEON) || !I.force )
+ return
+ playsound(src, 'sound/weapons/smash.ogg', 50, 1)
+ visible_message("[user] has hit \the [src] with [I].")
+ if(I.damtype == BURN || I.damtype == BRUTE)
+ healthcheck(I.force)
+ return
diff --git a/code/game/gamemodes/gang/gang.dm b/code/game/gamemodes/gang/gang.dm
index 6967dc894c7..97ed4eecbcd 100644
--- a/code/game/gamemodes/gang/gang.dm
+++ b/code/game/gamemodes/gang/gang.dm
@@ -15,6 +15,10 @@
var/list/A_territory_lost = list()
var/list/B_territory_new = list()
var/list/B_territory_lost = list()
+ var/gang_A_style
+ var/gang_A_headgear
+ var/gang_B_style
+ var/gang_B_headgear
/datum/game_mode/gang
name = "gang war"
@@ -26,14 +30,15 @@
recommended_enemies = 2
enemy_minimum_age = 14
var/finished = 0
- var/goal_scalar = 0.5 //Goal = Total territories x goal_scalar
-
+ // Victory timers
+ var/A_timer = "OFFLINE"
+ var/B_timer = "OFFLINE"
///////////////////////////
//Announces the game type//
///////////////////////////
/datum/game_mode/gang/announce()
world << "The current game mode is - Gang War!"
- world << "A violent turf war has erupted on the station!
Gangsters - Take over the station by claiming more than [round(100*goal_scalar,1)]% of the station!
Crew - The gangs will try to keep you on the station. Successfully evacuate the station to win!"
+ world << "A violent turf war has erupted on the station!
Gangsters - Take over the station by activating and defending a Dominator!
Crew - The gangs will try to keep you on the station. Successfully evacuate the station to win!"
///////////////////////////////////////////////////////////////////////////////
@@ -73,6 +78,15 @@
modePlayer += B_bosses
..()
+/datum/game_mode/gang/process(seconds)
+ if(!finished)
+ if(isnum(A_timer))
+ A_timer -= seconds
+ if(isnum(B_timer))
+ B_timer -= seconds
+
+ ticker.mode.check_win()
+
/datum/game_mode/gang/proc/assign_bosses()
var/datum/mind/boss = pick(antag_candidates)
A_bosses += boss
@@ -91,7 +105,7 @@
/datum/game_mode/proc/forge_gang_objectives(var/datum/mind/boss_mind)
var/datum/objective/rival_obj = new
rival_obj.owner = boss_mind
- rival_obj.explanation_text = "Claim more than 50% the station before the [(boss_mind in A_bosses) ? gang_name("B") : gang_name("A")] Gang does."
+ rival_obj.explanation_text = "Preform a hostile takeover of the station with a Dominator."
boss_mind.objectives += rival_obj
@@ -103,6 +117,17 @@
boss_mind.current << "Objective #[obj_count]: [objective.explanation_text]"
obj_count++
+/datum/game_mode/gang/proc/domination(var/gang,var/modifier=1,var/dominatorloc)
+ if(gang=="A")
+ A_timer = max(180,900 - ((round((ticker.mode.A_territory.len/start_state.num_territories)*200, 1) - 60) * 15)) * modifier
+ if(gang=="B")
+ B_timer = max(180,900 - ((round((ticker.mode.B_territory.len/start_state.num_territories)*200, 1) - 60) * 15)) * modifier
+ if(gang && dominatorloc)
+ priority_announce("Hostile runtimes detected in all station systems. A network breach by the [gang_name(gang)] Gang has been traced to [dominatorloc].","Network Alert")
+ if(get_security_level() != "delta")
+ set_security_level("red")
+ SSshuttle.emergencyNoEscape = 1
+
///////////////////////////////////////////////////////////////////////////
//This equips the bosses with their gear, and makes the clown not clumsy//
///////////////////////////////////////////////////////////////////////////
@@ -132,37 +157,107 @@
var/where = mob.equip_in_one_of_slots(gangtool, slots)
if (!where)
mob << "Your Syndicate benefactors were unfortunately unable to get you a Gangtool."
+ . += 1
else
gangtool.register_device(mob)
- mob << "The Gangtool in your [where] will allow you to use your influence to purchase items and prevent the station from evacuating before you can take over. Use it to recall the emergency shuttle from anywhere on the station."
+ mob << "The Gangtool in your [where] will allow you to purchase items, send messages to your gangsters and to recall the emergency shuttle from anywhere on the station."
mob << "You can also promote your gang members to lieutenant by giving them an unregistered gangtool. Lieutenants cannot be deconverted and are able to use recruitment pens and gangtools."
- . += 1
var/where2 = mob.equip_in_one_of_slots(T, slots)
if (!where2)
mob << "Your Syndicate benefactors were unfortunately unable to get you a recruitment pen to start."
+ . += 1
else
mob << "The recruitment pen in your [where2] will help you get your gang started. Use it on unsuspecting crew members to recruit them."
- . += 1
var/where3 = mob.equip_in_one_of_slots(SC, slots)
if (!where3)
mob << "Your Syndicate benefactors were unfortunately unable to get you a territory spraycan to start."
+ . += 1
else
mob << "The territory spraycan in your [where3] can be used to claim areas of the station for your gang. The more territory your gang controls, the more influence you get. Distribute these to your gangsters to grow your influence faster."
- . += 1
mob.update_icons()
return .
+//Used by recallers when purchasing a gang outfit. First time a gang outfit is purchased the buyer decides a gang style which is stored so gang outfits are uniform
+/datum/game_mode/proc/gang_outfit(mob/user,var/obj/item/device/gangtool/gangtool,var/gang)
+ if(!user || !gangtool || !gang)
+ return 0
+ if(!gangtool.can_use(user))
+ return 0
+
+ var/gang_style_list = list("Gang Colors","Leather Jackets","Fine Suits")
+ var/style
+ var/headgear
+ if(gang == "A")
+ if(!gang_A_style)
+ gang_A_style = input("Pick an outfit style.", "Pick Style") as null|anything in gang_style_list
+ if(gang_A_style && (alert(user,"Include headgear?","Option","Yes","No") == "Yes"))
+ gang_A_headgear = 1
+ style = gang_A_style
+ headgear = gang_A_headgear
+
+ if(gang == "B")
+ if(!gang_B_style)
+ gang_B_style = input("Pick an outfit style.", "Pick Style") as null|anything in gang_style_list
+ if(gang_B_style && (alert(user,"Include headgear?","Option","Yes","No") == "Yes"))
+ gang_B_headgear = 1
+ style = gang_B_style
+ headgear = gang_B_headgear
+
+ if(!style)
+ return 0
+
+ if(gangtool.can_use(user) && (((gang == "A") ? gang_points.A : gang_points.B) >= 1))
+ switch(style)
+ if("Gang Colors")
+ if(gang == "A")
+ new /obj/item/clothing/under/color/blue(user.loc)
+ if(headgear)
+ new /obj/item/clothing/mask/bandana/blue(user.loc)
+ if(gang == "B")
+ new /obj/item/clothing/under/color/red(user.loc)
+ if(headgear)
+ new /obj/item/clothing/mask/bandana/red(user.loc)
+ if("Leather Jackets")
+ new /obj/item/clothing/suit/jacket/leather(user.loc)
+ if(headgear)
+ if(gang == "A")
+ new /obj/item/clothing/mask/bandana/blue(user.loc)
+ if(gang == "B")
+ new /obj/item/clothing/mask/bandana/red(user.loc)
+ if("Fine Suits")
+ new /obj/item/clothing/under/suit_jacket/really_black(user.loc)
+ if(headgear)
+ new /obj/item/clothing/head/fedora(user.loc)
+
+ return 1
+
+ return 0
+
/////////////////////////////////////////////
//Checks if the either gang have won or not//
/////////////////////////////////////////////
/datum/game_mode/gang/check_win()
- if(A_territory.len > (start_state.num_territories * goal_scalar))
- finished = "A" //Gang A wins
- else if(B_territory.len > (start_state.num_territories * goal_scalar))
- finished = "B" //Gang B wins
+ var/winner = 0
+
+ if(isnum(A_timer))
+ if(A_timer < 0)
+ winner += 1
+ if(isnum(B_timer))
+ if(B_timer < 0)
+ winner += 2
+
+ if(winner)
+ if(winner == 3) //Edge Case: If both dominators activate at the same time
+ domination("A",0.5)
+ domination("B",0.5)
+ priority_announce("Multiple station takeover attempts have made simultaneously. Conflicting hostile runtimes have delayed both attempts.","Network Alert")
+ else if(winner == 1)
+ finished = "A" //Gang A wins
+ else if(winner == 2)
+ finished = "B" //Gang B wins
///////////////////////////////
//Checks if the round is over//
@@ -282,7 +377,7 @@
if(!finished)
world << "The station was [station_was_nuked ? "destroyed!" : "evacuated before either gang could claim it!"]"
else
- world << "The [finished=="A" ? gang_name("A") : gang_name("B")] Gang has claimed over [round(100*goal_scalar,1)]% of the station and has assumed control!"
+ world << "The [finished=="A" ? gang_name("A") : gang_name("B")] Gang successfully preformed a hostile takeover of the station!!"
..()
return 1
@@ -338,8 +433,8 @@
//////////////////////////////////////////////////////////
/datum/gang_points
- var/A = 30
- var/B = 30
+ var/A = 25
+ var/B = 25
var/next_point_interval = 1800
var/next_point_time
@@ -429,12 +524,9 @@
var/A_control = round((ticker.mode.A_territory.len/start_state.num_territories)*100, 1)
var/B_control = round((ticker.mode.B_territory.len/start_state.num_territories)*100, 1)
ticker.mode.message_gangtools((ticker.mode.A_tools),"Your gang now has [A_control]% control of the station.",0)
- ticker.mode.message_gangtools((ticker.mode.A_tools),"The [gang_name("B")] Gang has [B_control]% control of the station.",0,1)
+ //ticker.mode.message_gangtools((ticker.mode.A_tools),"The [gang_name("B")] Gang has [B_control]% control of the station.",0,1)
ticker.mode.message_gangtools((ticker.mode.B_tools),"Your gang now has [B_control]% control of the station.",0)
- ticker.mode.message_gangtools((ticker.mode.B_tools),"The [gang_name("A")] Gang has [A_control]% control of the station.",0,1)
-
- //Victory check
- ticker.mode.check_win()
+ //ticker.mode.message_gangtools((ticker.mode.B_tools),"The [gang_name("A")] Gang has [A_control]% control of the station.",0,1)
//Restart the counter
start()
diff --git a/code/game/objects/items/devices/recaller.dm b/code/game/gamemodes/gang/recaller.dm
similarity index 72%
rename from code/game/objects/items/devices/recaller.dm
rename to code/game/gamemodes/gang/recaller.dm
index de3f046635c..addef28d740 100644
--- a/code/game/objects/items/devices/recaller.dm
+++ b/code/game/gamemodes/gang/recaller.dm
@@ -2,7 +2,7 @@
/obj/item/device/gangtool
name = "suspicious device"
desc = "A strange device of sorts. Hard to really make out what it actually does just by looking."
- icon_state = "recaller"
+ icon_state = "gangtool"
item_state = "walkietalkie"
throwforce = 0
w_class = 1.0
@@ -33,30 +33,28 @@
else
dat += "Register Device
"
else
+ var/datum/game_mode/gang/gangmode
+ if(istype(ticker.mode, /datum/game_mode/gang))
+ gangmode = ticker.mode
+
var/gang_size = ((gang == "A")? (ticker.mode.A_gang.len + ticker.mode.A_bosses.len) : (ticker.mode.B_gang.len + ticker.mode.B_bosses.len))
var/gang_territory = ((gang == "A")? ticker.mode.A_territory.len : ticker.mode.B_territory.len)
var/points = ((gang == "A") ? ticker.mode.gang_points.A : ticker.mode.gang_points.B)
+ var/timer
+ if(gangmode)
+ timer = ((gang == "A") ? gangmode.A_timer : gangmode.B_timer)
+ if(isnum(timer))
+ dat += "
[timer] seconds remain
"
dat += "Registration: [(gang == "A")? gang_name("A") : gang_name("B")] Gang [boss ? "Administrator" : "Lieutenant"]
"
- dat += "Organization Size: [gang_size]
"
- dat += "Station Control: [round((gang_territory/start_state.num_territories)*100, 1)]%
"
+ dat += "Organization Size: [gang_size] | Station Control: [round((gang_territory/start_state.num_territories)*100, 1)]%
"
+ dat += "Send Gang-wide Message
"
dat += "Recall Emergency Shuttle
"
dat += "
"
dat += "Influence: [points]
"
- dat += "Time until Influence grows: [(points >= 100) ? ("--:--") : (time2text(ticker.mode.gang_points.next_point_time - world.time, "mm:ss"))]
"
- dat += "Purchase Items:
"
-
- dat += "(5 Influence) "
- if(points >= 5)
- dat += "Send Gang-wide Message
"
- else
- dat += "Send Gang-wide Message
"
-
- dat += "(10 Influence) "
- if(points >= 10)
- dat += "Territory Spraycan
"
- else
- dat += "Territory Spraycan
"
+ dat += "Time until Influence grows: [(points >= 999) ? ("--:--") : (time2text(ticker.mode.gang_points.next_point_time - world.time, "mm:ss"))]
"
+ dat += "
"
+ dat += "Purchase Weapons:
"
dat += "(10 Influence) "
if(points >= 10)
@@ -64,8 +62,8 @@
else
dat += "Switchblade
"
- dat += "(25 Influence) "
- if(points >= 25)
+ dat += "(20 Influence) "
+ if(points >= 20)
dat += "10mm Pistol
"
else
dat += "10mm Pistol
"
@@ -76,8 +74,35 @@
else
dat += "10mm Ammo
"
- dat += "(40 Influence) "
- if(points >= 40)
+ dat += "(50 Influence) "
+ if(points >= 50)
+ dat += "Thompson SMG
"
+ else
+ dat += "Thompson SMG
"
+
+ dat += "
"
+ dat += "Purchase Utilities:
"
+
+ dat += "(10 Influence) "
+ if(points >= 10)
+ dat += "Territory Spraycan
"
+ else
+ dat += "Territory Spraycan
"
+
+ dat += "(1 Influence) "
+ if(points >= 1)
+ dat += "Gang Outfit
"
+ else
+ dat += "Gang Outfit
"
+
+ dat += "(10 Influence) "
+ if(points >= 10)
+ dat += "Bulletproof Vest
"
+ else
+ dat += "Bulletproof Vest
"
+
+ dat += "(30 Influence) "
+ if(points >= 30)
dat += "Recruitment Pen
"
else
dat += "Recruitment Pen
"
@@ -91,14 +116,23 @@
dat += "Promote a Gangster
"
else
dat += "Promote a Gangster
"
+ if(gangmode)
+ dat += "(50 Influence) "
+ if(points >= 50)
+ dat += "Station Dominator
"
+ dat += "(Estimated Takeover Time: [round(max(180,900 - ((round((gang_territory/start_state.num_territories)*200, 10) - 60) * 15))/60,1)] minutes)
"
+ else
+ dat += "Station Dominator
"
dat += "
"
dat += "Refresh
"
- var/datum/browser/popup = new(user, "gangtool", "Welcome to GangTool v0.4")
+ var/datum/browser/popup = new(user, "gangtool", "Welcome to GangTool v0.4", 350, 550)
popup.set_content(dat)
popup.open()
+
+
/obj/item/device/gangtool/Topic(href, href_list)
if(!can_use(usr))
return
@@ -115,6 +149,10 @@
var/points = ((gang == "A") ? ticker.mode.gang_points.A : ticker.mode.gang_points.B)
var/item_type
switch(href_list["purchase"])
+ if("outfit")
+ if(points >= 1)
+ item_type = ticker.mode.gang_outfit(usr,src,gang)
+ points = 1
if("spraycan")
if(points >= 10)
item_type = /obj/item/toy/crayon/spraycan/gang
@@ -124,31 +162,60 @@
item_type = /obj/item/weapon/switchblade
points = 10
if("pistol")
- if(points >= 25)
+ if(points >= 20)
item_type = /obj/item/weapon/gun/projectile/automatic/pistol
- points = 25
+ points = 20
if("ammo")
if(points >= 10)
item_type = /obj/item/ammo_box/magazine/m10mm
points = 10
+ if("SMG")
+ if(points >= 50)
+ item_type = /obj/item/weapon/gun/projectile/automatic/tommygun
+ points = 50
+ if("vest")
+ if(points >= 10)
+ item_type = /obj/item/clothing/suit/armor/bulletproof
+ points = 10
if("pen")
- if(points >= 40)
+ if(points >= 30)
item_type = /obj/item/weapon/pen/gang
- points = 40
+ points = 30
if("gangtool")
if((promotions < 3) && (points >= (promotions*20)+10))
item_type = /obj/item/device/gangtool/lt
points = (promotions*20)+10
promotions++
+ if("dominator")
+ if(istype(ticker.mode, /datum/game_mode/gang))
+ var/datum/game_mode/gang/mode = ticker.mode
+ if(isnum((gang == "A") ? mode.A_timer : mode.B_timer))
+ return
+
+ var/fail = 0
+ var/usrarea = get_area(usr.loc)
+ var/usrturf = get_turf(usr.loc)
+ if(istype(usrarea,/area/space) || istype(usrturf,/turf/space) || usr.z != 1)
+ usr << "You can only use this on the station!"
+ fail = 1
+ for(var/obj/obj in usrturf)
+ if(obj.density)
+ usr << "There's not enough room here!"
+ fail = 1
+ break
+ if(!fail && points >= 50)
+ item_type = /obj/machinery/dominator
+ points = 50
if(item_type)
if(gang == "A")
ticker.mode.gang_points.A -= points
else if(gang == "B")
ticker.mode.gang_points.B -= points
- var/obj/purchased = new item_type(get_turf(usr))
- var/mob/living/carbon/human/H = usr
- H.put_in_any_hand_if_possible(purchased)
+ if(ispath(item_type))
+ var/obj/purchased = new item_type(get_turf(usr))
+ var/mob/living/carbon/human/H = usr
+ H.put_in_any_hand_if_possible(purchased)
ticker.mode.message_gangtools(((gang=="A")? ticker.mode.A_tools : ticker.mode.B_tools), "A [href_list["purchase"]] was purchased by [usr] for [points] Influence.")
log_game("A [href_list["purchase"]] was purchased by [key_name(usr)] for [points] Influence.")
@@ -172,18 +239,16 @@
return
var/list/members = list()
if(gang == "A")
- if(ticker.mode.gang_points.A >= 5)
- members += ticker.mode.A_bosses | ticker.mode.A_gang
- ticker.mode.gang_points.A -= 5
+ members += ticker.mode.A_bosses | ticker.mode.A_gang
else if(gang == "B")
- if(ticker.mode.gang_points.B >= 5)
- members += ticker.mode.B_bosses | ticker.mode.B_gang
- ticker.mode.gang_points.B -= 5
+ members += ticker.mode.B_bosses | ticker.mode.B_gang
if(members.len)
+ var/ping = "[boss ? "Gang Boss" : "Gang Lieutenant"]: [message]"
for(var/datum/mind/ganger in members)
if(ganger.current.z <= 2)
- ganger.current << "BOSS: [message]"
- message_admins("[key_name_admin(user)] sent a global message to the [gang_name(gang)] Gang ([gang]): [message].")
+ ganger.current << "[ping]"
+ for(var/mob/M in dead_mob_list)
+ M << "[gang_name(gang)] [ping]"
log_game("[key_name(user)] sent a global message to the [gang_name(gang)] Gang ([gang]): [message].")
@@ -196,6 +261,7 @@
if(user.mind in (ticker.mode.A_gang | ticker.mode.A_bosses))
ticker.mode.A_tools += src
gang = "A"
+ icon_state = "gangtool-a"
if(!(user.mind in ticker.mode.A_bosses))
ticker.mode.remove_gangster(user.mind, 0, 2)
ticker.mode.A_bosses += user.mind
@@ -206,6 +272,7 @@
else if(user.mind in (ticker.mode.B_gang | ticker.mode.B_bosses))
ticker.mode.B_tools += src
gang = "B"
+ icon_state = "gangtool-b"
if(!(user.mind in ticker.mode.B_bosses))
ticker.mode.remove_gangster(user.mind, 0, 2)
ticker.mode.B_bosses += user.mind
@@ -218,7 +285,7 @@
user << "You have been promoted to Lieutenant!"
ticker.mode.forge_gang_objectives(user.mind)
ticker.mode.greet_gang(user.mind,0)
- user << "The Gangtool you registered will allow you to use your gang's influence to purchase items and prevent the station from evacuating before your gang can take over. Use it to recall the emergency shuttle from anywhere on the station."
+ user << "The Gangtool you registered will allow you to purchase items, send messages to your gangsters and to recall the emergency shuttle from anywhere on the station."
user << "You may also now use recruitment pens to grow your gang membership. Use them on unsuspecting crew members to recruit them."
if(!gang)
usr << "ACCESS DENIED: Unauthorized user."
diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm
index 8a58076e663..da2e49f4af7 100644
--- a/code/game/gamemodes/wizard/spellbook.dm
+++ b/code/game/gamemodes/wizard/spellbook.dm
@@ -182,6 +182,11 @@
log_name = "IS"
category = "Utility Spells"
+/datum/spellbook_entry/lichdom
+ name = "Bind Soul"
+ spell_type = /obj/effect/proc_holder/spell/targeted/lichdom
+ log_name = "LD"
+
/datum/spellbook_entry/lightningbolt
name = "Lightning Bolt"
spell_type = /obj/effect/proc_holder/spell/targeted/lightning
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index 78297803c2a..76623347eb9 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -18,7 +18,8 @@
var/list/injection_chems = list() //list of injectable chems except ephedrine, coz ephedrine is always avalible
var/list/possible_chems = list(list("morphine", "salbutamol", "salglu_solution"),
list("morphine", "salbutamol", "salglu_solution", "oculine"),
- list("morphine", "salbutamol", "salglu_solution", "oculine", "charcoal", "mutadone", "mannitol", "pen_acid"))
+ list("morphine", "salbutamol", "salglu_solution", "oculine", "charcoal", "mutadone", "mannitol", "pen_acid"),
+ list("morphine", "salbutamol", "salglu_solution", "oculine", "charcoal", "mutadone", "mannitol", "omnizine"))
/obj/machinery/sleeper/New()
..()
component_parts = list()
diff --git a/code/game/machinery/atmo_control.dm b/code/game/machinery/atmo_control.dm
index 87eb95b4f42..abb5bc29586 100644
--- a/code/game/machinery/atmo_control.dm
+++ b/code/game/machinery/atmo_control.dm
@@ -78,6 +78,7 @@
set_frequency(frequency)
/obj/machinery/air_sensor/Destroy()
+ SSair.atmos_machinery -= src
if(radio_controller)
radio_controller.remove_object(src,frequency)
..()
diff --git a/code/game/machinery/atmoalter/meter.dm b/code/game/machinery/atmoalter/meter.dm
index d8ba823694b..99bd769543a 100644
--- a/code/game/machinery/atmoalter/meter.dm
+++ b/code/game/machinery/atmoalter/meter.dm
@@ -18,6 +18,11 @@
src.target = locate(/obj/machinery/atmospherics/pipe) in loc
return 1
+/obj/machinery/meter/Destroy()
+ SSair.atmos_machinery -= src
+ src.target = null
+ ..()
+
/obj/machinery/meter/initialize()
if (!target)
src.target = locate(/obj/machinery/atmospherics/pipe) in loc
diff --git a/code/game/machinery/atmoalter/zvent.dm b/code/game/machinery/atmoalter/zvent.dm
index 26bd2cff6c1..42e1926ef4e 100644
--- a/code/game/machinery/atmoalter/zvent.dm
+++ b/code/game/machinery/atmoalter/zvent.dm
@@ -9,6 +9,14 @@
var/on = 0
var/volume_rate = 800
+/obj/machinery/zvent/New()
+ ..()
+ SSair.atmos_machinery += src
+
+/obj/machinery/zvent/Destroy()
+ SSair.atmos_machinery -= src
+ ..()
+
/obj/machinery/zvent/process_atmos()
//all this object does, is make its turf share air with the ones above and below it, if they have a vent too.
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index ca4b9fdd034..ae2204f9da3 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -8,12 +8,12 @@
active_power_usage = 10
layer = 5
- var/datum/wires/camera/wires = null // Wires datum
+ var/health = 50
var/list/network = list("SS13")
var/c_tag = null
var/c_tag_order = 999
- var/status = 1.0
- anchored = 1.0
+ var/status = 1
+ anchored = 1
var/start_active = 0 //If it ignores the random chance to start broken on round start
var/invuln = null
var/obj/item/device/camera_bug/bug = null
@@ -30,8 +30,6 @@
var/emped = 0 //Number of consecutive EMP's on this camera
/obj/machinery/camera/New()
- wires = new(src)
-
assembly = new(src)
assembly.state = 4
assembly.anchored = 1
@@ -59,20 +57,18 @@
if(bug.current == src)
bug.current = null
bug = null
- qdel(wires)
cameranet.removeCamera(src) //Will handle removal from the camera network and the chunks, so we don't need to worry about that
..()
/obj/machinery/camera/emp_act(severity)
if(!isEmpProof())
- if(prob(100/severity))
+ if(prob(150/severity))
icon_state = "[initial(icon_state)]emp"
var/list/previous_network = network
network = list()
cameranet.removeCamera(src)
stat |= EMPED
SetLuminosity(0)
- triggerCameraAlarm()
emped = emped+1 //Increase the number of consecutive EMP's
var/thisemp = emped //Take note of which EMP this proc is for
spawn(900)
@@ -81,10 +77,12 @@
network = previous_network
icon_state = initial(icon_state)
stat &= ~EMPED
- cancelCameraAlarm()
if(can_use())
cameranet.addCamera(src)
emped = 0 //Resets the consecutive EMP count
+ triggerCameraAlarm()
+ spawn(100)
+ cancelCameraAlarm()
for(var/mob/O in mob_list)
if (O.client && O.client.eye == src)
O.unset_machine()
@@ -117,66 +115,71 @@
if(!istype(user))
return
user.do_attack_animation(src)
- status = 0
+ add_hiddenprint(user)
visible_message("\The [user] slashes at [src]!")
playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
- icon_state = "[initial(icon_state)]1"
- add_hiddenprint(user)
- deactivate(user,0)
+ health = max(0, health - 30)
+ if(!health && status)
+ deactivate(user, 0)
-/obj/machinery/camera/attackby(W as obj, mob/living/user as mob, params)
- var/msg = "You attach [W] into the assembly inner circuits."
- var/msg2 = "The camera already has that upgrade!"
+/obj/machinery/camera/attackby(obj/W, mob/living/user, params)
+ var/msg = "You attach [W] into the assembly's inner circuits."
+ var/msg2 = "[src] already has that upgrade!"
// DECONSTRUCTION
if(istype(W, /obj/item/weapon/screwdriver))
- //user << "You start to [panel_open ? "close" : "open"] the camera's panel."
- //if(toggle_panel(user)) // No delay because no one likes screwdrivers trying to be hip and have a duration cooldown
panel_open = !panel_open
- user.visible_message("[user] screws the camera's panel [panel_open ? "open" : "closed"]!",
- "You screw the camera's panel [panel_open ? "open" : "closed"].")
+ user << "You screw the camera's panel [panel_open ? "open" : "closed"]."
playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ return
- else if((istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/device/multitool)) && panel_open)
- wires.Interact(user)
+ if(panel_open)
+ if(istype(W, /obj/item/weapon/wirecutters)) //enable/disable the camera
+ deactivate(user, 1)
+ health = initial(health) //this is a pretty simplistic way to heal the camera, but there's no reason for this to be complex.
- else if(istype(W, /obj/item/weapon/weldingtool) && wires.CanDeconstruct())
- if(weld(W, user))
- user << "You unweld the camera leaving it as just a frame screwed to the wall."
- if(!assembly)
- assembly = new()
- assembly.loc = src.loc
- assembly.state = 1
- assembly.dir = src.dir
- assembly.update_icon()
- assembly = null
- qdel(src)
- return
- else if(istype(W, /obj/item/device/analyzer) && panel_open) //XRay
- if(!isXRay())
- upgradeXRay()
- qdel(W)
- user << "[msg]"
- else
- user << "[msg2]"
+ else if(istype(W, /obj/item/device/multitool)) //change focus
+ setViewRange((view_range == initial(view_range)) ? short_range : initial(view_range))
+ user << "You [(view_range == initial(view_range)) ? "restore" : "mess up"] the camera's focus."
- else if(istype(W, /obj/item/stack/sheet/mineral/plasma) && panel_open)
- if(!isEmpProof())
- upgradeEmpProof()
- user << "[msg]"
- qdel(W)
- else
- user << "[msg2]"
- else if(istype(W, /obj/item/device/assembly/prox_sensor) && panel_open)
- if(!isMotion())
- upgradeMotion()
- user << "[msg]"
- qdel(W)
- else
- user << "[msg2]"
+ else if(istype(W, /obj/item/weapon/weldingtool))
+ if(weld(W, user))
+ visible_message("[user] unwelds [src], leaving it as just a frame screwed to the wall.", "You unweld [src], leaving it as just a frame screwed to the wall")
+ if(!assembly)
+ assembly = new()
+ assembly.loc = src.loc
+ assembly.state = 1
+ assembly.dir = src.dir
+ assembly.update_icon()
+ assembly = null
+ qdel(src)
+ return
+
+ else if(istype(W, /obj/item/device/analyzer))
+ if(!isXRay())
+ upgradeXRay()
+ qdel(W)
+ user << "[msg]"
+ else
+ user << "[msg2]"
+
+ else if(istype(W, /obj/item/stack/sheet/mineral/plasma))
+ if(!isEmpProof())
+ upgradeEmpProof()
+ user << "[msg]"
+ qdel(W)
+ else
+ user << "[msg2]"
+ else if(istype(W, /obj/item/device/assembly/prox_sensor))
+ if(!isMotion())
+ upgradeMotion()
+ user << "[msg]"
+ qdel(W)
+ else
+ user << "[msg2]"
// OTHER
- else if ((istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/device/pda)) && isliving(user))
+ if((istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/device/pda)) && isliving(user))
var/mob/living/U = user
var/obj/item/weapon/paper/X = null
var/obj/item/device/pda/P = null
@@ -204,6 +207,7 @@
else if (O.client && O.client.eye == src)
O << "[U] holds \a [itemname] up to one of the cameras ..."
O << browse(text("", "\[list\]")
note = replacetext(note, "
", "\[/list\]")
- note = strip_html_properly(note)
+ note = html_encode(note)
notescanned = 1
user << "Paper scanned. Saved to PDA's notekeeper." //concept of scanning paper copyright brainoblivion 2009
@@ -1186,7 +1186,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
//ntrc handler proc
/obj/item/device/pda/proc/msg_chat(channel as text, sender as text, message as text)
- var/msg = "[strip_html_properly(sender)]| [strip_html_properly(message)]
"
+ var/msg = "[html_encode(sender)]| [html_encode(message)]
"
if(!channel)
for(var/C in ntrclog)
ntrclog[C] = msg + ntrclog[C]
diff --git a/code/game/objects/items/devices/PDA/chatroom.dm b/code/game/objects/items/devices/PDA/chatroom.dm
index 1cc8d642cd3..a46b4def36f 100644
--- a/code/game/objects/items/devices/PDA/chatroom.dm
+++ b/code/game/objects/items/devices/PDA/chatroom.dm
@@ -66,7 +66,7 @@ var/list/chatchannels = list(default_ntrc_chatroom.name = default_ntrc_chatroom)
/datum/chatroom/proc/send_message(client,nick,message) //standard message
if(!message)
return 0
- logs.Insert(1,"[strip_html_properly(nick)]> [strip_html_properly(message)]")
+ logs.Insert(1,"[html_encode(nick)]> [html_encode(message)]")
log_chat("[usr]/([usr.ckey]) as [nick] sent to [name]: [message]")
events.fireEvent("msg_chat",name,nick,message)
return 1
diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm
index 862fc2a89b8..bca8126ad81 100644
--- a/code/game/objects/items/devices/multitool.dm
+++ b/code/game/objects/items/devices/multitool.dm
@@ -30,23 +30,24 @@
..()
SSobj.processing += src
-
/obj/item/device/multitool/ai_detect/Destroy()
SSobj.processing -= src
..()
/obj/item/device/multitool/ai_detect/process()
-
if(track_delay > world.time)
return
var/found_eye = 0
var/turf/our_turf = get_turf(src)
- if(cameranet.chunkGenerated(our_turf.x, our_turf.y, our_turf.z))
+ for(var/mob/living/silicon/ai/AI in ai_list)
+ if(AI.cameraFollow == src)
+ found_eye = 1
+ break
+ if(!found_eye && cameranet.chunkGenerated(our_turf.x, our_turf.y, our_turf.z))
var/datum/camerachunk/chunk = cameranet.getCameraChunk(our_turf.x, our_turf.y, our_turf.z)
-
if(chunk)
if(chunk.seenby.len)
for(var/mob/camera/aiEye/A in chunk.seenby)
@@ -62,4 +63,3 @@
track_delay = world.time + 10 // 1 second
return
-
diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm
index 2a8ef3cae0b..fd5cb821462 100644
--- a/code/game/objects/items/devices/taperecorder.dm
+++ b/code/game/objects/items/devices/taperecorder.dm
@@ -100,7 +100,7 @@
/obj/item/device/taperecorder/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans)
if(mytape && recording)
mytape.timestamp += mytape.used_capacity
- mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [strip_html_properly(message)]"
+ mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [html_encode(message)]"
/obj/item/device/taperecorder/verb/record()
set name = "Start Recording"
diff --git a/code/game/objects/items/holotape.dm b/code/game/objects/items/holotape.dm
index bd10a107cad..68070972d6e 100644
--- a/code/game/objects/items/holotape.dm
+++ b/code/game/objects/items/holotape.dm
@@ -153,6 +153,8 @@
charging = 0
/obj/item/holotape/Bumped(var/mob/M)
+ if(!ismob(M))
+ return
if(iscarbon(M))
var/mob/living/carbon/C = M
if(C.m_intent == "walk")
@@ -227,11 +229,11 @@
/obj/item/holotape/proc/breaktape()
var/dir[2]
- var/icon_dir = src.icon_state
- if(icon_dir == "[src.icon_base]_h")
+ var/icon_dir = icon_state
+ if(icon_dir == "[icon_base]_h")
dir[1] = EAST
dir[2] = WEST
- if(icon_dir == "[src.icon_base]_v")
+ if(icon_dir == "[icon_base]_v")
dir[1] = NORTH
dir[2] = SOUTH
diff --git a/code/game/objects/items/stacks/sheets/sheets.dm b/code/game/objects/items/stacks/sheets/sheets.dm
index 34522d2ec59..35d3ae089ce 100644
--- a/code/game/objects/items/stacks/sheets/sheets.dm
+++ b/code/game/objects/items/stacks/sheets/sheets.dm
@@ -8,18 +8,4 @@
throw_range = 3
attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "smashed")
var/perunit = MINERAL_MATERIAL_AMOUNT
- var/sheettype = null //this is used for girders in the creation of walls/false walls
-
-
-// Since the sheetsnatcher was consolidated into weapon/storage/bag we now use
-// item/attackby() properly, making this unnecessary
-
-/*/obj/item/stack/sheet/attackby(obj/item/weapon/W as obj, mob/user as mob)
- if (istype(W, /obj/item/weapon/storage/bag/sheetsnatcher))
- var/obj/item/weapon/storage/bag/sheetsnatcher/S = W
- if(!S.mode)
- S.add(src,user)
- else
- for (var/obj/item/stack/sheet/stack in locate(src.x,src.y,src.z))
- S.add(stack,user)
- ..()*/
\ No newline at end of file
+ var/sheettype = null //this is used for girders in the creation of walls/false walls
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/storage/bags.dm b/code/game/objects/items/weapons/storage/bags.dm
index 92ebff9c716..7519804b005 100644
--- a/code/game/objects/items/weapons/storage/bags.dm
+++ b/code/game/objects/items/weapons/storage/bags.dm
@@ -335,3 +335,17 @@
..()
+/*
+ * Chemistry bag
+ */
+
+/obj/item/weapon/storage/bag/chemistry
+ name = "chemistry bag"
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "bag"
+ desc = "A bag for storing pills, patches, and bottles."
+ storage_slots = 50
+ max_combined_w_class = 200
+ w_class = 1
+ preposition = "in"
+ can_hold = list(/obj/item/weapon/reagent_containers/pill, /obj/item/weapon/reagent_containers/glass/beaker, /obj/item/weapon/reagent_containers/glass/bottle)
diff --git a/code/game/objects/items/weapons/storage/book.dm b/code/game/objects/items/weapons/storage/book.dm
index 9a71db5ab8d..5d5eb001840 100644
--- a/code/game/objects/items/weapons/storage/book.dm
+++ b/code/game/objects/items/weapons/storage/book.dm
@@ -68,11 +68,9 @@ var/global/list/bibleitemstates = list("bible", "koran", "scrapbook", "bible", "
/obj/item/weapon/storage/book/bible/proc/setupbiblespecifics(var/obj/item/weapon/storage/book/bible/B, var/mob/living/carbon/human/H)
switch(B.icon_state)
if("honk1","honk2")
- new /obj/item/weapon/grown/bananapeel(B)
- new /obj/item/weapon/grown/bananapeel(B)
-
- if(B.icon_state == "honk1")
- H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(H), slot_wear_mask)
+ new /obj/item/weapon/bikehorn(B)
+ H.dna.add_mutation(CLOWNMUT)
+ H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(H), slot_wear_mask)
if("bible")
for(var/area/chapel/main/A in world)
@@ -211,4 +209,4 @@ var/global/list/bibleitemstates = list("bible", "koran", "scrapbook", "bible", "
/obj/item/weapon/storage/book/bible/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
playsound(src.loc, "rustle", 50, 1, -5)
- ..()
\ No newline at end of file
+ ..()
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index bae96ce7ef0..dde6cba1c31 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -1,6 +1,5 @@
/obj
languages = HUMAN
- //var/datum/module/mod //not used
var/crit_fail = 0
var/unacidable = 0 //universal "unacidabliness" var, here so you can use it in any obj.
animate_movement = 2
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 85f3f7582bb..9de891501fa 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -68,7 +68,7 @@
return (!density)
/obj/structure/closet/proc/can_open()
- if(src.welded || src.locked)
+ if(welded || locked)
return 0
return 1
@@ -81,32 +81,32 @@
/obj/structure/closet/proc/dump_contents()
for(var/obj/O in src)
- O.loc = src.loc
+ O.loc = loc
for(var/mob/M in src)
- M.loc = src.loc
+ M.loc = loc
if(M.client)
M.client.eye = M.client.mob
M.client.perspective = MOB_PERSPECTIVE
/obj/structure/closet/proc/take_contents()
- for(var/atom/movable/AM in src.loc)
+ for(var/atom/movable/AM in loc)
if(insert(AM) == -1) // limit reached
break
/obj/structure/closet/proc/open()
- if(src.opened)
+ if(opened)
return 0
- if(!src.can_open())
+ if(!can_open())
return 0
- src.dump_contents()
+ dump_contents()
- src.opened = 1
+ opened = 1
if(istype(src, /obj/structure/closet/body_bag))
- playsound(src.loc, 'sound/items/zip.ogg', 15, 1, -3)
+ playsound(loc, 'sound/items/zip.ogg', 15, 1, -3)
else
- playsound(src.loc, 'sound/machines/click.ogg', 15, 1, -3)
+ playsound(loc, 'sound/machines/click.ogg', 15, 1, -3)
density = 0
update_icon()
return 1
@@ -139,25 +139,25 @@
return 1
/obj/structure/closet/proc/close()
- if(!src.opened)
+ if(!opened)
return 0
- if(!src.can_close())
+ if(!can_close())
return 0
take_contents()
- src.opened = 0
+ opened = 0
if(istype(src, /obj/structure/closet/body_bag))
- playsound(src.loc, 'sound/items/zip.ogg', 15, 1, -3)
+ playsound(loc, 'sound/items/zip.ogg', 15, 1, -3)
else
- playsound(src.loc, 'sound/machines/click.ogg', 15, 1, -3)
+ playsound(loc, 'sound/machines/click.ogg', 15, 1, -3)
density = 1
update_icon()
return 1
/obj/structure/closet/proc/toggle()
- if(src.opened)
- return src.close()
- return src.open()
+ if(opened)
+ return close()
+ return open()
/obj/structure/closet/ex_act(severity, target)
contents_explosion(severity, target)
@@ -192,9 +192,9 @@
return
if(opened)
if(istype(W, /obj/item/weapon/grab))
- if(src.large)
+ if(large)
var/obj/item/weapon/grab/G = W
- src.MouseDrop_T(G.affecting, user) //act like they were dragged onto the closet
+ MouseDrop_T(G.affecting, user) //act like they were dragged onto the closet
user.drop_item()
else
user << "The locker is too small to stuff [W] into!"
@@ -210,7 +210,7 @@
if( !opened || !istype(src, /obj/structure/closet) || !user || !WT || !WT.isOn() || !user.loc )
return
playsound(loc, 'sound/items/Welder2.ogg', 50, 1)
- new /obj/item/stack/sheet/metal(src.loc)
+ new /obj/item/stack/sheet/metal(loc)
visible_message("[user] has cut \the [src] apart with \the [WT].", "You hear welding.")
qdel(src)
return
@@ -239,10 +239,10 @@
user << "The locker appears to be broken."
return
if(!place(user, W) && !isnull(W))
- src.attack_hand(user)
+ attack_hand(user)
/obj/structure/closet/proc/place(var/mob/user, var/obj/item/I)
- if(!src.opened && secure)
+ if(!opened && secure)
togglelock(user)
return 1
return 0
@@ -258,21 +258,21 @@
return 0
if(!istype(user.loc, /turf)) // are you in a container/closet/pod/etc? Will also check for null loc
return 0
- if(needs_opened && !src.opened)
+ if(needs_opened && !opened)
return 0
if(istype(O, /obj/structure/closet))
return 0
if(move_them)
- step_towards(O, src.loc)
+ step_towards(O, loc)
if(show_message && user != O)
user.show_viewers("[user] stuffs [O] into [src]!")
- src.add_fingerprint(user)
+ add_fingerprint(user)
return 1
/obj/structure/closet/relaymove(mob/user as mob)
- if(user.stat || !isturf(src.loc))
+ if(user.stat || !isturf(loc))
return
- if(!src.open())
+ if(!open())
user << "It won't budge!"
if(world.time > lastbang+5)
lastbang = world.time
@@ -281,19 +281,20 @@
/obj/structure/closet/attack_paw(mob/user as mob)
- return src.attack_hand(user)
+ return attack_hand(user)
/obj/structure/closet/attack_hand(mob/user as mob)
- src.add_fingerprint(user)
+ add_fingerprint(user)
if(user.lying && get_dist(src, user) > 0)
return
- if(!src.toggle())
- return src.attackby(null, user)
+ if(!toggle())
+ user << "You cannot close the locker!"
+ return
// tk grab then use on self
/obj/structure/closet/attack_self_tk(mob/user as mob)
- return src.attack_hand(user)
+ return attack_hand(user)
/obj/structure/closet/verb/verb_toggleopen()
set src in oview(1)
@@ -304,7 +305,7 @@
return
if(iscarbon(usr) || issilicon(usr))
- src.attack_hand(usr)
+ attack_hand(usr)
else
usr << "This mob type can't use this verb."
@@ -322,7 +323,7 @@
if(istype(user.loc, /obj/structure/closet/critter) && !welded)
breakout_time = 0.75 //45 seconds if it's an unwelded critter crate
- if( opened || (!welded && !locked && !istype(src.loc, /obj/mecha)) )
+ if( opened || (!welded && !locked && !istype(loc, /obj/mecha)) )
return //Door's open, not locked or welded or inside a mech, no point in resisting.
//okay, so the closet is either welded or locked... resist!!!
@@ -332,7 +333,7 @@
for(var/mob/O in viewers(src))
O << "[src] begins to shake violently!"
if(do_after(user,(breakout_time*60*10))) //minutes * 60seconds * 10deciseconds
- if(!user || user.stat != CONSCIOUS || user.loc != src || opened || (!locked && !welded && !istype(src.loc, /obj/mecha)) )
+ if(!user || user.stat != CONSCIOUS || user.loc != src || opened || (!locked && !welded && !istype(loc, /obj/mecha)) )
return
//we check after a while whether there is a point of resisting anymore and whether the user is capable of resisting
@@ -340,11 +341,11 @@
locked = 0 //applies to critter crates and secure lockers only
broken = 1 //applies to secure lockers only
user.visible_message("[user] successfully broke out of [src]!", "You successfully break out of [src]!")
- if(istype( src.loc, /obj/structure/bigDelivery))
- var/obj/structure/bigDelivery/D = src.loc
+ if(istype( loc, /obj/structure/bigDelivery))
+ var/obj/structure/bigDelivery/D = loc
qdel(D)
- else if(istype( src.loc, /obj/mecha))
- src.loc = get_turf(src.loc)
+ else if(istype( loc, /obj/mecha))
+ loc = get_turf(loc)
open()
else
user << "You fail to break out of [src]!"
@@ -354,7 +355,7 @@
if(!user.canUseTopic(user) || broken)
user << "You can't do that right now!"
return
- if(src.opened || !secure || !in_range(src, user))
+ if(opened || !secure || !in_range(src, user))
return
else
togglelock(user)
@@ -364,20 +365,20 @@
O.emp_act(severity)
if(secure && !broken)
if(prob(50/severity))
- src.locked = !src.locked
- src.update_icon()
+ locked = !locked
+ update_icon()
if(prob(20/severity) && !opened)
if(!locked)
open()
else
- src.req_access = list()
- src.req_access += pick(get_all_accesses())
+ req_access = list()
+ req_access += pick(get_all_accesses())
..()
/obj/structure/closet/proc/togglelock(mob/user as mob)
if(secure)
- if(src.allowed(user))
- src.locked = !src.locked
+ if(allowed(user))
+ locked = !locked
add_fingerprint(user)
for(var/mob/O in viewers(user, 3))
if((O.client && !( O.eye_blind )))
diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
index a4510966df7..37433c2423c 100644
--- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
+++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
@@ -311,6 +311,8 @@
new /obj/item/weapon/storage/backpack/chemistry(src)
new /obj/item/weapon/storage/backpack/satchel_chem(src)
new /obj/item/weapon/storage/backpack/satchel_chem(src)
+ new /obj/item/weapon/storage/bag/chemistry(src)
+ new /obj/item/weapon/storage/bag/chemistry(src)
return
diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm
index 6eb5f7b9317..ffe58681ab0 100644
--- a/code/game/objects/structures/mirror.dm
+++ b/code/game/objects/structures/mirror.dm
@@ -106,7 +106,20 @@
name = "magic mirror"
desc = "Turn and face the strange... face."
icon_state = "magic_mirror"
+ var/list/races_blacklist = list("skeleton")
+ var/list/choosable_races = list()
+/obj/structure/mirror/magic/New()
+ if(!choosable_races.len)
+ for(var/datum/species/S in typesof(/datum/species) - /datum/species)
+ if(!(S.id in races_blacklist))
+ choosable_races += S
+ ..()
+
+/obj/structure/mirror/magic/badmin/New()
+ for(var/datum/species/S in typesof(/datum/species) - /datum/species)
+ choosable_races += S
+ ..()
/obj/structure/mirror/magic/attack_hand(mob/user as mob)
if(!ishuman(user))
@@ -130,7 +143,7 @@
if("race")
var/newrace
- var/racechoice = input(H, "What are we again?", "Race change") as null|anything in species_list
+ var/racechoice = input(H, "What are we again?", "Race change") as null|anything in choosable_races
newrace = species_list[racechoice]
if(!newrace || !H.dna)
diff --git a/code/game/objects/structures/table_frames.dm b/code/game/objects/structures/table_frames.dm
index 4e44968971b..0b1f15d41b3 100644
--- a/code/game/objects/structures/table_frames.dm
+++ b/code/game/objects/structures/table_frames.dm
@@ -32,28 +32,37 @@
return
if(istype(I, /obj/item/stack/sheet/plasteel))
var/obj/item/stack/sheet/plasteel/P = I
+ if(P.get_amount() < 1)
+ user << "You need one plasteel sheet to do this!"
+ return
user << "You start adding [P] to [src]..."
if(do_after(user, 50))
+ P.use(1)
new /obj/structure/table/reinforced(src.loc)
qdel(src)
- P.use(1)
- return
+ return
if(istype(I, /obj/item/stack/sheet/metal))
var/obj/item/stack/sheet/metal/M = I
+ if(M.get_amount() < 1)
+ user << "You need one metal sheet to do this!"
+ return
user << "You start adding [M] to [src]..."
if(do_after(user, 20))
+ M.use(1)
new /obj/structure/table(src.loc)
qdel(src)
- M.use(1)
- return
+ return
if(istype(I, /obj/item/stack/sheet/glass))
var/obj/item/stack/sheet/glass/G = I
+ if(G.get_amount() < 1)
+ user << "You need one glass sheet to do this!"
+ return
user << "You start adding [G] to [src]..."
if(do_after(user, 20))
+ G.use(1)
new /obj/structure/table/glass(src.loc)
qdel(src)
- G.use(1)
- return
+ return
/*
* Wooden Frames
@@ -71,17 +80,23 @@
..()
if(istype(I, /obj/item/stack/sheet/mineral/wood))
var/obj/item/stack/sheet/mineral/wood/W = I
+ if(W.get_amount() < 1)
+ user << "You need one wood sheet to do this!"
+ return
user << "You start adding [W] to [src]..."
if(do_after(user, 20))
+ W.use(1)
new /obj/structure/table/wood(src.loc)
qdel(src)
- W.use(1)
- return
+ return
if(istype(I, /obj/item/stack/tile/carpet))
var/obj/item/stack/tile/carpet/C = I
+ if(C.get_amount() < 1)
+ user << "You need one carpet sheet to do this!"
+ return
user << "You start adding [C] to [src]..."
if(do_after(user, 20))
+ C.use(1)
new /obj/structure/table/wood/poker(src.loc)
qdel(src)
- C.use(1)
- return
\ No newline at end of file
+ return
\ No newline at end of file
diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm
index b3a52450234..8262201bf28 100644
--- a/code/game/objects/structures/windoor_assembly.dm
+++ b/code/game/objects/structures/windoor_assembly.dm
@@ -29,7 +29,7 @@
/obj/structure/windoor_assembly/New(dir=NORTH)
..()
- src.ini_dir = src.dir
+ ini_dir = dir
air_update_turf(1)
/obj/structure/windoor_assembly/Destroy()
@@ -77,7 +77,7 @@
var/obj/item/weapon/weldingtool/WT = W
if (WT.remove_fuel(0,user))
user.visible_message("[user] disassembles the windoor assembly.", "You start to disassemble the windoor assembly...")
- playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
+ playsound(loc, 'sound/items/Welder2.ogg', 50, 1)
if(do_after(user, 40))
if(!src || !WT.isOn()) return
@@ -93,41 +93,41 @@
//Wrenching an unsecure assembly anchors it in place. Step 4 complete
if(istype(W, /obj/item/weapon/wrench) && !anchored)
- for(var/obj/machinery/door/window/WD in src.loc)
- if(WD.dir == src.dir)
+ for(var/obj/machinery/door/window/WD in loc)
+ if(WD.dir == dir)
user << "There is already a windoor in that location!"
return
- playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1)
+ playsound(loc, 'sound/items/Ratchet.ogg', 100, 1)
user.visible_message("[user] secures the windoor assembly to the floor.", "You start to secure the windoor assembly to the floor...")
if(do_after(user, 40))
- if(!src || src.anchored)
+ if(!src || anchored)
return
- for(var/obj/machinery/door/window/WD in src.loc)
- if(WD.dir == src.dir)
+ for(var/obj/machinery/door/window/WD in loc)
+ if(WD.dir == dir)
user << "There is already a windoor in that location!"
return
user << "You secure the windoor assembly."
- src.anchored = 1
- if(src.secure)
- src.name = "secure anchored windoor assembly"
+ anchored = 1
+ if(secure)
+ name = "secure anchored windoor assembly"
else
- src.name = "anchored windoor assembly"
+ name = "anchored windoor assembly"
//Unwrenching an unsecure assembly un-anchors it. Step 4 undone
else if(istype(W, /obj/item/weapon/wrench) && anchored)
- playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1)
+ playsound(loc, 'sound/items/Ratchet.ogg', 100, 1)
user.visible_message("[user] unsecures the windoor assembly to the floor.", "You start to unsecure the windoor assembly to the floor...")
if(do_after(user, 40))
- if(!src || !src.anchored)
+ if(!src || !anchored)
return
user << "You unsecure the windoor assembly."
- src.anchored = 0
- if(src.secure)
- src.name = "secure windoor assembly"
+ anchored = 0
+ if(secure)
+ name = "secure windoor assembly"
else
- src.name = "windoor assembly"
+ name = "windoor assembly"
//Adding plasteel makes the assembly a secure windoor assembly. Step 2 (optional) complete.
else if(istype(W, /obj/item/stack/sheet/plasteel) && !secure)
@@ -143,27 +143,29 @@
P.use(2)
user << "You reinforce the windoor."
- src.secure = 1
- if(src.anchored)
- src.name = "secure anchored windoor assembly"
+ secure = 1
+ if(anchored)
+ name = "secure anchored windoor assembly"
else
- src.name = "secure windoor assembly"
+ name = "secure windoor assembly"
//Adding cable to the assembly. Step 5 complete.
else if(istype(W, /obj/item/stack/cable_coil) && anchored)
user.visible_message("[user] wires the windoor assembly.", "You start to wire the windoor assembly...")
if(do_after(user, 40))
- if(!src || !src.anchored || src.state != "01")
+ if(!src || !anchored || state != "01")
return
var/obj/item/stack/cable_coil/CC = W
- CC.use(1)
+ if(!CC.use(1))
+ user << "You need more cable to do this!"
+ return
user << "You wire the windoor."
- src.state = "02"
- if(src.secure)
- src.name = "secure wired windoor assembly"
+ state = "02"
+ if(secure)
+ name = "secure wired windoor assembly"
else
- src.name = "wired windoor assembly"
+ name = "wired windoor assembly"
else
..()
@@ -171,61 +173,61 @@
//Removing wire from the assembly. Step 5 undone.
if(istype(W, /obj/item/weapon/wirecutters))
- playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1)
+ playsound(loc, 'sound/items/Wirecutter.ogg', 100, 1)
user.visible_message("[user] cuts the wires from the airlock assembly.", "You start to cut the wires from airlock assembly...")
if(do_after(user, 40))
- if(!src || src.state != "02")
+ if(!src || state != "02")
return
user << "You cut the windoor wires."
new/obj/item/stack/cable_coil(get_turf(user), 1)
- src.state = "01"
- if(src.secure)
- src.name = "secure anchored windoor assembly"
+ state = "01"
+ if(secure)
+ name = "secure anchored windoor assembly"
else
- src.name = "anchored windoor assembly"
+ name = "anchored windoor assembly"
//Adding airlock electronics for access. Step 6 complete.
else if(istype(W, /obj/item/weapon/airlock_electronics))
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1)
+ playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1)
user.visible_message("[user] installs the electronics into the airlock assembly.", "You start to install electronics into the airlock assembly...")
user.drop_item()
W.loc = src
if(do_after(user, 40))
- if(!src || src.electronics)
- W.loc = src.loc
+ if(!src || electronics)
+ W.loc = loc
return
user << "You install the airlock electronics."
- src.name = "near finished windoor assembly"
- src.electronics = W
+ name = "near finished windoor assembly"
+ electronics = W
else
- W.loc = src.loc
+ W.loc = loc
//Screwdriver to remove airlock electronics. Step 6 undone.
else if(istype(W, /obj/item/weapon/screwdriver))
if(!electronics)
return
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1)
+ playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1)
user.visible_message("[user] removes the electronics from the airlock assembly.", "You start to uninstall electronics from the airlock assembly...")
if(do_after(user, 40))
if(!src || !electronics)
return
user << "You remove the airlock electronics."
- src.name = "wired windoor assembly"
+ name = "wired windoor assembly"
var/obj/item/weapon/airlock_electronics/ae
ae = electronics
electronics = null
- ae.loc = src.loc
+ ae.loc = loc
else if(istype(W, /obj/item/weapon/pen))
- var/t = stripped_input(user, "Enter the name for the door.", src.name, src.created_name,MAX_NAME_LEN)
+ var/t = stripped_input(user, "Enter the name for the door.", name, created_name,MAX_NAME_LEN)
if(!t)
return
- if(!in_range(src, usr) && src.loc != usr)
+ if(!in_range(src, usr) && loc != usr)
return
created_name = t
return
@@ -234,37 +236,37 @@
//Crowbar to complete the assembly, Step 7 complete.
else if(istype(W, /obj/item/weapon/crowbar))
- if(!src.electronics)
+ if(!electronics)
usr << "The assembly is missing electronics!"
return
usr << browse(null, "window=windoor_access")
- playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1)
+ playsound(loc, 'sound/items/Crowbar.ogg', 100, 1)
user.visible_message("[user] pries the windoor into the frame.", "You start prying the windoor into the frame...")
if(do_after(user, 40))
- if(src.loc && src.electronics)
+ if(loc && electronics)
density = 1 //Shouldn't matter but just incase
user << "You finish the windoor."
if(secure)
- var/obj/machinery/door/window/brigdoor/windoor = new /obj/machinery/door/window/brigdoor(src.loc)
- if(src.facing == "l")
+ var/obj/machinery/door/window/brigdoor/windoor = new /obj/machinery/door/window/brigdoor(loc)
+ if(facing == "l")
windoor.icon_state = "leftsecureopen"
windoor.base_state = "leftsecure"
else
windoor.icon_state = "rightsecureopen"
windoor.base_state = "rightsecure"
- windoor.dir = src.dir
+ windoor.dir = dir
windoor.density = 0
- if(src.electronics.use_one_access)
- windoor.req_one_access = src.electronics.conf_access
+ if(electronics.use_one_access)
+ windoor.req_one_access = electronics.conf_access
else
- windoor.req_access = src.electronics.conf_access
- windoor.electronics = src.electronics
- src.electronics.loc = windoor
+ windoor.req_access = electronics.conf_access
+ windoor.electronics = electronics
+ electronics.loc = windoor
if(created_name)
windoor.name = created_name
qdel(src)
@@ -272,19 +274,19 @@
else
- var/obj/machinery/door/window/windoor = new /obj/machinery/door/window(src.loc)
- if(src.facing == "l")
+ var/obj/machinery/door/window/windoor = new /obj/machinery/door/window(loc)
+ if(facing == "l")
windoor.icon_state = "leftopen"
windoor.base_state = "left"
else
windoor.icon_state = "rightopen"
windoor.base_state = "right"
- windoor.dir = src.dir
+ windoor.dir = dir
windoor.density = 0
- windoor.req_access = src.electronics.conf_access
- windoor.electronics = src.electronics
- src.electronics.loc = windoor
+ windoor.req_access = electronics.conf_access
+ windoor.electronics = electronics
+ electronics.loc = windoor
if(created_name)
windoor.name = created_name
qdel(src)
@@ -305,18 +307,18 @@
set src in oview(1)
if(usr.stat || !usr.canmove || usr.restrained())
return
- if (src.anchored)
+ if (anchored)
usr << "It is fastened to the floor; therefore, you can't rotate it!"
return 0
- //if(src.state != "01")
+ //if(state != "01")
//update_nearby_tiles(need_rebuild=1) //Compel updates before
- src.dir = turn(src.dir, 270)
+ dir = turn(dir, 270)
- //if(src.state != "01")
+ //if(state != "01")
//update_nearby_tiles(need_rebuild=1)
- src.ini_dir = src.dir
+ ini_dir = dir
update_icon()
return
@@ -328,11 +330,11 @@
if(usr.stat || !usr.canmove || usr.restrained())
return
- if(src.facing == "l")
+ if(facing == "l")
usr << "The windoor will now slide to the right."
- src.facing = "r"
+ facing = "r"
else
- src.facing = "l"
+ facing = "l"
usr << "The windoor will now slide to the left."
update_icon()
diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm
index 6e565879c9f..25f2ec88ecb 100644
--- a/code/game/turfs/simulated/floor/plating.dm
+++ b/code/game/turfs/simulated/floor/plating.dm
@@ -105,6 +105,28 @@
ChangeTurf(/turf/simulated/floor/plating)
return
+
+/turf/simulated/floor/engine/ex_act(severity,target)
+ switch(severity)
+ if(1.0)
+ if(prob(80))
+ ReplaceWithLattice()
+ else if(prob(50))
+ qdel(src)
+ else
+ make_plating(1)
+ if(2.0)
+ if(prob(50))
+ make_plating(1)
+
+
+/turf/simulated/floor/engine/cult
+ name = "engraved floor"
+ icon_state = "cult"
+
+/turf/simulated/floor/engine/cult/narsie_act()
+ return
+
/turf/simulated/floor/engine/n20/New()
..()
var/datum/gas_mixture/adding = new
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index af5a84bdc3c..2829c18e6c9 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -6,6 +6,7 @@
opacity = 1
density = 1
blocks_air = 1
+ explosion_block = 1
thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m plasteel wall
diff --git a/code/game/turfs/simulated/walls_mineral.dm b/code/game/turfs/simulated/walls_mineral.dm
index c61a20cb100..fb73c1f61c6 100644
--- a/code/game/turfs/simulated/walls_mineral.dm
+++ b/code/game/turfs/simulated/walls_mineral.dm
@@ -17,6 +17,7 @@
mineral = "gold"
//var/electro = 1
//var/shocked = null
+ explosion_block = 0 //gold is a soft metal you dingus.
/turf/simulated/wall/mineral/silver
name = "silver wall"
@@ -34,6 +35,7 @@
walltype = "diamond"
mineral = "diamond"
slicing_duration = 200 //diamond wall takes twice as much time to slice
+ explosion_block = 3
/turf/simulated/wall/mineral/diamond/thermitemelt(mob/user as mob)
return
@@ -51,6 +53,7 @@
icon_state = "sandstone0"
walltype = "sandstone"
mineral = "sandstone"
+ explosion_block = 0
/turf/simulated/wall/mineral/uranium
name = "uranium wall"
@@ -143,3 +146,4 @@
walltype = "wood"
mineral = "wood"
hardness = 70
+ explosion_block = 0
\ No newline at end of file
diff --git a/code/game/turfs/simulated/walls_reinforced.dm b/code/game/turfs/simulated/walls_reinforced.dm
index aec87adc748..00f6f38825f 100644
--- a/code/game/turfs/simulated/walls_reinforced.dm
+++ b/code/game/turfs/simulated/walls_reinforced.dm
@@ -10,6 +10,7 @@
var/d_state = 0
hardness = 10
sheet_type = /obj/item/stack/sheet/plasteel
+ explosion_block = 2
/turf/simulated/wall/r_wall/break_wall()
builtin_sheet.loc = src
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 740ec63b06e..1c073505ab8 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -10,6 +10,7 @@ var/list/admin_verbs_default = list(
/client/proc/deadchat, /*toggles deadchat on/off*/
/client/proc/dsay, /*talk in deadchat using our ckey/fakekey*/
/client/proc/toggleprayers, /*toggles prayers on/off*/
+ /client/verb/toggleprayersounds, /*Toggles prayer sounds (HALLELUJAH!)*/
/client/proc/toggle_hear_radio, /*toggles whether we hear the radio*/
/client/proc/investigate_show, /*various admintools for investigation. Such as a singulo grief-log*/
/client/proc/secrets,
@@ -120,7 +121,9 @@ var/list/admin_verbs_debug = list(
/client/proc/SDQL2_query,
/client/proc/test_movable_UI,
/client/proc/test_snap_UI,
- /client/proc/debugNatureMapGenerator
+ /client/proc/debugNatureMapGenerator,
+ /client/proc/check_bomb_impacts,
+ /proc/machine_upgrade
)
var/list/admin_verbs_possess = list(
/proc/possess,
@@ -547,7 +550,7 @@ var/list/admin_verbs_hideable = list(
var/list/Lines = file2list("config/admins.txt")
for(var/line in Lines)
var/list/splitline = text2list(line, " = ")
- if(splitline[1] == ckey)
+ if(lowertext(splitline[1]) == ckey)
if(splitline.len >= 2)
rank = ckeyEx(splitline[2])
break
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 334190fbd20..14d8693c3e5 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -307,7 +307,7 @@
if(ratio)
config.midround_antag_life_check = ratio/100
- message_admins("[key_name_admin(usr)] edited the midround antagonist living crew ratio to [ratio * 100]% alive.")
+ message_admins("[key_name_admin(usr)] edited the midround antagonist living crew ratio to [ratio]% alive.")
check_antagonists()
else if(href_list["toggle_noncontinuous_behavior"])
@@ -1605,6 +1605,7 @@
message_admins("[key_name(H)] got their cookie, spawned by [key_name(src.owner)]")
feedback_inc("admin_cookies_spawned",1)
H << "Your prayers have been answered!! You received the best cookie!"
+ H << 'sound/effects/pray_chaplain.ogg'
else if(href_list["BlueSpaceArtillery"])
var/mob/living/M = locate(href_list["BlueSpaceArtillery"])
diff --git a/code/modules/admin/verbs/buildmode.dm b/code/modules/admin/verbs/buildmode.dm
index 767f30e1380..d06bd7e61c8 100644
--- a/code/modules/admin/verbs/buildmode.dm
+++ b/code/modules/admin/verbs/buildmode.dm
@@ -1,3 +1,10 @@
+#define BASIC_BUILDMODE 1
+#define ADV_BUILDMODE 2
+#define VAR_BUILDMODE 3
+#define THROW_BUILDMODE 4
+#define AREA_BUILDMODE 5
+#define NUM_BUILDMODES 5
+
/proc/togglebuildmode(mob/M as mob in player_list)
set name = "Toggle Build Mode"
set category = "Special Verbs"
@@ -35,7 +42,7 @@
M.client.screen += D
H.cl = M.client
-/obj/effect/bmode//Cleaning up the tree a bit
+/obj/effect/bmode //Cleaning up the tree a bit
density = 1
anchored = 1
layer = 20
@@ -68,7 +75,7 @@
/obj/effect/bmode/buildhelp/Click()
switch(master.cl.buildmode)
- if(1)
+ if(BASIC_BUILDMODE)
usr << "\blue ***********************************************************"
usr << "\blue Left Mouse Button = Construct / Upgrade"
usr << "\blue Right Mouse Button = Deconstruct / Delete / Downgrade"
@@ -78,7 +85,7 @@
usr << "\blue Use the button in the upper left corner to"
usr << "\blue change the direction of built objects."
usr << "\blue ***********************************************************"
- if(2)
+ if(ADV_BUILDMODE)
usr << "\blue ***********************************************************"
usr << "\blue Right Mouse Button on buildmode button = Set object type"
usr << "\blue Left Mouse Button on turf/obj = Place objects"
@@ -87,17 +94,23 @@
usr << "\blue Use the button in the upper left corner to"
usr << "\blue change the direction of built objects."
usr << "\blue ***********************************************************"
- if(3)
+ if(VAR_BUILDMODE)
usr << "\blue ***********************************************************"
usr << "\blue Right Mouse Button on buildmode button = Select var(type) & value"
usr << "\blue Left Mouse Button on turf/obj/mob = Set var(type) & value"
usr << "\blue Right Mouse Button on turf/obj/mob = Reset var's value"
usr << "\blue ***********************************************************"
- if(4)
+ if(THROW_BUILDMODE)
usr << "\blue ***********************************************************"
usr << "\blue Left Mouse Button on turf/obj/mob = Select"
usr << "\blue Right Mouse Button on turf/obj/mob = Throw"
usr << "\blue ***********************************************************"
+ if(AREA_BUILDMODE)
+ usr << "\blue ***********************************************************"
+ usr << "\blue Left Mouse Button on turf/obj/mob = Select corner"
+ usr << "\blue Right Mouse Button on buildmode button = Select generator"
+ usr << "\blue ***********************************************************"
+
return 1
/obj/effect/bmode/buildquit
@@ -117,6 +130,13 @@
var/obj/effect/bmode/buildmode/buildmode = null
var/obj/effect/bmode/buildquit/buildquit = null
var/atom/movable/throw_atom = null
+ var/turf/cornerA = null
+ var/turf/cornerB = null
+ var/generator_path = null
+
+/obj/effect/bmode/buildholder/proc/Reset()//Reset temporary variables
+ cornerA = null
+ cornerB = null
/obj/effect/bmode/buildmode
icon_state = "buildmode1"
@@ -129,25 +149,15 @@
var/list/pa = params2list(params)
if(pa.Find("left"))
- switch(master.cl.buildmode)
- if(1)
- master.cl.buildmode = 2
- src.icon_state = "buildmode2"
- if(2)
- master.cl.buildmode = 3
- src.icon_state = "buildmode3"
- if(3)
- master.cl.buildmode = 4
- src.icon_state = "buildmode4"
- if(4)
- master.cl.buildmode = 1
- src.icon_state = "buildmode1"
+ master.cl.buildmode = (master.cl.buildmode % NUM_BUILDMODES) +1
+ master.Reset()
+ src.icon_state = "buildmode[master.cl.buildmode]"
else if(pa.Find("right"))
switch(master.cl.buildmode)
- if(1)
+ if(BASIC_BUILDMODE)
return 1
- if(2)
+ if(ADV_BUILDMODE)
objholder = text2path(input(usr,"Enter typepath:" ,"Typepath","/obj/structure/closet"))
if(!ispath(objholder))
objholder = /obj/structure/closet
@@ -155,7 +165,7 @@
else
if(ispath(objholder,/mob) && !check_rights(R_DEBUG,0))
objholder = /obj/structure/closet
- if(3)
+ if(VAR_BUILDMODE)
var/list/locked = list("vars", "key", "ckey", "client", "firemut", "ishulk", "telekinesis", "xray", "virus", "viruses", "cuffed", "ka", "last_eaten", "urine")
master.buildmode.varholder = input(usr,"Enter variable name:" ,"Name", "name")
@@ -174,6 +184,16 @@
master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as obj in world
if("turf-reference")
master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as turf in world
+ if(AREA_BUILDMODE)
+ var/list/gen_paths = typesof(/datum/mapGenerator) - /datum/mapGenerator
+
+ var/type = input(usr,"Select Generator Type","Type") as null|anything in gen_paths
+ if(!type) return
+
+ master.generator_path = type
+ master.cornerA = null
+ master.cornerB = null
+
return 1
@@ -186,8 +206,11 @@
if(!holder) return
var/list/pa = params2list(params)
+ if(istype(object,/obj/effect/bmode))
+ return
+
switch(buildmode)
- if(1)
+ if(BASIC_BUILDMODE)
if(istype(object,/turf) && pa.Find("left") && !pa.Find("alt") && !pa.Find("ctrl") )
var/turf/T = object
if(istype(object,/turf/space))
@@ -233,7 +256,7 @@
var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object))
WIN.dir = NORTHWEST
log_admin("Build Mode: [key_name(usr)] built a window at ([object.x],[object.y],[object.z])")
- if(2)
+ if(ADV_BUILDMODE)
if(pa.Find("left"))
if(ispath(holder.buildmode.objholder,/turf))
var/turf/T = get_turf(object)
@@ -248,7 +271,7 @@
log_admin("Build Mode: [key_name(usr)] deleted [object] at ([object.x],[object.y],[object.z])")
qdel(object)
- if(3)
+ if(VAR_BUILDMODE)
if(pa.Find("left")) //I cant believe this shit actually compiles.
if(object.vars.Find(holder.buildmode.varholder))
log_admin("Build Mode: [key_name(usr)] modified [object.name]'s [holder.buildmode.varholder] to [holder.buildmode.valueholder]")
@@ -262,7 +285,7 @@
else
usr << "[initial(object.name)] does not have a var called '[holder.buildmode.varholder]'"
- if(4)
+ if(THROW_BUILDMODE)
if(pa.Find("left"))
if(isturf(object))
return
@@ -271,4 +294,35 @@
if(holder.throw_atom)
holder.throw_atom.throw_at(object, 10, 1)
log_admin("Build Mode: [key_name(usr)] threw [holder.throw_atom] at [object] ([object.x],[object.y],[object.z])")
-
+ if(AREA_BUILDMODE)
+ if(!holder.cornerA)
+ holder.cornerA = get_turf(object)
+ return
+ if(holder.cornerA && !holder.cornerB)
+ holder.cornerB = get_turf(object)
+
+ if(pa.Find("left")) //rectangular
+ if(holder.cornerA && holder.cornerB)
+ if(!holder.generator_path)
+ usr << "Select generator type first."
+ var/datum/mapGenerator/G = new holder.generator_path
+ G.defineRegion(holder.cornerA,holder.cornerB,1)
+ G.generate()
+ holder.cornerA = null
+ holder.cornerB = null
+ return
+ /* Something wrong with this, will check later
+ if(pa.Find("right")) // circular
+ if(holder.cornerA && holder.cornerB)
+ if(!holder.generator_path)
+ usr << "Select generator type first."
+ var/datum/mapGenerator/G = new holder.generator_path
+ G.defineCircularRegion(holder.cornerA,holder.cornerB,1)
+ G.generate()
+ holder.cornerA = null
+ holder.cornerB = null
+ return
+ */
+ //Something wrong - Reset
+ holder.cornerA = null
+ holder.cornerB = null
\ No newline at end of file
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index dac9d8d47ac..02aac7f6db8 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -1091,6 +1091,8 @@ var/global/list/g_fancy_list_of_types = null
usr << browse(dat, "window=dellog")
+
+
//Deathsquad
/proc/equip_deathsquad(var/mob/living/carbon/human/M, var/officer)
var/obj/item/device/radio/R = new /obj/item/device/radio/headset/headset_cent/alt(M)
diff --git a/code/modules/admin/verbs/machine_upgrade.dm b/code/modules/admin/verbs/machine_upgrade.dm
new file mode 100644
index 00000000000..9c1089c5fff
--- /dev/null
+++ b/code/modules/admin/verbs/machine_upgrade.dm
@@ -0,0 +1,10 @@
+/proc/machine_upgrade(obj/machinery/M as obj in world)
+ set name = "Tweak Component Ratings"
+ set category = "Debug"
+ var/new_rating = input("Enter new rating:","Num") as num
+ if(new_rating && M.component_parts)
+ for(var/obj/item/weapon/stock_parts/P in M.component_parts)
+ P.rating = new_rating
+ M.RefreshParts()
+
+ feedback_add_details("admin_verb","MU") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm
index f14df6a3fc9..3125067f32b 100644
--- a/code/modules/admin/verbs/modifyvariables.dm
+++ b/code/modules/admin/verbs/modifyvariables.dm
@@ -142,15 +142,33 @@ var/list/VVckey_edit = list("key", "ckey")
if(confirm != "Continue")
return
- var/list/names = sortList(L)
+ var/assoc = 0
+ if(L.len > 0)
+ var/a = L[1]
+ if(istext(a) && L[a] != null)
+ assoc = 1 //This is pretty weak test but i can't think of anything else
+ usr << "List appears to be associative."
- var/variable = input("Which var?","Var") as null|anything in names + "(ADD VAR)"
+ var/list/names = null
+ if(!assoc)
+ names = sortList(L)
+
+ var/variable
+ var/assoc_key
+ if(assoc)
+ variable = input("Which var?","Var") as null|anything in L + "(ADD VAR)"
+ else
+ variable = input("Which var?","Var") as null|anything in names + "(ADD VAR)"
if(variable == "(ADD VAR)")
mod_list_add(L, O, original_name, objectvar)
return
- if(!variable)
+ if(assoc)
+ assoc_key = variable
+ variable = L[assoc_key]
+
+ if(!assoc && !variable || assoc && !assoc_key)
return
var/default
@@ -240,7 +258,12 @@ var/list/VVckey_edit = list("key", "ckey")
if(holder.marked_datum && class == "marked datum ([holder.marked_datum.type])")
class = "marked datum"
- var/original_var = L[L.Find(variable)]
+ var/original_var
+ if(assoc)
+ original_var = L[assoc_key]
+ else
+ original_var = L[L.Find(variable)]
+
var/new_var
switch(class) //Spits a runtime error if you try to modify an entry in the contents list. Dunno how to fix it, yet.
@@ -249,7 +272,10 @@ var/list/VVckey_edit = list("key", "ckey")
if("restore to default")
new_var = initial(variable)
- L[L.Find(variable)] = new_var
+ if(assoc)
+ L[assoc_key] = new_var
+ else
+ L[L.Find(variable)] = new_var
if("edit referenced object")
modify_variables(variable)
@@ -263,35 +289,59 @@ var/list/VVckey_edit = list("key", "ckey")
if("text")
new_var = input("Enter new text:","Text") as text
- L[L.Find(variable)] = new_var
+ if(assoc)
+ L[assoc_key] = new_var
+ else
+ L[L.Find(variable)] = new_var
if("num")
new_var = input("Enter new number:","Num") as num
- L[L.Find(variable)] = new_var
+ if(assoc)
+ L[assoc_key] = new_var
+ else
+ L[L.Find(variable)] = new_var
if("type")
new_var = input("Enter type:","Type") in typesof(/obj,/mob,/area,/turf)
- L[L.Find(variable)] = new_var
+ if(assoc)
+ L[assoc_key] = new_var
+ else
+ L[L.Find(variable)] = new_var
if("reference")
new_var = input("Select reference:","Reference") as mob|obj|turf|area in world
- L[L.Find(variable)] = new_var
+ if(assoc)
+ L[assoc_key] = new_var
+ else
+ L[L.Find(variable)] = new_var
if("mob reference")
new_var = input("Select reference:","Reference") as mob in world
- L[L.Find(variable)] = new_var
+ if(assoc)
+ L[assoc_key] = new_var
+ else
+ L[L.Find(variable)] = new_var
if("file")
new_var = input("Pick file:","File") as file
- L[L.Find(variable)] = new_var
+ if(assoc)
+ L[assoc_key] = new_var
+ else
+ L[L.Find(variable)] = new_var
if("icon")
new_var = input("Pick icon:","Icon") as icon
- L[L.Find(variable)] = new_var
+ if(assoc)
+ L[assoc_key] = new_var
+ else
+ L[L.Find(variable)] = new_var
if("marked datum")
new_var = holder.marked_datum
- L[L.Find(variable)] = new_var
+ if(assoc)
+ L[assoc_key] = new_var
+ else
+ L[L.Find(variable)] = new_var
world.log << "### ListVarEdit by [src]: [O.type] [objectvar]: [original_var]=[new_var]"
log_admin("[key_name(src)] modified [original_name]'s [objectvar]: [original_var]=[new_var]")
@@ -539,4 +589,4 @@ var/list/VVckey_edit = list("key", "ckey")
world.log << "### VarEdit by [src]: [O.type] [variable]=[html_encode("[O.vars[variable]]")]"
log_admin("[key_name(src)] modified [original_name]'s [variable] to [O.vars[variable]]")
- message_admins("[key_name_admin(src)] modified [original_name]'s [variable] to [O.vars[variable]]")
\ No newline at end of file
+ message_admins("[key_name_admin(src)] modified [original_name]'s [variable] to [O.vars[variable]]")
diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm
index 85fb049bd4d..5671bd85046 100644
--- a/code/modules/admin/verbs/pray.dm
+++ b/code/modules/admin/verbs/pray.dm
@@ -17,11 +17,21 @@
return
var/image/cross = image('icons/obj/storage.dmi',"bible")
- msg = "\icon[cross] PRAY: [key_name(src, 1)] (?) (PP) (VV) (SM) (JMP) (TP) (SC): [msg]"
-
+ if(usr.job == "Chaplain")
+ cross = image('icons/obj/storage.dmi',"kingyellow")
+ msg = "\icon[cross] CHAPLAIN PRAYER: [key_name(src, 1)] (?) (PP) (VV) (SM) (JMP) (TP) (SC): [msg]"
+ else if(iscultist(usr))
+ cross = image('icons/obj/storage.dmi',"tome")
+ msg = "\icon[cross] CULTIST PRAYER: [key_name(src, 1)] (?) (PP) (VV) (SM) (JMP) (TP) (SC): [msg]"
+ else
+ cross = image('icons/obj/storage.dmi',"bible")
+ msg = "\icon[cross] PRAYER: [key_name(src, 1)] (?) (PP) (VV) (SM) (JMP) (TP) (SC): [msg]"
for(var/client/C in admins)
if(C.prefs.chat_toggles & CHAT_PRAYER)
C << msg
+ if(C.prefs.toggles & SOUND_PRAYERS)
+ if(usr.job == "Chaplain")
+ C << 'sound/effects/pray.ogg'
usr << "Your prayers have been received by the gods."
feedback_add_details("admin_verb","PR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm
index 5d5aefac0be..1769315acab 100644
--- a/code/modules/assembly/holder.dm
+++ b/code/modules/assembly/holder.dm
@@ -21,6 +21,7 @@
attach(A2,user)
name = "[A.name]-[A2.name] assembly"
update_icon()
+ feedback_add_details("assembly_made","[name]")
/obj/item/device/assembly_holder/proc/attach(var/obj/item/device/assembly/A, var/mob/user)
if(!A.remove_item_from_storage(src))
diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm
index db9fbce26e5..99218130f57 100644
--- a/code/modules/client/preferences_toggles.dm
+++ b/code/modules/client/preferences_toggles.dm
@@ -82,6 +82,18 @@
src << "You will [(prefs.chat_toggles & CHAT_PRAYER) ? "now" : "no longer"] see prayerchat."
feedback_add_details("admin_verb","TP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+/client/verb/toggleprayersounds()
+ set name = "Hear/Silence Prayer Sounds"
+ set category = "Preferences"
+ set desc = "Toggles hearing pray sounds."
+ prefs.toggles ^= SOUND_PRAYERS
+ prefs.save_preferences()
+ if(prefs.toggles & SOUND_PRAYERS)
+ src << "You will now hear prayer sounds."
+ else
+ src << "You will no longer prayer sounds."
+ feedback_add_details("admin_verb", "PSounds")
+
/client/verb/togglePRs()
set name = "Show/Hide Pull Request Announcements"
set category = "Preferences"
@@ -208,7 +220,8 @@
var/list/ghost_forms = list("ghost","ghostking","ghostian2","skeleghost","ghost_red","ghost_black", \
"ghost_blue","ghost_yellow","ghost_green","ghost_pink", \
"ghost_cyan","ghost_dblue","ghost_dred","ghost_dgreen", \
- "ghost_dcyan","ghost_grey","ghost_dyellow","ghost_dpink")
+ "ghost_dcyan","ghost_grey","ghost_dyellow","ghost_dpink", "ghost_purpleswirl","ghost_funkypurp","ghost_pinksherbert","ghost_blazeit",\
+ "ghost_mellow","ghost_rainbow","ghost_camo","ghost_fire")
/client/verb/pick_form()
set name = "Choose Ghost Form"
set category = "Preferences"
diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm
index 2aecf9f789b..dd22a1e9f5c 100644
--- a/code/modules/clothing/suits/wiz_robe.dm
+++ b/code/modules/clothing/suits/wiz_robe.dm
@@ -19,6 +19,11 @@
desc = "Strange-looking yellow hat-wear that most certainly belongs to a powerful magic user."
icon_state = "yellowwizard"
+/obj/item/clothing/head/wizard/black
+ name = "black wizard hat"
+ desc = "Strange-looking black hat-wear that most certainly belongs to a real skeleton. Spooky."
+ icon_state = "blackwizard"
+
/obj/item/clothing/head/wizard/fake
name = "wizard hat"
desc = "It has WIZZARD written across it in sequins. Comes with a cool beard."
@@ -72,6 +77,12 @@
icon_state = "yellowwizard"
item_state = "yellowwizrobe"
+/obj/item/clothing/suit/wizrobe/black
+ name = "black wizard robe"
+ desc = "An unnerving black gem-lined robe that reeks of death and decay."
+ icon_state = "blackwizard"
+ item_state = "blackwizrobe"
+
/obj/item/clothing/suit/wizrobe/marisa
name = "witch robe"
desc = "Magic is all about the spell power, ZE!"
diff --git a/code/modules/crafting/table.dm b/code/modules/crafting/table.dm
index 75847c323f4..7f6e111599a 100644
--- a/code/modules/crafting/table.dm
+++ b/code/modules/crafting/table.dm
@@ -78,6 +78,7 @@
/obj/structure/table/proc/construct_item(mob/user, datum/table_recipe/R)
check_table()
+ var/send_feedback = 1
if(check_contents(R) && check_tools(user, R))
if(do_after(user, R.time))
if(!check_contents(R) || !check_tools(user, R))
@@ -86,6 +87,8 @@
if(istype(I, /obj/item/weapon/reagent_containers/food/snacks))
var/obj/item/weapon/reagent_containers/food/snacks/S = I
S.create_reagents(S.volume)
+ feedback_add_details("food_made","[S.name]")
+ send_feedback = 0
var/list/parts = del_reqs(R, I)
for(var/A in parts)
if(istype(A, /obj/item))
@@ -98,6 +101,8 @@
I.reagents = new /datum/reagents()
I.reagents.reagent_list.Add(A)
I.CheckParts()
+ if(send_feedback)
+ feedback_add_details("object_crafted","[I.name]")
return 1
return 0
diff --git a/code/modules/events/camerafailure.dm b/code/modules/events/camerafailure.dm
new file mode 100644
index 00000000000..458b50e9a83
--- /dev/null
+++ b/code/modules/events/camerafailure.dm
@@ -0,0 +1,20 @@
+/datum/round_event_control/camera_failure
+ name = "Camera Failure"
+ typepath = /datum/round_event/camera_failure
+ weight = 100
+ max_occurrences = 20
+ alertadmins = 0
+
+/datum/round_event/camera_failure
+ startWhen = 1
+ endWhen = 2
+ announceWhen = 0
+
+/datum/round_event/camera_failure/tick()
+ var/iterations = 1
+ var/obj/machinery/camera/C = pick(cameranet.cameras)
+ while(prob(round(100/iterations)))
+ while(!("SS13" in C.network))
+ C = pick(cameranet.cameras)
+ C.deactivate(null, 0)
+ iterations *= 2.5
diff --git a/code/modules/events/dust.dm b/code/modules/events/dust.dm
index 3dad124aabe..078f7dab63b 100644
--- a/code/modules/events/dust.dm
+++ b/code/modules/events/dust.dm
@@ -1,12 +1,11 @@
/datum/round_event_control/meteor_wave/dust
name = "Minor Space Dust"
typepath = /datum/round_event/meteor_wave/dust
- weight = 300
+ weight = 200
max_occurrences = 1000
earliest_start = 0
alertadmins = 0
-
/datum/round_event/meteor_wave/dust
startWhen = 1
endWhen = 2
@@ -19,4 +18,4 @@
spawn_meteors(1, meteorsC)
/datum/round_event/meteor_wave/dust/tick()
- return
\ No newline at end of file
+ return
diff --git a/code/modules/events/event.dm b/code/modules/events/event.dm
index e9661d5dc7c..07dbff7d269 100644
--- a/code/modules/events/event.dm
+++ b/code/modules/events/event.dm
@@ -28,6 +28,7 @@
return PROCESS_KILL
var/datum/round_event/E = new typepath()
E.control = src
+ feedback_add_details("event_ran","[E]")
occurrences++
testing("[time2text(world.time, "hh:mm:ss")] [E.type]")
diff --git a/code/modules/food&drinks/kitchen machinery/gibber.dm b/code/modules/food&drinks/kitchen machinery/gibber.dm
index 38a52ffa9ff..e5111bfb000 100644
--- a/code/modules/food&drinks/kitchen machinery/gibber.dm
+++ b/code/modules/food&drinks/kitchen machinery/gibber.dm
@@ -9,7 +9,9 @@
var/operating = 0 //Is it on?
var/dirty = 0 // Does it need cleaning?
var/gibtime = 40 // Time from starting until meat appears
- var/typeofmeat = /obj/item/weapon/reagent_containers/food/snacks/meat/
+ var/typeofmeat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/human
+ var/meat_produced = 0
+ var/ignore_clothing = 0
use_power = 1
idle_power_usage = 2
active_power_usage = 500
@@ -47,6 +49,21 @@
/obj/machinery/gibber/New()
..()
src.overlays += image('icons/obj/kitchen.dmi', "grjam")
+ component_parts = list()
+ component_parts += new /obj/item/weapon/circuitboard/gibber(null)
+ component_parts += new /obj/item/weapon/stock_parts/matter_bin(null)
+ component_parts += new /obj/item/weapon/stock_parts/manipulator(null)
+ RefreshParts()
+
+/obj/machinery/gibber/RefreshParts()
+ var/gib_time = 40
+ for(var/obj/item/weapon/stock_parts/matter_bin/B in component_parts)
+ meat_produced += 3 * B.rating
+ for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
+ gib_time -= 5 * M.rating
+ gibtime = gib_time
+ if(M.rating >= 2)
+ ignore_clothing = 1
/obj/machinery/gibber/update_icon()
overlays.Cut()
@@ -77,29 +94,43 @@
else
src.startgibbing(user)
-/obj/machinery/gibber/attackby(obj/item/weapon/grab/G as obj, mob/user as mob, params)
- if(default_unfasten_wrench(user, G))
+/obj/machinery/gibber/attackby(obj/item/P as obj, mob/user as mob, params)
+ if (istype(P, /obj/item/weapon/grab))
+ var/obj/item/weapon/grab/G = P
+ if(!istype(G.affecting, /mob/living/carbon/))
+ user << "This item is not suitable for the gibber!"
+ return
+ if(G.affecting.abiotic(1) && !ignore_clothing)
+ user << "Subject may not have abiotic items on."
+ return
+
+ user.visible_message("[user] starts to put [G.affecting] into the gibber!")
+ src.add_fingerprint(user)
+ if(do_after(user, gibtime) && G && G.affecting && !occupant)
+ user.visible_message("[user] stuffs [G.affecting] into the gibber!")
+ var/mob/M = G.affecting
+ if(M.client)
+ M.client.perspective = EYE_PERSPECTIVE
+ M.client.eye = src
+ M.loc = src
+ src.occupant = M
+ qdel(G)
+ update_icon()
+
+ if(default_deconstruction_screwdriver(user, "grinder_open", "grinder", P))
return
- if (!( istype(G, /obj/item/weapon/grab)) || !(istype(G.affecting, /mob/living/carbon/human)))
- user << "This item is not suitable for the gibber!"
- return
- if(G.affecting.abiotic(1))
- user << "Subject may not have abiotic items on."
+ if(exchange_parts(user, P))
return
- user.visible_message("[user] starts to put [G.affecting] into the gibber!")
- src.add_fingerprint(user)
- if(do_after(user, 30) && G && G.affecting && !occupant)
- user.visible_message("[user] stuffs [G.affecting] into the gibber!")
- var/mob/M = G.affecting
- if(M.client)
- M.client.perspective = EYE_PERSPECTIVE
- M.client.eye = src
- M.loc = src
- src.occupant = M
- qdel(G)
- update_icon()
+ if(default_pry_open(P))
+ return
+
+ if(default_unfasten_wrench(user, P))
+ return
+
+ default_deconstruction_crowbar(P)
+
/obj/machinery/gibber/verb/eject()
@@ -125,15 +156,21 @@
return
use_power(1000)
visible_message("You hear a loud squelchy grinding sound.")
+ playsound(src.loc, 'sound/machines/juicer.ogg', 50, 1)
src.operating = 1
update_icon()
+ var/offset = prob(50) ? -2 : 2
+ animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 200) //start shaking
var/sourcename = src.occupant.real_name
- var/sourcejob = src.occupant.job
+ var/sourcejob
+ if(ishuman(occupant))
+ var/mob/living/carbon/human/gibee = occupant
+ sourcejob = gibee.job
var/sourcenutriment = src.occupant.nutrition / 15
var/sourcetotalreagents = src.occupant.reagents.total_volume
- var/totalslabs = 3
+ var/gibtype = /obj/effect/decal/cleanable/blood/gibs
- var/obj/item/weapon/reagent_containers/food/snacks/meat/slab/human/allmeat[totalslabs]
+ var/obj/item/weapon/reagent_containers/food/snacks/meat/slab/allmeat[meat_produced]
if(ishuman(occupant))
var/mob/living/carbon/human/gibee = occupant
@@ -141,13 +178,19 @@
typeofmeat = gibee.dna.species.meat
else
typeofmeat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/human
- for (var/i=1 to totalslabs)
- var/obj/item/weapon/reagent_containers/food/snacks/meat/slab/human/newmeat = new typeofmeat
+ else
+ if(iscarbon(occupant))
+ var/mob/living/carbon/C = occupant
+ typeofmeat = C.type_of_meat
+ gibtype = C.gib_type
+ for (var/i=1 to meat_produced)
+ var/obj/item/weapon/reagent_containers/food/snacks/meat/slab/newmeat = new typeofmeat
newmeat.name = sourcename + newmeat.name
newmeat.subjectname = sourcename
- newmeat.subjectjob = sourcejob
- newmeat.reagents.add_reagent ("nutriment", sourcenutriment / totalslabs) // Thehehe. Fat guys go first
- src.occupant.reagents.trans_to (newmeat, round (sourcetotalreagents / totalslabs, 1)) // Transfer all the reagents from the
+ if(sourcejob)
+ newmeat.subjectjob = sourcejob
+ newmeat.reagents.add_reagent ("nutriment", sourcenutriment / meat_produced) // Thehehe. Fat guys go first
+ src.occupant.reagents.trans_to (newmeat, round (sourcetotalreagents / meat_produced, 1)) // Transfer all the reagents from the
allmeat[i] = newmeat
add_logs(user, occupant, "gibbed")
@@ -157,13 +200,17 @@
spawn(src.gibtime)
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
operating = 0
- for (var/i=1 to totalslabs)
+ for (var/i=1 to meat_produced)
+ var/list/nearby_turfs = orange(3, get_turf(src))
var/obj/item/meatslab = allmeat[i]
- var/turf/Tx = locate(src.x - i, src.y, src.z)
meatslab.loc = src.loc
- meatslab.throw_at(Tx,i,3)
- if (!Tx.density)
- new /obj/effect/decal/cleanable/blood/gibs(Tx,i)
+ meatslab.throw_at(pick(nearby_turfs),i,3)
+ for (var/turfs=1 to meat_produced*3)
+ var/turf/gibturf = pick(nearby_turfs)
+ if (!gibturf.density && src in viewers(gibturf))
+ new gibtype(gibturf,i)
+
+ pixel_x = initial(pixel_x) //return to its spot after shaking
src.operating = 0
update_icon()
diff --git a/code/modules/food&drinks/kitchen machinery/microwave.dm b/code/modules/food&drinks/kitchen machinery/microwave.dm
index ff196ae88db..b04ac183825 100644
--- a/code/modules/food&drinks/kitchen machinery/microwave.dm
+++ b/code/modules/food&drinks/kitchen machinery/microwave.dm
@@ -12,7 +12,7 @@
var/operating = 0 // Is it on?
var/dirty = 0 // = {0..100} Does it need cleaning?
var/broken = 0 // ={0,1,2} How broken is it???
- var/global/max_n_of_items = 10
+ var/max_n_of_items = 10 // whatever fat fuck made this a global var needs to look at themselves in the mirror sometime
var/efficiency = 0
var/microwavepower = 1
@@ -28,15 +28,20 @@
component_parts = list()
component_parts += new /obj/item/weapon/circuitboard/microwave(null)
component_parts += new /obj/item/weapon/stock_parts/micro_laser(null)
+ component_parts += new /obj/item/weapon/stock_parts/matter_bin(null)
component_parts += new /obj/item/weapon/stock_parts/console_screen(null)
component_parts += new /obj/item/stack/cable_coil(null, 2)
RefreshParts()
/obj/machinery/microwave/RefreshParts()
var/E
+ var/max_items = 10
for(var/obj/item/weapon/stock_parts/micro_laser/M in component_parts)
E += M.rating
+ for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts)
+ max_items = 10 * M.rating
efficiency = E
+ max_n_of_items = max_items
/*******************
* Item Adding
@@ -246,6 +251,7 @@
if(F.cooked_type)
var/obj/item/weapon/reagent_containers/food/snacks/S = new F.cooked_type (get_turf(src))
F.initialize_cooked_food(S, efficiency)
+ feedback_add_details("food_made","[F.name]")
else
new /obj/item/weapon/reagent_containers/food/snacks/badrecipe(src)
if(dirty < 100)
diff --git a/code/modules/food&drinks/kitchen machinery/monkeyrecycler.dm b/code/modules/food&drinks/kitchen machinery/monkeyrecycler.dm
index 7d709d9cf8f..bb88e5ec867 100644
--- a/code/modules/food&drinks/kitchen machinery/monkeyrecycler.dm
+++ b/code/modules/food&drinks/kitchen machinery/monkeyrecycler.dm
@@ -10,12 +10,44 @@
idle_power_usage = 5
active_power_usage = 50
var/grinded = 0
+ var/required_grind = 5
+ var/cube_production = 1
+/obj/machinery/monkey_recycler/New()
+ ..()
+ component_parts = list()
+ component_parts += new /obj/item/weapon/circuitboard/monkey_recycler(null)
+ component_parts += new /obj/item/weapon/stock_parts/manipulator(null)
+ component_parts += new /obj/item/weapon/stock_parts/matter_bin(null)
+ RefreshParts()
+
+/obj/machinery/monkey_recycler/RefreshParts()
+ var/req_grind = 5
+ var/cubes_made = 1
+ for(var/obj/item/weapon/stock_parts/manipulator/B in component_parts)
+ req_grind -= B.rating
+ for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts)
+ cubes_made = M.rating
+ cube_production = cubes_made
+ required_grind = req_grind
+
/obj/machinery/monkey_recycler/attackby(var/obj/item/O as obj, var/mob/user as mob, params)
- if(default_unfasten_wrench(user, O))
+ if(default_deconstruction_screwdriver(user, "grinder_open", "grinder", O))
return
+ if(exchange_parts(user, O))
+ return
+
+ if(default_pry_open(O))
+ return
+
+ if(default_unfasten_wrench(user, O))
+ power_change()
+ return
+
+ default_deconstruction_crowbar(O)
+
if (src.stat != 0) //NOPOWER etc
return
if (istype(O, /obj/item/weapon/grab))
@@ -32,8 +64,12 @@
qdel(target)
user << "You stuff the monkey in the machine."
playsound(src.loc, 'sound/machines/juicer.ogg', 50, 1)
+ var/offset = prob(50) ? -2 : 2
+ animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 200) //start shaking
use_power(500)
src.grinded++
+ sleep(50)
+ pixel_x = initial(pixel_x) //return to its spot after shaking
user << "The machine now has [grinded] monkey\s worth of material stored."
else
@@ -43,12 +79,13 @@
/obj/machinery/monkey_recycler/attack_hand(var/mob/user as mob)
if (src.stat != 0) //NOPOWER etc
return
- if(grinded >= 5)
+ if(grinded >= required_grind)
user << "The machine hisses loudly as it condenses the grinded monkey meat. After a moment, it dispenses a brand new monkey cube."
playsound(src.loc, 'sound/machines/hiss.ogg', 50, 1)
- grinded -= 5
- new /obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped(src.loc)
+ grinded -= required_grind
+ for(var/i = 0, i < cube_production, i++)
+ new /obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped(src.loc)
user << "The machine's display flashes that it has [grinded] monkeys worth of material left."
else
- user << "The machine needs at least 5 monkeys worth of material to produce a monkey cube. It only has [grinded]."
+ user << "The machine needs at least [required_grind] monkey(s) worth of material to produce a monkey cube. It only has [grinded]."
return
diff --git a/code/modules/food&drinks/kitchen machinery/processor.dm b/code/modules/food&drinks/kitchen machinery/processor.dm
index cde0bf70683..78038266d98 100644
--- a/code/modules/food&drinks/kitchen machinery/processor.dm
+++ b/code/modules/food&drinks/kitchen machinery/processor.dm
@@ -12,16 +12,31 @@
use_power = 1
idle_power_usage = 5
active_power_usage = 50
+ var/rating_speed = 1
+ var/rating_amount = 1
+/obj/machinery/processor/New()
+ ..()
+ component_parts = list()
+ component_parts += new /obj/item/weapon/circuitboard/processor(null)
+ component_parts += new /obj/item/weapon/stock_parts/matter_bin(null)
+ component_parts += new /obj/item/weapon/stock_parts/manipulator(null)
+ RefreshParts()
+/obj/machinery/processor/RefreshParts()
+ for(var/obj/item/weapon/stock_parts/matter_bin/B in component_parts)
+ rating_amount = B.rating
+ for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
+ rating_speed = M.rating
/datum/food_processor_process
var/input
var/output
var/time = 40
-/datum/food_processor_process/proc/process_food(loc, what)
- if (src.output && loc)
- new src.output(loc)
+/datum/food_processor_process/proc/process_food(loc, what, var/obj/machinery/processor/processor)
+ if (src.output && loc && processor)
+ for(var/i = 0, i < processor.rating_amount, i++)
+ new src.output(loc)
if (what)
qdel(what) // Note to self: Make this safer
@@ -60,18 +75,18 @@
/* mobs */
-/datum/food_processor_process/mob/process_food(loc, what)
+/datum/food_processor_process/mob/process_food(loc, what, processor)
..()
-/datum/food_processor_process/mob/slime/process_food(loc, what)
+/datum/food_processor_process/mob/slime/process_food(loc, what, var/obj/machinery/processor/processor)
var/mob/living/simple_animal/slime/S = what
var/C = S.cores
if(S.stat != DEAD)
S.loc = loc
S.visible_message("[C] crawls free of the processor!")
return
- for(var/i = 1, i <= C, i++)
+ for(var/i = 1, i <= C + processor.rating_amount, i++)
new S.coretype(loc)
feedback_add_details("slime_core_harvested","[replacetext(S.colour," ","_")]")
..()
@@ -79,7 +94,7 @@
/datum/food_processor_process/mob/slime/input = /mob/living/simple_animal/slime
/datum/food_processor_process/mob/slime/output = null
-/datum/food_processor_process/mob/monkey/process_food(loc, what)
+/datum/food_processor_process/mob/monkey/process_food(loc, what, processor)
var/mob/living/carbon/monkey/O = what
if (O.client) //grief-proof
O.loc = loc
@@ -123,8 +138,20 @@
if(src.processing)
user << "The processor is in the process of processing!"
return 1
+ if(default_deconstruction_screwdriver(user, "processor1", "processor", O))
+ return
+
+ if(exchange_parts(user, O))
+ return
+
+ if(default_pry_open(O))
+ return
+
if(default_unfasten_wrench(user, O))
return
+
+ default_deconstruction_crowbar(O)
+
var/what = O
if (istype(O, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = O
@@ -151,20 +178,30 @@
if(src.contents.len == 0)
user << "The processor is empty!"
return 1
+ src.processing = 1
+ user.visible_message("[user] turns on [src].", \
+ "You turn on [src].", \
+ "You hear a food processor.")
+ playsound(src.loc, 'sound/machines/blender.ogg', 50, 1)
+ use_power(500)
+ var/total_time = 0
+ for(var/O in src.contents)
+ var/datum/food_processor_process/P = select_recipe(O)
+ if (!P)
+ log_admin("DEBUG: [O] in processor havent suitable recipe. How do you put it in?") //-rastaf0 // DEAR GOD THIS BURNS MY EYES HAVE YOU EVER LOOKED IN AN ENGLISH DICTONARY BEFORE IN YOUR LIFE AAAAAAAAAAAAAAAAAAAAA - Iamgoofball
+ continue
+ total_time += P.time
+ var/offset = prob(50) ? -2 : 2
+ animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = (total_time / rating_speed)*5) //start shaking
+ sleep(total_time / rating_speed)
for(var/O in src.contents)
var/datum/food_processor_process/P = select_recipe(O)
if (!P)
log_admin("DEBUG: [O] in processor havent suitable recipe. How do you put it in?") //-rastaf0
continue
- src.processing = 1
- user.visible_message("[user] turns on \a [src].", \
- "You turn on \a [src].", \
- "You hear a food processor.")
- playsound(src.loc, 'sound/machines/blender.ogg', 50, 1)
- use_power(500)
- sleep(P.time)
- P.process_food(src.loc, O)
- src.processing = 0
+ P.process_food(src.loc, O, src)
+ pixel_x = initial(pixel_x) //return to its spot after shaking
+ src.processing = 0
src.visible_message("\the [src] finishes processing.")
/obj/machinery/processor/verb/eject()
diff --git a/code/modules/food&drinks/kitchen machinery/smartfridge.dm b/code/modules/food&drinks/kitchen machinery/smartfridge.dm
index 9746ee4a83c..dce85ce5ed2 100644
--- a/code/modules/food&drinks/kitchen machinery/smartfridge.dm
+++ b/code/modules/food&drinks/kitchen machinery/smartfridge.dm
@@ -13,11 +13,22 @@
idle_power_usage = 5
active_power_usage = 100
flags = NOREACT
- var/global/max_n_of_items = 999 // Sorry but the BYOND infinite loop detector doesn't like things over 1000.
+ var/max_n_of_items = 1500
var/icon_on = "smartfridge"
var/icon_off = "smartfridge-off"
var/item_quants = list()
+/obj/machinery/smartfridge/New()
+ ..()
+ component_parts = list()
+ component_parts += new /obj/item/weapon/circuitboard/smartfridge(null)
+ component_parts += new /obj/item/weapon/stock_parts/matter_bin(null)
+ RefreshParts()
+
+/obj/machinery/smartfridge/RefreshParts()
+ for(var/obj/item/weapon/stock_parts/matter_bin/B in component_parts)
+ max_n_of_items = 1500 * B.rating
+
/obj/machinery/smartfridge/power_change()
..()
update_icon()
@@ -35,9 +46,21 @@
********************/
/obj/machinery/smartfridge/attackby(var/obj/item/O as obj, var/mob/user as mob, params)
+ if(default_deconstruction_screwdriver(user, "smartfridge_open", "smartfridge", O))
+ return
+
+ if(exchange_parts(user, O))
+ return
+
+ if(default_pry_open(O))
+ return
+
if(default_unfasten_wrench(user, O))
power_change()
return
+
+ default_deconstruction_crowbar(O)
+
if(stat)
return 0
diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm
index 41d7dedaaa5..ba32bb2c6ff 100644
--- a/code/modules/hydroponics/biogenerator.dm
+++ b/code/modules/hydroponics/biogenerator.dm
@@ -13,6 +13,7 @@
var/menustat = "menu"
var/efficiency = 0
var/productivity = 0
+ var/max_items = 40
/obj/machinery/biogenerator/New()
..()
@@ -28,12 +29,15 @@
/obj/machinery/biogenerator/RefreshParts()
var/E = 0
var/P = 0
+ var/max_storage = 40
for(var/obj/item/weapon/stock_parts/matter_bin/B in component_parts)
P += B.rating
+ max_storage = 40 * B.rating
for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
E += M.rating
efficiency = E
productivity = P
+ max_items = max_storage
/obj/machinery/biogenerator/on_reagent_change() //When the reagents change, change the icon as well.
update_icon()
@@ -65,15 +69,15 @@
var/i = 0
for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in contents)
i++
- if(i >= 10)
+ if(i >= max_items)
user << "The biogenerator is already full! Activate it."
else
for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in O.contents)
- if(i >= 10)
+ if(i >= max_items)
break
G.loc = src
i++
- if(i<10)
+ if(i
"
dat += "Plant bag: Make ([200/efficiency])
"
dat += "Mining satchel: Make ([200/efficiency])
"
+ dat += "Chemistry bag: Make ([200/efficiency])
"
dat += "Botanical gloves: Make ([250/efficiency])
"
dat += "Utility belt: Make ([300/efficiency])
"
dat += "Security belt: Make ([300/efficiency])
"
@@ -266,6 +271,9 @@
if("mnbag")
if (check_cost(200/efficiency)) return 0
else new/obj/item/weapon/storage/bag/ore(src.loc)
+ if("chbag")
+ if (check_cost(200/efficiency)) return 0
+ else new/obj/item/weapon/storage/bag/chemistry(src.loc)
if("gloves")
if (check_cost(250/efficiency)) return 0
else new/obj/item/clothing/gloves/botanic_leather(src.loc)
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index 78a92dc1481..608414b38c2 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -22,6 +22,7 @@
var/planted = 0 //Is it occupied?
var/harvest = 0 //Ready to harvest?
var/obj/item/seeds/myseed = null //The currently planted seed
+ var/rating = 1
var/unwrenchable = 1
pixel_y=8
@@ -37,22 +38,34 @@
component_parts += new /obj/item/weapon/circuitboard/hydroponics(null)
component_parts += new /obj/item/weapon/stock_parts/matter_bin(null)
component_parts += new /obj/item/weapon/stock_parts/matter_bin(null)
+ component_parts += new /obj/item/weapon/stock_parts/manipulator(null)
component_parts += new /obj/item/weapon/stock_parts/console_screen(null)
RefreshParts()
/obj/machinery/hydroponics/constructable/RefreshParts()
- var tmp_capacity = 0
+ var/tmp_capacity = 0
for (var/obj/item/weapon/stock_parts/matter_bin/M in component_parts)
tmp_capacity += M.rating
+ for (var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
+ rating = M.rating
maxwater = tmp_capacity * 50 // Up to 300
maxnutri = tmp_capacity * 5 // Up to 30
waterlevel = maxwater
nutrilevel = 3
/obj/machinery/hydroponics/constructable/attackby(obj/item/I, mob/user, params)
+ if(default_deconstruction_screwdriver(user, "hydrotray3", "hydrotray3", I))
+ return
+
if(exchange_parts(user, I))
return
+ if(default_pry_open(I))
+ return
+
+ if(default_unfasten_wrench(user, I))
+ return
+
if(istype(I, /obj/item/weapon/crowbar))
if(anchored==2)
user << "Unscrew the hoses first!"
@@ -89,10 +102,10 @@
mutate()
else if(istype(Proj ,/obj/item/projectile/energy/florayield))
if(myseed.yield == 0)//Oh god don't divide by zero you'll doom us all.
- adjustSYield(1)
+ adjustSYield(1 * rating)
//world << "Yield increased by 1, from 0, to a total of [myseed.yield]"
else if(prob(1/(myseed.yield * myseed.yield) * 100))//This formula gives you diminishing returns based on yield. 100% with 1 yield, decreasing to 25%, 11%, 6, 4, 2...
- adjustSYield(1)
+ adjustSYield(1 * rating)
//world << "Yield increased by 1, to a total of [myseed.yield]"
else
..()
@@ -115,7 +128,7 @@
//Nutrients//////////////////////////////////////////////////////////////
// Nutrients deplete slowly
if(prob(50))
- adjustNutri(-1)
+ adjustNutri(-1 / rating)
// Lack of nutrients hurts non-weeds
if(nutrilevel <= 0 && myseed.plant_type != 1)
@@ -128,56 +141,56 @@
var/lightAmt = currentTurf.lighting_lumcount
if(myseed.plant_type == 2) // Mushroom
if(lightAmt < 2)
- adjustHealth(-1)
+ adjustHealth(-1 / rating)
else // Non-mushroom
if(lightAmt < 4)
- adjustHealth(-2)
+ adjustHealth(-2 / rating)
//Water//////////////////////////////////////////////////////////////////
// Drink random amount of water
- adjustWater(-rand(1,6))
+ adjustWater(-rand(1,6) / rating)
// If the plant is dry, it loses health pretty fast, unless mushroom
if(waterlevel <= 10 && myseed.plant_type != 2)
- adjustHealth(-rand(0,1))
+ adjustHealth(-rand(0,1) / rating)
if(waterlevel <= 0)
- adjustHealth(-rand(0,2))
+ adjustHealth(-rand(0,2) / rating)
// Sufficient water level and nutrient level = plant healthy
else if(waterlevel > 10 && nutrilevel > 0)
- adjustHealth(rand(1,2))
+ adjustHealth(rand(1,2) / rating)
if(prob(5)) //5 percent chance the weed population will increase
- adjustWeeds(1)
+ adjustWeeds(1 / rating)
//Toxins/////////////////////////////////////////////////////////////////
// Too much toxins cause harm, but when the plant drinks the contaiminated water, the toxins disappear slowly
if(toxic >= 40 && toxic < 80)
- adjustHealth(-1)
- adjustToxic(-rand(1,10))
+ adjustHealth(-1 / rating)
+ adjustToxic(-rand(1,10) / rating)
else if(toxic >= 80) // I don't think it ever gets here tbh unless above is commented out
adjustHealth(-3)
- adjustToxic(-rand(1,10))
+ adjustToxic(-rand(1,10) / rating)
//Pests & Weeds//////////////////////////////////////////////////////////
else if(pestlevel >= 5)
- adjustHealth(-1)
+ adjustHealth(-1 / rating)
// If it's a weed, it doesn't stunt the growth
if(weedlevel >= 5 && myseed.plant_type != 1 )
- adjustHealth(-1)
+ adjustHealth(-1 / rating)
//Health & Age///////////////////////////////////////////////////////////
// Plant dies if health <= 0
if(health <= 0)
plantdies()
- adjustWeeds(1) // Weeds flourish
+ adjustWeeds(1 / rating) // Weeds flourish
// If the plant is too old, lose health fast
if(age > myseed.lifespan)
- adjustHealth(-rand(1,5))
+ adjustHealth(-rand(1,5) / rating)
// Harvest code
if(age > myseed.production && (age - lastproduce) > myseed.production && (!harvest && !dead))
@@ -187,10 +200,10 @@
else
lastproduce = age
if(prob(5)) // On each tick, there's a 5 percent chance the pest population will increase
- adjustPests(1)
+ adjustPests(1 / rating)
else
if(waterlevel > 10 && nutrilevel > 0 && prob(10)) // If there's no plant, the percentage chance is 10%
- adjustWeeds(1)
+ adjustWeeds(1 / rating)
// Weeeeeeeeeeeeeeedddssss
@@ -436,18 +449,18 @@
// Nutriments
if(S.has_reagent("eznutriment", 1))
- yieldmod = 1
- mutmod = 1
+ yieldmod = 1 * rating
+ mutmod = 1 * rating
adjustNutri(round(S.get_reagent_amount("eznutriment") * 1))
if(S.has_reagent("left4zednutriment", 1))
- yieldmod = 0
- mutmod = 2
+ yieldmod = 0 * rating
+ mutmod = 2 * rating
adjustNutri(round(S.get_reagent_amount("left4zednutriment") * 1))
if(S.has_reagent("robustharvestnutriment", 1))
- yieldmod = 2
- mutmod = 0
+ yieldmod = 2 * rating
+ mutmod = 0 * rating
adjustNutri(round(S.get_reagent_amount("robustharvestnutriment") *1 ))
// Antitoxin binds shit pretty well. So the tox goes significantly down
@@ -734,17 +747,17 @@
user.visible_message("[user] unwrenches [src].", \
"You unwrench [src].")
- else if(istype(O, /obj/item/weapon/screwdriver) && unwrenchable) //THIS NEED TO BE DONE DIFFERENTLY, SOMEONE REFACTOR THE TRAY CODE ALREADY
+ else if(istype(O, /obj/item/weapon/wirecutters) && unwrenchable) //THIS NEED TO BE DONE DIFFERENTLY, SOMEONE REFACTOR THE TRAY CODE ALREADY
if(anchored)
if(anchored == 2)
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1)
anchored = 1
- user << "You unscrew \the [src]'s hoses."
+ user << "You snip \the [src]'s hoses."
else if(anchored == 1)
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1)
anchored = 2
- user << "You screw in \the [src]'s hoses."
+ user << "You reconnect \the [src]'s hoses."
for(var/obj/machinery/hydroponics/h in range(1,src))
spawn()
@@ -789,7 +802,7 @@
var/t_amount = 0
var/list/result = list()
var/output_loc = parent.Adjacent(user) ? user.loc : parent.loc //needed for TK
-
+ var/product_name
while(t_amount < getYield())
var/obj/item/weapon/reagent_containers/food/snacks/grown/t_prod = new product(output_loc, potency)
result.Add(t_prod) // User gets a consumable
@@ -802,7 +815,9 @@
t_prod.potency = potency
t_prod.plant_type = plant_type
t_amount++
-
+ product_name = t_prod.name
+ if(getYield() >= 1)
+ feedback_add_details("food_harvested","[product_name]|[getYield()]")
parent.update_tray()
return result
diff --git a/code/modules/hydroponics/seed_extractor.dm b/code/modules/hydroponics/seed_extractor.dm
index c7169acc0c3..0ad83aeb190 100644
--- a/code/modules/hydroponics/seed_extractor.dm
+++ b/code/modules/hydroponics/seed_extractor.dm
@@ -1,7 +1,10 @@
-/proc/seedify(var/obj/item/O as obj, var/t_max)
+/proc/seedify(var/obj/item/O as obj, var/t_max, var/obj/machinery/seed_extractor/extractor)
var/t_amount = 0
if(t_max == -1)
- t_max = rand(1,4)
+ if(extractor)
+ t_max = rand(1,4) * extractor.seed_multiplier
+ else
+ t_max = rand(1,4)
if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/grown/))
var/obj/item/weapon/reagent_containers/food/snacks/grown/F = O
@@ -51,8 +54,39 @@
density = 1
anchored = 1
var/piles = list()
+ var/max_seeds = 1000
+ var/seed_multiplier = 1
+
+/obj/machinery/seed_extractor/New()
+ ..()
+ component_parts = list()
+ component_parts += new /obj/item/weapon/circuitboard/seed_extractor(null)
+ component_parts += new /obj/item/weapon/stock_parts/matter_bin(null)
+ component_parts += new /obj/item/weapon/stock_parts/manipulator(null)
+ RefreshParts()
+
+/obj/machinery/seed_extractor/RefreshParts()
+ for(var/obj/item/weapon/stock_parts/matter_bin/B in component_parts)
+ max_seeds = 1000 * B.rating
+ for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
+ seed_multiplier = M.rating
/obj/machinery/seed_extractor/attackby(var/obj/item/O as obj, var/mob/user as mob, params)
+
+ if(default_deconstruction_screwdriver(user, "sextractor_open", "sextractor", O))
+ return
+
+ if(exchange_parts(user, O))
+ return
+
+ if(default_pry_open(O))
+ return
+
+ if(default_unfasten_wrench(user, O))
+ return
+
+ default_deconstruction_crowbar(O)
+
if(isrobot(user))
return
@@ -60,7 +94,7 @@
var/obj/item/weapon/storage/P = O
var/loaded = 0
for(var/obj/item/seeds/G in P.contents)
- if(contents.len >= 999)
+ if(contents.len >= max_seeds)
break
++loaded
add(G)
diff --git a/code/modules/mining/equipment_locker.dm b/code/modules/mining/equipment_locker.dm
index 1b81cbe8e9c..1dd002229be 100644
--- a/code/modules/mining/equipment_locker.dm
+++ b/code/modules/mining/equipment_locker.dm
@@ -16,6 +16,9 @@
var/stack_list[0] //Key: Type. Value: Instance of type.
var/obj/item/weapon/card/id/inserted_id
var/points = 0
+ var/ore_pickup_rate = 15
+ var/sheet_per_ore = 1
+ var/point_upgrade = 1
var/list/ore_values = list(("sand" = 1), ("iron" = 1), ("gold" = 20), ("silver" = 20), ("uranium" = 20), ("bananium" = 30), ("diamond" = 40), ("plasma" = 40))
/obj/machinery/mineral/ore_redemption/New()
@@ -23,10 +26,26 @@
component_parts = list()
component_parts += new /obj/item/weapon/circuitboard/ore_redemption(null)
component_parts += new /obj/item/weapon/stock_parts/matter_bin(null)
+ component_parts += new /obj/item/weapon/stock_parts/manipulator(null)
+ component_parts += new /obj/item/weapon/stock_parts/micro_laser(null)
component_parts += new /obj/item/device/assembly/igniter(null)
component_parts += new /obj/item/weapon/stock_parts/console_screen(null)
RefreshParts()
+/obj/machinery/mineral/ore_redemption/RefreshParts()
+ var/ore_pickup_rate_temp = 15
+ var/point_upgrade_temp = 1
+ var/sheet_per_ore_temp = 1
+ for(var/obj/item/weapon/stock_parts/matter_bin/B in component_parts)
+ sheet_per_ore_temp = B.rating
+ for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
+ ore_pickup_rate_temp = 15 * M.rating
+ for(var/obj/item/weapon/stock_parts/micro_laser/L in component_parts)
+ point_upgrade_temp = L.rating
+ ore_pickup_rate = ore_pickup_rate_temp
+ point_upgrade = point_upgrade_temp
+ sheet_per_ore = sheet_per_ore_temp
+
/obj/machinery/mineral/ore_redemption/proc/process_sheet(obj/item/weapon/ore/O)
var/obj/item/stack/sheet/processed_sheet = SmeltMineral(O)
if(processed_sheet)
@@ -40,7 +59,7 @@
if(D.department == "Science" || D.department == "Robotics" || D.department == "Research Director's Desk" || (D.department == "Chemistry" && (s.name == "uranium" || s.name == "solid plasma")))
D.createmessage("Ore Redemption Machine", "New minerals available!", msg, 1, 0)
var/obj/item/stack/sheet/storage = stack_list[processed_sheet]
- storage.amount += 1 //Stack the sheets
+ storage.amount += sheet_per_ore //Stack the sheets
O.loc = null //Let the old sheet...
qdel(O) //... garbage collect
@@ -50,7 +69,7 @@
var/i
if(T)
if(locate(/obj/item/weapon/ore) in T)
- for (i = 0; i < 10; i++)
+ for (i = 0; i < ore_pickup_rate; i++)
var/obj/item/weapon/ore/O = locate() in T
if(O)
process_sheet(O)
@@ -59,7 +78,7 @@
else
var/obj/structure/ore_box/B = locate() in T
if(B)
- for (i = 0; i < 10; i++)
+ for (i = 0; i < ore_pickup_rate; i++)
var/obj/item/weapon/ore/O = locate() in B.contents
if(O)
process_sheet(O)
@@ -75,6 +94,14 @@
inserted_id = I
interact(user)
return
+ if(exchange_parts(user, W))
+ return
+
+ if(default_pry_open(W))
+ return
+
+ if(default_unfasten_wrench(user, W))
+ return
if(default_deconstruction_screwdriver(user, "ore_redemption-open", "ore_redemption", W))
updateUsrDialog()
return
@@ -88,7 +115,7 @@
/obj/machinery/mineral/ore_redemption/proc/SmeltMineral(var/obj/item/weapon/ore/O)
if(O.refined_type)
var/obj/item/stack/sheet/M = O.refined_type
- points += O.points
+ points += O.points * point_upgrade
return M
qdel(O)//No refined type? Purge it.
return
@@ -135,7 +162,7 @@
var/dat = "
| [capitalize(ore)] | [value] |
| [capitalize(ore)] | [value * point_upgrade] |