diff --git a/code/ATMOSPHERICS/components/shutoff.dm b/code/ATMOSPHERICS/components/shutoff.dm
new file mode 100644
index 0000000000..de69f5e395
--- /dev/null
+++ b/code/ATMOSPHERICS/components/shutoff.dm
@@ -0,0 +1,57 @@
+GLOBAL_LIST_EMPTY(shutoff_valves)
+
+/obj/machinery/atmospherics/valve/shutoff
+ icon = 'icons/atmos/clamp.dmi'
+ icon_state = "map_vclamp0"
+ pipe_state = "vclamp"
+
+ 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
+
+/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()
+ GLOB.shutoff_valves += src
+ hide(1)
+
+/obj/machinery/atmospherics/valve/shutoff/Destroy()
+ GLOB.shutoff_valves -= src
+ ..()
+
+/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/he_pipes_vr.dm b/code/ATMOSPHERICS/pipes/he_pipes_vr.dm
new file mode 100644
index 0000000000..d763f75b74
--- /dev/null
+++ b/code/ATMOSPHERICS/pipes/he_pipes_vr.dm
@@ -0,0 +1,2 @@
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/set_leaking(var/new_leaking)
+ return //Nope
\ No newline at end of file
diff --git a/code/ATMOSPHERICS/pipes/manifold.dm b/code/ATMOSPHERICS/pipes/manifold.dm
index 524d420d39..f44bfc5686 100644
--- a/code/ATMOSPHERICS/pipes/manifold.dm
+++ b/code/ATMOSPHERICS/pipes/manifold.dm
@@ -68,9 +68,24 @@
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/process()
+ if(!parent)
+ ..()
+ else if(leaking)
+ parent.mingle_with_turf(loc, volume)
+ else
+ . = PROCESS_KILL
+
/obj/machinery/atmospherics/pipe/manifold/change_color(var/new_color)
..()
//for updating connected atmos device pipes (i.e. vents, manifolds, etc)
@@ -154,6 +169,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..197c1a090b 100644
--- a/code/ATMOSPHERICS/pipes/manifold4w.dm
+++ b/code/ATMOSPHERICS/pipes/manifold4w.dm
@@ -66,9 +66,24 @@
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/process()
+ if(!parent)
+ ..()
+ else if(leaking)
+ parent.mingle_with_turf(loc, volume)
+ else
+ . = PROCESS_KILL
+
/obj/machinery/atmospherics/pipe/manifold4w/change_color(var/new_color)
..()
//for updating connected atmos device pipes (i.e. vents, manifolds, etc)
@@ -156,6 +171,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/pipe_base_vr.dm b/code/ATMOSPHERICS/pipes/pipe_base_vr.dm
new file mode 100644
index 0000000000..d20e73ae89
--- /dev/null
+++ b/code/ATMOSPHERICS/pipes/pipe_base_vr.dm
@@ -0,0 +1,2 @@
+/obj/machinery/atmospherics/pipe/set_leaking(var/new_leaking)
+ return // N O P E
\ No newline at end of file
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/__defines/species_languages_vr.dm b/code/__defines/species_languages_vr.dm
index 224478646d..1004c1e22c 100644
--- a/code/__defines/species_languages_vr.dm
+++ b/code/__defines/species_languages_vr.dm
@@ -1,3 +1,5 @@
+#define SPECIES_WHITELIST_SELECTABLE 0x20 // Can select and customize, but not join as
+
#define LANGUAGE_BIRDSONG "Birdsong"
#define LANGUAGE_SAGARU "Sagaru"
#define LANGUAGE_CANILUNZT "Canilunzt"
diff --git a/code/_helpers/global_lists_vr.dm b/code/_helpers/global_lists_vr.dm
index 2a273eaab1..846291edc4 100644
--- a/code/_helpers/global_lists_vr.dm
+++ b/code/_helpers/global_lists_vr.dm
@@ -11,6 +11,8 @@ var/global/list/positive_traits = list() // Positive custom species traits, inde
var/global/list/traits_costs = list() // Just path = cost list, saves time in char setup
var/global/list/all_traits = list() // All of 'em at once (same instances)
+var/global/list/sensorpreflist = list("Off", "Binary", "Vitals", "Tracking", "No Preference") //TFF 5/8/19 - Suit Sensors global list
+
var/global/list/custom_species_bases = list() // Species that can be used for a Custom Species icon base
//stores numeric player size options indexed by name
diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm
index 0343fe4249..eb363c08cb 100644
--- a/code/_helpers/text.dm
+++ b/code/_helpers/text.dm
@@ -84,7 +84,6 @@
// 0 .. 9
if(48 to 57) //Numbers
- if(!last_char_group) continue //suppress at start of string
if(!allow_numbers) continue // If allow_numbers is 0, then don't do this.
output += ascii2text(ascii_char)
number_of_alphanumeric++
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index e367769b07..3bd1a0afb2 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -2,6 +2,9 @@
/atom/proc/attack_generic(mob/user as mob)
return 0
+/atom/proc/take_damage(var/damage)
+ return 0
+
/*
Humans:
Adds an exception for gloves, to allow special glove types like the ninja ones.
diff --git a/code/datums/helper_datums/teleport_vr.dm b/code/datums/helper_datums/teleport_vr.dm
index b3054a44c0..d8e8428535 100644
--- a/code/datums/helper_datums/teleport_vr.dm
+++ b/code/datums/helper_datums/teleport_vr.dm
@@ -1,5 +1,5 @@
//wrapper
-/proc/do_noeffect_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=TRUE)
+/proc/do_noeffect_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=FALSE)
new /datum/teleport/instant/science/noeffect(arglist(args))
return
diff --git a/code/datums/supplypacks/engineering.dm b/code/datums/supplypacks/engineering.dm
index 8f58b97baf..e387309da7 100644
--- a/code/datums/supplypacks/engineering.dm
+++ b/code/datums/supplypacks/engineering.dm
@@ -21,6 +21,20 @@
containertype = /obj/structure/closet/crate/engineering
containername = "Superconducting Magnetic Coil crate"
+/datum/supply_pack/eng/smescoil/super_capacity
+ name = "Superconducting Capacitance Coil"
+ contains = list(/obj/item/weapon/smes_coil/super_capacity)
+ cost = 90
+ containertype = /obj/structure/closet/crate/engineering
+ containername = "Superconducting Capacitance Coil crate"
+
+/datum/supply_pack/eng/smescoil/super_io
+ name = "Superconducting Transmission Coil"
+ contains = list(/obj/item/weapon/smes_coil/super_io)
+ cost = 90
+ containertype = /obj/structure/closet/crate/engineering
+ containername = "Superconducting Transmission Coil crate"
+
/datum/supply_pack/eng/shield_capacitor
name = "Shield Capacitor"
contains = list(/obj/machinery/shield_capacitor)
@@ -291,27 +305,3 @@
containername = "Tritium crate"
containertype = /obj/structure/closet/crate/engineering
contains = list(/obj/fiftyspawner/tritium)
-
-/datum/supply_pack/eng/am_shielding
- contains = list(/obj/item/device/am_shielding_container = 3)
- name = "Antimatter shielding three units"
- cost = 50
- containertype = /obj/structure/closet/crate/secure
- containername = "Antimatter shielding crate"
- access = access_engine
-
-/datum/supply_pack/eng/am_container
- contains = list(/obj/item/weapon/am_containment)
- name = "Antimatter container"
- cost = 25
- containertype = /obj/structure/closet/crate/secure
- containername = "AM container crate"
- access = access_engine
-
-/datum/supply_pack/eng/am_controlunit
- contains = list(/obj/machinery/power/am_control_unit)
- name = "Antimatter control unit"
- cost = 75
- containertype = /obj/structure/closet/crate/secure/large
- containername = "AM control unit crate"
- access = access_engine
\ No newline at end of file
diff --git a/code/datums/supplypacks/misc_vr.dm b/code/datums/supplypacks/misc_vr.dm
index f85d7b9723..613a01cfd4 100644
--- a/code/datums/supplypacks/misc_vr.dm
+++ b/code/datums/supplypacks/misc_vr.dm
@@ -43,6 +43,7 @@
access_eva,
access_explorer,
access_pilot)
+ one_access = TRUE
/datum/supply_pack/misc/mining_rig
name = "industrial hardsuit (empty)"
@@ -53,4 +54,5 @@
containertype = /obj/structure/closet/crate/secure/gear
containername = "industrial hardsuit crate"
access = list(access_mining,
- access_eva)
\ No newline at end of file
+ access_eva)
+ one_access = TRUE
\ No newline at end of file
diff --git a/code/datums/supplypacks/recreation.dm b/code/datums/supplypacks/recreation.dm
index 9c12c17a14..357f0eaead 100644
--- a/code/datums/supplypacks/recreation.dm
+++ b/code/datums/supplypacks/recreation.dm
@@ -87,4 +87,14 @@
contains = list(
/obj/item/weapon/storage/box/wormcan,
/obj/item/weapon/storage/box/wormcan/deluxe
+ )
+
+/datum/supply_pack/recreation/ltagturrets
+ name = "Laser Tag Turrets"
+ cost = 40
+ containername = "laser tag turret crate"
+ containertype = /obj/structure/closet/crate
+ contains = list(
+ /obj/machinery/porta_turret/lasertag/blue,
+ /obj/machinery/porta_turret/lasertag/red
)
\ No newline at end of file
diff --git a/code/datums/supplypacks/security_vr.dm b/code/datums/supplypacks/security_vr.dm
index 12f2fa33b3..852b44adee 100644
--- a/code/datums/supplypacks/security_vr.dm
+++ b/code/datums/supplypacks/security_vr.dm
@@ -6,6 +6,7 @@
access = list(
access_security,
access_xenobiology)
+ one_access = TRUE
/datum/supply_pack/security/guardmutant
name = "VARMAcorp autoNOMous security solution for hostile environments"
@@ -15,6 +16,7 @@
access = list(
access_security,
access_xenobiology)
+ one_access = TRUE
*/
/datum/supply_pack/randomised/security/armor
diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm
index 8699f11920..482598027a 100644
--- a/code/defines/obj/weapon.dm
+++ b/code/defines/obj/weapon.dm
@@ -29,6 +29,7 @@
gender = PLURAL
icon = 'icons/obj/items.dmi'
icon_state = "soap"
+ flags = NOCONDUCT
w_class = ITEMSIZE_SMALL
slot_flags = SLOT_HOLSTER
throwforce = 0
@@ -395,7 +396,7 @@
display_contents_with_number = 1
max_w_class = ITEMSIZE_NORMAL
max_storage_space = 100
-
+
/obj/item/weapon/storage/part_replacer/adv
name = "advanced rapid part exchange device"
desc = "Special mechanical module made to store, sort, and apply standard machine parts. This one has a greatly upgraded storage capacity"
diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm
index c87427bc44..24c2ed5f52 100644
--- a/code/game/gamemodes/cult/cult_structures.dm
+++ b/code/game/gamemodes/cult/cult_structures.dm
@@ -35,6 +35,22 @@
/obj/structure/cult/pylon/attackby(obj/item/W as obj, mob/user as mob)
attackpylon(user, W.force)
+/obj/structure/cult/pylon/take_damage(var/damage)
+ pylonhit(damage)
+
+/obj/structure/cult/pylon/bullet_act(var/obj/item/projectile/Proj)
+ pylonhit(Proj.get_structure_damage())
+
+/obj/structure/cult/pylon/proc/pylonhit(var/damage)
+ if(!isbroken)
+ if(prob(1+ damage * 5))
+ visible_message("The pylon shatters!")
+ playsound(get_turf(src), 'sound/effects/Glassbr3.ogg', 75, 1)
+ isbroken = 1
+ density = 0
+ icon_state = "pylon-broken"
+ set_light(0)
+
/obj/structure/cult/pylon/proc/attackpylon(mob/user as mob, var/damage)
if(!isbroken)
if(prob(1+ damage * 5))
diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm
index f7a454a7de..889e11c4e4 100644
--- a/code/game/machinery/OpTable.dm
+++ b/code/game/machinery/OpTable.dm
@@ -80,7 +80,7 @@
if(C == user)
user.visible_message("[user] climbs on \the [src].","You climb on \the [src].")
else
- visible_message("\The [C] has been laid on \the [src] by [user].", 3)
+ visible_message("\The [C] has been laid on \the [src] by [user].")
if(C.client)
C.client.perspective = EYE_PERSPECTIVE
C.client.eye = src
diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm
index ed23884103..484678c942 100644
--- a/code/game/machinery/atmoalter/canister.dm
+++ b/code/game/machinery/atmoalter/canister.dm
@@ -448,4 +448,8 @@ update_flag
..()
src.air_contents.adjust_gas("phoron", MolesForPressure())
src.update_icon()
- return 1
\ No newline at end of file
+ return 1
+
+/obj/machinery/portable_atmospherics/canister/take_damage(var/damage)
+ src.health -= damage
+ healthcheck()
\ No newline at end of file
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/camera/camera.dm b/code/game/machinery/camera/camera.dm
index b3d5af5f3e..34fda2bb06 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -113,7 +113,7 @@
triggerCameraAlarm()
update_icon()
update_coverage()
- START_PROCESSING(SSobj, src)
+ START_PROCESSING(SSobj, src)
/obj/machinery/camera/bullet_act(var/obj/item/projectile/P)
take_damage(P.get_structure_damage())
@@ -283,7 +283,7 @@
icon_state = initial(icon_state)
add_hiddenprint(user)
-/obj/machinery/camera/proc/take_damage(var/force, var/message)
+/obj/machinery/camera/take_damage(var/force, var/message)
//prob(25) gives an average of 3-4 hits
if (force >= toughness && (force > toughness*4 || prob(25)))
destroy()
diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm
index bad819a985..7c7f704392 100644
--- a/code/game/machinery/cell_charger.dm
+++ b/code/game/machinery/cell_charger.dm
@@ -7,9 +7,19 @@
use_power = 1
idle_power_usage = 5
active_power_usage = 60000 //60 kW. (this the power drawn when charging)
+ var/efficiency = 60000 //will provide the modified power rate when upgraded
power_channel = EQUIP
var/obj/item/weapon/cell/charging = null
var/chargelevel = -1
+ circuit = /obj/item/weapon/circuitboard/cell_charger
+
+/obj/machinery/cell_charger/New()
+ component_parts = list()
+ component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
+ component_parts += new /obj/item/stack/cable_coil(src, 5)
+ RefreshParts()
+ ..()
+ return
/obj/machinery/cell_charger/update_icon()
icon_state = "ccharger[charging ? 1 : 0]"
@@ -32,9 +42,9 @@
if(!..(user, 5))
return
- user << "There's [charging ? "a" : "no"] cell in the charger."
+ to_chat(user, "[charging ? "[charging]" : "Nothing"] is in [src].")
if(charging)
- user << "Current charge: [charging.charge]"
+ to_chat(user, "Current charge: [charging.charge] / [charging.maxcharge]")
/obj/machinery/cell_charger/attackby(obj/item/weapon/W, mob/user)
if(stat & BROKEN)
@@ -42,56 +52,60 @@
if(istype(W, /obj/item/weapon/cell) && anchored)
if(istype(W, /obj/item/weapon/cell/device))
- user << " The charger isn't fitted for that type of cell."
+ to_chat(user, "\The [src] isn't fitted for that type of cell.")
return
if(charging)
- user << "There is already a cell in the charger."
+ to_chat(user, "There is already [charging] in [src].")
return
else
var/area/a = loc.loc // Gets our locations location, like a dream within a dream
if(!isarea(a))
return
if(a.power_equip == 0) // There's no APC in this area, don't try to cheat power!
- user << "The [name] blinks red as you try to insert the cell!"
+ to_chat(user, "\The [src] blinks red as you try to insert [W]!")
return
user.drop_item()
W.loc = src
charging = W
- user.visible_message("[user] inserts a cell into the charger.", "You insert a cell into the charger.")
+ user.visible_message("[user] inserts [charging] into [src].", "You insert [charging] into [src].")
chargelevel = -1
update_icon()
else if(W.is_wrench())
if(charging)
- user << "Remove the cell first!"
+ to_chat(user, "Remove [charging] first!")
return
anchored = !anchored
- user << "You [anchored ? "attach" : "detach"] the cell charger [anchored ? "to" : "from"] the ground"
+ to_chat(user, "You [anchored ? "attach" : "detach"] [src] [anchored ? "to" : "from"] the ground")
playsound(src, W.usesound, 75, 1)
+ else if(default_deconstruction_screwdriver(user, W))
+ return
+ else if(default_deconstruction_crowbar(user, W))
+ return
+ else if(default_part_replacement(user, W))
+ return
/obj/machinery/cell_charger/attack_hand(mob/user)
+ add_fingerprint(user)
+
if(charging)
- usr.put_in_hands(charging)
- charging.add_fingerprint(user)
+ user.put_in_hands(charging)
charging.update_icon()
+ user.visible_message("[user] removes [charging] from [src].", "You remove [charging] from [src].")
charging = null
- user.visible_message("[user] removes the cell from the charger.", "You remove the cell from the charger.")
chargelevel = -1
update_icon()
/obj/machinery/cell_charger/attack_ai(mob/user)
if(istype(user, /mob/living/silicon/robot) && Adjacent(user)) // Borgs can remove the cell if they are near enough
- if(!charging)
- return
-
- charging.loc = src.loc
- charging.update_icon()
- charging = null
- update_icon()
- user.visible_message("[user] removes the cell from the charger.", "You remove the cell from the charger.")
-
+ if(charging)
+ user.visible_message("[user] removes [charging] from [src].", "You remove [charging] from [src].")
+ charging.loc = src.loc
+ charging.update_icon()
+ charging = null
+ update_icon()
/obj/machinery/cell_charger/emp_act(severity)
if(stat & (BROKEN|NOPOWER))
@@ -108,9 +122,15 @@
return
if(charging && !charging.fully_charged())
- charging.give(active_power_usage*CELLRATE)
+ charging.give(efficiency*CELLRATE)
update_use_power(2)
update_icon()
else
update_use_power(1)
+
+/obj/machinery/cell_charger/RefreshParts()
+ var/E = 0
+ for(var/obj/item/weapon/stock_parts/capacitor/C in component_parts)
+ E += C.rating
+ efficiency = active_power_usage * (1+ (E - 1)*0.5)
\ No newline at end of file
diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm
index 9b1dd198d9..eb78d41e26 100644
--- a/code/game/machinery/computer/card.dm
+++ b/code/game/machinery/computer/card.dm
@@ -279,7 +279,7 @@
if ("terminate")
if (is_authenticated())
- modify.assignment = "Terminated"
+ modify.assignment = "Dismissed" //VOREStation Edit: setting adjustment
modify.access = list()
callHook("terminate_employee", list(modify))
diff --git a/code/game/machinery/computer/shutoff_monitor.dm b/code/game/machinery/computer/shutoff_monitor.dm
new file mode 100644
index 0000000000..4dd79376c9
--- /dev/null
+++ b/code/game/machinery/computer/shutoff_monitor.dm
@@ -0,0 +1,42 @@
+/obj/machinery/computer/shutoff_monitor
+ name = "automated shutoff valve monitor"
+ desc = "Console used to remotely monitor shutoff valves on the station."
+ icon_keyboard = "power_key"
+ icon_screen = "power:0"
+ light_color = "#a97faa"
+ circuit = /obj/item/weapon/circuitboard/shutoff_monitor
+
+/obj/machinery/computer/shutoff_monitor/attack_hand(var/mob/user)
+ ..()
+ ui_interact(user)
+
+/obj/machinery/computer/shutoff_monitor/attack_robot(var/mob/user) // Borgs and AI will want to see this too
+ ..()
+ ui_interact(user)
+
+/obj/machinery/computer/shutoff_monitor/attack_ai(var/mob/user)
+ ui_interact(user)
+
+/obj/machinery/computer/shutoff_monitor/ui_interact(mob/user, ui_key = "shutoff_monitor", var/datum/nanoui/ui = null, var/force_open = 1, var/key_state = null)
+ var/data[0]
+ data["valves"] = list()
+ for(var/obj/machinery/atmospherics/valve/shutoff/S in GLOB.shutoff_valves)
+ data["valves"][++data["valves"].len] = list("name" = S.name, "enable" = S.close_on_leaks, "open" = S.open, "x" = S.x, "y" = S.y, "z" = S.z)
+
+ // update the ui if it exists, returns null if no ui is passed/found
+ ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if(!ui)
+ // the ui does not exist, so we'll create a new() one
+ // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
+ ui = new(user, src, ui_key, "shutoff_monitor.tmpl", "Automated Shutoff Valve Monitor", 625, 700, state = key_state)
+ // when the ui is first opened this is the data it will use
+ ui.set_initial_data(data)
+ // open the new ui window
+ ui.open()
+ // auto update every 20 Master Controller tick
+ ui.set_auto_update(20) // Longer term to reduce the rate of data collection and processing
+
+/obj/machinery/computer/shutoff_monitor/update_icon()
+ ..()
+ if(!(stat & (NOPOWER|BROKEN)))
+ overlays += image('icons/obj/computer.dmi', "ai-fixer-empty", overlay_layer)
diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm
index 765ced8a39..42725bbe28 100644
--- a/code/game/machinery/deployable.dm
+++ b/code/game/machinery/deployable.dm
@@ -2,52 +2,6 @@
CONTAINS:
Deployable items
Barricades
-
-for reference:
- access_security = 1
- access_brig = 2
- access_armory = 3
- access_forensics_lockers= 4
- access_medical = 5
- access_morgue = 6
- access_tox = 7
- access_tox_storage = 8
- access_genetics = 9
- access_engine = 10
- access_engine_equip= 11
- access_maint_tunnels = 12
- access_external_airlocks = 13
- access_emergency_storage = 14
- access_change_ids = 15
- access_ai_upload = 16
- access_teleporter = 17
- access_eva = 18
- access_heads = 19
- access_captain = 20
- access_all_personal_lockers = 21
- access_chapel_office = 22
- access_tech_storage = 23
- access_atmospherics = 24
- access_bar = 25
- access_janitor = 26
- access_crematorium = 27
- access_kitchen = 28
- access_robotics = 29
- access_rd = 30
- access_cargo = 31
- access_construction = 32
- access_chemistry = 33
- access_cargo_bot = 34
- access_hydroponics = 35
- access_manufacturing = 36
- access_library = 37
- access_lawyer = 38
- access_virology = 39
- access_cmo = 40
- access_qm = 41
- access_court = 42
- access_clown = 43
- access_mime = 44
*/
//Barricades!
@@ -80,6 +34,7 @@ for reference:
return material
/obj/structure/barricade/attackby(obj/item/W as obj, mob/user as mob)
+ user.setClickCooldown(user.get_attack_speed(W))
if(istype(W, /obj/item/stack))
var/obj/item/stack/D = W
if(D.get_material_name() != material.name)
@@ -96,37 +51,54 @@ for reference:
return
return
else
- user.setClickCooldown(user.get_attack_speed(W))
switch(W.damtype)
if("fire")
health -= W.force * 1
if("brute")
health -= W.force * 0.75
- else
- if(health <= 0)
- visible_message("The barricade is smashed apart!")
- dismantle()
- qdel(src)
- return
+ if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD)))
+ playsound(loc, 'sound/effects/woodcutting.ogg', 100, 1)
+ else
+ playsound(src, 'sound/weapons/smash.ogg', 50, 1)
+ CheckHealth()
..()
+/obj/structure/barricade/proc/CheckHealth()
+ if(health <= 0)
+ dismantle()
+ return
+
+/obj/structure/barricade/take_damage(var/damage)
+ health -= damage
+ CheckHealth()
+ return
+
+/obj/structure/barricade/attack_generic(var/mob/user, var/damage, var/attack_verb)
+ visible_message("[user] [attack_verb] the [src]!")
+ if(material == get_material_by_name("resin"))
+ playsound(loc, 'sound/effects/attackblob.ogg', 100, 1)
+ else if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD)))
+ playsound(loc, 'sound/effects/woodcutting.ogg', 100, 1)
+ else
+ playsound(src, 'sound/weapons/smash.ogg', 50, 1)
+ user.do_attack_animation(src)
+ health -= damage
+ CheckHealth()
+ return
+
/obj/structure/barricade/proc/dismantle()
material.place_dismantled_product(get_turf(src))
+ visible_message("\The [src] falls apart!")
qdel(src)
return
/obj/structure/barricade/ex_act(severity)
switch(severity)
if(1.0)
- visible_message("\The [src] is blown apart!")
- qdel(src)
- return
+ dismantle()
if(2.0)
health -= 25
- if(health <= 0)
- visible_message("\The [src] is blown apart!")
- dismantle()
- return
+ CheckHealth()
/obj/structure/barricade/CanPass(atom/movable/mover, turf/target)//So bullets will fly over and stuff.
if(istype(mover) && mover.checkpass(PASSTABLE))
@@ -158,6 +130,7 @@ for reference:
icon_state = "barrier[locked]"
/obj/machinery/deployable/barrier/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(istype(W, /obj/item/weapon/card/id/))
if(allowed(user))
if (emagged < 2.0)
@@ -196,11 +169,28 @@ for reference:
health -= W.force * 0.75
if("brute")
health -= W.force * 0.5
- else
- if(health <= 0)
- explode()
+ playsound(src, 'sound/weapons/smash.ogg', 50, 1)
+ CheckHealth()
..()
+/obj/machinery/deployable/barrier/proc/CheckHealth()
+ if(health <= 0)
+ explode()
+ return
+
+/obj/machinery/deployable/barrier/attack_generic(var/mob/user, var/damage, var/attack_verb)
+ visible_message("[user] [attack_verb] the [src]!")
+ playsound(src, 'sound/weapons/smash.ogg', 50, 1)
+ user.do_attack_animation(src)
+ health -= damage
+ CheckHealth()
+ return
+
+/obj/machinery/deployable/barrier/take_damage(var/damage)
+ health -= damage
+ CheckHealth()
+ return
+
/obj/machinery/deployable/barrier/ex_act(severity)
switch(severity)
if(1.0)
@@ -208,8 +198,7 @@ for reference:
return
if(2.0)
health -= 25
- if(health <= 0)
- explode()
+ CheckHealth()
return
/obj/machinery/deployable/barrier/emp_act(severity)
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index d276efef35..c55a7d8345 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -308,7 +308,7 @@
operating = -1
return 1
-/obj/machinery/door/proc/take_damage(var/damage)
+/obj/machinery/door/take_damage(var/damage)
var/initialhealth = src.health
src.health = max(0, src.health - damage)
if(src.health <= 0 && initialhealth > 0)
diff --git a/code/game/machinery/frame.dm b/code/game/machinery/frame.dm
index c54734aec0..88bf735f53 100644
--- a/code/game/machinery/frame.dm
+++ b/code/game/machinery/frame.dm
@@ -90,6 +90,12 @@
circuit = /obj/item/weapon/circuitboard/recharger
frame_size = 3
+/datum/frame/frame_types/cell_charger
+ name = "Heavy-Duty Cell Charger"
+ frame_class = FRAME_CLASS_MACHINE
+ circuit = /obj/item/weapon/circuitboard/cell_charger
+ frame_size = 3
+
/datum/frame/frame_types/grinder
name = "Grinder"
frame_class = FRAME_CLASS_MACHINE
diff --git a/code/game/machinery/pipe/pipe_recipes.dm b/code/game/machinery/pipe/pipe_recipes.dm
index f0ae483055..a54cdd4eee 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), //VOREStation Removal: Without leaks, those are just regular valves,
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 31a3a74d63..ab77220281 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -36,83 +36,73 @@
name = "turret"
catalogue_data = list(/datum/category_item/catalogue/technology/turret)
icon = 'icons/obj/turrets.dmi'
- icon_state = "turret_cover"
- anchored = 1
+ icon_state = "turret_cover_normal"
+ anchored = TRUE
- density = 0
- use_power = 1 //this turret uses and requires power
+ density = FALSE
+ use_power = TRUE //this turret uses and requires power
idle_power_usage = 50 //when inactive, this turret takes up constant 50 Equipment power
active_power_usage = 300 //when active, this turret takes up constant 300 Equipment power
power_channel = EQUIP //drains power from the EQUIPMENT channel
req_one_access = list(access_security, access_heads)
- // icon_states for turrets.
- // These are for the turret covers.
- var/closed_state = "turret_cover" // For when it is closed.
- var/raising_state = "popup" // When turret is opening.
- var/opened_state = "open" // When fully opened.
- var/lowering_state = "popdown" // When closing.
- var/gun_active_state = "target_prism" // The actual gun's icon_state when active.
- var/gun_disabled_state = "grey_target_prism" // Gun sprite when depowered/disabled.
- var/gun_destroyed_state = "destroyed_target_prism" // Turret sprite for when the turret dies.
-
- var/raised = 0 //if the turret cover is "open" and the turret is raised
- var/raising= 0 //if the turret is currently opening or closing its cover
- var/health = 80 //the turret's health
- var/maxhealth = 80 //turrets maximal health.
- var/auto_repair = 0 //if 1 the turret slowly repairs itself.
- var/locked = 1 //if the turret's behaviour control access is locked
- var/controllock = 0 //if the turret responds to control panels
+ var/raised = FALSE //if the turret cover is "open" and the turret is raised
+ var/raising= FALSE //if the turret is currently opening or closing its cover
+ var/health = 80 //the turret's health
+ var/maxhealth = 80 //turrets maximal health.
+ var/auto_repair = FALSE //if 1 the turret slowly repairs itself.
+ var/locked = TRUE //if the turret's behaviour control access is locked
+ var/controllock = FALSE //if the turret responds to control panels
var/installation = /obj/item/weapon/gun/energy/gun //the type of weapon installed
- var/gun_charge = 0 //the charge of the gun inserted
- var/projectile = null //holder for bullettype
- var/eprojectile = null //holder for the shot when emagged
- var/reqpower = 500 //holder for power needed
- var/iconholder = null //holder for the icon_state. 1 for sprite based on icon_color, null for blue.
- var/icon_color = "orange" // When iconholder is set to 1, the icon_state changes based on what is in this variable.
- var/egun = null //holder to handle certain guns switching bullettypes
+ var/gun_charge = 0 //the charge of the gun inserted
+ var/projectile = null //holder for bullettype
+ var/lethal_projectile = null //holder for the shot when emagged
+ var/reqpower = 500 //holder for power needed
+ var/turret_type = "normal"
+ var/icon_color = "blue"
+ var/lethal_icon_color = "blue"
- var/last_fired = 0 //1: if the turret is cooling down from a shot, 0: turret is ready to fire
+ var/last_fired = FALSE //TRUE: if the turret is cooling down from a shot, FALSE: turret is ready to fire
var/shot_delay = 1.5 SECONDS //1.5 seconds between each shot
- var/check_arrest = 1 //checks if the perp is set to arrest
- var/check_records = 1 //checks if a security record exists at all
- var/check_weapons = 0 //checks if it can shoot people that have a weapon they aren't authorized to have
- var/check_access = 1 //if this is active, the turret shoots everything that does not meet the access requirements
- var/check_anomalies = 1 //checks if it can shoot at unidentified lifeforms (ie xenos)
- var/check_synth = 0 //if active, will shoot at anything not an AI or cyborg
- var/check_all = 0 //If active, will fire on anything, including synthetics.
- var/ailock = 0 // AI cannot use this
- var/faction = null //if set, will not fire at people in the same faction for any reason.
+ var/check_arrest = TRUE //checks if the perp is set to arrest
+ var/check_records = TRUE //checks if a security record exists at all
+ var/check_weapons = FALSE //checks if it can shoot people that have a weapon they aren't authorized to have
+ var/check_access = TRUE //if this is active, the turret shoots everything that does not meet the access requirements
+ var/check_anomalies = TRUE //checks if it can shoot at unidentified lifeforms (ie xenos)
+ var/check_synth = FALSE //if active, will shoot at anything not an AI or cyborg
+ var/check_all = FALSE //If active, will fire on anything, including synthetics.
+ var/ailock = FALSE // AI cannot use this
+ var/faction = null //if set, will not fire at people in the same faction for any reason.
- var/attacked = 0 //if set to 1, the turret gets pissed off and shoots at people nearby (unless they have sec access!)
+ var/attacked = FALSE //if set to TRUE, the turret gets pissed off and shoots at people nearby (unless they have sec access!)
- var/enabled = 1 //determines if the turret is on
- var/lethal = 0 //whether in lethal or stun mode
- var/disabled = 0
+ var/enabled = TRUE //determines if the turret is on
+ var/lethal = FALSE //whether in lethal or stun mode
+ var/disabled = FALSE
- var/shot_sound //what sound should play when the turret fires
- var/eshot_sound //what sound should play when the emagged turret fires
+ var/shot_sound //what sound should play when the turret fires
+ var/lethal_shot_sound //what sound should play when the emagged turret fires
var/datum/effect/effect/system/spark_spread/spark_system //the spark system, used for generating... sparks?
- var/wrenching = 0
+ var/wrenching = FALSE
var/last_target //last target fired at, prevents turrets from erratically firing at all valid targets in range
var/timeout = 10 // When a turret pops up, then finds nothing to shoot at, this number decrements until 0, when it pops down.
var/can_salvage = TRUE // If false, salvaging doesn't give you anything.
/obj/machinery/porta_turret/crescent
req_one_access = list(access_cent_specops)
- enabled = 0
- ailock = 1
- check_synth = 0
- check_access = 1
- check_arrest = 1
- check_records = 1
- check_weapons = 1
- check_anomalies = 1
- check_all = 0
+ enabled = FALSE
+ ailock = TRUE
+ check_synth = FALSE
+ check_access = TRUE
+ check_arrest = TRUE
+ check_records = TRUE
+ check_weapons = TRUE
+ check_anomalies = TRUE
+ check_all = FALSE
/obj/machinery/porta_turret/can_catalogue(mob/user) // Dead turrets can't be scanned.
if(stat & BROKEN)
@@ -121,8 +111,8 @@
return ..()
/obj/machinery/porta_turret/stationary
- ailock = 1
- lethal = 1
+ ailock = TRUE
+ lethal = TRUE
installation = /obj/item/weapon/gun/energy/laser
/obj/machinery/porta_turret/stationary/syndie // Generic turrets for POIs that need to not shoot their buddies.
@@ -155,7 +145,7 @@
name = "interior anti-boarding turret"
desc = "A very tough looking turret made by alien hands."
catalogue_data = list(/datum/category_item/catalogue/anomalous/precursor_a/alien_turret)
- icon_state = "alien_turret_cover"
+ icon_state = "turret_cover_alien"
req_one_access = list(access_alien)
installation = /obj/item/weapon/gun/energy/alien
enabled = TRUE
@@ -164,19 +154,12 @@
check_all = TRUE
health = 250 // Similar to the AI turrets.
maxhealth = 250
-
- closed_state = "alien_turret_cover"
- raising_state = "alien_popup"
- opened_state = "alien_open"
- lowering_state = "alien_popdown"
- gun_active_state = "alien_gun"
- gun_disabled_state = "alien_gun_disabled"
- gun_destroyed_state = "alien_gun_destroyed"
+ turret_type = "alien"
/obj/machinery/porta_turret/alien/destroyed // Turrets that are already dead, to act as a warning of what the rest of the submap contains.
name = "broken interior anti-boarding turret"
desc = "A very tough looking turret made by alien hands. This one looks destroyed, thankfully."
- icon_state = "alien_gun_destroyed"
+ icon_state = "destroyed_target_prism_alien"
stat = BROKEN
can_salvage = FALSE // So you need to actually kill a turret to get the alien gun.
@@ -184,18 +167,11 @@
name = "industrial turret"
desc = "This variant appears to be much more rugged."
req_one_access = list(access_heads)
+ icon_state = "turret_cover_industrial"
installation = /obj/item/weapon/gun/energy/phasegun
health = 200
maxhealth = 200
-
- icon_state = "turret_cover_industrial"
- closed_state = "turret_cover_industrial"
- raising_state = "popup_industrial"
- opened_state = "open_industrial"
- lowering_state = "popdown_industrial"
- gun_active_state = "target_prism_industrial"
- gun_disabled_state = "grey_target_prism_industrial"
- gun_destroyed_state = "destroyed_target_prism_industrial"
+ turret_type = "industrial"
/obj/machinery/porta_turret/industrial/bullet_act(obj/item/projectile/Proj)
var/damage = round(Proj.get_structure_damage() * 1.33)
@@ -205,10 +181,10 @@
if(enabled)
if(!attacked && !emagged)
- attacked = 1
+ attacked = TRUE
spawn()
sleep(60)
- attacked = 0
+ attacked = FALSE
take_damage(damage)
@@ -230,6 +206,97 @@
check_all = TRUE
can_salvage = FALSE // So you can't just twoshot a turret and get a fancy gun
+/obj/machinery/porta_turret/lasertag
+ name = "lasertag turret"
+ turret_type = "normal"
+ req_one_access = list()
+ installation = /obj/item/weapon/gun/energy/lasertag/omni
+
+ locked = FALSE
+ enabled = FALSE
+ anchored = FALSE
+ //These two are used for lasertag
+ check_synth = FALSE
+ check_weapons = FALSE
+ //These vars aren't used
+ check_access = FALSE
+ check_arrest = FALSE
+ check_records = FALSE
+ check_anomalies = FALSE
+ check_all = FALSE
+
+/obj/machinery/porta_turret/lasertag/red
+ turret_type = "red"
+ installation = /obj/item/weapon/gun/energy/lasertag/red
+ check_weapons = TRUE // Used to target blue players
+
+/obj/machinery/porta_turret/lasertag/blue
+ turret_type = "blue"
+ installation = /obj/item/weapon/gun/energy/lasertag/blue
+ check_synth = TRUE // Used to target red players
+
+/obj/machinery/porta_turret/lasertag/assess_living(var/mob/living/L)
+ if(!ishuman(L))
+ return TURRET_NOT_TARGET
+
+ if(L.invisibility >= INVISIBILITY_LEVEL_ONE) // Cannot see him. see_invisible is a mob-var
+ return TURRET_NOT_TARGET
+
+ if(get_dist(src, L) > 7) //if it's too far away, why bother?
+ return TURRET_NOT_TARGET
+
+ if(!(L in check_trajectory(L, src))) //check if we have true line of sight
+ return TURRET_NOT_TARGET
+
+ if(L.lying) //Don't need to stun-lock the players
+ return TURRET_NOT_TARGET
+
+ if(ishuman(L))
+ var/mob/living/carbon/human/M = L
+ if(istype(M.wear_suit, /obj/item/clothing/suit/redtag) && check_synth) // Checks if they are a red player
+ return TURRET_PRIORITY_TARGET
+
+ if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag) && check_weapons) // Checks if they are a blue player
+ return TURRET_PRIORITY_TARGET
+
+/obj/machinery/porta_turret/lasertag/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+ var/data[0]
+ data["access"] = !isLocked(user)
+ data["locked"] = locked
+ data["enabled"] = enabled
+ data["is_lethal"] = 1
+ data["lethal"] = lethal
+
+ if(data["access"])
+ var/settings[0]
+ settings[++settings.len] = list("category" = "Target Red", "setting" = "check_synth", "value" = check_synth) // Could not get the UI to work with new vars specifically for lasertag turrets -Nalarac
+ settings[++settings.len] = list("category" = "Target Blue", "setting" = "check_weapons", "value" = check_weapons) // So I'm using these variables since they don't do anything else in this case
+ data["settings"] = settings
+
+ ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 300)
+ ui.set_initial_data(data)
+ ui.open()
+ ui.set_auto_update(1)
+
+/obj/machinery/porta_turret/lasertag/Topic(href, href_list)
+ if(..())
+ return 1
+
+ if(href_list["command"] && href_list["value"])
+ var/value = text2num(href_list["value"])
+ if(href_list["command"] == "enable")
+ enabled = value
+ else if(href_list["command"] == "lethal")
+ lethal = value
+ else if(href_list["command"] == "check_synth")
+ check_synth = value
+ else if(href_list["command"] == "check_weapons")
+ check_weapons = value
+
+ return 1
+
/obj/machinery/porta_turret/Initialize()
//Sets up a spark system
spark_system = new /datum/effect/effect/system/spark_spread
@@ -239,7 +306,7 @@
setup()
// If turrets ever switch overlays, this will need to be cached and reapplied each time overlays_cut() is called.
- var/image/turret_opened_overlay = image(icon, opened_state)
+ var/image/turret_opened_overlay = image(icon, "open_[turret_type]")
turret_opened_overlay.layer = layer-0.1
add_overlay(turret_opened_overlay)
return ..()
@@ -251,99 +318,85 @@
/obj/machinery/porta_turret/update_icon()
if(stat & BROKEN) // Turret is dead.
- icon_state = gun_destroyed_state
+ icon_state = "destroyed_target_prism_[turret_type]"
else if(raised || raising)
// Turret is open.
if(powered() && enabled)
// Trying to shoot someone.
- icon_state = gun_active_state
+ if(lethal)
+ icon_state = "[lethal_icon_color]_target_prism_[turret_type]"
+ else
+ icon_state = "[icon_color]_target_prism_[turret_type]"
else
// Disabled.
- icon_state = gun_disabled_state
+ icon_state = "grey_target_prism_[turret_type]"
else
// Its closed.
- icon_state = closed_state
+ icon_state = "turret_cover_[turret_type]"
/obj/machinery/porta_turret/proc/setup()
var/obj/item/weapon/gun/energy/E = installation //All energy-based weapons are applicable
+ var/obj/item/projectile/P = initial(E.projectile_type)
//var/obj/item/ammo_casing/shottype = E.projectile_type
- projectile = initial(E.projectile_type)
- eprojectile = projectile
- shot_sound = initial(E.fire_sound)
- eshot_sound = shot_sound
+ projectile = P
+ lethal_projectile = projectile
+ shot_sound = initial(P.fire_sound)
+ lethal_shot_sound = shot_sound
+
+ if(istype(P, /obj/item/projectile/energy))
+ icon_color = "orange"
+
+ else if(istype(P, /obj/item/projectile/beam/stun))
+ icon_color = "blue"
+
+ else if(istype(P, /obj/item/projectile/beam/lasertag))
+ icon_color = "blue"
+
+ else if(istype(P, /obj/item/projectile/beam))
+ icon_color = "red"
+
+ else
+ icon_color = "blue"
+
+ lethal_icon_color = icon_color
weapon_setup(installation)
/obj/machinery/porta_turret/proc/weapon_setup(var/guntype)
switch(guntype)
- if(/obj/item/weapon/gun/energy/laser/practice)
- iconholder = 1
- eprojectile = /obj/item/projectile/beam
-
-// if(/obj/item/weapon/gun/energy/laser/practice/sc_laser)
-// iconholder = 1
-// eprojectile = /obj/item/projectile/beam
-
if(/obj/item/weapon/gun/energy/gun/burst)
- iconholder = 1
- eprojectile = /obj/item/projectile/beam/burstlaser
- eshot_sound = 'sound/weapons/Laser.ogg'
- icon_color = "red"
- projectile = /obj/item/projectile/beam/stun/weak
- shot_sound = 'sound/weapons/Taser.ogg'
+ lethal_icon_color = "red"
+ lethal_projectile = /obj/item/projectile/beam/burstlaser
+ lethal_shot_sound = 'sound/weapons/Laser.ogg'
shot_delay = 1 SECOND
if(/obj/item/weapon/gun/energy/phasegun)
- iconholder = 1
- eprojectile = /obj/item/projectile/energy/phase/heavy
- eshot_sound = 'sound/weapons/gunshot_pathetic.ogg'
icon_color = "orange"
- projectile = /obj/item/projectile/energy/phase
- shot_sound = 'sound/weapons/gunshot_pathetic.ogg'
+ lethal_icon_color = "orange"
+ lethal_projectile = /obj/item/projectile/energy/phase/heavy
shot_delay = 1 SECOND
- if(/obj/item/weapon/gun/energy/retro)
- iconholder = 1
-
-// if(/obj/item/weapon/gun/energy/retro/sc_retro)
-// iconholder = 1
-
- if(/obj/item/weapon/gun/energy/captain)
- iconholder = 1
-
- if(/obj/item/weapon/gun/energy/lasercannon)
- iconholder = 1
-
- if(/obj/item/weapon/gun/energy/taser)
- eprojectile = /obj/item/projectile/beam
- eshot_sound = 'sound/weapons/Laser.ogg'
-
- if(/obj/item/weapon/gun/energy/stunrevolver)
- eprojectile = /obj/item/projectile/beam
- eshot_sound = 'sound/weapons/Laser.ogg'
-
if(/obj/item/weapon/gun/energy/gun)
- eprojectile = /obj/item/projectile/beam //If it has, going to kill mode
- eshot_sound = 'sound/weapons/Laser.ogg'
- egun = 1
+ lethal_icon_color = "red"
+ lethal_projectile = /obj/item/projectile/beam //If it has, going to kill mode
+ lethal_shot_sound = 'sound/weapons/Laser.ogg'
if(/obj/item/weapon/gun/energy/gun/nuclear)
- eprojectile = /obj/item/projectile/beam //If it has, going to kill mode
- eshot_sound = 'sound/weapons/Laser.ogg'
- egun = 1
+ lethal_icon_color = "red"
+ lethal_projectile = /obj/item/projectile/beam //If it has, going to kill mode
+ lethal_shot_sound = 'sound/weapons/Laser.ogg'
if(/obj/item/weapon/gun/energy/xray)
- eprojectile = /obj/item/projectile/beam/xray
+ lethal_icon_color = "green"
+ lethal_projectile = /obj/item/projectile/beam/xray
projectile = /obj/item/projectile/beam/stun // Otherwise we fire xrays on both modes.
- eshot_sound = 'sound/weapons/eluger.ogg'
+ lethal_shot_sound = 'sound/weapons/eluger.ogg'
shot_sound = 'sound/weapons/Taser.ogg'
- iconholder = 1
- icon_color = "green"
/obj/machinery/porta_turret/proc/isLocked(mob/user)
if(ailock && issilicon(user))
@@ -486,20 +539,20 @@
"You begin [anchored ? "un" : ""]securing the turret." \
)
- wrenching = 1
+ wrenching = TRUE
if(do_after(user, 50 * I.toolspeed))
//This code handles moving the turret around. After all, it's a portable turret!
if(!anchored)
playsound(loc, I.usesound, 100, 1)
- anchored = 1
+ anchored = TRUE
update_icon()
to_chat(user, "You secure the exterior bolts on the turret.")
else if(anchored)
playsound(loc, I.usesound, 100, 1)
- anchored = 0
+ anchored = FALSE
to_chat(user, "You unsecure the exterior bolts on the turret.")
update_icon()
- wrenching = 0
+ wrenching = FALSE
else if(istype(I, /obj/item/weapon/card/id)||istype(I, /obj/item/device/pda))
//Behavior lock/unlock mangement
@@ -540,15 +593,14 @@
//the turret shoot much, much faster.
to_chat(user, "You short out [src]'s threat assessment circuits.")
visible_message("[src] hums oddly...")
- emagged = 1
- iconholder = 1
- controllock = 1
- enabled = 0 //turns off the turret temporarily
+ emagged = TRUE
+ controllock = TRUE
+ enabled = FALSE //turns off the turret temporarily
sleep(60) //6 seconds for the traitor to gtfo of the area before the turret decides to ruin his shit
- enabled = 1 //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here
+ enabled = TRUE //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here
return 1
-/obj/machinery/porta_turret/proc/take_damage(var/force)
+/obj/machinery/porta_turret/take_damage(var/force)
if(!raised && !raising)
force = force / 8
if(force < 5)
@@ -571,7 +623,7 @@
attacked = 1
spawn()
sleep(60)
- attacked = 0
+ attacked = FALSE
..()
@@ -587,12 +639,12 @@
check_access = prob(20) // check_access is a pretty big deal, so it's least likely to get turned on
check_anomalies = prob(50)
if(prob(5))
- emagged = 1
+ emagged = TRUE
enabled=0
spawn(rand(60,600))
if(!enabled)
- enabled=1
+ enabled = TRUE
..()
@@ -677,7 +729,7 @@
if(faction && L.faction == faction)
return TURRET_NOT_TARGET
- if(!emagged && issilicon(L) && check_all == 0) // Don't target silica, unless told to neutralize everything.
+ if(!emagged && issilicon(L) && check_all == FALSE) // Don't target silica, unless told to neutralize everything.
return TURRET_NOT_TARGET
if(L.stat && !emagged) //if the perp is dead/dying, no need to bother really
@@ -703,7 +755,7 @@
if(iscuffed(L)) // If the target is handcuffed, leave it alone
return TURRET_NOT_TARGET
- if(isanimal(L) || issmall(L)) // Animals are not so dangerous
+ if(isanimal(L)) // Animals are not so dangerous
return check_anomalies ? TURRET_SECONDARY_TARGET : TURRET_NOT_TARGET
if(isxenomorph(L) || isalien(L)) // Xenos are dangerous
@@ -750,7 +802,7 @@
var/atom/flick_holder = new /atom/movable/porta_turret_cover(loc)
flick_holder.layer = layer + 0.1
- flick(raising_state, flick_holder)
+ flick("popup_[turret_type]", flick_holder)
sleep(10)
qdel(flick_holder)
@@ -771,7 +823,7 @@
var/atom/flick_holder = new /atom/movable/porta_turret_cover(loc)
flick_holder.layer = layer + 0.1
- flick(lowering_state, flick_holder)
+ flick("popdown_[turret_type]", flick_holder)
sleep(10)
qdel(flick_holder)
@@ -802,10 +854,10 @@
if(!(emagged || attacked)) //if it hasn't been emagged or attacked, it has to obey a cooldown rate
if(last_fired || !raised) //prevents rapid-fire shooting, unless it's been emagged
return
- last_fired = 1
+ last_fired = TRUE
spawn()
sleep(shot_delay)
- last_fired = 0
+ last_fired = FALSE
var/turf/T = get_turf(src)
var/turf/U = get_turf(target)
@@ -818,8 +870,8 @@
update_icon()
var/obj/item/projectile/A
if(emagged || lethal)
- A = new eprojectile(loc)
- playsound(loc, eshot_sound, 75, 1)
+ A = new lethal_projectile(loc)
+ playsound(loc, lethal_shot_sound, 75, 1)
else
A = new projectile(loc)
playsound(loc, shot_sound, 75, 1)
@@ -840,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
@@ -863,7 +914,6 @@
return
enabled = TC.enabled
lethal = TC.lethal
- iconholder = TC.lethal
check_synth = TC.check_synth
check_access = TC.check_access
@@ -899,7 +949,7 @@
if(I.is_wrench() && !anchored)
playsound(loc, I.usesound, 100, 1)
to_chat(user, "You secure the external bolts.")
- anchored = 1
+ anchored = TRUE
build_step = 1
return
@@ -924,7 +974,7 @@
else if(I.is_wrench())
playsound(loc, I.usesound, 75, 1)
to_chat(user, "You unfasten the external bolts.")
- anchored = 0
+ anchored = FALSE
build_step = 0
return
diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm
index 3205d16a61..691492a88f 100644
--- a/code/game/machinery/recharger.dm
+++ b/code/game/machinery/recharger.dm
@@ -1,6 +1,7 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
-obj/machinery/recharger
+/obj/machinery/recharger
name = "recharger"
+ desc = "A standard recharger for all devices that use power."
icon = 'icons/obj/stationobjs_vr.dmi' //VOREStation Edit
icon_state = "recharger0"
anchored = 1
@@ -24,10 +25,16 @@ obj/machinery/recharger
..()
return
-/obj/machinery/recharger/attackby(obj/item/weapon/G as obj, mob/user as mob)
- if(istype(user,/mob/living/silicon))
+/obj/machinery/recharger/examine(mob/user)
+ if(!..(user, 5))
return
+ to_chat(user, "[charging ? "[charging]" : "Nothing"] is in [src].")
+ if(charging)
+ var/obj/item/weapon/cell/C = charging.get_cell()
+ to_chat(user, "Current charge: [C.charge] / [C.maxcharge]")
+
+/obj/machinery/recharger/attackby(obj/item/weapon/G as obj, mob/user as mob)
var/allowed = 0
for (var/allowed_type in allowed_devices)
if(istype(G, allowed_type)) allowed = 1
@@ -38,32 +45,49 @@ obj/machinery/recharger
return
// Checks to make sure he's not in space doing it, and that the area got proper power.
if(!powered())
- to_chat(user, "The [name] blinks red as you try to insert the item!")
+ to_chat(user, "\The [src] blinks red as you try to insert [G]!")
return
if(istype(G, /obj/item/weapon/gun/energy))
var/obj/item/weapon/gun/energy/E = G
if(E.self_recharge)
- to_chat(user, "Your gun has no recharge port.")
+ to_chat(user, "\The [E] has no recharge port.")
return
if(istype(G, /obj/item/modular_computer))
var/obj/item/modular_computer/C = G
if(!C.battery_module)
- to_chat(user, "This device does not have a battery installed.")
+ to_chat(user, "\The [C] does not have a battery installed. ")
+ return
+ if(istype(G, /obj/item/weapon/melee/baton))
+ var/obj/item/weapon/melee/baton/B = G
+ if(B.use_external_power)
+ to_chat(user, "\The [B] has no recharge port.")
+ return
+ if(istype(G, /obj/item/device/flash))
+ var/obj/item/device/flash/F = G
+ if(F.use_external_power)
+ to_chat(user, "\The [F] has no recharge port.")
+ return
+ if(istype(G, /obj/item/weapon/weldingtool/electric))
+ var/obj/item/weapon/weldingtool/electric/EW = G
+ if(EW.use_external_power)
+ to_chat(user, "\The [EW] has no recharge port.")
return
else if(!G.get_cell() && !istype(G, /obj/item/ammo_casing/nsfw_batt)) //VOREStation Edit: NSFW charging
- to_chat(user, "This device does not have a battery installed.")
+ to_chat(user, "\The [G] does not have a battery installed.")
return
user.drop_item()
G.loc = src
charging = G
update_icon()
+ user.visible_message("[user] inserts [charging] into [src].", "You insert [charging] into [src].")
+
else if(portable && G.is_wrench())
if(charging)
to_chat(user, "Remove [charging] first!")
return
anchored = !anchored
- to_chat(user, "You [anchored ? "attached" : "detached"] the recharger.")
+ to_chat(user, "You [anchored ? "attached" : "detached"] [src].")
playsound(loc, G.usesound, 75, 1)
else if(default_deconstruction_screwdriver(user, G))
return
@@ -73,17 +97,24 @@ obj/machinery/recharger
return
/obj/machinery/recharger/attack_hand(mob/user as mob)
- if(istype(user,/mob/living/silicon))
- return
-
add_fingerprint(user)
if(charging)
+ user.visible_message("[user] removes [charging] from [src].", "You remove [charging] from [src].")
charging.update_icon()
user.put_in_hands(charging)
charging = null
update_icon()
+/obj/machinery/cell_charger/attack_ai(mob/user)
+ if(istype(user, /mob/living/silicon/robot) && Adjacent(user)) // Borgs can remove the cell if they are near enough
+ if(charging)
+ user.visible_message("[user] removes [charging] from [src].", "You remove [charging] from [src].")
+ charging.update_icon()
+ charging.loc = src.loc
+ charging = null
+ update_icon()
+
/obj/machinery/recharger/process()
if(stat & (NOPOWER|BROKEN) || !anchored)
update_use_power(0)
@@ -164,6 +195,7 @@ obj/machinery/recharger
/obj/machinery/recharger/wallcharger
name = "wall recharger"
+ desc = "A more powerful recharger designed for energy weapons."
icon = 'icons/obj/stationobjs.dmi'
icon_state = "wrecharger0"
plane = TURF_PLANE
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index f499c521e9..0fe0a98f27 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -1151,7 +1151,7 @@
/obj/item/toy/plushie/tabby_cat = 50)
/obj/machinery/vending/fishing
- name = "loot trawler"
+ name = "Loot Trawler"
desc = "A special vendor for fishing equipment."
product_ads = "Tired of trawling across the ocean floor? Get our loot!;Chum and rods.;Don't get baited into fishing without us!;Baby is your star-sign pisces? We'd make a perfect match.;Do not fear, plenty to catch around here.;Don't get reeled in helplessly, get your own rod today!"
icon_state = "fishvendor"
diff --git a/code/game/mecha/combat/combat.dm b/code/game/mecha/combat/combat.dm
index a3532a1b32..b58956579a 100644
--- a/code/game/mecha/combat/combat.dm
+++ b/code/game/mecha/combat/combat.dm
@@ -2,7 +2,7 @@
force = 30
var/melee_cooldown = 10
var/melee_can_hit = 1
- var/list/destroyable_obj = list(/obj/mecha, /obj/structure/window, /obj/structure/grille, /turf/simulated/wall, /obj/structure/girder)
+ //var/list/destroyable_obj = list(/obj/mecha, /obj/structure/window, /obj/structure/grille, /turf/simulated/wall, /obj/structure/girder)
internal_damage_threshold = 50
maint_access = 0
//add_req_access = 0
@@ -26,14 +26,15 @@
return
*/
-/obj/mecha/combat/melee_action(target as obj|mob|turf)
+/obj/mecha/combat/melee_action(atom/T)
if(internal_damage&MECHA_INT_CONTROL_LOST)
- target = safepick(oview(1,src))
- if(!melee_can_hit || !istype(target, /atom)) return
- if(istype(target, /mob/living))
- var/mob/living/M = target
+ T = safepick(oview(1,src))
+ if(!melee_can_hit)
+ return
+ if(istype(T, /mob/living))
+ var/mob/living/M = T
if(src.occupant.a_intent == I_HURT || istype(src.occupant, /mob/living/carbon/brain)) //Brains cannot change intents; Exo-piloting brains lack any form of physical feedback for control, limiting the ability to 'play nice'.
- playsound(src, 'sound/weapons/punch4.ogg', 50, 1)
+ playsound(src, 'sound/weapons/heavysmash.ogg', 50, 1)
if(damtype == "brute")
step_away(M,src,15)
/*
@@ -44,8 +45,8 @@
melee_can_hit = 1
return
*/
- if(istype(target, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = target
+ if(ishuman(T))
+ var/mob/living/carbon/human/H = T
// if (M.health <= 0) return
var/obj/item/organ/external/temp = H.get_organ(pick(BP_TORSO, BP_TORSO, BP_TORSO, BP_HEAD))
@@ -86,12 +87,12 @@
else
return
M.updatehealth()
- src.occupant_message("You hit [target].")
- src.visible_message("[src.name] hits [target].")
+ src.occupant_message("You hit [T].")
+ src.visible_message("[src.name] hits [T].")
else
step_away(M,src)
- src.occupant_message("You push [target] out of the way.")
- src.visible_message("[src] pushes [target] out of the way.")
+ src.occupant_message("You push [T] out of the way.")
+ src.visible_message("[src] pushes [T] out of the way.")
melee_can_hit = 0
if(do_after(melee_cooldown))
@@ -99,27 +100,23 @@
return
else
- if(damtype == "brute")
- for(var/target_type in src.destroyable_obj)
- if(istype(target, target_type) && hascall(target, "attackby"))
- src.occupant_message("You hit [target].")
- src.visible_message("[src.name] hits [target]")
- if(!istype(target, /turf/simulated/wall) && !istype(target, /obj/structure/girder))
- target:attackby(src,src.occupant)
- else if(prob(5))
- target:dismantle_wall(1)
- src.occupant_message("You smash through the wall.")
- src.visible_message("[src.name] smashes through the wall")
- playsound(src, 'sound/weapons/smash.ogg', 50, 1)
- else if(istype(target, /turf/simulated/wall))
- target:take_damage(force)
- else if(istype(target, /obj/structure/girder))
- target:take_damage(force * 3) //Girders have 200 health by default. Steel, non-reinforced walls take four punches, girders take (with this value-mod) two, girders took five without.
- melee_can_hit = 0
+ if(istype(T, /obj/machinery/disposal)) // Stops mechs from climbing into disposals
+ return
+ if(src.occupant.a_intent == I_HURT || istype(src.occupant, /mob/living/carbon/brain)) // Don't smash unless we mean it
+ if(damtype == "brute")
+ src.occupant_message("You hit [T].")
+ src.visible_message("[src.name] hits [T]")
+ playsound(src, 'sound/weapons/heavysmash.ogg', 50, 1)
- if(do_after(melee_cooldown))
- melee_can_hit = 1
- break
+ if(istype(T, /obj/structure/girder))
+ T:take_damage(force * 3) //Girders have 200 health by default. Steel, non-reinforced walls take four punches, girders take (with this value-mod) two, girders took five without.
+ else
+ T:take_damage(force)
+
+ melee_can_hit = 0
+
+ if(do_after(melee_cooldown))
+ melee_can_hit = 1
return
/*
diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm
index 0519bf2ca4..ee42467121 100644
--- a/code/game/mecha/equipment/tools/tools.dm
+++ b/code/game/mecha/equipment/tools/tools.dm
@@ -166,14 +166,7 @@
if(ore_box)
for(var/obj/item/weapon/ore/ore in range(chassis,1))
if(get_dir(chassis,ore)&chassis.dir)
- ore.Move(ore_box)
- log_message("Drilled through [target]")
- if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment)
- var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo
- if(ore_box)
- for(var/obj/item/weapon/ore/ore in range(chassis,1))
- if(get_dir(chassis,ore)&chassis.dir)
- ore.Move(ore_box)
+ ore.forceMove(ore_box)
else if(target.loc == C)
log_message("Drilled through [target]")
target.ex_act(2)
@@ -219,7 +212,7 @@
if(ore_box)
for(var/obj/item/weapon/ore/ore in range(chassis,1))
if(get_dir(chassis,ore)&chassis.dir)
- ore.Move(ore_box)
+ ore.forceMove(ore_box)
else if(target.loc == C)
log_message("Drilled through [target]")
target.ex_act(2)
@@ -267,13 +260,7 @@
if(ore_box)
for(var/obj/item/weapon/ore/ore in range(chassis,1))
if(get_dir(chassis,ore)&chassis.dir)
- ore.Move(ore_box)
- if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment)
- var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo
- if(ore_box)
- for(var/obj/item/weapon/ore/ore in range(chassis,1))
- if(get_dir(chassis,ore)&chassis.dir)
- ore.Move(ore_box)
+ ore.forceMove(ore_box)
else if(target.loc == C)
log_message("Drilled through [target]")
target.ex_act(2)
@@ -328,7 +315,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 +1214,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 +1515,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/mecha/mecha.dm b/code/game/mecha/mecha.dm
index b556286292..5b783c8e50 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -535,7 +535,7 @@
//////// Health related procs ////////
////////////////////////////////////////
-/obj/mecha/proc/take_damage(amount, type="brute")
+/obj/mecha/take_damage(amount, type="brute")
if(amount)
var/damage = absorbDamage(amount,type)
health -= damage
diff --git a/code/game/mecha/micro/micro_equipment.dm b/code/game/mecha/micro/micro_equipment.dm
index b8e4557b47..d36f9fa0a3 100644
--- a/code/game/mecha/micro/micro_equipment.dm
+++ b/code/game/mecha/micro/micro_equipment.dm
@@ -146,7 +146,7 @@
occupant_message("The ore compartment is full.")
return 1
else
- ore.Move(ore_box)
+ ore.forceMove(ore_box)
else if(target.loc == C)
log_message("Drilled through [target]")
target.ex_act(2)
diff --git a/code/game/objects/effects/alien/aliens.dm b/code/game/objects/effects/alien/aliens.dm
index 44963c31d2..0de8d332b7 100644
--- a/code/game/objects/effects/alien/aliens.dm
+++ b/code/game/objects/effects/alien/aliens.dm
@@ -64,6 +64,19 @@
healthcheck()
return
+/obj/effect/alien/resin/attack_generic(var/mob/user, var/damage, var/attack_verb)
+ visible_message("[user] [attack_verb] the [src]!")
+ playsound(loc, 'sound/effects/attackblob.ogg', 100, 1)
+ user.do_attack_animation(src)
+ health -= damage
+ healthcheck()
+ return
+
+/obj/effect/alien/resin/take_damage(var/damage)
+ health -= damage
+ healthcheck()
+ return
+
/obj/effect/alien/resin/ex_act(severity)
switch(severity)
if(1.0)
@@ -246,6 +259,18 @@ Alien plants should do something if theres a lot of poison
health -= damage
healthcheck()
+/obj/effect/alien/weeds/attack_generic(var/mob/user, var/damage, var/attack_verb)
+ visible_message("[user] [attack_verb] the [src]!")
+ user.do_attack_animation(src)
+ health -= damage
+ healthcheck()
+ return
+
+/obj/effect/alien/weeds/take_damage(var/damage)
+ health -= damage
+ healthcheck()
+ return
+
/obj/effect/alien/weeds/proc/healthcheck()
if(health <= 0)
qdel(src)
@@ -401,6 +426,18 @@ Alien plants should do something if theres a lot of poison
healthcheck()
return
+/obj/effect/alien/egg/attack_generic(var/mob/user, var/damage, var/attack_verb)
+ visible_message("[user] [attack_verb] the [src]!")
+ user.do_attack_animation(src)
+ health -= damage
+ healthcheck()
+ return
+
+/obj/effect/alien/egg/take_damage(var/damage)
+ health -= damage
+ healthcheck()
+ return
+
/obj/effect/alien/egg/attackby(var/obj/item/weapon/W, var/mob/user)
if(health <= 0)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 3ba9c1bac7..591da02757 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -492,13 +492,15 @@ var/list/global/slot_flags_enumeration = list(
user << "You cannot locate any eyes on [M]!"
return
- if(U.get_accuracy_penalty(U)) //Should only trigger if they're not aiming well
- var/hit_zone = get_zone_with_miss_chance(U.zone_sel.selecting, M, U.get_accuracy_penalty(U))
- if(!hit_zone)
- U.do_attack_animation(M)
- playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
- visible_message("[U] attempts to stab [M] in the eyes, but misses!")
- return
+ //this should absolutely trigger even if not aim-impaired in some way
+ var/hit_zone = get_zone_with_miss_chance(U.zone_sel.selecting, M, U.get_accuracy_penalty(U))
+ if(!hit_zone)
+ U.do_attack_animation(M)
+ playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
+ //visible_message("[U] attempts to stab [M] in the eyes, but misses!")
+ for(var/mob/V in viewers(M))
+ V.show_message("[U] attempts to stab [M] in the eyes, but misses!")
+ return
add_attack_logs(user,M,"Attack eyes with [name]")
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index ec121bfed2..90ae753da2 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -1,3 +1,4 @@
+#define DEFIB_TIME_LIMIT (10 MINUTES) //VOREStation addition- past this many seconds, defib is useless.
/*
CONTAINS:
T-RAY
@@ -54,6 +55,8 @@ HALOGEN COUNTER - Radcount on mobs
if (!(ishuman(user) || ticker) && ticker.mode.name != "monkey")
to_chat(user, "You don't have the dexterity to do this!")
return
+
+ flick("[icon_state]-scan", src) //makes it so that it plays the scan animation on a succesful scan
user.visible_message("[user] has analyzed [M]'s vitals.","You have analyzed [M]'s vitals.")
if (!ishuman(M) || M.isSynthetic())
@@ -81,8 +84,13 @@ HALOGEN COUNTER - Radcount on mobs
dat += "\tKey: Suffocation/Toxin/Burns/Brute
"
dat += "\tDamage Specifics: [OX] - [TX] - [BU] - [BR]
"
dat += "Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)
"
- if(M.tod && (M.stat == DEAD || (M.status_flags & FAKEDEATH)))
- dat += "Time of Death: [M.tod]
"
+ //VOREStation edit/addition starts
+ if(M.timeofdeath && (M.stat == DEAD || (M.status_flags & FAKEDEATH)))
+ dat += "Time of Death: [worldtime2stationtime(M.timeofdeath)]
"
+ var/tdelta = round(world.time - M.timeofdeath)
+ if(tdelta < (DEFIB_TIME_LIMIT * 10))
+ dat += "Subject died [DisplayTimeText(tdelta)] ago - resuscitation may be possible!
"
+ //VOREStation edit/addition ends
if(istype(M, /mob/living/carbon/human) && mode == 1)
var/mob/living/carbon/human/H = M
var/list/damaged = H.get_damaged_organs(1,1)
@@ -501,3 +509,5 @@ HALOGEN COUNTER - Radcount on mobs
else
to_chat(user, "No radiation detected.")
return
+
+#undef DEFIB_TIME_LIMIT //VOREStation addition
\ No newline at end of file
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 6a51e9eb17..612a14c4d4 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -220,6 +220,7 @@
W.heal_damage(heal_brute)
playsound(src, pick(apply_sounds), 25)
used = 1 //VOREStation Edit
+ update_icon() // VOREStation Edit - Support for stack icons
affecting.update_damages()
if(used == amount)
if(affecting.is_bandaged())
@@ -266,6 +267,7 @@
use(1)
affecting.salve()
playsound(src, pick(apply_sounds), 25)
+ update_icon() // VOREStation Edit - Support for stack icons
/obj/item/stack/medical/splint
name = "medical splints"
diff --git a/code/game/objects/items/stacks/medical_vr.dm b/code/game/objects/items/stacks/medical_vr.dm
new file mode 100644
index 0000000000..eda72a3fce
--- /dev/null
+++ b/code/game/objects/items/stacks/medical_vr.dm
@@ -0,0 +1,21 @@
+/obj/item/stack/medical/advanced
+ icon = 'icons/obj/stacks_vr.dmi'
+
+/obj/item/stack/medical/advanced/Initialize()
+ . = ..()
+ update_icon()
+
+/obj/item/stack/medical/advanced/update_icon()
+ switch(amount)
+ if(1 to 2)
+ icon_state = initial(icon_state)
+ if(3 to 4)
+ icon_state = "[initial(icon_state)]_4"
+ if(5 to 6)
+ icon_state = "[initial(icon_state)]_6"
+ if(7 to 8)
+ icon_state = "[initial(icon_state)]_8"
+ if(9)
+ icon_state = "[initial(icon_state)]_9"
+ else
+ icon_state = "[initial(icon_state)]_10"
\ No newline at end of file
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index 93c70930d1..7c441e8169 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -202,4 +202,12 @@
name = "roofing"
singular_name = "roofing"
desc = "A section of roofing material. You can use it to repair the ceiling, or expand it."
- icon_state = "techtile_grid"
\ No newline at end of file
+ icon_state = "techtile_grid"
+
+/obj/item/stack/tile/roofing/cyborg
+ name = "roofing synthesizer"
+ desc = "A device that makes roofing tiles."
+ uses_charge = 1
+ charge_costs = list(250)
+ stacktype = /obj/item/stack/tile/roofing
+ build_type = /obj/item/stack/tile/roofing
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/circuitboards/computer/computer.dm b/code/game/objects/items/weapons/circuitboards/computer/computer.dm
index 8bc26a13f1..2190650d67 100644
--- a/code/game/objects/items/weapons/circuitboards/computer/computer.dm
+++ b/code/game/objects/items/weapons/circuitboards/computer/computer.dm
@@ -191,3 +191,8 @@
name = T_BOARD("RCON remote control console")
build_path = /obj/machinery/computer/rcon
origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 3, TECH_POWER = 5)
+
+/obj/item/weapon/circuitboard/shutoff_monitor
+ name = T_BOARD("automatic shutoff valve monitor")
+ build_path = /obj/machinery/computer/shutoff_monitor
+ origin_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 4)
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/circuitboards/frame.dm b/code/game/objects/items/weapons/circuitboards/frame.dm
index 913506c9e6..63308e6caa 100644
--- a/code/game/objects/items/weapons/circuitboards/frame.dm
+++ b/code/game/objects/items/weapons/circuitboards/frame.dm
@@ -144,6 +144,14 @@
build_path = /obj/machinery/recharger/wallcharger
board_type = new /datum/frame/frame_types/wall_charger
+/obj/item/weapon/circuitboard/cell_charger
+ name = T_BOARD("heavy-duty cell charger")
+ build_path = /obj/machinery/cell_charger
+ board_type = new /datum/frame/frame_types/cell_charger
+ req_components = list(
+ /obj/item/weapon/stock_parts/capacitor = 1,
+ /obj/item/stack/cable_coil = 5)
+
/obj/item/weapon/circuitboard/washing
name = T_BOARD("washing machine")
build_path = /obj/machinery/washing_machine
diff --git a/code/game/objects/items/weapons/manuals.dm b/code/game/objects/items/weapons/manuals.dm
index 1fd46dd6dd..6ae36ca0dd 100644
--- a/code/game/objects/items/weapons/manuals.dm
+++ b/code/game/objects/items/weapons/manuals.dm
@@ -98,11 +98,11 @@
| [current_species.blurb] | " + //vorestation edit begin + if(current_species.wikilink) + dat += "[current_species.blurb] See the wiki for more details. | "
+ else
+ dat += "[current_species.blurb] | " + //vorestation edit end dat += "" if("preview" in icon_states(current_species.icobase)) usr << browse_rsc(icon(current_species.icobase,"preview"), "species_preview_[current_species.name].png") @@ -873,7 +878,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O dat += "You cannot play as this species.If you wish to be whitelisted, you can make an application post on the forums." else if(restricted == 2) dat += "You cannot play as this species.This species is not available for play as a station race.." - if(!restricted || check_rights(R_ADMIN, 0)) + if(!restricted || check_rights(R_ADMIN, 0) || current_species.spawn_flags & SPECIES_WHITELIST_SELECTABLE) //VOREStation Edit: selectability dat += "\[select\]" dat += " |