diff --git a/code/ATMOSPHERICS/components/shutoff.dm b/code/ATMOSPHERICS/components/shutoff.dm
new file mode 100644
index 0000000000..b1fb43baa1
--- /dev/null
+++ b/code/ATMOSPHERICS/components/shutoff.dm
@@ -0,0 +1,50 @@
+/obj/machinery/atmospherics/valve/shutoff
+ icon = 'icons/atmos/clamp.dmi'
+ icon_state = "map_vclamp0"
+
+ name = "automatic shutoff valve"
+ desc = "An automatic valve with control circuitry and pipe integrity sensor, capable of automatically isolating damaged segments of the pipe network."
+ var/close_on_leaks = TRUE // If false it will be always open
+ level = 1
+ connect_types = CONNECT_TYPE_SCRUBBER | CONNECT_TYPE_SUPPLY | CONNECT_TYPE_REGULAR
+
+/obj/machinery/atmospherics/valve/shutoff/update_icon()
+ icon_state = "vclamp[open]"
+
+/obj/machinery/atmospherics/valve/shutoff/examine(var/mob/user)
+ ..()
+ to_chat(user, "The automatic shutoff circuit is [close_on_leaks ? "enabled" : "disabled"].")
+
+/obj/machinery/atmospherics/valve/shutoff/Initialize()
+ . = ..()
+ open()
+ hide(1)
+
+/obj/machinery/atmospherics/valve/shutoff/attack_ai(mob/user as mob)
+ return src.attack_hand(user)
+
+/obj/machinery/atmospherics/valve/shutoff/attack_hand(var/mob/user)
+ src.add_fingerprint(usr)
+ update_icon(1)
+ close_on_leaks = !close_on_leaks
+ to_chat(user, "You [close_on_leaks ? "enable" : "disable"] the automatic shutoff circuit.")
+ return TRUE
+
+/obj/machinery/atmospherics/valve/shutoff/process()
+ ..()
+
+ if (!network_node1 || !network_node2)
+ if(open)
+ close()
+ return
+
+ if (!close_on_leaks)
+ if (!open)
+ open()
+ return
+
+ if (network_node1.leaks.len || network_node2.leaks.len)
+ if (open)
+ close()
+ else if (!open)
+ open()
diff --git a/code/ATMOSPHERICS/datum_pipe_network.dm b/code/ATMOSPHERICS/datum_pipe_network.dm
index eb5e89276e..a611e30a89 100644
--- a/code/ATMOSPHERICS/datum_pipe_network.dm
+++ b/code/ATMOSPHERICS/datum_pipe_network.dm
@@ -8,76 +8,83 @@ var/global/list/datum/pipe_network/pipe_networks = list() // TODO - Move into SS
var/list/datum/pipeline/line_members = list()
//membership roster to go through for updates and what not
+ var/list/leaks = list()
+
var/update = 1
//var/datum/gas_mixture/air_transient = null
- Destroy()
- STOP_PROCESSING_PIPENET(src)
- for(var/datum/pipeline/line_member in line_members)
- line_member.network = null
- for(var/obj/machinery/atmospherics/normal_member in normal_members)
- normal_member.reassign_network(src, null)
- gases.Cut() // Do not qdel the gases, we don't own them
- return ..()
+/datum/pipe_network/Destroy()
+ STOP_PROCESSING_PIPENET(src)
+ for(var/datum/pipeline/line_member in line_members)
+ line_member.network = null
+ for(var/obj/machinery/atmospherics/normal_member in normal_members)
+ normal_member.reassign_network(src, null)
+ gases.Cut() // Do not qdel the gases, we don't own them
+ leaks.Cut()
+ return ..()
- process()
- //Equalize gases amongst pipe if called for
- if(update)
- update = 0
- reconcile_air() //equalize_gases(gases)
+/datum/pipe_network/process()
+ //Equalize gases amongst pipe if called for
+ if(update)
+ update = 0
+ reconcile_air() //equalize_gases(gases)
- //Give pipelines their process call for pressure checking and what not. Have to remove pressure checks for the time being as pipes dont radiate heat - Mport
- //for(var/datum/pipeline/line_member in line_members)
- // line_member.process()
+ listclearnulls(leaks) // Let's not have forever-seals.
- proc/build_network(obj/machinery/atmospherics/start_normal, obj/machinery/atmospherics/reference)
- //Purpose: Generate membership roster
- //Notes: Assuming that members will add themselves to appropriate roster in network_expand()
+ //Give pipelines their process call for pressure checking and what not. Have to remove pressure checks for the time being as pipes dont radiate heat - Mport
+ //for(var/datum/pipeline/line_member in line_members)
+ // line_member.process()
- if(!start_normal)
- qdel(src)
- return
+/datum/pipe_network/proc/build_network(obj/machinery/atmospherics/start_normal, obj/machinery/atmospherics/reference)
+ //Purpose: Generate membership roster
+ //Notes: Assuming that members will add themselves to appropriate roster in network_expand()
- start_normal.network_expand(src, reference)
+ if(!start_normal)
+ qdel(src)
+ return
- update_network_gases()
+ start_normal.network_expand(src, reference)
- if((normal_members.len>0)||(line_members.len>0))
- START_PROCESSING_PIPENET(src)
- else
- qdel(src)
+ update_network_gases()
- proc/merge(datum/pipe_network/giver)
- if(giver==src) return 0
+ if((normal_members.len>0)||(line_members.len>0))
+ START_PROCESSING_PIPENET(src)
+ else
+ qdel(src)
- normal_members |= giver.normal_members
+/datum/pipe_network/proc/merge(datum/pipe_network/giver)
+ if(giver==src) return 0
- line_members |= giver.line_members
+ normal_members |= giver.normal_members
- for(var/obj/machinery/atmospherics/normal_member in giver.normal_members)
- normal_member.reassign_network(giver, src)
+ line_members |= giver.line_members
- for(var/datum/pipeline/line_member in giver.line_members)
- line_member.network = src
+ leaks |= giver.leaks
- update_network_gases()
- return 1
+ for(var/obj/machinery/atmospherics/normal_member in giver.normal_members)
+ normal_member.reassign_network(giver, src)
- proc/update_network_gases()
- //Go through membership roster and make sure gases is up to date
+ for(var/datum/pipeline/line_member in giver.line_members)
+ line_member.network = src
- gases = list()
- volume = 0
+ update_network_gases()
+ return 1
- for(var/obj/machinery/atmospherics/normal_member in normal_members)
- var/result = normal_member.return_network_air(src)
- if(result) gases += result
+/datum/pipe_network/proc/update_network_gases()
+ //Go through membership roster and make sure gases is up to date
- for(var/datum/pipeline/line_member in line_members)
- gases += line_member.air
+ gases = list()
+ volume = 0
- for(var/datum/gas_mixture/air in gases)
- volume += air.volume
+ for(var/obj/machinery/atmospherics/normal_member in normal_members)
+ var/result = normal_member.return_network_air(src)
+ if(result) gases += result
- proc/reconcile_air()
- equalize_gases(gases)
+ for(var/datum/pipeline/line_member in line_members)
+ gases += line_member.air
+
+ for(var/datum/gas_mixture/air in gases)
+ volume += air.volume
+
+/datum/pipe_network/proc/reconcile_air()
+ equalize_gases(gases)
diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm
index fc47bca938..b53d722458 100644
--- a/code/ATMOSPHERICS/datum_pipeline.dm
+++ b/code/ATMOSPHERICS/datum_pipeline.dm
@@ -1,219 +1,234 @@
-datum/pipeline
+/datum/pipeline
var/datum/gas_mixture/air
var/list/obj/machinery/atmospherics/pipe/members
var/list/obj/machinery/atmospherics/pipe/edges //Used for building networks
+ // Nodes that are leaking. Used for A.S. Valves.
+ var/list/leaks = list()
+
var/datum/pipe_network/network
var/alert_pressure = 0
- Destroy()
- QDEL_NULL(network)
+/datum/pipeline/Destroy()
+ QDEL_NULL(network)
- if(air && air.volume)
- temporarily_store_air()
- for(var/obj/machinery/atmospherics/pipe/P in members)
- P.parent = null
- members = null
- edges = null
- . = ..()
+ if(air && air.volume)
+ temporarily_store_air()
+ for(var/obj/machinery/atmospherics/pipe/P in members)
+ P.parent = null
+ members = null
+ edges = null
+ leaks = null
+ . = ..()
- process()//This use to be called called from the pipe networks
-
- //Check to see if pressure is within acceptable limits
- var/pressure = air.return_pressure()
- if(pressure > alert_pressure)
- for(var/obj/machinery/atmospherics/pipe/member in members)
- if(!member.check_pressure(pressure))
- break //Only delete 1 pipe per process
-
- proc/temporarily_store_air()
- //Update individual gas_mixtures by volume ratio
+/datum/pipeline/process()//This use to be called called from the pipe networks
+ //Check to see if pressure is within acceptable limits
+ var/pressure = air.return_pressure()
+ if(pressure > alert_pressure)
for(var/obj/machinery/atmospherics/pipe/member in members)
- member.air_temporary = new
- member.air_temporary.copy_from(air)
- member.air_temporary.volume = member.volume
- member.air_temporary.multiply(member.volume / air.volume)
+ if(!member.check_pressure(pressure))
+ break //Only delete 1 pipe per process
- proc/build_pipeline(obj/machinery/atmospherics/pipe/base)
+/datum/pipeline/proc/temporarily_store_air()
+ //Update individual gas_mixtures by volume ratio
+
+ for(var/obj/machinery/atmospherics/pipe/member in members)
+ member.air_temporary = new
+ member.air_temporary.copy_from(air)
+ member.air_temporary.volume = member.volume
+ member.air_temporary.multiply(member.volume / air.volume)
+
+/datum/pipeline/proc/build_pipeline(obj/machinery/atmospherics/pipe/base)
+ air = new
+
+ var/list/possible_expansions = list(base)
+ members = list(base)
+ edges = list()
+
+ var/volume = base.volume
+ base.parent = src
+ alert_pressure = base.alert_pressure
+
+ if(base.air_temporary)
+ air = base.air_temporary
+ base.air_temporary = null
+ else
air = new
- var/list/possible_expansions = list(base)
- members = list(base)
- edges = list()
+ if(base.leaking)
+ leaks |= base
- var/volume = base.volume
- base.parent = src
- alert_pressure = base.alert_pressure
+ while(possible_expansions.len>0)
+ for(var/obj/machinery/atmospherics/pipe/borderline in possible_expansions)
- if(base.air_temporary)
- air = base.air_temporary
- base.air_temporary = null
- else
- air = new
+ var/list/result = borderline.pipeline_expansion()
+ var/edge_check = result.len
- while(possible_expansions.len>0)
- for(var/obj/machinery/atmospherics/pipe/borderline in possible_expansions)
+ if(result.len>0)
+ for(var/obj/machinery/atmospherics/pipe/item in result)
- var/list/result = borderline.pipeline_expansion()
- var/edge_check = result.len
+ if(item.in_stasis)
+ continue
- if(result.len>0)
- for(var/obj/machinery/atmospherics/pipe/item in result)
- if(!members.Find(item))
- members += item
- possible_expansions += item
+ if(!members.Find(item))
+ members += item
+ possible_expansions += item
- volume += item.volume
- item.parent = src
+ volume += item.volume
+ item.parent = src
- alert_pressure = min(alert_pressure, item.alert_pressure)
+ alert_pressure = min(alert_pressure, item.alert_pressure)
- if(item.air_temporary)
- air.merge(item.air_temporary)
+ if(item.air_temporary)
+ air.merge(item.air_temporary)
- edge_check--
+ if(item.leaking)
+ leaks |= item
- if(edge_check>0)
- edges += borderline
+ edge_check--
- possible_expansions -= borderline
+ if(edge_check>0)
+ edges += borderline
- air.volume = volume
+ possible_expansions -= borderline
- proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
+ air.volume = volume
- if(new_network.line_members.Find(src))
- return 0
+/datum/pipeline/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
- new_network.line_members += src
+ if(new_network.line_members.Find(src))
+ return 0
- network = new_network
+ new_network.line_members += src
- for(var/obj/machinery/atmospherics/pipe/edge in edges)
- for(var/obj/machinery/atmospherics/result in edge.pipeline_expansion())
- if(!istype(result,/obj/machinery/atmospherics/pipe) && (result!=reference))
- result.network_expand(new_network, edge)
+ network = new_network
+ network.leaks |= leaks
- return 1
+ for(var/obj/machinery/atmospherics/pipe/edge in edges)
+ for(var/obj/machinery/atmospherics/result in edge.pipeline_expansion())
+ if(!istype(result,/obj/machinery/atmospherics/pipe) && (result!=reference))
+ result.network_expand(new_network, edge)
- proc/return_network(obj/machinery/atmospherics/reference)
- if(!network)
- network = new /datum/pipe_network()
- network.build_network(src, null)
- //technically passing these parameters should not be allowed
- //however pipe_network.build_network(..) and pipeline.network_extend(...)
- // were setup to properly handle this case
+ return 1
- return network
+/datum/pipeline/proc/return_network(obj/machinery/atmospherics/reference)
+ if(!network)
+ network = new /datum/pipe_network()
+ network.build_network(src, null)
+ //technically passing these parameters should not be allowed
+ //however pipe_network.build_network(..) and pipeline.network_extend(...)
+ // were setup to properly handle this case
- proc/mingle_with_turf(turf/simulated/target, mingle_volume)
- var/datum/gas_mixture/air_sample = air.remove_ratio(mingle_volume/air.volume)
- air_sample.volume = mingle_volume
+ return network
- if(istype(target) && target.zone)
- //Have to consider preservation of group statuses
- var/datum/gas_mixture/turf_copy = new
- var/datum/gas_mixture/turf_original = new
+/datum/pipeline/proc/mingle_with_turf(turf/simulated/target, mingle_volume)
+ var/datum/gas_mixture/air_sample = air.remove_ratio(mingle_volume/air.volume)
+ air_sample.volume = mingle_volume
- turf_copy.copy_from(target.zone.air)
- turf_copy.volume = target.zone.air.volume //Copy a good representation of the turf from parent group
- turf_original.copy_from(turf_copy)
+ if(istype(target) && target.zone)
+ //Have to consider preservation of group statuses
+ var/datum/gas_mixture/turf_copy = new
+ var/datum/gas_mixture/turf_original = new
- equalize_gases(list(air_sample, turf_copy))
- air.merge(air_sample)
+ turf_copy.copy_from(target.zone.air)
+ turf_copy.volume = target.zone.air.volume //Copy a good representation of the turf from parent group
+ turf_original.copy_from(turf_copy)
+
+ equalize_gases(list(air_sample, turf_copy))
+ air.merge(air_sample)
- target.zone.air.remove(turf_original.total_moles)
- target.zone.air.merge(turf_copy)
+ target.zone.air.remove(turf_original.total_moles)
+ target.zone.air.merge(turf_copy)
- else
- var/datum/gas_mixture/turf_air = target.return_air()
+ else
+ var/datum/gas_mixture/turf_air = target.return_air()
- equalize_gases(list(air_sample, turf_air))
- air.merge(air_sample)
- //turf_air already modified by equalize_gases()
+ equalize_gases(list(air_sample, turf_air))
+ air.merge(air_sample)
+ //turf_air already modified by equalize_gases()
- if(network)
- network.update = 1
+ if(network)
+ network.update = 1
- proc/temperature_interact(turf/target, share_volume, thermal_conductivity)
- var/total_heat_capacity = air.heat_capacity()
- var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume)
+/datum/pipeline/proc/temperature_interact(turf/target, share_volume, thermal_conductivity)
+ var/total_heat_capacity = air.heat_capacity()
+ var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume)
- if(istype(target, /turf/simulated))
- var/turf/simulated/modeled_location = target
+ if(istype(target, /turf/simulated))
+ var/turf/simulated/modeled_location = target
- if(modeled_location.blocks_air)
+ if(modeled_location.blocks_air)
- if((modeled_location.heat_capacity>0) && (partial_heat_capacity>0))
- var/delta_temperature = air.temperature - modeled_location.temperature
-
- var/heat = thermal_conductivity*delta_temperature* \
- (partial_heat_capacity*modeled_location.heat_capacity/(partial_heat_capacity+modeled_location.heat_capacity))
-
- air.temperature -= heat/total_heat_capacity
- modeled_location.temperature += heat/modeled_location.heat_capacity
-
- else
- var/delta_temperature = 0
- var/sharer_heat_capacity = 0
-
- if(modeled_location.zone)
- delta_temperature = (air.temperature - modeled_location.zone.air.temperature)
- sharer_heat_capacity = modeled_location.zone.air.heat_capacity()
- else
- delta_temperature = (air.temperature - modeled_location.air.temperature)
- sharer_heat_capacity = modeled_location.air.heat_capacity()
-
- var/self_temperature_delta = 0
- var/sharer_temperature_delta = 0
-
- if((sharer_heat_capacity>0) && (partial_heat_capacity>0))
- var/heat = thermal_conductivity*delta_temperature* \
- (partial_heat_capacity*sharer_heat_capacity/(partial_heat_capacity+sharer_heat_capacity))
-
- self_temperature_delta = -heat/total_heat_capacity
- sharer_temperature_delta = heat/sharer_heat_capacity
- else
- return 1
-
- air.temperature += self_temperature_delta
-
- if(modeled_location.zone)
- modeled_location.zone.air.temperature += sharer_temperature_delta/modeled_location.zone.air.group_multiplier
- else
- modeled_location.air.temperature += sharer_temperature_delta
-
-
- else
- if((target.heat_capacity>0) && (partial_heat_capacity>0))
- var/delta_temperature = air.temperature - target.temperature
+ if((modeled_location.heat_capacity>0) && (partial_heat_capacity>0))
+ var/delta_temperature = air.temperature - modeled_location.temperature
var/heat = thermal_conductivity*delta_temperature* \
- (partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity))
+ (partial_heat_capacity*modeled_location.heat_capacity/(partial_heat_capacity+modeled_location.heat_capacity))
air.temperature -= heat/total_heat_capacity
- if(network)
- network.update = 1
+ modeled_location.temperature += heat/modeled_location.heat_capacity
- //surface must be the surface area in m^2
- proc/radiate_heat_to_space(surface, thermal_conductivity)
- var/gas_density = air.total_moles/air.volume
- thermal_conductivity *= min(gas_density / ( RADIATOR_OPTIMUM_PRESSURE/(R_IDEAL_GAS_EQUATION*GAS_CRITICAL_TEMPERATURE) ), 1) //mult by density ratio
+ else
+ var/delta_temperature = 0
+ var/sharer_heat_capacity = 0
- // We only get heat from the star on the exposed surface area.
- // If the HE pipes gain more energy from AVERAGE_SOLAR_RADIATION than they can radiate, then they have a net heat increase.
- var/heat_gain = AVERAGE_SOLAR_RADIATION * (RADIATOR_EXPOSED_SURFACE_AREA_RATIO * surface) * thermal_conductivity
+ if(modeled_location.zone)
+ delta_temperature = (air.temperature - modeled_location.zone.air.temperature)
+ sharer_heat_capacity = modeled_location.zone.air.heat_capacity()
+ else
+ delta_temperature = (air.temperature - modeled_location.air.temperature)
+ sharer_heat_capacity = modeled_location.air.heat_capacity()
- // Previously, the temperature would enter equilibrium at 26C or 294K.
- // Only would happen if both sides (all 2 square meters of surface area) were exposed to sunlight. We now assume it aligned edge on.
- // It currently should stabilise at 129.6K or -143.6C
- heat_gain -= surface * STEFAN_BOLTZMANN_CONSTANT * thermal_conductivity * (air.temperature - COSMIC_RADIATION_TEMPERATURE) ** 4
+ var/self_temperature_delta = 0
+ var/sharer_temperature_delta = 0
- air.add_thermal_energy(heat_gain)
- if(network)
- network.update = 1
+ if((sharer_heat_capacity>0) && (partial_heat_capacity>0))
+ var/heat = thermal_conductivity*delta_temperature* \
+ (partial_heat_capacity*sharer_heat_capacity/(partial_heat_capacity+sharer_heat_capacity))
+
+ self_temperature_delta = -heat/total_heat_capacity
+ sharer_temperature_delta = heat/sharer_heat_capacity
+ else
+ return 1
+
+ air.temperature += self_temperature_delta
+
+ if(modeled_location.zone)
+ modeled_location.zone.air.temperature += sharer_temperature_delta/modeled_location.zone.air.group_multiplier
+ else
+ modeled_location.air.temperature += sharer_temperature_delta
+
+
+ else
+ if((target.heat_capacity>0) && (partial_heat_capacity>0))
+ var/delta_temperature = air.temperature - target.temperature
+
+ var/heat = thermal_conductivity*delta_temperature* \
+ (partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity))
+
+ air.temperature -= heat/total_heat_capacity
+ if(network)
+ network.update = 1
+
+//surface must be the surface area in m^2
+/datum/pipeline/proc/radiate_heat_to_space(surface, thermal_conductivity)
+ var/gas_density = air.total_moles/air.volume
+ thermal_conductivity *= min(gas_density / ( RADIATOR_OPTIMUM_PRESSURE/(R_IDEAL_GAS_EQUATION*GAS_CRITICAL_TEMPERATURE) ), 1) //mult by density ratio
+
+ // We only get heat from the star on the exposed surface area.
+ // If the HE pipes gain more energy from AVERAGE_SOLAR_RADIATION than they can radiate, then they have a net heat increase.
+ var/heat_gain = AVERAGE_SOLAR_RADIATION * (RADIATOR_EXPOSED_SURFACE_AREA_RATIO * surface) * thermal_conductivity
+
+ // Previously, the temperature would enter equilibrium at 26C or 294K.
+ // Only would happen if both sides (all 2 square meters of surface area) were exposed to sunlight. We now assume it aligned edge on.
+ // It currently should stabilise at 129.6K or -143.6C
+ heat_gain -= surface * STEFAN_BOLTZMANN_CONSTANT * thermal_conductivity * (air.temperature - COSMIC_RADIATION_TEMPERATURE) ** 4
+
+ air.add_thermal_energy(heat_gain)
+ if(network)
+ network.update = 1
diff --git a/code/ATMOSPHERICS/pipes/he_pipes.dm b/code/ATMOSPHERICS/pipes/he_pipes.dm
index 2d77e3a4ca..1b283e3ba4 100644
--- a/code/ATMOSPHERICS/pipes/he_pipes.dm
+++ b/code/ATMOSPHERICS/pipes/he_pipes.dm
@@ -67,8 +67,22 @@
return
update_icon()
+ handle_leaking()
return
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/set_leaking(var/new_leaking) // They already process, no need for manual processing toggles.
+ if(new_leaking && !leaking)
+ leaking = TRUE
+ if(parent)
+ parent.leaks |= src
+ if(parent.network)
+ parent.network.leaks |= src
+ else if (!new_leaking && leaking)
+ leaking = FALSE
+ if(parent)
+ parent.leaks -= src
+ if(parent.network)
+ parent.network.leaks -= src
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/process()
if(!parent)
@@ -180,4 +194,5 @@
return
update_icon()
+ handle_leaking()
return
diff --git a/code/ATMOSPHERICS/pipes/manifold.dm b/code/ATMOSPHERICS/pipes/manifold.dm
index 524d420d39..1af1eaa767 100644
--- a/code/ATMOSPHERICS/pipes/manifold.dm
+++ b/code/ATMOSPHERICS/pipes/manifold.dm
@@ -68,9 +68,16 @@
node3 = null
update_icon()
+ handle_leaking()
..()
+/obj/machinery/atmospherics/pipe/manifold/handle_leaking()
+ if(node1 && node2 && node3)
+ set_leaking(FALSE)
+ else
+ set_leaking(TRUE)
+
/obj/machinery/atmospherics/pipe/manifold/change_color(var/new_color)
..()
//for updating connected atmos device pipes (i.e. vents, manifolds, etc)
@@ -154,6 +161,7 @@
var/turf/T = get_turf(src)
if(level == 1 && !T.is_plating()) hide(1)
update_icon()
+ handle_leaking()
/obj/machinery/atmospherics/pipe/manifold/visible
icon_state = "map"
diff --git a/code/ATMOSPHERICS/pipes/manifold4w.dm b/code/ATMOSPHERICS/pipes/manifold4w.dm
index 0cc022423b..500088fec6 100644
--- a/code/ATMOSPHERICS/pipes/manifold4w.dm
+++ b/code/ATMOSPHERICS/pipes/manifold4w.dm
@@ -66,9 +66,16 @@
node4 = null
update_icon()
+ handle_leaking()
..()
+/obj/machinery/atmospherics/pipe/manifold4w/handle_leaking()
+ if(node1 && node2 && node3 && node4)
+ set_leaking(FALSE)
+ else
+ set_leaking(TRUE)
+
/obj/machinery/atmospherics/pipe/manifold4w/change_color(var/new_color)
..()
//for updating connected atmos device pipes (i.e. vents, manifolds, etc)
@@ -156,6 +163,7 @@
var/turf/T = get_turf(src)
if(level == 1 && !T.is_plating()) hide(1)
update_icon()
+ handle_leaking()
/obj/machinery/atmospherics/pipe/manifold4w/visible
icon_state = "map_4way"
diff --git a/code/ATMOSPHERICS/pipes/pipe_base.dm b/code/ATMOSPHERICS/pipes/pipe_base.dm
index a035857e54..d1bb92fac7 100644
--- a/code/ATMOSPHERICS/pipes/pipe_base.dm
+++ b/code/ATMOSPHERICS/pipes/pipe_base.dm
@@ -6,6 +6,7 @@
var/datum/gas_mixture/air_temporary // used when reconstructing a pipeline that broke
var/datum/pipeline/parent
var/volume = 0
+ var/leaking = FALSE // Do not set directly, use set_leaking(TRUE/FALSE)
layer = PIPES_LAYER
use_power = 0
@@ -13,6 +14,7 @@
pipe_flags = 0 // Does not have PIPING_DEFAULT_LAYER_ONLY flag.
var/alert_pressure = 80*ONE_ATMOSPHERE
+ var/in_stasis = FALSE
//minimum pressure before check_pressure(...) should be called
can_buckle = 1
@@ -30,6 +32,31 @@
/obj/machinery/atmospherics/pipe/hides_under_flooring()
return level != 2
+/obj/machinery/atmospherics/pipe/proc/set_leaking(var/new_leaking)
+ if(new_leaking && !leaking)
+ if(!speed_process)
+ START_MACHINE_PROCESSING(src)
+ else
+ START_PROCESSING(SSfastprocess, src)
+ leaking = TRUE
+ if(parent)
+ parent.leaks |= src
+ if(parent.network)
+ parent.network.leaks |= src
+ else if (!new_leaking && leaking)
+ if(!speed_process)
+ STOP_MACHINE_PROCESSING(src)
+ else
+ STOP_PROCESSING(SSfastprocess, src)
+ leaking = FALSE
+ if(parent)
+ parent.leaks -= src
+ if(parent.network)
+ parent.network.leaks -= src
+
+/obj/machinery/atmospherics/pipe/proc/handle_leaking() // Used specifically to update leaking status on different pipes.
+ return
+
/obj/machinery/atmospherics/pipe/proc/pipeline_expansion()
return null
diff --git a/code/ATMOSPHERICS/pipes/simple.dm b/code/ATMOSPHERICS/pipes/simple.dm
index 6aee81807e..eb980c3b47 100644
--- a/code/ATMOSPHERICS/pipes/simple.dm
+++ b/code/ATMOSPHERICS/pipes/simple.dm
@@ -1,6 +1,6 @@
//
// Simple Pipes - Just a tube, maybe bent
-//
+//
/obj/machinery/atmospherics/pipe/simple
icon = 'icons/atmos/pipes.dmi'
icon_state = ""
@@ -34,6 +34,14 @@
icon = null
alpha = 255
+/obj/machinery/atmospherics/pipe/simple/process()
+ if(!parent)
+ ..()
+ else if(leaking)
+ parent.mingle_with_turf(loc, volume)
+ else
+ . = PROCESS_KILL
+
/obj/machinery/atmospherics/pipe/simple/check_pressure(pressure)
var/datum/gas_mixture/environment = loc.return_air()
@@ -147,6 +155,7 @@
var/turf/T = loc
if(level == 1 && !T.is_plating()) hide(1)
update_icon()
+ handle_leaking()
/obj/machinery/atmospherics/pipe/simple/disconnect(obj/machinery/atmospherics/reference)
if(reference == node1)
@@ -160,9 +169,16 @@
node2 = null
update_icon()
+ handle_leaking()
return null
+/obj/machinery/atmospherics/pipe/simple/handle_leaking()
+ if(node1 && node2)
+ set_leaking(FALSE)
+ else
+ set_leaking(TRUE)
+
/obj/machinery/atmospherics/pipe/simple/visible
icon_state = "intact"
level = 2
diff --git a/code/ATMOSPHERICS/pipes/universal.dm b/code/ATMOSPHERICS/pipes/universal.dm
index 2d8bd09dff..00d2746947 100644
--- a/code/ATMOSPHERICS/pipes/universal.dm
+++ b/code/ATMOSPHERICS/pipes/universal.dm
@@ -48,7 +48,7 @@
construction_type = /obj/item/pipe/binary
pipe_state = "universal"
-/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_icon(var/safety = 0)
+/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_icon(var/safety = 0) // Doesn't leak. It's a special pipe.
if(!check_icon_cache())
return
diff --git a/code/datums/autolathe/autolathe.dm b/code/datums/autolathe/autolathe.dm
index a049a4456c..91c9ec37b7 100644
--- a/code/datums/autolathe/autolathe.dm
+++ b/code/datums/autolathe/autolathe.dm
@@ -8,9 +8,12 @@ var/datum/category_collection/autolathe/autolathe_recipes
for(var/material in I.matter)
var/coeff = (no_scale ? 1 : 1.25) //most objects are more expensive to produce than to recycle
resources[material] = I.matter[material]*coeff // but if it's a sheet or RCD cartridge, it's 1:1
- if(is_stack && istype(I, /obj/item/stack))
- var/obj/item/stack/IS = I
- max_stack = IS.max_amount
+ if(is_stack)
+ if(istype(I, /obj/item/stack))
+ var/obj/item/stack/IS = I
+ max_stack = IS.max_amount
+ else
+ max_stack = 10
qdel(I)
/****************************
@@ -65,7 +68,7 @@ var/datum/category_collection/autolathe/autolathe_recipes
var/list/resources
var/hidden
var/power_use = 0
- var/is_stack
+ var/is_stack // Creates multiple of an item if applied to non-stack items
var/max_stack
var/no_scale
diff --git a/code/datums/autolathe/general.dm b/code/datums/autolathe/general.dm
index 2e2fa3c6fb..2f4436bf55 100644
--- a/code/datums/autolathe/general.dm
+++ b/code/datums/autolathe/general.dm
@@ -105,10 +105,12 @@
/datum/category_item/autolathe/general/tube
name = "light tube"
path =/obj/item/weapon/light/tube
+ is_stack = TRUE
/datum/category_item/autolathe/general/bulb
name = "light bulb"
path =/obj/item/weapon/light/bulb
+ is_stack = TRUE
/datum/category_item/autolathe/general/ashtray_glass
name = "glass ashtray"
diff --git a/code/game/machinery/atmoalter/clamp.dm b/code/game/machinery/atmoalter/clamp.dm
new file mode 100644
index 0000000000..318145c229
--- /dev/null
+++ b/code/game/machinery/atmoalter/clamp.dm
@@ -0,0 +1,154 @@
+//Good luck. --BlueNexus
+
+//Static version of the clamp
+/obj/machinery/clamp
+ name = "stasis clamp"
+ desc = "A magnetic clamp which can halt the flow of gas in a pipe, via a localised stasis field."
+ description_info = "Click-dragging this to yourself while adjacent will attempt to remove it from the pipe."
+ icon = 'icons/atmos/clamp.dmi'
+ icon_state = "pclamp0"
+ anchored = 1.0
+ var/obj/machinery/atmospherics/pipe/simple/target = null
+ var/open = 1
+
+ var/datum/pipe_network/network_node1
+ var/datum/pipe_network/network_node2
+
+/obj/machinery/clamp/New(loc, var/obj/machinery/atmospherics/pipe/simple/to_attach = null)
+ ..()
+ if(istype(to_attach))
+ target = to_attach
+ else
+ target = locate(/obj/machinery/atmospherics/pipe/simple) in loc
+ if(target)
+ update_networks()
+ dir = target.dir
+ return 1
+
+/obj/machinery/clamp/proc/update_networks()
+ if(!target)
+ return
+ else
+ var/obj/machinery/atmospherics/pipe/node1 = target.node1
+ var/obj/machinery/atmospherics/pipe/node2 = target.node2
+ if(istype(node1))
+ var/datum/pipeline/P1 = node1.parent
+ network_node1 = P1.network
+ if(istype(node2))
+ var/datum/pipeline/P2 = node2.parent
+ network_node2 = P2.network
+
+/obj/machinery/clamp/attack_hand(var/mob/user)
+ if(!target)
+ return FALSE
+ if(!open)
+ open()
+ else
+ close()
+ to_chat(user, "You turn [open ? "off" : "on"] \the [src]")
+ return TRUE
+
+/obj/machinery/clamp/Destroy()
+ if(!open)
+ spawn(-1) open()
+ . = ..()
+
+/obj/machinery/clamp/proc/open()
+ if(open || !target)
+ return 0
+
+ target.build_network()
+
+
+ if(network_node1&&network_node2)
+ network_node1.merge(network_node2)
+ network_node2 = network_node1
+
+ if(network_node1)
+ network_node1.update = 1
+ else if(network_node2)
+ network_node2.update = 1
+
+ update_networks()
+
+ open = 1
+ icon_state = "pclamp0"
+ target.in_stasis = 0
+ return 1
+
+/obj/machinery/clamp/proc/close()
+ if(!open)
+ return 0
+
+ qdel(target.parent)
+
+ if(network_node1)
+ qdel(network_node1)
+ if(network_node2)
+ qdel(network_node2)
+
+ var/obj/machinery/atmospherics/pipe/node1 = null
+ var/obj/machinery/atmospherics/pipe/node2 = null
+
+ if(target.node1)
+ target.node1.build_network()
+ node1 = target.node1
+ if(target.node2)
+ target.node2.build_network()
+ node2 = target.node2
+ if(istype(node1) && node1.parent)
+ var/datum/pipeline/P1 = node1.parent
+ P1.build_pipeline(node1)
+ qdel(P1)
+ if(istype(node2) && node2.parent)
+ var/datum/pipeline/P2 = node2.parent
+ P2.build_pipeline(node2)
+ qdel(P2)
+// P1.build_network()
+// P2.build_network()
+
+ open = 0
+ icon_state = "pclamp1"
+ target.in_stasis = 1
+
+ return 1
+
+/obj/machinery/clamp/MouseDrop(obj/over_object as obj)
+ if(!usr)
+ return
+
+ if(open && over_object == usr && Adjacent(usr))
+ to_chat(usr, "You begin to remove \the [src]...")
+ if (do_after(usr, 30, src))
+ to_chat(usr, "You have removed \the [src].")
+ var/obj/item/clamp/C = new/obj/item/clamp(src.loc)
+ C.forceMove(usr.loc)
+ if(ishuman(usr))
+ usr.put_in_hands(C)
+ qdel(src)
+ return
+ else
+ to_chat(usr, "You can't remove \the [src] while it's active!")
+
+/obj/item/clamp
+ name = "stasis clamp"
+ desc = "A magnetic clamp which can halt the flow of gas in a pipe, via a localised stasis field."
+ icon = 'icons/atmos/clamp.dmi'
+ icon_state = "pclamp0"
+ origin_tech = list(TECH_ENGINEERING = 4, TECH_MAGNET = 4)
+
+/obj/item/clamp/afterattack(var/atom/A, mob/user as mob, proximity)
+ if(!proximity)
+ return
+
+ if (istype(A, /obj/machinery/atmospherics/pipe/simple))
+ to_chat(user, "You begin to attach \the [src] to \the [A]...")
+ var/C = locate(/obj/machinery/clamp) in get_turf(A)
+ if (do_after(user, 30, src) && !C)
+ if(!user.unEquip(src))
+ return
+ to_chat(user, "You have attached \the [src] to \the [A].")
+ new/obj/machinery/clamp(A.loc, A)
+ qdel(src)
+ if(C)
+ to_chat(user, "\The [C] is already attached to the pipe at this location!")
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 7d7c64f949..d1090f9f0a 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -276,9 +276,13 @@
//Create the desired item.
var/obj/item/I = new making.path(src.loc)
- if(multiplier > 1 && istype(I, /obj/item/stack))
- var/obj/item/stack/S = I
- S.amount = multiplier
+ if(multiplier > 1)
+ if(istype(I, /obj/item/stack))
+ var/obj/item/stack/S = I
+ S.amount = multiplier
+ else
+ for(multiplier; multiplier > 1; --multiplier) // Create multiple items if it's not a stack.
+ new making.path(src.loc)
updateUsrDialog()
diff --git a/code/game/machinery/pipe/pipe_recipes.dm b/code/game/machinery/pipe/pipe_recipes.dm
index f0ae483055..24661951e9 100644
--- a/code/game/machinery/pipe/pipe_recipes.dm
+++ b/code/game/machinery/pipe/pipe_recipes.dm
@@ -27,6 +27,7 @@ var/global/list/atmos_pipe_recipes = null
new /datum/pipe_recipe/pipe("Gas Pump", /obj/machinery/atmospherics/binary/pump),
new /datum/pipe_recipe/pipe("Pressure Regulator", /obj/machinery/atmospherics/binary/passive_gate),
new /datum/pipe_recipe/pipe("High Power Gas Pump",/obj/machinery/atmospherics/binary/pump/high_power),
+ new /datum/pipe_recipe/pipe("Automatic Shutoff Valve",/obj/machinery/atmospherics/valve/shutoff),
new /datum/pipe_recipe/pipe("Scrubber", /obj/machinery/atmospherics/unary/vent_scrubber),
new /datum/pipe_recipe/meter("Meter"),
new /datum/pipe_recipe/pipe("Gas Filter", /obj/machinery/atmospherics/trinary/atmos_filter),
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index 78dd0164fe..bf946b444e 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -892,8 +892,7 @@
//Shooting Code:
A.firer = src
A.old_style_target(target)
- A.def_zone = def_zone
- A.fire()
+ A.launch_projectile_from_turf(target, def_zone, src)
// Reset the time needed to go back down, since we just tried to shoot at someone.
timeout = 10
diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm
index 0519bf2ca4..e2ce2d3638 100644
--- a/code/game/mecha/equipment/tools/tools.dm
+++ b/code/game/mecha/equipment/tools/tools.dm
@@ -328,7 +328,7 @@
equip_cooldown = 5
energy_drain = 0
range = MELEE|RANGED
- required_type = /obj/mecha/working
+ required_type = list(/obj/mecha/working)
var/spray_particles = 5
var/spray_amount = 5 //units of liquid per particle. 5 is enough to wet the floor - it's a big fire extinguisher, so should be fine
var/max_water = 1000
@@ -1227,7 +1227,7 @@
energy_drain = 0
var/dam_force = 0
var/obj/mecha/working/ripley/cargo_holder
- required_type = /obj/mecha/working/ripley
+ required_type = list(/obj/mecha/working/ripley)
equip_type = EQUIP_SPECIAL
@@ -1528,3 +1528,25 @@
sleep(equip_cooldown)
wait = 0
return 1
+
+/obj/item/mecha_parts/mecha_equipment/speedboost
+ name = "ripley leg actuator overdrive"
+ desc = "System enhancements and overdrives to make a ripley's legs move faster."
+ icon_state = "tesla"
+ origin_tech = list( TECH_POWER = 5, TECH_MATERIAL = 4, TECH_ENGINEERING = 4)
+ required_type = list(/obj/mecha/working/ripley)
+
+ equip_type = EQUIP_HULL
+
+/obj/item/mecha_parts/mecha_equipment/speedboost/attach(obj/mecha/M as obj)
+ ..()
+ if(enable_special)
+ chassis.step_in = (chassis.step_in-2) // Make the ripley as fast as a durand
+ else
+ chassis.step_in = (chassis.step_in+1) // Improper parts slow the mech down
+ return
+
+/obj/item/mecha_parts/mecha_equipment/speedboost/detach()
+ chassis.step_in = initial(chassis.step_in)
+ ..()
+ return
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index a7af75cd40..98f396df5e 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -577,31 +577,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
if(mode==3)
- var/turf/T = get_turf(user.loc)
- if(!isnull(T))
- var/datum/gas_mixture/environment = T.return_air()
-
- var/pressure = environment.return_pressure()
- var/total_moles = environment.total_moles
-
- if (total_moles)
- var/o2_level = environment.gas["oxygen"]/total_moles
- var/n2_level = environment.gas["nitrogen"]/total_moles
- var/co2_level = environment.gas["carbon_dioxide"]/total_moles
- var/phoron_level = environment.gas["phoron"]/total_moles
- var/unknown_level = 1-(o2_level+n2_level+co2_level+phoron_level)
- data["aircontents"] = list(\
- "pressure" = "[round(pressure,0.1)]",\
- "nitrogen" = "[round(n2_level*100,0.1)]",\
- "oxygen" = "[round(o2_level*100,0.1)]",\
- "carbon_dioxide" = "[round(co2_level*100,0.1)]",\
- "phoron" = "[round(phoron_level*100,0.01)]",\
- "other" = "[round(unknown_level, 0.01)]",\
- "temp" = "[round(environment.temperature-T0C,0.1)]",\
- "reading" = 1\
- )
- if(isnull(data["aircontents"]))
- data["aircontents"] = list("reading" = 0)
+ data["aircontents"] = src.analyze_air()
if(mode==6)
if(has_reception)
feeds.Cut()
@@ -1544,3 +1520,37 @@ var/global/list/obj/item/device/pda/PDAs = list()
/obj/item/device/pda/emp_act(severity)
for(var/atom/A in src)
A.emp_act(severity)
+
+/obj/item/device/pda/proc/analyze_air()
+ var/list/results = list()
+ var/turf/T = get_turf(src.loc)
+ if(!isnull(T))
+ var/datum/gas_mixture/environment = T.return_air()
+ var/pressure = environment.return_pressure()
+ var/total_moles = environment.total_moles
+ if (total_moles)
+ var/o2_level = environment.gas["oxygen"]/total_moles
+ var/n2_level = environment.gas["nitrogen"]/total_moles
+ var/co2_level = environment.gas["carbon_dioxide"]/total_moles
+ var/phoron_level = environment.gas["phoron"]/total_moles
+ var/unknown_level = 1-(o2_level+n2_level+co2_level+phoron_level)
+
+ // entry is what the element is describing
+ // Type identifies which unit or other special characters to use
+ // Val is the information reported
+ // Bad_high/_low are the values outside of which the entry reports as dangerous
+ // Poor_high/_low are the values outside of which the entry reports as unideal
+ // Values were extracted from the template itself
+ results = list(
+ list("entry" = "Pressure", "units" = "kPa", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80),
+ list("entry" = "Temperature", "units" = "°C", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5),
+ list("entry" = "Oxygen", "units" = "kPa", "val" = "[round(o2_level*100,0.1)]", "bad_high" = 140, "poor_high" = 135, "poor_low" = 19, "bad_low" = 17),
+ list("entry" = "Nitrogen", "units" = "kPa", "val" = "[round(n2_level*100,0.1)]", "bad_high" = 105, "poor_high" = 85, "poor_low" = 50, "bad_low" = 40),
+ list("entry" = "Carbon Dioxide", "units" = "kPa", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0),
+ list("entry" = "Phoron", "units" = "kPa", "val" = "[round(phoron_level*100,0.01)]", "bad_high" = 0.5, "poor_high" = 0, "poor_low" = 0, "bad_low" = 0),
+ list("entry" = "Other", "units" = "kPa", "val" = "[round(unknown_level, 0.01)]", "bad_high" = 1, "poor_high" = 0.5, "poor_low" = 0, "bad_low" = 0)
+ )
+
+ if(isnull(results))
+ results = list(list("entry" = "pressure", "units" = "kPa", "val" = "0", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80))
+ return results
diff --git a/code/game/objects/items/devices/communicator/helper.dm b/code/game/objects/items/devices/communicator/helper.dm
index b7a3b752d9..273686fb46 100644
--- a/code/game/objects/items/devices/communicator/helper.dm
+++ b/code/game/objects/items/devices/communicator/helper.dm
@@ -19,17 +19,17 @@
// Poor_high/_low are the values outside of which the entry reports as unideal
// Values were extracted from the template itself
results = list(
- list("entry" = "Pressure", "type" = "pressure", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80),
- list("entry" = "Temperature", "type" = "temp", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5),
- list("entry" = "Oxygen", "type" = "pressure", "val" = "[round(o2_level*100,0.1)]", "bad_high" = 140, "poor_high" = 135, "poor_low" = 19, "bad_low" = 17),
- list("entry" = "Nitrogen", "type" = "pressure", "val" = "[round(n2_level*100,0.1)]", "bad_high" = 105, "poor_high" = 85, "poor_low" = 50, "bad_low" = 40),
- list("entry" = "Carbon Dioxide", "type" = "pressure", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0),
- list("entry" = "Phoron", "type" = "pressure", "val" = "[round(phoron_level*100,0.01)]", "bad_high" = 0.5, "poor_high" = 0, "poor_low" = 0, "bad_low" = 0),
- list("entry" = "Other", "type" = "pressure", "val" = "[round(unknown_level, 0.01)]", "bad_high" = 1, "poor_high" = 0.5, "poor_low" = 0, "bad_low" = 0)
+ list("entry" = "Pressure", "units" = "kPa", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80),
+ list("entry" = "Temperature", "units" = "°C", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5),
+ list("entry" = "Oxygen", "units" = "kPa", "val" = "[round(o2_level*100,0.1)]", "bad_high" = 140, "poor_high" = 135, "poor_low" = 19, "bad_low" = 17),
+ list("entry" = "Nitrogen", "units" = "kPa", "val" = "[round(n2_level*100,0.1)]", "bad_high" = 105, "poor_high" = 85, "poor_low" = 50, "bad_low" = 40),
+ list("entry" = "Carbon Dioxide", "units" = "kPa", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0),
+ list("entry" = "Phoron", "units" = "kPa", "val" = "[round(phoron_level*100,0.01)]", "bad_high" = 0.5, "poor_high" = 0, "poor_low" = 0, "bad_low" = 0),
+ list("entry" = "Other", "units" = "kPa", "val" = "[round(unknown_level, 0.01)]", "bad_high" = 1, "poor_high" = 0.5, "poor_low" = 0, "bad_low" = 0)
)
if(isnull(results))
- results = list(list("entry" = "pressure", "val" = "0"))
+ results = list(list("entry" = "pressure", "units" = "kPa", "val" = "0", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80))
return results
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
index 973e9f0125..4b10fe7bb6 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
@@ -11,6 +11,8 @@
starts_with = list(
/obj/item/clothing/accessory/storage/brown_vest,
/obj/item/blueprints,
+ /obj/item/clamp,
+ /obj/item/clamp,
/obj/item/clothing/under/rank/chief_engineer,
/obj/item/clothing/under/rank/chief_engineer/skirt,
/obj/item/clothing/head/hardhat/white,
@@ -123,6 +125,7 @@
/obj/item/clothing/suit/fire/firefighter,
/obj/item/device/flashlight,
/obj/item/weapon/extinguisher,
+ /obj/item/clamp,
/obj/item/device/radio/headset/headset_eng,
/obj/item/device/radio/headset/headset_eng/alt,
/obj/item/clothing/suit/storage/hazardvest,
diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm
index 1c74b467e2..6bf7cf38b4 100644
--- a/code/game/turfs/simulated.dm
+++ b/code/game/turfs/simulated.dm
@@ -13,6 +13,8 @@
var/to_be_destroyed = 0 //Used for fire, if a melting temperature was reached, it will be destroyed
var/max_fire_temperature_sustained = 0 //The max temperature of the fire which it was subjected to
var/can_dirty = TRUE // If false, tile never gets dirty
+ var/can_start_dirty = TRUE // If false, cannot start dirty roundstart
+ var/dirty_prob = 2 // Chance of being dirty roundstart
var/dirt = 0
// This is not great.
diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm
index c51fc614d1..2c7f8ff12e 100644
--- a/code/game/turfs/simulated/floor.dm
+++ b/code/game/turfs/simulated/floor.dm
@@ -41,9 +41,10 @@
set_flooring(get_flooring_data(floortype))
else
footstep_sounds = base_footstep_sounds
- if(can_dirty)
- if(prob(2))
- new /obj/effect/decal/cleanable/dirt(src) //5% chance to start with dirt on a floor tile- give the janitor something to do
+ if(can_dirty && can_start_dirty)
+ if(prob(dirty_prob))
+ dirt += rand(50,100)
+ update_dirt() //5% chance to start with dirt on a floor tile- give the janitor something to do
/turf/simulated/floor/proc/set_flooring(var/decl/flooring/newflooring)
make_plating(defer_icon_update = 1)
diff --git a/code/modules/ai/ai_holder_combat.dm b/code/modules/ai/ai_holder_combat.dm
index 12cf9e2436..63154e4fe4 100644
--- a/code/modules/ai/ai_holder_combat.dm
+++ b/code/modules/ai/ai_holder_combat.dm
@@ -65,6 +65,11 @@
on_engagement(target)
melee_attack(target)
+ else if(distance <= 1 && !holder.ICheckRangedAttack(target)) // Doesn't have projectile, but is pointblank
+ ai_log("engage_target() : Attempting a melee attack.", AI_LOG_TRACE)
+ on_engagement(target)
+ melee_attack(target)
+
// Shoot them.
else if(holder.ICheckRangedAttack(target) && (distance <= max_range(target)) )
on_engagement(target)
diff --git a/code/modules/blob2/overmind/overmind.dm b/code/modules/blob2/overmind/overmind.dm
index 6477c86f22..223cb41e60 100644
--- a/code/modules/blob2/overmind/overmind.dm
+++ b/code/modules/blob2/overmind/overmind.dm
@@ -9,7 +9,6 @@ var/list/overminds = list()
mouse_opacity = 1
see_in_dark = 8
invisibility = INVISIBILITY_OBSERVER
- layer = FLY_LAYER + 0.1
faction = "blob"
var/obj/structure/blob/core/blob_core = null // The blob overmind's core
diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm
index 17a44db61d..5020307699 100644
--- a/code/modules/clothing/shoes/magboots.dm
+++ b/code/modules/clothing/shoes/magboots.dm
@@ -2,6 +2,7 @@
desc = "Magnetic boots, often used during extravehicular activity to ensure the user remains safely attached to the vehicle. They're large enough to be worn over other footwear."
name = "magboots"
icon_state = "magboots0"
+ item_flags = PHORONGUARD
item_state_slots = list(slot_r_hand_str = "magboots", slot_l_hand_str = "magboots")
species_restricted = null
force = 3
diff --git a/code/modules/clothing/spacesuits/rig/rig_pieces.dm b/code/modules/clothing/spacesuits/rig/rig_pieces.dm
index 5c4853a791..6bc6865a21 100644
--- a/code/modules/clothing/spacesuits/rig/rig_pieces.dm
+++ b/code/modules/clothing/spacesuits/rig/rig_pieces.dm
@@ -23,7 +23,7 @@
/obj/item/clothing/gloves/gauntlets/rig
name = "gauntlets"
- item_flags = THICKMATERIAL
+ item_flags = THICKMATERIAL|PHORONGUARD
body_parts_covered = HANDS
heat_protection = HANDS
cold_protection = HANDS
diff --git a/code/modules/food/recipes_microwave.dm b/code/modules/food/recipes_microwave.dm
index acbbc7666a..55ecc2f637 100644
--- a/code/modules/food/recipes_microwave.dm
+++ b/code/modules/food/recipes_microwave.dm
@@ -35,7 +35,7 @@ I said no!
/datum/recipe/devilledegg
fruit = list("chili" = 1)
- reagents = list("salt" = 2, "mayo" = 5)
+ reagents = list("sodiumchloride" = 2, "mayo" = 5)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/egg,
/obj/item/weapon/reagent_containers/food/snacks/egg
@@ -90,13 +90,6 @@ I said no!
)
result = /obj/item/weapon/reagent_containers/food/snacks/monkeyburger
-/datum/recipe/syntiburger
- items = list(
- /obj/item/weapon/reagent_containers/food/snacks/bun,
- /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh
- )
- result = /obj/item/weapon/reagent_containers/food/snacks/monkeyburger
-
/datum/recipe/brainburger
items = list(
/obj/item/weapon/reagent_containers/food/snacks/bun,
@@ -214,20 +207,6 @@ I said no!
)
result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/meatbread
-/datum/recipe/syntibread
- items = list(
- /obj/item/weapon/reagent_containers/food/snacks/dough,
- /obj/item/weapon/reagent_containers/food/snacks/dough,
- /obj/item/weapon/reagent_containers/food/snacks/dough,
- /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh,
- /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh,
- /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh,
- /obj/item/weapon/reagent_containers/food/snacks/cheesewedge,
- /obj/item/weapon/reagent_containers/food/snacks/cheesewedge,
- /obj/item/weapon/reagent_containers/food/snacks/cheesewedge,
- )
- result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/meatbread
-
/datum/recipe/xenomeatbread
items = list(
/obj/item/weapon/reagent_containers/food/snacks/dough,
@@ -353,19 +332,11 @@ I said no!
)
result = /obj/item/weapon/reagent_containers/food/snacks/human/kabob
-/datum/recipe/monkeykabob
+/datum/recipe/kabob //Do not put before humankabob
items = list(
/obj/item/stack/rods,
- /obj/item/weapon/reagent_containers/food/snacks/meat/monkey,
- /obj/item/weapon/reagent_containers/food/snacks/meat/monkey,
- )
- result = /obj/item/weapon/reagent_containers/food/snacks/monkeykabob
-
-/datum/recipe/syntikabob
- items = list(
- /obj/item/stack/rods,
- /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh,
- /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh,
+ /obj/item/weapon/reagent_containers/food/snacks/meat,
+ /obj/item/weapon/reagent_containers/food/snacks/meat,
)
result = /obj/item/weapon/reagent_containers/food/snacks/monkeykabob
@@ -477,11 +448,6 @@ I said no!
items = list(/obj/item/weapon/reagent_containers/food/snacks/meat)
result = /obj/item/weapon/reagent_containers/food/snacks/meatsteak
-/datum/recipe/syntisteak
- reagents = list("sodiumchloride" = 1, "blackpepper" = 1)
- items = list(/obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh)
- result = /obj/item/weapon/reagent_containers/food/snacks/meatsteak
-
/datum/recipe/pizzamargherita
fruit = list("tomato" = 1)
items = list(
@@ -513,17 +479,6 @@ I said no!
)
result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza
-/datum/recipe/syntipizza
- fruit = list("tomato" = 1)
- items = list(
- /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough,
- /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh,
- /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh,
- /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh,
- /obj/item/weapon/reagent_containers/food/snacks/cheesewedge
- )
- result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza
-
/datum/recipe/mushroompizza
fruit = list("mushroom" = 5, "tomato" = 1)
items = list(
@@ -902,7 +857,7 @@ I said no!
/datum/recipe/zestfish
fruit = list("lemon" = 1)
- reagents = list("salt" = 3)
+ reagents = list("sodiumchloride" = 3)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/carpmeat
)
@@ -910,7 +865,7 @@ I said no!
/datum/recipe/limezestfish
fruit = list("lime" = 1)
- reagents = list("salt" = 3)
+ reagents = list("sodiumchloride" = 3)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/carpmeat
)
@@ -1084,14 +1039,14 @@ I said no!
result = /obj/item/weapon/reagent_containers/food/snacks/fries
/datum/recipe/roastedsunflowerseeds
- reagents = list("salt" = 1, "cornoil" = 1)
+ reagents = list("sodiumchloride" = 1, "cornoil" = 1)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/rawsunflower
)
result = /obj/item/weapon/reagent_containers/food/snacks/roastedsunflower
/datum/recipe/roastedpeanutsunflowerseeds
- reagents = list("salt" = 1, "peanutoil" = 1)
+ reagents = list("sodiumchloride" = 1, "peanutoil" = 1)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/rawsunflower
)
@@ -1099,7 +1054,7 @@ I said no!
/datum/recipe/roastedpeanuts
fruit = list("peanut" = 2)
- reagents = list("salt" = 2, "cornoil" = 1)
+ reagents = list("sodiumchloride" = 2, "cornoil" = 1)
result = /obj/item/weapon/reagent_containers/food/snacks/roastedpeanuts
/datum/recipe/mint
diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm
index 2500da6764..9e34611b7d 100644
--- a/code/modules/hydroponics/seed_datums.dm
+++ b/code/modules/hydroponics/seed_datums.dm
@@ -3,9 +3,9 @@
name = "chili"
seed_name = "chili"
display_name = "chili plants"
+ kitchen_tag = "chili"
chems = list("capsaicin" = list(3,5), "nutriment" = list(1,25))
mutants = list("icechili")
- kitchen_tag = "chili"
/datum/seed/chili/New()
..()
@@ -24,9 +24,9 @@
name = "icechili"
seed_name = "ice pepper"
display_name = "ice-pepper plants"
+ kitchen_tag = "icechili"
mutants = null
chems = list("frostoil" = list(3,5), "nutriment" = list(1,50))
- kitchen_tag = "icechili"
/datum/seed/chili/ice/New()
..()
@@ -39,9 +39,9 @@
name = "berries"
seed_name = "berry"
display_name = "berry bush"
+ kitchen_tag = "berries"
mutants = list("glowberries","poisonberries")
chems = list("nutriment" = list(1,10), "berryjuice" = list(10,10))
- kitchen_tag = "berries"
/datum/seed/berry/New()
..()
@@ -129,9 +129,9 @@
name = "deathnettle"
seed_name = "death nettle"
display_name = "death nettles"
+ kitchen_tag = "deathnettle"
mutants = null
chems = list("nutriment" = list(1,50), "pacid" = list(0,1))
- kitchen_tag = "deathnettle"
/datum/seed/nettle/death/New()
..()
@@ -221,9 +221,9 @@
name = "eggplant"
seed_name = "eggplant"
display_name = "eggplants"
+ kitchen_tag = "eggplant"
mutants = list("egg-plant")
chems = list("nutriment" = list(1,10))
- kitchen_tag = "eggplant"
/datum/seed/eggplant/New()
..()
@@ -243,9 +243,9 @@
name = "egg-plant"
seed_name = "egg-plant"
display_name = "egg-plants"
+ kitchen_tag = "egg-plant"
mutants = null
chems = list("nutriment" = list(1,5), "egg" = list(3,12))
- kitchen_tag = "egg-plant"
has_item_product = /obj/item/weapon/reagent_containers/food/snacks/egg/purple
//Apples/varieties.
@@ -253,9 +253,9 @@
name = "apple"
seed_name = "apple"
display_name = "apple tree"
+ kitchen_tag = "apple"
mutants = list("poisonapple","goldapple")
chems = list("nutriment" = list(1,10),"applejuice" = list(10,20))
- kitchen_tag = "apple"
/datum/seed/apple/New()
..()
@@ -279,9 +279,9 @@
name = "goldapple"
seed_name = "golden apple"
display_name = "gold apple tree"
+ kitchen_tag = "goldapple"
mutants = null
chems = list("nutriment" = list(1,10), "gold" = list(1,5))
- kitchen_tag = "goldapple"
/datum/seed/apple/gold/New()
..()
@@ -296,9 +296,9 @@
name = "ambrosia"
seed_name = "ambrosia vulgaris"
display_name = "ambrosia vulgaris"
+ kitchen_tag = "ambrosia"
mutants = list("ambrosiadeus")
chems = list("nutriment" = list(1), "space_drugs" = list(1,8), "kelotane" = list(1,8,1), "bicaridine" = list(1,10,1), "toxin" = list(1,10))
- kitchen_tag = "ambrosia"
/datum/seed/ambrosia/New()
..()
@@ -316,9 +316,9 @@
name = "ambrosiadeus"
seed_name = "ambrosia deus"
display_name = "ambrosia deus"
+ kitchen_tag = "ambrosiadeus"
mutants = null
chems = list("nutriment" = list(1), "bicaridine" = list(1,8), "synaptizine" = list(1,8,1), "hyperzine" = list(1,10,1), "space_drugs" = list(1,10))
- kitchen_tag = "ambrosiadeus"
/datum/seed/ambrosia/deus/New()
..()
@@ -512,8 +512,8 @@
name = "harebells"
seed_name = "harebell"
display_name = "harebells"
- chems = list("nutriment" = list(1,20))
kitchen_tag = "harebell"
+ chems = list("nutriment" = list(1,20))
/datum/seed/flower/New()
..()
@@ -530,8 +530,8 @@
name = "poppies"
seed_name = "poppy"
display_name = "poppies"
- chems = list("nutriment" = list(1,20), "bicaridine" = list(1,10))
kitchen_tag = "poppy"
+ chems = list("nutriment" = list(1,20), "bicaridine" = list(1,10))
/datum/seed/flower/poppy/New()
..()
@@ -621,6 +621,7 @@
name = "grapes"
seed_name = "grape"
display_name = "grapevines"
+ kitchen_tag = "grapes"
mutants = list("greengrapes")
chems = list("nutriment" = list(1,10), "sugar" = list(1,5), "grapejuice" = list(10,10))
@@ -654,8 +655,8 @@
name = "lettuce"
seed_name = "lettuce"
display_name = "lettuce"
- chems = list("nutriment" = list(1,15))
kitchen_tag = "cabbage"
+ chems = list("nutriment" = list(1,15))
/datum/seed/lettuce/New()
..()
@@ -676,8 +677,8 @@
name = "siflettuce"
seed_name = "glacial lettuce"
display_name = "glacial lettuce"
- chems = list("nutriment" = list(1,5), "paracetamol" = list(0,2))
kitchen_tag = "icelettuce"
+ chems = list("nutriment" = list(1,5), "paracetamol" = list(0,2))
/datum/seed/lettuce/ice/New()
..()
@@ -744,8 +745,8 @@
name = "peanut"
seed_name = "peanut"
display_name = "peanut vines"
- chems = list("nutriment" = list(1,10), "peanutoil" = list(1,3))
kitchen_tag = "peanut"
+ chems = list("nutriment" = list(1,10), "peanutoil" = list(1,3))
/datum/seed/peanuts/New()
..()
@@ -763,6 +764,7 @@
name = "vanilla"
seed_name = "vanilla"
display_name = "vanilla"
+ kitchen_tag = "vanilla"
chems = list("nutriment" = list(1,10), "vanilla" = list(0,3), "sugar" = list(0, 1))
/datum/seed/vanilla/New()
@@ -782,8 +784,8 @@
name = "cabbage"
seed_name = "cabbage"
display_name = "cabbages"
- chems = list("nutriment" = list(1,10))
kitchen_tag = "cabbage"
+ chems = list("nutriment" = list(1,10))
/datum/seed/cabbage/New()
..()
@@ -804,9 +806,9 @@
name = "banana"
seed_name = "banana"
display_name = "banana tree"
+ kitchen_tag = "banana"
chems = list("banana" = list(10,10))
trash_type = /obj/item/weapon/bananapeel
- kitchen_tag = "banana"
/datum/seed/banana/New()
..()
@@ -826,8 +828,8 @@
name = "corn"
seed_name = "corn"
display_name = "ears of corn"
- chems = list("nutriment" = list(1,10), "cornoil" = list(1,10))
kitchen_tag = "corn"
+ chems = list("nutriment" = list(1,10), "cornoil" = list(1,10))
trash_type = /obj/item/weapon/corncob
/datum/seed/corn/New()
@@ -848,8 +850,8 @@
name = "potato"
seed_name = "potato"
display_name = "potatoes"
- chems = list("nutriment" = list(1,10), "potatojuice" = list(10,10))
kitchen_tag = "potato"
+ chems = list("nutriment" = list(1,10), "potatojuice" = list(10,10))
/datum/seed/potato/New()
..()
@@ -867,8 +869,8 @@
name = "onion"
seed_name = "onion"
display_name = "onions"
- chems = list("nutriment" = list(1,10))
kitchen_tag = "onion"
+ chems = list("nutriment" = list(1,10))
/datum/seed/onion/New()
..()
@@ -885,8 +887,8 @@
name = "soybean"
seed_name = "soybean"
display_name = "soybeans"
- chems = list("nutriment" = list(1,20), "soymilk" = list(10,20))
kitchen_tag = "soybeans"
+ chems = list("nutriment" = list(1,20), "soymilk" = list(10,20))
/datum/seed/soybean/New()
..()
@@ -903,8 +905,8 @@
name = "wheat"
seed_name = "wheat"
display_name = "wheat stalks"
- chems = list("nutriment" = list(1,25), "flour" = list(15,15))
kitchen_tag = "wheat"
+ chems = list("nutriment" = list(1,25), "flour" = list(15,15))
/datum/seed/wheat/New()
..()
@@ -923,8 +925,8 @@
name = "rice"
seed_name = "rice"
display_name = "rice stalks"
- chems = list("nutriment" = list(1,25), "rice" = list(10,15))
kitchen_tag = "rice"
+ chems = list("nutriment" = list(1,25), "rice" = list(10,15))
/datum/seed/rice/New()
..()
@@ -943,8 +945,8 @@
name = "carrot"
seed_name = "carrot"
display_name = "carrots"
- chems = list("nutriment" = list(1,20), "imidazoline" = list(3,5), "carrotjuice" = list(10,20))
kitchen_tag = "carrot"
+ chems = list("nutriment" = list(1,20), "imidazoline" = list(3,5), "carrotjuice" = list(10,20))
/datum/seed/carrots/New()
..()
@@ -978,8 +980,8 @@
name = "whitebeet"
seed_name = "white-beet"
display_name = "white-beets"
- chems = list("nutriment" = list(0,20), "sugar" = list(1,5))
kitchen_tag = "whitebeet"
+ chems = list("nutriment" = list(0,20), "sugar" = list(1,5))
/datum/seed/whitebeets/New()
..()
@@ -997,6 +999,7 @@
name = "sugarcane"
seed_name = "sugarcane"
display_name = "sugarcanes"
+ kitchen_tag = "sugarcanes"
chems = list("sugar" = list(4,5))
/datum/seed/sugarcane/New()
@@ -1016,8 +1019,8 @@
name = "rhubarb"
seed_name = "rhubarb"
display_name = "rhubarb"
- chems = list("nutriment" = list(1,15))
kitchen_tag = "rhubarb"
+ chems = list("nutriment" = list(1,15))
/datum/seed/rhubarb/New()
..()
@@ -1034,8 +1037,8 @@
name = "celery"
seed_name = "celery"
display_name = "celery"
- chems = list("nutriment" = list(5,20))
kitchen_tag = "celery"
+ chems = list("nutriment" = list(5,20))
/datum/seed/celery/New()
..()
@@ -1052,8 +1055,8 @@
name = "spineapple"
seed_name = "spineapple"
display_name = "spineapple"
- chems = list("nutriment" = list(1,5), "enzyme" = list(1,5), "pineapplejuice" = list(1, 20))
kitchen_tag = "pineapple"
+ chems = list("nutriment" = list(1,5), "enzyme" = list(1,5), "pineapplejuice" = list(1, 20))
/datum/seed/spineapple/New()
..()
@@ -1076,8 +1079,8 @@
seed_name = "durian"
seed_noun = "pits"
display_name = "durian"
- chems = list("nutriment" = list(1,5), "durianpaste" = list(1, 20))
kitchen_tag = "durian"
+ chems = list("nutriment" = list(1,5), "durianpaste" = list(1, 20))
/datum/seed/durian/New()
..()
@@ -1097,8 +1100,8 @@
name = "watermelon"
seed_name = "watermelon"
display_name = "watermelon vine"
- chems = list("nutriment" = list(1,6), "watermelonjuice" = list(10,6))
kitchen_tag = "watermelon"
+ chems = list("nutriment" = list(1,6), "watermelonjuice" = list(10,6))
/datum/seed/watermelon/New()
..()
@@ -1121,8 +1124,8 @@
name = "pumpkin"
seed_name = "pumpkin"
display_name = "pumpkin vine"
- chems = list("nutriment" = list(1,6))
kitchen_tag = "pumpkin"
+ chems = list("nutriment" = list(1,6))
/datum/seed/pumpkin/New()
..()
@@ -1141,8 +1144,8 @@
name = "lime"
seed_name = "lime"
display_name = "lime trees"
- chems = list("nutriment" = list(1,20), "limejuice" = list(10,20))
kitchen_tag = "lime"
+ chems = list("nutriment" = list(1,20), "limejuice" = list(10,20))
/datum/seed/citrus/New()
..()
@@ -1161,8 +1164,8 @@
name = "lemon"
seed_name = "lemon"
display_name = "lemon trees"
- chems = list("nutriment" = list(1,20), "lemonjuice" = list(10,20))
kitchen_tag = "lemon"
+ chems = list("nutriment" = list(1,20), "lemonjuice" = list(10,20))
/datum/seed/citrus/lemon/New()
..()
@@ -1188,8 +1191,8 @@
name = "grass"
seed_name = "grass"
display_name = "grass"
- chems = list("nutriment" = list(1,20))
kitchen_tag = "grass"
+ chems = list("nutriment" = list(1,20))
/datum/seed/grass/New()
..()
@@ -1208,6 +1211,7 @@
name = "cocoa"
seed_name = "cacao"
display_name = "cacao tree"
+ kitchen_tag = "cocoa"
chems = list("nutriment" = list(1,10), "coco" = list(4,5))
/datum/seed/cocoa/New()
@@ -1228,8 +1232,8 @@
seed_name = "cherry"
seed_noun = "pits"
display_name = "cherry tree"
- chems = list("nutriment" = list(1,15), "sugar" = list(1,15), "cherryjelly" = list(10,15))
kitchen_tag = "cherries"
+ chems = list("nutriment" = list(1,15), "sugar" = list(1,15), "cherryjelly" = list(10,15))
/datum/seed/cherries/New()
..()
@@ -1248,8 +1252,8 @@
name = "kudzu"
seed_name = "kudzu"
display_name = "kudzu vines"
- chems = list("nutriment" = list(1,50), "anti_toxin" = list(1,25))
kitchen_tag = "kudzu"
+ chems = list("nutriment" = list(1,50), "anti_toxin" = list(1,25))
/datum/seed/kudzu/New()
..()
@@ -1290,8 +1294,8 @@
name = "shand"
seed_name = "Selem's hand"
display_name = "Selem's hand leaves"
- chems = list("bicaridine" = list(0,10))
kitchen_tag = "shand"
+ chems = list("bicaridine" = list(0,10))
/datum/seed/shand/New()
..()
@@ -1310,8 +1314,8 @@
name = "mtear"
seed_name = "Malani's tear"
display_name = "Malani's tear leaves"
- chems = list("honey" = list(1,10), "kelotane" = list(3,5))
kitchen_tag = "mtear"
+ chems = list("honey" = list(1,10), "kelotane" = list(3,5))
/datum/seed/mtear/New()
..()
@@ -1330,6 +1334,7 @@
name = "telriis"
seed_name = "telriis"
display_name = "telriis grass"
+ kitchen_tag = "telriis"
chems = list("pwine" = list(1,5), "nutriment" = list(1,6))
/datum/seed/telriis/New()
@@ -1346,6 +1351,7 @@
name = "thaadra"
seed_name = "thaa'dra"
display_name = "thaa'dra lichen"
+ kitchen_tag = "thaadra"
chems = list("frostoil" = list(1,5),"nutriment" = list(1,5))
/datum/seed/thaadra/New()
@@ -1362,6 +1368,7 @@
name = "jurlmah"
seed_name = "jurl'mah"
display_name = "jurl'mah reeds"
+ kitchen_tag = "jurlmah"
chems = list("serotrotium" = list(1,5),"nutriment" = list(1,5))
/datum/seed/jurlmah/New()
@@ -1377,6 +1384,7 @@
name = "amauri"
seed_name = "amauri"
display_name = "amauri plant"
+ kitchen_tag = "amauri"
chems = list("zombiepowder" = list(1,10),"condensedcapsaicin" = list(1,5),"nutriment" = list(1,5))
/datum/seed/amauri/New()
@@ -1392,6 +1400,7 @@
name = "gelthi"
seed_name = "gelthi"
display_name = "gelthi plant"
+ kitchen_tag = "gelthi"
chems = list("stoxin" = list(1,5),"capsaicin" = list(1,5),"nutriment" = list(1,5))
/datum/seed/gelthi/New()
@@ -1407,6 +1416,7 @@
name = "vale"
seed_name = "vale"
display_name = "vale bush"
+ kitchen_tag = "vale"
chems = list("paracetamol" = list(1,5),"dexalin" = list(1,2),"nutriment"= list(1,5))
/datum/seed/vale/New()
@@ -1422,6 +1432,7 @@
name = "surik"
seed_name = "surik"
display_name = "surik vine"
+ kitchen_tag = "surik"
chems = list("impedrezene" = list(1,3),"synaptizine" = list(1,2),"nutriment" = list(1,5))
/datum/seed/surik/New()
diff --git a/code/modules/mining/ore_redemption_machine/equipment_vendor.dm b/code/modules/mining/ore_redemption_machine/equipment_vendor.dm
index 7f7b896345..d1773bc163 100644
--- a/code/modules/mining/ore_redemption_machine/equipment_vendor.dm
+++ b/code/modules/mining/ore_redemption_machine/equipment_vendor.dm
@@ -38,8 +38,8 @@
new /datum/data/mining_equipment("Industrial Hardsuit - Maneuvering Jets", /obj/item/rig_module/maneuvering_jets, 1250),
new /datum/data/mining_equipment("Hardsuit - Intelligence Storage", /obj/item/rig_module/ai_container, 2500),
new /datum/data/mining_equipment("Hardsuit - Smoke Bomb Deployer", /obj/item/rig_module/grenade_launcher/smoke, 2000),
- new /datum/data/mining_equipment("Industrial Equipment - Sheet-Snatcher", /obj/item/weapon/gun/magnetic/matfed, 3000),
- new /datum/data/mining_equipment("Industrial Equipment - Phoron Bore",/obj/item/weapon/storage/bag/sheetsnatcher, 500),
+ new /datum/data/mining_equipment("Industrial Equipment - Phoron Bore", /obj/item/weapon/gun/magnetic/matfed, 3000),
+ new /datum/data/mining_equipment("Industrial Equipment - Sheet-Snatcher",/obj/item/weapon/storage/bag/sheetsnatcher, 500),
new /datum/data/mining_equipment("Digital Tablet - Standard", /obj/item/modular_computer/tablet/preset/custom_loadout/standard, 500),
new /datum/data/mining_equipment("Digital Tablet - Advanced", /obj/item/modular_computer/tablet/preset/custom_loadout/advanced, 1000),
new /datum/data/mining_equipment("Fine Excavation Kit - Chisels",/obj/item/weapon/storage/excavation, 500),
diff --git a/code/modules/mob/living/bot/SLed209bot.dm b/code/modules/mob/living/bot/SLed209bot.dm
new file mode 100644
index 0000000000..989c2e708d
--- /dev/null
+++ b/code/modules/mob/living/bot/SLed209bot.dm
@@ -0,0 +1,173 @@
+/mob/living/bot/secbot/ed209/slime
+ name = "SL-ED-209 Security Robot"
+ desc = "A security robot. He looks less than thrilled."
+ icon = 'icons/obj/aibots.dmi'
+ icon_state = "sled2090"
+ density = 1
+ health = 200
+ maxHealth = 200
+
+ is_ranged = 1
+ preparing_arrest_sounds = new()
+
+ a_intent = I_HURT
+ mob_bump_flag = HEAVY
+ mob_swap_flags = ~HEAVY
+ mob_push_flags = HEAVY
+
+ used_weapon = /obj/item/weapon/gun/energy/taser/xeno
+
+ stun_strength = 10
+ xeno_harm_strength = 9
+ req_one_access = list(access_research, access_robotics)
+ botcard_access = list(access_research, access_robotics, access_xenobiology, access_xenoarch, access_tox, access_tox_storage, access_maint_tunnels)
+ used_weapon = /obj/item/weapon/melee/baton/slime
+ var/xeno_stun_strength = 6
+
+/mob/living/bot/secbot/ed209/slime/update_icons()
+ if(on && busy)
+ icon_state = "sled209-c"
+ else
+ icon_state = "sled209[on]"
+
+/mob/living/bot/secbot/ed209/slime/RangedAttack(var/atom/A)
+ if(last_shot + shot_delay > world.time)
+ to_chat(src, "You are not ready to fire yet!")
+ return
+
+ last_shot = world.time
+
+ var/projectile = /obj/item/projectile/beam/stun/xeno
+ if(emagged)
+ projectile = /obj/item/projectile/beam/shock
+
+ playsound(loc, emagged ? 'sound/weapons/laser3.ogg' : 'sound/weapons/Taser.ogg', 50, 1)
+ var/obj/item/projectile/P = new projectile(loc)
+
+ P.firer = src
+ P.old_style_target(A)
+ P.fire()
+
+/mob/living/bot/secbot/ed209/slime/UnarmedAttack(var/mob/living/L, var/proximity)
+ ..()
+
+ if(istype(L, /mob/living/simple_mob/slime/xenobio))
+ var/mob/living/simple_mob/slime/xenobio/S = L
+ S.slimebatoned(src, xeno_stun_strength)
+
+// Assembly
+
+/obj/item/weapon/secbot_assembly/ed209_assembly/slime
+ name = "SL-ED-209 assembly"
+ desc = "Some sort of bizarre assembly."
+ icon = 'icons/obj/aibots.dmi'
+ icon_state = "ed209_frame"
+ item_state = "buildpipe"
+ created_name = "SL-ED-209 Security Robot"
+
+/obj/item/weapon/secbot_assembly/ed209_assembly/slime/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) // Here in the event it's added into a PoI or some such. Standard construction relies on the standard ED up until taser.
+ if(istype(W, /obj/item/weapon/pen))
+ var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN)
+ if(!t)
+ return
+ if(!in_range(src, usr) && src.loc != usr)
+ return
+ created_name = t
+ return
+
+ switch(build_step)
+ if(0, 1)
+ if(istype(W, /obj/item/robot_parts/l_leg) || istype(W, /obj/item/robot_parts/r_leg) || (istype(W, /obj/item/organ/external/leg) && ((W.name == "robotic right leg") || (W.name == "robotic left leg"))))
+ user.drop_item()
+ qdel(W)
+ build_step++
+ to_chat(user, "You add the robot leg to [src].")
+ name = "legs/frame assembly"
+ if(build_step == 1)
+ icon_state = "ed209_leg"
+ else
+ icon_state = "ed209_legs"
+
+ if(2)
+ if(istype(W, /obj/item/clothing/suit/storage/vest))
+ user.drop_item()
+ qdel(W)
+ build_step++
+ to_chat(user, "You add the armor to [src].")
+ name = "vest/legs/frame assembly"
+ item_state = "ed209_shell"
+ icon_state = "ed209_shell"
+
+ if(3)
+ if(istype(W, /obj/item/weapon/weldingtool))
+ var/obj/item/weapon/weldingtool/WT = W
+ if(WT.remove_fuel(0, user))
+ build_step++
+ name = "shielded frame assembly"
+ to_chat(user, "You welded the vest to [src].")
+ if(4)
+ if(istype(W, /obj/item/clothing/head/helmet))
+ user.drop_item()
+ qdel(W)
+ build_step++
+ to_chat(user, "You add the helmet to [src].")
+ name = "covered and shielded frame assembly"
+ item_state = "ed209_hat"
+ icon_state = "ed209_hat"
+
+ if(5)
+ if(isprox(W))
+ user.drop_item()
+ qdel(W)
+ build_step++
+ to_chat(user, "You add the prox sensor to [src].")
+ name = "covered, shielded and sensored frame assembly"
+ item_state = "ed209_prox"
+ icon_state = "ed209_prox"
+
+ if(6)
+ if(istype(W, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/C = W
+ if (C.get_amount() < 1)
+ to_chat(user, "You need one coil of wire to wire [src].")
+ return
+ to_chat(user, "You start to wire [src].")
+ if(do_after(user, 40) && build_step == 6)
+ if(C.use(1))
+ build_step++
+ to_chat(user, "You wire the ED-209 assembly.")
+ name = "wired ED-209 assembly"
+ return
+
+ if(7)
+ if(istype(W, /obj/item/weapon/gun/energy/taser/xeno))
+ name = "xenotaser SL-ED-209 assembly"
+ item_state = "sled209_taser"
+ icon_state = "sled209_taser"
+ build_step++
+ to_chat(user, "You add [W] to [src].")
+ user.drop_item()
+ qdel(W)
+
+ if(8)
+ if(W.is_screwdriver())
+ playsound(src, W.usesound, 100, 1)
+ var/turf/T = get_turf(user)
+ to_chat(user, "Now attaching the gun to the frame...")
+ sleep(40)
+ if(get_turf(user) == T && build_step == 8)
+ build_step++
+ name = "armed [name]"
+ to_chat(user, "Taser gun attached.")
+
+ if(9)
+ if(istype(W, /obj/item/weapon/cell))
+ build_step++
+ to_chat(user, "You complete the ED-209.")
+ var/turf/T = get_turf(src)
+ new /mob/living/bot/secbot/ed209/slime(T,created_name,lasercolor)
+ user.drop_item()
+ qdel(W)
+ user.drop_from_inventory(src)
+ qdel(src)
+
diff --git a/code/modules/mob/living/bot/ed209bot.dm b/code/modules/mob/living/bot/ed209bot.dm
index b8f1c85485..4db5978d0d 100644
--- a/code/modules/mob/living/bot/ed209bot.dm
+++ b/code/modules/mob/living/bot/ed209bot.dm
@@ -160,12 +160,30 @@
return
if(7)
- if(istype(W, /obj/item/weapon/gun/energy/taser))
- name = "taser ED-209 assembly"
+ if(istype(W, /obj/item/weapon/gun/energy/taser/xeno))
+ name = "xenotaser SL-ED-209 assembly"
+ item_state = "sled209_taser"
+ icon_state = "sled209_taser"
build_step++
to_chat(user, "You add [W] to [src].")
+ user.drop_item()
+ qdel(W)
+ var/turf/T = get_turf(src)
+ var/obj/item/weapon/secbot_assembly/ed209_assembly/slime/S = new /obj/item/weapon/secbot_assembly/ed209_assembly/slime(T)
+ S.name = name
+ S.item_state = item_state
+ S.icon_state = icon_state
+ S.build_step = build_step
+ S.created_name = created_name
+ user.drop_from_inventory(src)
+ qdel(src)
+
+ else if(istype(W, /obj/item/weapon/gun/energy/taser))
+ name = "taser ED-209 assembly"
item_state = "ed209_taser"
icon_state = "ed209_taser"
+ build_step++
+ to_chat(user, "You add [W] to [src].")
user.drop_item()
qdel(W)
diff --git a/code/modules/mob/living/bot/secbot.dm b/code/modules/mob/living/bot/secbot.dm
index d8e0b457cd..23379e7248 100644
--- a/code/modules/mob/living/bot/secbot.dm
+++ b/code/modules/mob/living/bot/secbot.dm
@@ -280,8 +280,6 @@
var/mob/living/simple_mob/slime/xenobio/S = L
S.slimebatoned(src, xeno_stun_strength)
-
-
/mob/living/bot/secbot/explode()
visible_message("[src] blows apart!")
var/turf/Tsec = get_turf(src)
diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans.dm b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
index ee11e70cd2..e0ecbad000 100644
--- a/code/modules/mob/living/carbon/human/species/station/prometheans.dm
+++ b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
@@ -122,11 +122,7 @@ var/datum/species/shapeshifter/promethean/prometheans
/obj/item/weapon/storage/toolbox/lunchbox/nymph,
/obj/item/weapon/storage/toolbox/lunchbox/syndicate)) //Only pick the empty types
var/obj/item/weapon/storage/toolbox/lunchbox/L = new boxtype(get_turf(H))
- var/mob/living/simple_mob/animal/passive/mouse/mouse = new (L)
- var/obj/item/weapon/holder/holder = new (L)
- holder.held_mob = mouse
- mouse.forceMove(holder)
- holder.sync(mouse)
+ new /obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar(L)
if(H.backbag == 1)
H.equip_to_slot_or_del(L, slot_r_hand)
else
diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/viscerator.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/viscerator.dm
index 03d0c215ca..4098d9ff9c 100644
--- a/code/modules/mob/living/simple_mob/subtypes/mechanical/viscerator.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/viscerator.dm
@@ -83,4 +83,4 @@
if(!.)
if(isrobot(L)) // They ignore synths.
return TRUE
- return L.assess_perp(src, FALSE, FALSE, TRUE, FALSE) <= 4
+ return L.assess_perp(src, FALSE, FALSE, TRUE, FALSE) <= 3
diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/ward/monitor_ward.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/ward/monitor_ward.dm
index 3f778d6e2e..aa49ce806b 100644
--- a/code/modules/mob/living/simple_mob/subtypes/mechanical/ward/monitor_ward.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/ward/monitor_ward.dm
@@ -56,7 +56,7 @@
if(!.)
if(isrobot(L)) // They ignore synths.
return TRUE
- return L.assess_perp(src, FALSE, FALSE, TRUE, FALSE) <= 4
+ return L.assess_perp(src, FALSE, FALSE, TRUE, FALSE) <= 3
/mob/living/simple_mob/mechanical/ward/monitor/death()
if(owner)
@@ -71,7 +71,7 @@
icon_living = "[initial(icon_state)]_spotted"
glow_color = "#FF0000"
else
- icon_living = "[initial(icon_state)]_ward"
+ icon_living = "[initial(icon_state)]"
glow_color = "#00FF00"
handle_light() // Update the light immediately.
..()
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 1cbb48bf25..7656249d6d 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -150,15 +150,15 @@
if(dna_lock && attached_lock.stored_dna)
if(!authorized_user(user))
if(attached_lock.safety_level == 0)
- to_chat(M, "\The [src] buzzes in dissapoint and displays an invalid DNA symbol.")
+ to_chat(M, "\The [src] buzzes in dissapointment and displays an invalid DNA symbol.")
return 0
if(!attached_lock.exploding)
if(attached_lock.safety_level == 1)
to_chat(M, "\The [src] hisses in dissapointment.")
visible_message("\The [src] announces, \"Self-destruct occurring in ten seconds.\"", "\The [src] announces, \"Self-destruct occurring in ten seconds.\"")
+ attached_lock.exploding = 1
spawn(100)
explosion(src, 0, 0, 3, 4)
- attached_lock.exploding = 1
sleep(1)
qdel(src)
return 0
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index ebcba528d2..e3fcf6abc5 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -1,249 +1,263 @@
-/obj/item/weapon/gun/energy/laser
- name = "laser rifle"
- desc = "A Hephaestus Industries G40E rifle, designed to kill with concentrated energy blasts. This variant has the ability to \
- switch between standard fire and a more efficent but weaker 'suppressive' fire."
- icon_state = "laser"
- item_state = "laser"
- wielded_item_state = "laser-wielded"
- fire_delay = 8
- slot_flags = SLOT_BELT|SLOT_BACK
- w_class = ITEMSIZE_LARGE
- force = 10
- origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 2)
- matter = list(DEFAULT_WALL_MATERIAL = 2000)
- projectile_type = /obj/item/projectile/beam/midlaser
-// one_handed_penalty = 30
-
- firemodes = list(
- list(mode_name="normal", fire_delay=8, projectile_type=/obj/item/projectile/beam/midlaser, charge_cost = 240),
- list(mode_name="suppressive", fire_delay=5, projectile_type=/obj/item/projectile/beam/weaklaser, charge_cost = 60),
- )
-
-/obj/item/weapon/gun/energy/laser/mounted
- self_recharge = 1
- use_external_power = 1
- one_handed_penalty = 0 // Not sure if two-handing gets checked for mounted weapons, but better safe than sorry.
-
-/obj/item/weapon/gun/energy/laser/practice
- name = "practice laser carbine"
- desc = "A modified version of the HI G40E, this one fires less concentrated energy bolts designed for target practice."
- projectile_type = /obj/item/projectile/beam/practice
- charge_cost = 48
-
- cell_type = /obj/item/weapon/cell/device
-
- firemodes = list(
- list(mode_name="normal", projectile_type=/obj/item/projectile/beam/practice, charge_cost = 48),
- list(mode_name="suppressive", projectile_type=/obj/item/projectile/beam/practice, charge_cost = 12),
- )
-
-/obj/item/weapon/gun/energy/retro
- name = "retro laser"
- icon_state = "retro"
- item_state = "retro"
- desc = "An older model of the basic lasergun. Nevertheless, it is still quite deadly and easy to maintain, making it a favorite amongst pirates and other outlaws."
- slot_flags = SLOT_BELT
- w_class = ITEMSIZE_NORMAL
- projectile_type = /obj/item/projectile/beam
- fire_delay = 10 //old technology
-
-/obj/item/weapon/gun/energy/retro/mounted
- self_recharge = 1
- use_external_power = 1
-
-/obj/item/weapon/gun/energy/retro/empty
- icon_state = "retro"
- cell_type = null
-
-
-/datum/category_item/catalogue/anomalous/precursor_a/alien_pistol
- name = "Precursor Alpha Weapon - Appendageheld Laser"
- desc = "This object strongly resembles a weapon, and if one were to pull the \
- trigger located on the handle of the object, it would fire a deadly \
- laser at whatever it was pointed at. The beam fired appears to cause too \
- much damage to whatever it would hit to have served as a long ranged repair tool, \
- therefore this object was most likely designed to be a deadly weapon. If so, this \
- has several implications towards its creators;\
-
\
- Firstly, it implies that these precursors, at some point during their development, \
- had needed to defend themselves, or otherwise had a need to utilize violence, and \
- as such created better tools to do so. It is unclear if violence was employed against \
- themselves as a form of in-fighting, or if violence was exclusive to outside species.\
-
\
- Secondly, the shape and design of the weapon implies that the creators of this \
- weapon were able to grasp objects, and be able to manipulate the trigger independently \
- from merely holding onto the weapon, making certain types of appendages like tentacles be \
- unlikely.\
-
\
- An interesting note about this weapon, when compared to contemporary energy weapons, is \
- that this gun appears to be inferior to modern laser weapons. The beam fired has less \
- of an ability to harm, and the power consumption appears to be higher than average for \
- a human-made energy side-arm. One possible explaination is that the creators of this \
- weapon, in their later years, had less of a need to optimize their capability for war, \
- and instead focused on other endeavors. Another explaination is that vast age of the weapon \
- may have caused it to degrade, yet still remain functional at a reduced capability."
- value = CATALOGUER_REWARD_MEDIUM
-
-/obj/item/weapon/gun/energy/alien
- name = "alien pistol"
- desc = "A weapon that works very similarly to a traditional energy weapon. How this came to be will likely be a mystery for the ages."
- catalogue_data = list(/datum/category_item/catalogue/anomalous/precursor_a/alien_pistol)
- icon_state = "alienpistol"
- item_state = "alienpistol"
- fire_delay = 10 // Handguns should be inferior to two-handed weapons. Even alien ones I suppose.
- charge_cost = 480 // Five shots.
-
- projectile_type = /obj/item/projectile/beam/cyan
- cell_type = /obj/item/weapon/cell/device/weapon/recharge/alien // Self charges.
- origin_tech = list(TECH_COMBAT = 8, TECH_MAGNET = 7)
- modifystate = "alienpistol"
-
-
-/obj/item/weapon/gun/energy/captain
- name = "antique laser gun"
- icon_state = "caplaser"
- item_state = "caplaser"
- desc = "A rare weapon, handcrafted by a now defunct specialty manufacturer on Luna for a small fortune. It's certainly aged well."
- force = 5
- slot_flags = SLOT_BELT
- w_class = ITEMSIZE_NORMAL
- projectile_type = /obj/item/projectile/beam
- origin_tech = null
- fire_delay = 10 //Old pistol
- charge_cost = 480 //to compensate a bit for self-recharging
- cell_type = /obj/item/weapon/cell/device/weapon/recharge/captain
- battery_lock = 1
-
-/obj/item/weapon/gun/energy/lasercannon
- name = "laser cannon"
- desc = "With the laser cannon, the lasing medium is enclosed in a tube lined with uranium-235 and subjected to high neutron \
- flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with small laser volumes!"
- icon_state = "lasercannon"
- item_state = null
- origin_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3, TECH_POWER = 3)
- slot_flags = SLOT_BELT|SLOT_BACK
- projectile_type = /obj/item/projectile/beam/heavylaser/cannon
- battery_lock = 1
- fire_delay = 20
- w_class = ITEMSIZE_LARGE
-// one_handed_penalty = 90 // The thing's heavy and huge.
- accuracy = 45
- charge_cost = 600
-
-/obj/item/weapon/gun/energy/lasercannon/mounted
- name = "mounted laser cannon"
- self_recharge = 1
- use_external_power = 1
- recharge_time = 10
- accuracy = 0 // Mounted cannons are just fine the way they are.
- one_handed_penalty = 0 // Not sure if two-handing gets checked for mounted weapons, but better safe than sorry.
- projectile_type = /obj/item/projectile/beam/heavylaser
- charge_cost = 400
- fire_delay = 20
-
-/obj/item/weapon/gun/energy/xray
- name = "xray laser gun"
- desc = "A high-power laser gun capable of expelling concentrated xray blasts, which are able to penetrate matter easier than \
- standard photonic beams, resulting in an effective 'anti-armor' energy weapon."
- icon_state = "xray"
- item_state = "xray"
- origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 3, TECH_MAGNET = 2)
- projectile_type = /obj/item/projectile/beam/xray
- charge_cost = 200
-
-/obj/item/weapon/gun/energy/sniperrifle
- name = "marksman energy rifle"
- desc = "The HI DMR 9E is an older design of Hephaestus Industries. A designated marksman rifle capable of shooting powerful \
- ionized beams, this is a weapon to kill from a distance."
- icon_state = "sniper"
- item_state = "sniper"
- item_state_slots = list(slot_r_hand_str = "z8carbine", slot_l_hand_str = "z8carbine") //placeholder
- origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 5, TECH_POWER = 4)
- projectile_type = /obj/item/projectile/beam/sniper
- slot_flags = SLOT_BACK
- battery_lock = 1
- charge_cost = 600
- fire_delay = 35
- force = 10
- w_class = ITEMSIZE_HUGE // So it can't fit in a backpack.
- accuracy = -45 //shooting at the hip
- scoped_accuracy = 0
-// requires_two_hands = 1
-// one_handed_penalty = 60 // The weapon itself is heavy, and the long barrel makes it hard to hold steady with just one hand.
-
-/obj/item/weapon/gun/energy/sniperrifle/verb/scope()
- set category = "Object"
- set name = "Use Scope"
- set popup_menu = 1
-
- toggle_scope(2.0)
-
-/obj/item/weapon/gun/energy/monorifle
- name = "antique mono-rifle"
- desc = "An old laser rifle. This one can only fire once before requiring recharging."
- description_fluff = "Modeled after ancient hunting rifles, this rifle was dubbed the 'Rainy Day Special' by some, due to its use as some barmens' fight-stopper of choice. One shot is all it takes, or so they say."
- icon_state = "eshotgun"
- item_state = "shotgun"
- origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 4, TECH_POWER = 3)
- projectile_type = /obj/item/projectile/beam/sniper
- slot_flags = SLOT_BACK
- charge_cost = 1300
- fire_delay = 20
- force = 8
- w_class = ITEMSIZE_LARGE
- accuracy = 10
- scoped_accuracy = 15
- var/scope_multiplier = 1.5
-
-/obj/item/weapon/gun/energy/monorifle/verb/sights()
- set category = "Object"
- set name = "Aim Down Sights"
- set popup_menu = 1
-
- toggle_scope(scope_multiplier)
-
-/obj/item/weapon/gun/energy/monorifle/combat
- name = "combat mono-rifle"
- desc = "A modernized version of the mono-rifle. This one can fire twice before requiring recharging."
- description_fluff = "A modern design produced by a company once working from Saint Columbia, based on the antique mono-rifle 'Rainy Day Special' design."
- icon_state = "ecshotgun"
- item_state = "cshotgun"
- charge_cost = 1000
- force = 12
- accuracy = 0
- scoped_accuracy = 20
-
-////////Laser Tag////////////////////
-
-/obj/item/weapon/gun/energy/lasertag
- name = "laser tag gun"
- item_state = "laser"
- desc = "Standard issue weapon of the Imperial Guard"
- origin_tech = list(TECH_COMBAT = 1, TECH_MAGNET = 2)
- matter = list(DEFAULT_WALL_MATERIAL = 2000)
- projectile_type = /obj/item/projectile/beam/lasertag/blue
- cell_type = /obj/item/weapon/cell/device/weapon/recharge
- battery_lock = 1
- var/required_vest
-
-/obj/item/weapon/gun/energy/lasertag/special_check(var/mob/living/carbon/human/M)
- if(ishuman(M))
- if(!istype(M.wear_suit, required_vest))
- M << "You need to be wearing your laser tag vest!"
- return 0
- return ..()
-
-/obj/item/weapon/gun/energy/lasertag/blue
- icon_state = "bluetag"
- item_state = "bluetag"
- projectile_type = /obj/item/projectile/beam/lasertag/blue
- required_vest = /obj/item/clothing/suit/bluetag
-
-/obj/item/weapon/gun/energy/lasertag/red
- icon_state = "redtag"
- item_state = "redtag"
- projectile_type = /obj/item/projectile/beam/lasertag/red
- required_vest = /obj/item/clothing/suit/redtag
-
-/obj/item/weapon/gun/energy/lasertag/omni
- projectile_type = /obj/item/projectile/beam/lasertag/omni
\ No newline at end of file
+/obj/item/weapon/gun/energy/laser
+ name = "laser rifle"
+ desc = "A Hephaestus Industries G40E rifle, designed to kill with concentrated energy blasts. This variant has the ability to \
+ switch between standard fire and a more efficent but weaker 'suppressive' fire."
+ icon_state = "laser"
+ item_state = "laser"
+ wielded_item_state = "laser-wielded"
+ fire_delay = 8
+ slot_flags = SLOT_BELT|SLOT_BACK
+ w_class = ITEMSIZE_LARGE
+ force = 10
+ origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 2)
+ matter = list(DEFAULT_WALL_MATERIAL = 2000)
+ projectile_type = /obj/item/projectile/beam/midlaser
+// one_handed_penalty = 30
+
+ firemodes = list(
+ list(mode_name="normal", fire_delay=8, projectile_type=/obj/item/projectile/beam/midlaser, charge_cost = 240),
+ list(mode_name="suppressive", fire_delay=5, projectile_type=/obj/item/projectile/beam/weaklaser, charge_cost = 60),
+ )
+
+/obj/item/weapon/gun/energy/laser/mounted
+ self_recharge = 1
+ use_external_power = 1
+ one_handed_penalty = 0 // Not sure if two-handing gets checked for mounted weapons, but better safe than sorry.
+
+/obj/item/weapon/gun/energy/laser/practice
+ name = "practice laser carbine"
+ desc = "A modified version of the HI G40E, this one fires less concentrated energy bolts designed for target practice."
+ projectile_type = /obj/item/projectile/beam/practice
+ charge_cost = 48
+
+ cell_type = /obj/item/weapon/cell/device
+
+ firemodes = list(
+ list(mode_name="normal", projectile_type=/obj/item/projectile/beam/practice, charge_cost = 48),
+ list(mode_name="suppressive", projectile_type=/obj/item/projectile/beam/practice, charge_cost = 12),
+ )
+
+/obj/item/weapon/gun/energy/retro
+ name = "retro laser"
+ icon_state = "retro"
+ item_state = "retro"
+ desc = "An older model of the basic lasergun. Nevertheless, it is still quite deadly and easy to maintain, making it a favorite amongst pirates and other outlaws."
+ slot_flags = SLOT_BELT
+ w_class = ITEMSIZE_NORMAL
+ projectile_type = /obj/item/projectile/beam
+ fire_delay = 10 //old technology
+
+/obj/item/weapon/gun/energy/retro/mounted
+ self_recharge = 1
+ use_external_power = 1
+
+/obj/item/weapon/gun/energy/retro/empty
+ icon_state = "retro"
+ cell_type = null
+
+
+/datum/category_item/catalogue/anomalous/precursor_a/alien_pistol
+ name = "Precursor Alpha Weapon - Appendageheld Laser"
+ desc = "This object strongly resembles a weapon, and if one were to pull the \
+ trigger located on the handle of the object, it would fire a deadly \
+ laser at whatever it was pointed at. The beam fired appears to cause too \
+ much damage to whatever it would hit to have served as a long ranged repair tool, \
+ therefore this object was most likely designed to be a deadly weapon. If so, this \
+ has several implications towards its creators;\
+
\
+ Firstly, it implies that these precursors, at some point during their development, \
+ had needed to defend themselves, or otherwise had a need to utilize violence, and \
+ as such created better tools to do so. It is unclear if violence was employed against \
+ themselves as a form of in-fighting, or if violence was exclusive to outside species.\
+
\
+ Secondly, the shape and design of the weapon implies that the creators of this \
+ weapon were able to grasp objects, and be able to manipulate the trigger independently \
+ from merely holding onto the weapon, making certain types of appendages like tentacles be \
+ unlikely.\
+
\
+ An interesting note about this weapon, when compared to contemporary energy weapons, is \
+ that this gun appears to be inferior to modern laser weapons. The beam fired has less \
+ of an ability to harm, and the power consumption appears to be higher than average for \
+ a human-made energy side-arm. One possible explaination is that the creators of this \
+ weapon, in their later years, had less of a need to optimize their capability for war, \
+ and instead focused on other endeavors. Another explaination is that vast age of the weapon \
+ may have caused it to degrade, yet still remain functional at a reduced capability."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/obj/item/weapon/gun/energy/alien
+ name = "alien pistol"
+ desc = "A weapon that works very similarly to a traditional energy weapon. How this came to be will likely be a mystery for the ages."
+ catalogue_data = list(/datum/category_item/catalogue/anomalous/precursor_a/alien_pistol)
+ icon_state = "alienpistol"
+ item_state = "alienpistol"
+ fire_delay = 10 // Handguns should be inferior to two-handed weapons. Even alien ones I suppose.
+ charge_cost = 480 // Five shots.
+
+ projectile_type = /obj/item/projectile/beam/cyan
+ cell_type = /obj/item/weapon/cell/device/weapon/recharge/alien // Self charges.
+ origin_tech = list(TECH_COMBAT = 8, TECH_MAGNET = 7)
+ modifystate = "alienpistol"
+
+
+/obj/item/weapon/gun/energy/captain
+ name = "antique laser gun"
+ icon_state = "caplaser"
+ item_state = "caplaser"
+ desc = "A rare weapon, handcrafted by a now defunct specialty manufacturer on Luna for a small fortune. It's certainly aged well."
+ force = 5
+ slot_flags = SLOT_BELT
+ w_class = ITEMSIZE_NORMAL
+ projectile_type = /obj/item/projectile/beam
+ origin_tech = null
+ fire_delay = 10 //Old pistol
+ charge_cost = 480 //to compensate a bit for self-recharging
+ cell_type = /obj/item/weapon/cell/device/weapon/recharge/captain
+ battery_lock = 1
+
+/obj/item/weapon/gun/energy/lasercannon
+ name = "laser cannon"
+ desc = "With the laser cannon, the lasing medium is enclosed in a tube lined with uranium-235 and subjected to high neutron \
+ flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with small laser volumes!"
+ icon_state = "lasercannon"
+ item_state = null
+ origin_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3, TECH_POWER = 3)
+ slot_flags = SLOT_BELT|SLOT_BACK
+ projectile_type = /obj/item/projectile/beam/heavylaser/cannon
+ battery_lock = 1
+ fire_delay = 20
+ w_class = ITEMSIZE_LARGE
+// one_handed_penalty = 90 // The thing's heavy and huge.
+ accuracy = 45
+ charge_cost = 600
+
+/obj/item/weapon/gun/energy/lasercannon/mounted
+ name = "mounted laser cannon"
+ self_recharge = 1
+ use_external_power = 1
+ recharge_time = 10
+ accuracy = 0 // Mounted cannons are just fine the way they are.
+ one_handed_penalty = 0 // Not sure if two-handing gets checked for mounted weapons, but better safe than sorry.
+ projectile_type = /obj/item/projectile/beam/heavylaser
+ charge_cost = 400
+ fire_delay = 20
+
+/obj/item/weapon/gun/energy/xray
+ name = "xray laser gun"
+ desc = "A high-power laser gun capable of expelling concentrated xray blasts, which are able to penetrate matter easier than \
+ standard photonic beams, resulting in an effective 'anti-armor' energy weapon."
+ icon_state = "xray"
+ item_state = "xray"
+ origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 3, TECH_MAGNET = 2)
+ projectile_type = /obj/item/projectile/beam/xray
+ charge_cost = 200
+
+/obj/item/weapon/gun/energy/sniperrifle
+ name = "marksman energy rifle"
+ desc = "The HI DMR 9E is an older design of Hephaestus Industries. A designated marksman rifle capable of shooting powerful \
+ ionized beams, this is a weapon to kill from a distance."
+ icon_state = "sniper"
+ item_state = "sniper"
+ item_state_slots = list(slot_r_hand_str = "z8carbine", slot_l_hand_str = "z8carbine") //placeholder
+ origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 5, TECH_POWER = 4)
+ projectile_type = /obj/item/projectile/beam/sniper
+ slot_flags = SLOT_BACK
+ battery_lock = 1
+ charge_cost = 600
+ fire_delay = 35
+ force = 10
+ w_class = ITEMSIZE_HUGE // So it can't fit in a backpack.
+ accuracy = -45 //shooting at the hip
+ scoped_accuracy = 0
+// requires_two_hands = 1
+// one_handed_penalty = 60 // The weapon itself is heavy, and the long barrel makes it hard to hold steady with just one hand.
+
+/obj/item/weapon/gun/energy/sniperrifle/verb/scope()
+ set category = "Object"
+ set name = "Use Scope"
+ set popup_menu = 1
+
+ toggle_scope(2.0)
+
+/obj/item/weapon/gun/energy/monorifle
+ name = "antique mono-rifle"
+ desc = "An old laser rifle. This one can only fire once before requiring recharging."
+ description_fluff = "Modeled after ancient hunting rifles, this rifle was dubbed the 'Rainy Day Special' by some, due to its use as some barmens' fight-stopper of choice. One shot is all it takes, or so they say."
+ icon_state = "eshotgun"
+ item_state = "shotgun"
+ origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 4, TECH_POWER = 3)
+ projectile_type = /obj/item/projectile/beam/sniper
+ slot_flags = SLOT_BACK
+ charge_cost = 1300
+ fire_delay = 20
+ force = 8
+ w_class = ITEMSIZE_LARGE
+ accuracy = 10
+ scoped_accuracy = 15
+ var/scope_multiplier = 1.5
+
+/obj/item/weapon/gun/energy/monorifle/verb/sights()
+ set category = "Object"
+ set name = "Aim Down Sights"
+ set popup_menu = 1
+
+ toggle_scope(scope_multiplier)
+
+/obj/item/weapon/gun/energy/monorifle/combat
+ name = "combat mono-rifle"
+ desc = "A modernized version of the mono-rifle. This one can fire twice before requiring recharging."
+ description_fluff = "A modern design produced by a company once working from Saint Columbia, based on the antique mono-rifle 'Rainy Day Special' design."
+ icon_state = "ecshotgun"
+ item_state = "cshotgun"
+ charge_cost = 1000
+ force = 12
+ accuracy = 0
+ scoped_accuracy = 20
+
+////////Laser Tag////////////////////
+
+/obj/item/weapon/gun/energy/lasertag
+ name = "laser tag gun"
+ item_state = "laser"
+ desc = "Standard issue weapon of the Imperial Guard"
+ origin_tech = list(TECH_COMBAT = 1, TECH_MAGNET = 2)
+ matter = list(DEFAULT_WALL_MATERIAL = 2000)
+ projectile_type = /obj/item/projectile/beam/lasertag/blue
+ cell_type = /obj/item/weapon/cell/device/weapon/recharge
+ battery_lock = 1
+ var/required_vest
+
+/obj/item/weapon/gun/energy/lasertag/special_check(var/mob/living/carbon/human/M)
+ if(ishuman(M))
+ if(!istype(M.wear_suit, required_vest))
+ M << "You need to be wearing your laser tag vest!"
+ return 0
+ return ..()
+
+/obj/item/weapon/gun/energy/lasertag/blue
+ icon_state = "bluetag"
+ item_state = "bluetag"
+ projectile_type = /obj/item/projectile/beam/lasertag/blue
+ required_vest = /obj/item/clothing/suit/bluetag
+
+/obj/item/weapon/gun/energy/lasertag/red
+ icon_state = "redtag"
+ item_state = "redtag"
+ projectile_type = /obj/item/projectile/beam/lasertag/red
+ required_vest = /obj/item/clothing/suit/redtag
+
+/obj/item/weapon/gun/energy/lasertag/omni
+ projectile_type = /obj/item/projectile/beam/lasertag/omni
+
+/*
+ * Laser scattergun, proof of concept.
+ */
+
+/obj/item/weapon/gun/energy/lasershotgun
+ name = "laser scattergun"
+ icon = 'icons/obj/energygun.dmi'
+ item_state = "laser"
+ icon_state = "scatter"
+ desc = "A strange Almachi weapon, utilizing a refracting prism to turn a single laser blast into a diverging cluster."
+ origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 1, TECH_MATERIAL = 4)
+
+ projectile_type = /obj/item/projectile/scatter/laser
\ No newline at end of file
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index d74bfb9caf..0eaf2d2f42 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -84,8 +84,17 @@
var/accuracy = 0
var/dispersion = 0.0
+ // Sub-munitions. Basically, multi-projectile shotgun, rather than pellets.
+ var/use_submunitions = FALSE
+ var/only_submunitions = FALSE // Will the projectile delete itself after firing the submunitions?
+ var/list/submunitions = list() // Assoc list of the paths of any submunitions, and how many they are. [projectilepath] = [projectilecount].
+ var/submunition_spread_max = 30 // Divided by 10 to get the percentile dispersion.
+ var/submunition_spread_min = 5 // Above.
+ var/force_max_submunition_spread = FALSE // Do we just force the maximum?
+ var/spread_submunition_damage = FALSE // Do we assign damage to our sub projectiles based on our main projectile damage?
+
var/damage = 10
- var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE, HALLOSS are the only things that should be in here
+ var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE, HALLOSS, ELECTROCUTE, BIOACID are the only things that should be in here
var/SA_bonus_damage = 0 // Some bullets inflict extra damage on simple animals.
var/SA_vulnerability = null // What kind of simple animal the above bonus damage should be applied to. Set to null to apply to all SAs.
var/nodamage = 0 //Determines if the projectile will skip any damage inflictions
@@ -649,6 +658,37 @@
if(get_turf(target) == get_turf(src))
direct_target = target
+ if(use_submunitions && submunitions.len)
+ var/temp_min_spread = 0
+ if(force_max_submunition_spread)
+ temp_min_spread = submunition_spread_max
+ else
+ temp_min_spread = submunition_spread_min
+
+ var/damage_override = null
+
+ if(spread_submunition_damage)
+ damage_override = damage
+ if(nodamage)
+ damage_override = 0
+
+ var/projectile_count = 0
+
+ for(var/proj in submunitions)
+ projectile_count += submunitions[proj]
+
+ damage_override = round(damage_override / max(1, projectile_count))
+
+ for(var/path in submunitions)
+ for(var/count = 1 to submunitions[path])
+ var/obj/item/projectile/SM = new path(get_turf(loc))
+ SM.shot_from = shot_from
+ SM.silenced = silenced
+ SM.dispersion = rand(temp_min_spread, submunition_spread_max) / 10
+ if(!isnull(damage_override))
+ SM.damage = damage_override
+ SM.launch_projectile(target, target_zone, user, params, angle_override)
+
preparePixelProjectile(target, user? user : get_turf(src), params, forced_spread)
return fire(angle_override, direct_target)
@@ -668,5 +708,36 @@
if(get_turf(target) == get_turf(src))
direct_target = target
+ if(use_submunitions && submunitions.len)
+ var/temp_min_spread = 0
+ if(force_max_submunition_spread)
+ temp_min_spread = submunition_spread_max
+ else
+ temp_min_spread = submunition_spread_min
+
+ var/damage_override = null
+
+ if(spread_submunition_damage)
+ damage_override = damage
+ if(nodamage)
+ damage_override = 0
+
+ var/projectile_count = 0
+
+ for(var/proj in submunitions)
+ projectile_count += submunitions[proj]
+
+ damage_override = round(damage_override / max(1, projectile_count))
+
+ for(var/path in submunitions)
+ for(var/count = 1 to submunitions[path])
+ var/obj/item/projectile/SM = new path(get_turf(loc))
+ SM.shot_from = shot_from
+ SM.silenced = silenced
+ SM.dispersion = rand(temp_min_spread, submunition_spread_max) / 10
+ if(!isnull(damage_override))
+ SM.damage = damage_override
+ SM.launch_projectile_from_turf(target, target_zone, user, params, angle_override)
+
preparePixelProjectile(target, get_turf(src), params, forced_spread)
return fire(angle_override, direct_target)
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index b046ca7123..ec2670c61d 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -213,4 +213,17 @@
/obj/item/projectile/beam/stun/med
name = "stun beam"
icon_state = "stun"
- agony = 30
\ No newline at end of file
+ agony = 30
+
+/obj/item/projectile/beam/shock
+ name = "shock beam"
+ icon_state = "lightning"
+ damage_type = ELECTROCUTE
+
+ muzzle_type = /obj/effect/projectile/muzzle/lightning
+ tracer_type = /obj/effect/projectile/tracer/lightning
+ impact_type = /obj/effect/projectile/impact/lightning
+
+ damage = 30
+ agony = 15
+ eyeblur = 2
diff --git a/code/modules/projectiles/projectile/scatter.dm b/code/modules/projectiles/projectile/scatter.dm
new file mode 100644
index 0000000000..0aa6ad5719
--- /dev/null
+++ b/code/modules/projectiles/projectile/scatter.dm
@@ -0,0 +1,62 @@
+
+/*
+ * Home of the purely submunition projectiles.
+ */
+
+/obj/item/projectile/scatter
+ name = "scatter projectile"
+ icon = 'icons/obj/projectiles.dmi'
+ icon_state = "bullet"
+ density = FALSE
+ anchored = TRUE
+ unacidable = TRUE
+ pass_flags = PASSTABLE
+ mouse_opacity = 0
+
+ use_submunitions = TRUE
+
+ damage = 8
+ spread_submunition_damage = TRUE
+ only_submunitions = TRUE
+ range = 0 // Immediately deletes itself after firing, as its only job is to fire other projectiles.
+
+ submunition_spread_max = 30
+ submunition_spread_min = 2
+
+ submunitions = list(
+ /obj/item/projectile/bullet/pellet/shotgun/flak = 3
+ )
+
+/obj/item/projectile/scatter/laser
+ damage = 40
+
+ submunition_spread_max = 40
+ submunition_spread_min = 10
+
+ submunitions = list(
+ /obj/item/projectile/beam/prismatic = 4
+ )
+
+/obj/item/projectile/beam/prismatic
+ name = "prismatic beam"
+ icon_state = "omnilaser"
+ damage = 10
+ damage_type = BURN
+ check_armour = "laser"
+ light_color = "#00C6FF"
+
+ stutter = 2
+
+ muzzle_type = /obj/effect/projectile/muzzle/laser_omni
+ tracer_type = /obj/effect/projectile/tracer/laser_omni
+ impact_type = /obj/effect/projectile/impact/laser_omni
+
+/obj/item/projectile/scatter/ion
+ damage = 20
+
+ submunition_spread_max = 40
+ submunition_spread_min = 10
+
+ submunitions = list(
+ /obj/item/projectile/bullet/shotgun/ion = 3
+ )
diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm
index 89d03e9673..ea4c2aded9 100644
--- a/code/modules/reagents/Chemistry-Recipes.dm
+++ b/code/modules/reagents/Chemistry-Recipes.dm
@@ -1198,7 +1198,7 @@
name = "Peanut Butter"
id = "peanutbutter"
result = "peanutbutter"
- required_reagents = list("peanutoil" = 2, "sugar" = 1, "salt" = 1)
+ required_reagents = list("peanutoil" = 2, "sugar" = 1, "sodiumchloride" = 1)
catalysts = list("enzyme" = 5)
result_amount = 3
@@ -1206,7 +1206,7 @@
name = "mayonnaise"
id = "mayo"
result = "mayo"
- required_reagents = list("egg" = 9, "cornoil" = 5, "lemonjuice" = 5, "salt" = 1)
+ required_reagents = list("egg" = 9, "cornoil" = 5, "lemonjuice" = 5, "sodiumchloride" = 1)
result_amount = 15
/datum/chemical_reaction/food/cheesewheel
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index 4f0b3ab8b6..8eb7e7cbfc 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -135,8 +135,8 @@
/obj/item/weapon/reagent_containers/glass/proc/update_name_label()
if(label_text == "")
name = base_name
- else if(length(label_text) > 10)
- var/short_label_text = copytext(label_text, 1, 11)
+ else if(length(label_text) > 20)
+ var/short_label_text = copytext(label_text, 1, 21)
name = "[base_name] ([short_label_text]...)"
else
name = "[base_name] ([label_text])"
diff --git a/code/modules/research/mechfab_designs.dm b/code/modules/research/mechfab_designs.dm
index 436d5e85d9..5c6a024e18 100644
--- a/code/modules/research/mechfab_designs.dm
+++ b/code/modules/research/mechfab_designs.dm
@@ -664,6 +664,13 @@
materials = list(DEFAULT_WALL_MATERIAL = 7500, "silver" = 375, "glass" = 750)
build_path = /obj/item/mecha_parts/mecha_equipment/generator/nuclear
+/datum/design/item/mecha/speedboost_ripley
+ name = "Ripley Leg Actuator Overdrive"
+ desc = "System enhancements and overdrives to make a mech's legs move faster."
+ req_tech = list( TECH_POWER = 5, TECH_MATERIAL = 4, TECH_ENGINEERING = 4)
+ materials = list(DEFAULT_WALL_MATERIAL = 10000, "silver" = 1000, "gold" = 1000)
+ build_path = /obj/item/mecha_parts/mecha_equipment/speedboost
+
/datum/design/item/synthetic_flash
name = "Synthetic Flash"
id = "sflash"
diff --git a/html/changelog.html b/html/changelog.html
index 7a0461244c..fab075d8ed 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -53,6 +53,18 @@
-->