diff --git a/code/ATMOSPHERICS/components/shutoff.dm b/code/ATMOSPHERICS/components/shutoff.dm
new file mode 100644
index 0000000000..b1fb43baa1
--- /dev/null
+++ b/code/ATMOSPHERICS/components/shutoff.dm
@@ -0,0 +1,50 @@
+/obj/machinery/atmospherics/valve/shutoff
+ icon = 'icons/atmos/clamp.dmi'
+ icon_state = "map_vclamp0"
+
+ name = "automatic shutoff valve"
+ desc = "An automatic valve with control circuitry and pipe integrity sensor, capable of automatically isolating damaged segments of the pipe network."
+ var/close_on_leaks = TRUE // If false it will be always open
+ level = 1
+ connect_types = CONNECT_TYPE_SCRUBBER | CONNECT_TYPE_SUPPLY | CONNECT_TYPE_REGULAR
+
+/obj/machinery/atmospherics/valve/shutoff/update_icon()
+ icon_state = "vclamp[open]"
+
+/obj/machinery/atmospherics/valve/shutoff/examine(var/mob/user)
+ ..()
+ to_chat(user, "The automatic shutoff circuit is [close_on_leaks ? "enabled" : "disabled"].")
+
+/obj/machinery/atmospherics/valve/shutoff/Initialize()
+ . = ..()
+ open()
+ hide(1)
+
+/obj/machinery/atmospherics/valve/shutoff/attack_ai(mob/user as mob)
+ return src.attack_hand(user)
+
+/obj/machinery/atmospherics/valve/shutoff/attack_hand(var/mob/user)
+ src.add_fingerprint(usr)
+ update_icon(1)
+ close_on_leaks = !close_on_leaks
+ to_chat(user, "You [close_on_leaks ? "enable" : "disable"] the automatic shutoff circuit.")
+ return TRUE
+
+/obj/machinery/atmospherics/valve/shutoff/process()
+ ..()
+
+ if (!network_node1 || !network_node2)
+ if(open)
+ close()
+ return
+
+ if (!close_on_leaks)
+ if (!open)
+ open()
+ return
+
+ if (network_node1.leaks.len || network_node2.leaks.len)
+ if (open)
+ close()
+ else if (!open)
+ open()
diff --git a/code/ATMOSPHERICS/datum_pipe_network.dm b/code/ATMOSPHERICS/datum_pipe_network.dm
index eb5e89276e..a611e30a89 100644
--- a/code/ATMOSPHERICS/datum_pipe_network.dm
+++ b/code/ATMOSPHERICS/datum_pipe_network.dm
@@ -8,76 +8,83 @@ var/global/list/datum/pipe_network/pipe_networks = list() // TODO - Move into SS
var/list/datum/pipeline/line_members = list()
//membership roster to go through for updates and what not
+ var/list/leaks = list()
+
var/update = 1
//var/datum/gas_mixture/air_transient = null
- Destroy()
- STOP_PROCESSING_PIPENET(src)
- for(var/datum/pipeline/line_member in line_members)
- line_member.network = null
- for(var/obj/machinery/atmospherics/normal_member in normal_members)
- normal_member.reassign_network(src, null)
- gases.Cut() // Do not qdel the gases, we don't own them
- return ..()
+/datum/pipe_network/Destroy()
+ STOP_PROCESSING_PIPENET(src)
+ for(var/datum/pipeline/line_member in line_members)
+ line_member.network = null
+ for(var/obj/machinery/atmospherics/normal_member in normal_members)
+ normal_member.reassign_network(src, null)
+ gases.Cut() // Do not qdel the gases, we don't own them
+ leaks.Cut()
+ return ..()
- process()
- //Equalize gases amongst pipe if called for
- if(update)
- update = 0
- reconcile_air() //equalize_gases(gases)
+/datum/pipe_network/process()
+ //Equalize gases amongst pipe if called for
+ if(update)
+ update = 0
+ reconcile_air() //equalize_gases(gases)
- //Give pipelines their process call for pressure checking and what not. Have to remove pressure checks for the time being as pipes dont radiate heat - Mport
- //for(var/datum/pipeline/line_member in line_members)
- // line_member.process()
+ listclearnulls(leaks) // Let's not have forever-seals.
- proc/build_network(obj/machinery/atmospherics/start_normal, obj/machinery/atmospherics/reference)
- //Purpose: Generate membership roster
- //Notes: Assuming that members will add themselves to appropriate roster in network_expand()
+ //Give pipelines their process call for pressure checking and what not. Have to remove pressure checks for the time being as pipes dont radiate heat - Mport
+ //for(var/datum/pipeline/line_member in line_members)
+ // line_member.process()
- if(!start_normal)
- qdel(src)
- return
+/datum/pipe_network/proc/build_network(obj/machinery/atmospherics/start_normal, obj/machinery/atmospherics/reference)
+ //Purpose: Generate membership roster
+ //Notes: Assuming that members will add themselves to appropriate roster in network_expand()
- start_normal.network_expand(src, reference)
+ if(!start_normal)
+ qdel(src)
+ return
- update_network_gases()
+ start_normal.network_expand(src, reference)
- if((normal_members.len>0)||(line_members.len>0))
- START_PROCESSING_PIPENET(src)
- else
- qdel(src)
+ update_network_gases()
- proc/merge(datum/pipe_network/giver)
- if(giver==src) return 0
+ if((normal_members.len>0)||(line_members.len>0))
+ START_PROCESSING_PIPENET(src)
+ else
+ qdel(src)
- normal_members |= giver.normal_members
+/datum/pipe_network/proc/merge(datum/pipe_network/giver)
+ if(giver==src) return 0
- line_members |= giver.line_members
+ normal_members |= giver.normal_members
- for(var/obj/machinery/atmospherics/normal_member in giver.normal_members)
- normal_member.reassign_network(giver, src)
+ line_members |= giver.line_members
- for(var/datum/pipeline/line_member in giver.line_members)
- line_member.network = src
+ leaks |= giver.leaks
- update_network_gases()
- return 1
+ for(var/obj/machinery/atmospherics/normal_member in giver.normal_members)
+ normal_member.reassign_network(giver, src)
- proc/update_network_gases()
- //Go through membership roster and make sure gases is up to date
+ for(var/datum/pipeline/line_member in giver.line_members)
+ line_member.network = src
- gases = list()
- volume = 0
+ update_network_gases()
+ return 1
- for(var/obj/machinery/atmospherics/normal_member in normal_members)
- var/result = normal_member.return_network_air(src)
- if(result) gases += result
+/datum/pipe_network/proc/update_network_gases()
+ //Go through membership roster and make sure gases is up to date
- for(var/datum/pipeline/line_member in line_members)
- gases += line_member.air
+ gases = list()
+ volume = 0
- for(var/datum/gas_mixture/air in gases)
- volume += air.volume
+ for(var/obj/machinery/atmospherics/normal_member in normal_members)
+ var/result = normal_member.return_network_air(src)
+ if(result) gases += result
- proc/reconcile_air()
- equalize_gases(gases)
+ for(var/datum/pipeline/line_member in line_members)
+ gases += line_member.air
+
+ for(var/datum/gas_mixture/air in gases)
+ volume += air.volume
+
+/datum/pipe_network/proc/reconcile_air()
+ equalize_gases(gases)
diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm
index fc47bca938..b53d722458 100644
--- a/code/ATMOSPHERICS/datum_pipeline.dm
+++ b/code/ATMOSPHERICS/datum_pipeline.dm
@@ -1,219 +1,234 @@
-datum/pipeline
+/datum/pipeline
var/datum/gas_mixture/air
var/list/obj/machinery/atmospherics/pipe/members
var/list/obj/machinery/atmospherics/pipe/edges //Used for building networks
+ // Nodes that are leaking. Used for A.S. Valves.
+ var/list/leaks = list()
+
var/datum/pipe_network/network
var/alert_pressure = 0
- Destroy()
- QDEL_NULL(network)
+/datum/pipeline/Destroy()
+ QDEL_NULL(network)
- if(air && air.volume)
- temporarily_store_air()
- for(var/obj/machinery/atmospherics/pipe/P in members)
- P.parent = null
- members = null
- edges = null
- . = ..()
+ if(air && air.volume)
+ temporarily_store_air()
+ for(var/obj/machinery/atmospherics/pipe/P in members)
+ P.parent = null
+ members = null
+ edges = null
+ leaks = null
+ . = ..()
- process()//This use to be called called from the pipe networks
-
- //Check to see if pressure is within acceptable limits
- var/pressure = air.return_pressure()
- if(pressure > alert_pressure)
- for(var/obj/machinery/atmospherics/pipe/member in members)
- if(!member.check_pressure(pressure))
- break //Only delete 1 pipe per process
-
- proc/temporarily_store_air()
- //Update individual gas_mixtures by volume ratio
+/datum/pipeline/process()//This use to be called called from the pipe networks
+ //Check to see if pressure is within acceptable limits
+ var/pressure = air.return_pressure()
+ if(pressure > alert_pressure)
for(var/obj/machinery/atmospherics/pipe/member in members)
- member.air_temporary = new
- member.air_temporary.copy_from(air)
- member.air_temporary.volume = member.volume
- member.air_temporary.multiply(member.volume / air.volume)
+ if(!member.check_pressure(pressure))
+ break //Only delete 1 pipe per process
- proc/build_pipeline(obj/machinery/atmospherics/pipe/base)
+/datum/pipeline/proc/temporarily_store_air()
+ //Update individual gas_mixtures by volume ratio
+
+ for(var/obj/machinery/atmospherics/pipe/member in members)
+ member.air_temporary = new
+ member.air_temporary.copy_from(air)
+ member.air_temporary.volume = member.volume
+ member.air_temporary.multiply(member.volume / air.volume)
+
+/datum/pipeline/proc/build_pipeline(obj/machinery/atmospherics/pipe/base)
+ air = new
+
+ var/list/possible_expansions = list(base)
+ members = list(base)
+ edges = list()
+
+ var/volume = base.volume
+ base.parent = src
+ alert_pressure = base.alert_pressure
+
+ if(base.air_temporary)
+ air = base.air_temporary
+ base.air_temporary = null
+ else
air = new
- var/list/possible_expansions = list(base)
- members = list(base)
- edges = list()
+ if(base.leaking)
+ leaks |= base
- var/volume = base.volume
- base.parent = src
- alert_pressure = base.alert_pressure
+ while(possible_expansions.len>0)
+ for(var/obj/machinery/atmospherics/pipe/borderline in possible_expansions)
- if(base.air_temporary)
- air = base.air_temporary
- base.air_temporary = null
- else
- air = new
+ var/list/result = borderline.pipeline_expansion()
+ var/edge_check = result.len
- while(possible_expansions.len>0)
- for(var/obj/machinery/atmospherics/pipe/borderline in possible_expansions)
+ if(result.len>0)
+ for(var/obj/machinery/atmospherics/pipe/item in result)
- var/list/result = borderline.pipeline_expansion()
- var/edge_check = result.len
+ if(item.in_stasis)
+ continue
- if(result.len>0)
- for(var/obj/machinery/atmospherics/pipe/item in result)
- if(!members.Find(item))
- members += item
- possible_expansions += item
+ if(!members.Find(item))
+ members += item
+ possible_expansions += item
- volume += item.volume
- item.parent = src
+ volume += item.volume
+ item.parent = src
- alert_pressure = min(alert_pressure, item.alert_pressure)
+ alert_pressure = min(alert_pressure, item.alert_pressure)
- if(item.air_temporary)
- air.merge(item.air_temporary)
+ if(item.air_temporary)
+ air.merge(item.air_temporary)
- edge_check--
+ if(item.leaking)
+ leaks |= item
- if(edge_check>0)
- edges += borderline
+ edge_check--
- possible_expansions -= borderline
+ if(edge_check>0)
+ edges += borderline
- air.volume = volume
+ possible_expansions -= borderline
- proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
+ air.volume = volume
- if(new_network.line_members.Find(src))
- return 0
+/datum/pipeline/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
- new_network.line_members += src
+ if(new_network.line_members.Find(src))
+ return 0
- network = new_network
+ new_network.line_members += src
- for(var/obj/machinery/atmospherics/pipe/edge in edges)
- for(var/obj/machinery/atmospherics/result in edge.pipeline_expansion())
- if(!istype(result,/obj/machinery/atmospherics/pipe) && (result!=reference))
- result.network_expand(new_network, edge)
+ network = new_network
+ network.leaks |= leaks
- return 1
+ for(var/obj/machinery/atmospherics/pipe/edge in edges)
+ for(var/obj/machinery/atmospherics/result in edge.pipeline_expansion())
+ if(!istype(result,/obj/machinery/atmospherics/pipe) && (result!=reference))
+ result.network_expand(new_network, edge)
- proc/return_network(obj/machinery/atmospherics/reference)
- if(!network)
- network = new /datum/pipe_network()
- network.build_network(src, null)
- //technically passing these parameters should not be allowed
- //however pipe_network.build_network(..) and pipeline.network_extend(...)
- // were setup to properly handle this case
+ return 1
- return network
+/datum/pipeline/proc/return_network(obj/machinery/atmospherics/reference)
+ if(!network)
+ network = new /datum/pipe_network()
+ network.build_network(src, null)
+ //technically passing these parameters should not be allowed
+ //however pipe_network.build_network(..) and pipeline.network_extend(...)
+ // were setup to properly handle this case
- proc/mingle_with_turf(turf/simulated/target, mingle_volume)
- var/datum/gas_mixture/air_sample = air.remove_ratio(mingle_volume/air.volume)
- air_sample.volume = mingle_volume
+ return network
- if(istype(target) && target.zone)
- //Have to consider preservation of group statuses
- var/datum/gas_mixture/turf_copy = new
- var/datum/gas_mixture/turf_original = new
+/datum/pipeline/proc/mingle_with_turf(turf/simulated/target, mingle_volume)
+ var/datum/gas_mixture/air_sample = air.remove_ratio(mingle_volume/air.volume)
+ air_sample.volume = mingle_volume
- turf_copy.copy_from(target.zone.air)
- turf_copy.volume = target.zone.air.volume //Copy a good representation of the turf from parent group
- turf_original.copy_from(turf_copy)
+ if(istype(target) && target.zone)
+ //Have to consider preservation of group statuses
+ var/datum/gas_mixture/turf_copy = new
+ var/datum/gas_mixture/turf_original = new
- equalize_gases(list(air_sample, turf_copy))
- air.merge(air_sample)
+ turf_copy.copy_from(target.zone.air)
+ turf_copy.volume = target.zone.air.volume //Copy a good representation of the turf from parent group
+ turf_original.copy_from(turf_copy)
+
+ equalize_gases(list(air_sample, turf_copy))
+ air.merge(air_sample)
- target.zone.air.remove(turf_original.total_moles)
- target.zone.air.merge(turf_copy)
+ target.zone.air.remove(turf_original.total_moles)
+ target.zone.air.merge(turf_copy)
- else
- var/datum/gas_mixture/turf_air = target.return_air()
+ else
+ var/datum/gas_mixture/turf_air = target.return_air()
- equalize_gases(list(air_sample, turf_air))
- air.merge(air_sample)
- //turf_air already modified by equalize_gases()
+ equalize_gases(list(air_sample, turf_air))
+ air.merge(air_sample)
+ //turf_air already modified by equalize_gases()
- if(network)
- network.update = 1
+ if(network)
+ network.update = 1
- proc/temperature_interact(turf/target, share_volume, thermal_conductivity)
- var/total_heat_capacity = air.heat_capacity()
- var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume)
+/datum/pipeline/proc/temperature_interact(turf/target, share_volume, thermal_conductivity)
+ var/total_heat_capacity = air.heat_capacity()
+ var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume)
- if(istype(target, /turf/simulated))
- var/turf/simulated/modeled_location = target
+ if(istype(target, /turf/simulated))
+ var/turf/simulated/modeled_location = target
- if(modeled_location.blocks_air)
+ if(modeled_location.blocks_air)
- if((modeled_location.heat_capacity>0) && (partial_heat_capacity>0))
- var/delta_temperature = air.temperature - modeled_location.temperature
-
- var/heat = thermal_conductivity*delta_temperature* \
- (partial_heat_capacity*modeled_location.heat_capacity/(partial_heat_capacity+modeled_location.heat_capacity))
-
- air.temperature -= heat/total_heat_capacity
- modeled_location.temperature += heat/modeled_location.heat_capacity
-
- else
- var/delta_temperature = 0
- var/sharer_heat_capacity = 0
-
- if(modeled_location.zone)
- delta_temperature = (air.temperature - modeled_location.zone.air.temperature)
- sharer_heat_capacity = modeled_location.zone.air.heat_capacity()
- else
- delta_temperature = (air.temperature - modeled_location.air.temperature)
- sharer_heat_capacity = modeled_location.air.heat_capacity()
-
- var/self_temperature_delta = 0
- var/sharer_temperature_delta = 0
-
- if((sharer_heat_capacity>0) && (partial_heat_capacity>0))
- var/heat = thermal_conductivity*delta_temperature* \
- (partial_heat_capacity*sharer_heat_capacity/(partial_heat_capacity+sharer_heat_capacity))
-
- self_temperature_delta = -heat/total_heat_capacity
- sharer_temperature_delta = heat/sharer_heat_capacity
- else
- return 1
-
- air.temperature += self_temperature_delta
-
- if(modeled_location.zone)
- modeled_location.zone.air.temperature += sharer_temperature_delta/modeled_location.zone.air.group_multiplier
- else
- modeled_location.air.temperature += sharer_temperature_delta
-
-
- else
- if((target.heat_capacity>0) && (partial_heat_capacity>0))
- var/delta_temperature = air.temperature - target.temperature
+ if((modeled_location.heat_capacity>0) && (partial_heat_capacity>0))
+ var/delta_temperature = air.temperature - modeled_location.temperature
var/heat = thermal_conductivity*delta_temperature* \
- (partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity))
+ (partial_heat_capacity*modeled_location.heat_capacity/(partial_heat_capacity+modeled_location.heat_capacity))
air.temperature -= heat/total_heat_capacity
- if(network)
- network.update = 1
+ modeled_location.temperature += heat/modeled_location.heat_capacity
- //surface must be the surface area in m^2
- proc/radiate_heat_to_space(surface, thermal_conductivity)
- var/gas_density = air.total_moles/air.volume
- thermal_conductivity *= min(gas_density / ( RADIATOR_OPTIMUM_PRESSURE/(R_IDEAL_GAS_EQUATION*GAS_CRITICAL_TEMPERATURE) ), 1) //mult by density ratio
+ else
+ var/delta_temperature = 0
+ var/sharer_heat_capacity = 0
- // We only get heat from the star on the exposed surface area.
- // If the HE pipes gain more energy from AVERAGE_SOLAR_RADIATION than they can radiate, then they have a net heat increase.
- var/heat_gain = AVERAGE_SOLAR_RADIATION * (RADIATOR_EXPOSED_SURFACE_AREA_RATIO * surface) * thermal_conductivity
+ if(modeled_location.zone)
+ delta_temperature = (air.temperature - modeled_location.zone.air.temperature)
+ sharer_heat_capacity = modeled_location.zone.air.heat_capacity()
+ else
+ delta_temperature = (air.temperature - modeled_location.air.temperature)
+ sharer_heat_capacity = modeled_location.air.heat_capacity()
- // Previously, the temperature would enter equilibrium at 26C or 294K.
- // Only would happen if both sides (all 2 square meters of surface area) were exposed to sunlight. We now assume it aligned edge on.
- // It currently should stabilise at 129.6K or -143.6C
- heat_gain -= surface * STEFAN_BOLTZMANN_CONSTANT * thermal_conductivity * (air.temperature - COSMIC_RADIATION_TEMPERATURE) ** 4
+ var/self_temperature_delta = 0
+ var/sharer_temperature_delta = 0
- air.add_thermal_energy(heat_gain)
- if(network)
- network.update = 1
+ if((sharer_heat_capacity>0) && (partial_heat_capacity>0))
+ var/heat = thermal_conductivity*delta_temperature* \
+ (partial_heat_capacity*sharer_heat_capacity/(partial_heat_capacity+sharer_heat_capacity))
+
+ self_temperature_delta = -heat/total_heat_capacity
+ sharer_temperature_delta = heat/sharer_heat_capacity
+ else
+ return 1
+
+ air.temperature += self_temperature_delta
+
+ if(modeled_location.zone)
+ modeled_location.zone.air.temperature += sharer_temperature_delta/modeled_location.zone.air.group_multiplier
+ else
+ modeled_location.air.temperature += sharer_temperature_delta
+
+
+ else
+ if((target.heat_capacity>0) && (partial_heat_capacity>0))
+ var/delta_temperature = air.temperature - target.temperature
+
+ var/heat = thermal_conductivity*delta_temperature* \
+ (partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity))
+
+ air.temperature -= heat/total_heat_capacity
+ if(network)
+ network.update = 1
+
+//surface must be the surface area in m^2
+/datum/pipeline/proc/radiate_heat_to_space(surface, thermal_conductivity)
+ var/gas_density = air.total_moles/air.volume
+ thermal_conductivity *= min(gas_density / ( RADIATOR_OPTIMUM_PRESSURE/(R_IDEAL_GAS_EQUATION*GAS_CRITICAL_TEMPERATURE) ), 1) //mult by density ratio
+
+ // We only get heat from the star on the exposed surface area.
+ // If the HE pipes gain more energy from AVERAGE_SOLAR_RADIATION than they can radiate, then they have a net heat increase.
+ var/heat_gain = AVERAGE_SOLAR_RADIATION * (RADIATOR_EXPOSED_SURFACE_AREA_RATIO * surface) * thermal_conductivity
+
+ // Previously, the temperature would enter equilibrium at 26C or 294K.
+ // Only would happen if both sides (all 2 square meters of surface area) were exposed to sunlight. We now assume it aligned edge on.
+ // It currently should stabilise at 129.6K or -143.6C
+ heat_gain -= surface * STEFAN_BOLTZMANN_CONSTANT * thermal_conductivity * (air.temperature - COSMIC_RADIATION_TEMPERATURE) ** 4
+
+ air.add_thermal_energy(heat_gain)
+ if(network)
+ network.update = 1
diff --git a/code/ATMOSPHERICS/pipes/he_pipes.dm b/code/ATMOSPHERICS/pipes/he_pipes.dm
index 2d77e3a4ca..1b283e3ba4 100644
--- a/code/ATMOSPHERICS/pipes/he_pipes.dm
+++ b/code/ATMOSPHERICS/pipes/he_pipes.dm
@@ -67,8 +67,22 @@
return
update_icon()
+ handle_leaking()
return
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/set_leaking(var/new_leaking) // They already process, no need for manual processing toggles.
+ if(new_leaking && !leaking)
+ leaking = TRUE
+ if(parent)
+ parent.leaks |= src
+ if(parent.network)
+ parent.network.leaks |= src
+ else if (!new_leaking && leaking)
+ leaking = FALSE
+ if(parent)
+ parent.leaks -= src
+ if(parent.network)
+ parent.network.leaks -= src
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/process()
if(!parent)
@@ -180,4 +194,5 @@
return
update_icon()
+ handle_leaking()
return
diff --git a/code/ATMOSPHERICS/pipes/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 4b0df6f2ef..f44bfc5686 100644
--- a/code/ATMOSPHERICS/pipes/manifold.dm
+++ b/code/ATMOSPHERICS/pipes/manifold.dm
@@ -68,11 +68,10 @@
node3 = null
update_icon()
+ handle_leaking()
..()
-<<<<<<< HEAD
-=======
/obj/machinery/atmospherics/pipe/manifold/handle_leaking()
if(node1 && node2 && node3)
set_leaking(FALSE)
@@ -87,7 +86,6 @@
else
. = PROCESS_KILL
->>>>>>> 31518fe... Merge pull request #6344 from Mechoid/ManifoldLeaking
/obj/machinery/atmospherics/pipe/manifold/change_color(var/new_color)
..()
//for updating connected atmos device pipes (i.e. vents, manifolds, etc)
@@ -171,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 99274183b4..197c1a090b 100644
--- a/code/ATMOSPHERICS/pipes/manifold4w.dm
+++ b/code/ATMOSPHERICS/pipes/manifold4w.dm
@@ -66,11 +66,10 @@
node4 = null
update_icon()
+ handle_leaking()
..()
-<<<<<<< HEAD
-=======
/obj/machinery/atmospherics/pipe/manifold4w/handle_leaking()
if(node1 && node2 && node3 && node4)
set_leaking(FALSE)
@@ -85,7 +84,6 @@
else
. = PROCESS_KILL
->>>>>>> 31518fe... Merge pull request #6344 from Mechoid/ManifoldLeaking
/obj/machinery/atmospherics/pipe/manifold4w/change_color(var/new_color)
..()
//for updating connected atmos device pipes (i.e. vents, manifolds, etc)
@@ -173,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/_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/supplypacks/engineering.dm b/code/datums/supplypacks/engineering.dm
index e3b9a148cc..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)
@@ -290,4 +304,4 @@
cost = 75
containername = "Tritium crate"
containertype = /obj/structure/closet/crate/engineering
- contains = list(/obj/fiftyspawner/tritium)
\ No newline at end of file
+ contains = list(/obj/fiftyspawner/tritium)
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/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/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/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 12343bb343..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)
@@ -862,7 +914,6 @@
return
enabled = TC.enabled
lethal = TC.lethal
- iconholder = TC.lethal
check_synth = TC.check_synth
check_access = TC.check_access
@@ -898,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
@@ -923,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/vending.dm b/code/game/machinery/vending.dm
index 43911b54d8..663230b11f 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -1153,7 +1153,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 e2ce2d3638..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)
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/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/mob_spawner_vr.dm b/code/game/objects/mob_spawner_vr.dm
index 0422c408f8..23ec38c907 100644
--- a/code/game/objects/mob_spawner_vr.dm
+++ b/code/game/objects/mob_spawner_vr.dm
@@ -84,7 +84,7 @@
if(destructible)
take_damage(Proj.get_structure_damage())
-/obj/structure/mob_spawner/proc/take_damage(var/damage)
+/obj/structure/mob_spawner/take_damage(var/damage)
health -= damage
if(health <= 0)
visible_message("\The [src] breaks apart!")
diff --git a/code/game/objects/structures/catwalk.dm b/code/game/objects/structures/catwalk.dm
index 68b9ccc787..20fd025ea9 100644
--- a/code/game/objects/structures/catwalk.dm
+++ b/code/game/objects/structures/catwalk.dm
@@ -98,7 +98,7 @@
return 0
return 1
-/obj/structure/catwalk/proc/take_damage(amount)
+/obj/structure/catwalk/take_damage(amount)
health -= amount
if(health <= 0)
visible_message("\The [src] breaks down!")
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 4234c99391..95d38c4473 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -468,3 +468,10 @@
if(istype(src.loc, /obj/structure/closet))
return (loc.return_air_for_internal_lifeform(L))
return return_air()
+
+/obj/structure/closet/take_damage(var/damage)
+ if(damage < STRUCTURE_MIN_DAMAGE_THRESHOLD)
+ return
+ dump_contents()
+ spawn(1) qdel(src)
+ return 1
\ No newline at end of file
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
index 8380c059ec..da686ad455 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
@@ -11,6 +11,8 @@
starts_with = list(
/obj/item/clothing/accessory/storage/brown_vest,
/obj/item/blueprints,
+ ///obj/item/clamp, //VOREStation Removal: without leaks those are pointless,
+ ///obj/item/clamp, //VOREStation Removal: without leaks those are pointless,
/obj/item/clothing/under/rank/chief_engineer,
/obj/item/clothing/under/rank/chief_engineer/skirt,
/obj/item/clothing/head/hardhat/white,
@@ -125,6 +127,7 @@
/obj/item/clothing/suit/fire/firefighter,
/obj/item/device/flashlight,
/obj/item/weapon/extinguisher,
+ ///obj/item/clamp, //VOREStation Removal: without leaks those are pointless,
/obj/item/device/radio/headset/headset_eng,
/obj/item/device/radio/headset/headset_eng/alt,
/obj/item/clothing/suit/storage/hazardvest,
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index a24f2868da..072dd43de6 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -212,7 +212,7 @@
else
return ..()
-/obj/structure/girder/proc/take_damage(var/damage)
+/obj/structure/girder/take_damage(var/damage)
health -= damage
if(health <= 0)
dismantle()
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index c4b91fc73a..1057a5094c 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -281,3 +281,8 @@
return TRUE
return FALSE
+/obj/structure/grille/take_damage(var/damage)
+ health -= damage
+ spawn(1) healthcheck()
+ return 1
+
diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm
index 2192b5690c..f5bebdf529 100644
--- a/code/game/objects/structures/inflatable.dm
+++ b/code/game/objects/structures/inflatable.dm
@@ -137,6 +137,13 @@
user.visible_message("[user] [attack_verb] at [src]!")
return 1
+/obj/structure/inflatable/take_damage(var/damage)
+ health -= damage
+ if(health <= 0)
+ visible_message("The [src] deflates!")
+ spawn(1) puncture()
+ return 1
+
/obj/item/inflatable/door/
name = "inflatable door"
desc = "A folded membrane which rapidly expands into a simple door on activation."
diff --git a/code/game/objects/structures/railing.dm b/code/game/objects/structures/railing.dm
index 9d96f0cc25..8027b5db5e 100644
--- a/code/game/objects/structures/railing.dm
+++ b/code/game/objects/structures/railing.dm
@@ -52,7 +52,7 @@
if(0.5 to 1.0)
to_chat(user, "It has a few scrapes and dents.")
-/obj/structure/railing/proc/take_damage(amount)
+/obj/structure/railing/take_damage(amount)
health -= amount
if(health <= 0)
visible_message("\The [src] breaks down!")
diff --git a/code/game/objects/structures/simple_doors.dm b/code/game/objects/structures/simple_doors.dm
index 17619c3158..431ef0cdbb 100644
--- a/code/game/objects/structures/simple_doors.dm
+++ b/code/game/objects/structures/simple_doors.dm
@@ -124,15 +124,22 @@
icon_state = material.door_icon_base
/obj/structure/simple_door/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(istype(W,/obj/item/weapon/pickaxe))
var/obj/item/weapon/pickaxe/digTool = W
- user << "You start digging the [name]."
+ visible_message("[user] starts digging [src]!")
if(do_after(user,digTool.digspeed*hardness) && src)
- user << "You finished digging."
+ visible_message("[user] finished digging [src]!")
Dismantle()
else if(istype(W,/obj/item/weapon)) //not sure, can't not just weapons get passed to this proc?
hardness -= W.force/10
- user << "You hit the [name] with your [W.name]!"
+ visible_message("[user] hits [src] with [W]!")
+ 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)
CheckHardness()
else if(istype(W,/obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
@@ -146,12 +153,29 @@
hardness -= Proj.force/10
CheckHardness()
+/obj/structure/simple_door/take_damage(var/damage)
+ hardness -= damage/10
+ CheckHardness()
+
+/obj/structure/simple_door/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)
+ hardness -= damage/10
+ CheckHardness()
+
/obj/structure/simple_door/proc/CheckHardness()
if(hardness <= 0)
Dismantle(1)
/obj/structure/simple_door/proc/Dismantle(devastated = 0)
material.place_dismantled_product(get_turf(src))
+ visible_message("The [src] is destroyed!")
qdel(src)
/obj/structure/simple_door/ex_act(severity = 1)
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index cc3bcf1648..b2867d5ead 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -47,7 +47,7 @@
else
to_chat(user, "There is a thick layer of silicate covering it.")
-/obj/structure/window/proc/take_damage(var/damage = 0, var/sound_effect = 1)
+/obj/structure/window/take_damage(var/damage = 0, var/sound_effect = 1)
var/initialhealth = health
if(silicate)
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index cb1a0f631a..1847767083 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -153,7 +153,7 @@
visible_message("\The [src] spontaneously combusts!.") //!!OH SHIT!!
return
-/turf/simulated/wall/proc/take_damage(dam)
+/turf/simulated/wall/take_damage(dam)
if(dam)
damage = max(0, damage + dam)
update_damage()
diff --git a/code/game/turfs/simulated_vr.dm b/code/game/turfs/simulated_vr.dm
new file mode 100644
index 0000000000..6c7325305f
--- /dev/null
+++ b/code/game/turfs/simulated_vr.dm
@@ -0,0 +1,5 @@
+/turf/simulated
+ can_start_dirty = FALSE // We have enough premapped dirt where needed
+
+/turf/simulated/floor/plating
+ can_start_dirty = TRUE // But let maints and decrepit areas have some randomness
\ No newline at end of file
diff --git a/code/modules/admin/verbs/adminhelp_vr.dm b/code/modules/admin/verbs/adminhelp_vr.dm
index 9f3aee4a83..8d27022ae4 100644
--- a/code/modules/admin/verbs/adminhelp_vr.dm
+++ b/code/modules/admin/verbs/adminhelp_vr.dm
@@ -1,8 +1,8 @@
-/datum/admin_help/proc/send2adminchat()
+/datum/admin_help/proc/send2adminchat()
if(!config.chat_webhook_url)
return
- var/list/adm = get_admin_counts()
+ var/list/adm = get_admin_counts()
var/list/afkmins = adm["afk"]
var/list/allmins = adm["total"]
@@ -14,3 +14,23 @@
query_string += "&admin_number=[allmins.len]"
query_string += "&admin_number_afk=[afkmins.len]"
world.Export("[config.chat_webhook_url]?[query_string]")
+
+/client/verb/adminspice()
+ set category = "Admin"
+ set name = "Request Spice"
+
+ //handle muting and automuting
+ if(prefs.muted & MUTE_ADMINHELP)
+ to_chat(usr, "Error: You cannot request spice (muted from adminhelps).")
+ return
+
+ if(alert(usr, "Are you sure you want to request the admins spice things up for you? You accept the consequences if you do.",,"No","Yes") != "No")
+ message_admins("[ADMIN_FULLMONTY(usr)] has requested the round be spiced up a little.")
+ else
+ to_chat(usr, "Spice request cancelled.")
+ return
+
+ //if they requested spice, then remove spice verb temporarily to prevent spamming
+ usr.verbs -= /client/verb/adminspice
+ spawn(6000)
+ usr.verbs += /client/verb/adminspice // 10 minute cool-down for spice request
diff --git a/code/modules/blob/blob.dm b/code/modules/blob/blob.dm
index c9ab387753..877c684b5e 100644
--- a/code/modules/blob/blob.dm
+++ b/code/modules/blob/blob.dm
@@ -40,7 +40,7 @@
else
icon_state = "blob_damaged"
-/obj/effect/blob/proc/take_damage(var/damage)
+/obj/effect/blob/take_damage(var/damage) // VOREStation Edit
health -= damage
if(health < 0)
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
diff --git a/code/modules/client/preference_setup/loadout/loadout_suit.dm b/code/modules/client/preference_setup/loadout/loadout_suit.dm
index 3cb84bcb81..1802d2c009 100644
--- a/code/modules/client/preference_setup/loadout/loadout_suit.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_suit.dm
@@ -495,3 +495,11 @@ datum/gear/suit/duster
display_name = "snowsuit, supply"
path = /obj/item/clothing/suit/storage/snowsuit/cargo
allowed_roles = list("Quartermaster","Shaft Miner","Cargo Technician","Head of Personnel")
+
+/datum/gear/suit/miscellaneous/cardigan
+ display_name = "cardigan"
+ path = /obj/item/clothing/suit/storage/toggle/cardigan
+
+/datum/gear/suit/miscellaneous/cardigan/New()
+ ..()
+ gear_tweaks = list(gear_tweak_free_color_choice)
\ No newline at end of file
diff --git a/code/modules/client/preference_setup/loadout/loadout_uniform.dm b/code/modules/client/preference_setup/loadout/loadout_uniform.dm
index d3e70872c9..7de598fc83 100644
--- a/code/modules/client/preference_setup/loadout/loadout_uniform.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_uniform.dm
@@ -506,3 +506,14 @@
display_name = "plain ascetic garb"
path = /obj/item/clothing/under/ascetic
+/datum/gear/uniform/pleated
+ display_name = "pleated skirt"
+ path = /obj/item/clothing/under/skirt/pleated
+
+/datum/gear/uniform/pleated/New()
+ ..()
+ gear_tweaks = list(gear_tweak_free_color_choice)
+
+/datum/gear/uniform/lilacdress
+ display_name = "lilac dress"
+ path = /obj/item/clothing/under/dress/lilacdress
diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm
index 0f8b999b4c..91f441fa37 100644
--- a/code/modules/clothing/suits/miscellaneous.dm
+++ b/code/modules/clothing/suits/miscellaneous.dm
@@ -323,7 +323,7 @@ obj/item/clothing/suit/kamishimo
item_state_slots = list(slot_r_hand_str = "leather_jacket", slot_l_hand_str = "leather_jacket")
flags_inv = HIDEHOLSTER
-obj/item/clothing/suit/storage/toggle/peacoat
+/obj/item/clothing/suit/storage/toggle/peacoat
name = "peacoat"
desc = "A well-tailored, stylish peacoat."
icon_state = "peacoat"
@@ -338,6 +338,14 @@ obj/item/clothing/suit/storage/toggle/peacoat
blood_overlay_type = "coat"
allowed = list(/obj/item/weapon/tank/emergency/oxygen, /obj/item/device/flashlight,/obj/item/weapon/gun/energy,/obj/item/weapon/gun/projectile,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/flame/lighter)
flags_inv = HIDEHOLSTER
+
+/obj/item/clothing/suit/storage/toggle/cardigan
+ name = "cardigan"
+ desc = "A cozy cardigan in a classic style."
+ icon_state = "cardigan"
+ addblends = "cardigan_a"
+ flags_inv = HIDEHOLSTER
+
/*
* stripper
*/
diff --git a/code/modules/clothing/under/accessories/clothing.dm b/code/modules/clothing/under/accessories/clothing.dm
index 66636aac6f..d5991e4f10 100644
--- a/code/modules/clothing/under/accessories/clothing.dm
+++ b/code/modules/clothing/under/accessories/clothing.dm
@@ -349,6 +349,25 @@
desc = "A really cheesy holiday sweater, it actually kinda itches."
icon_state = "turtleneck_winterred"
+/obj/item/clothing/accessory/sweater/uglyxmas
+ name = "ugly Christmas sweater"
+ desc = "A gift that probably should've stayed in the back of the closet."
+ icon_state = "uglyxmas"
+
+/obj/item/clothing/accessory/sweater/flowersweater
+ name = "flowery sweater"
+ desc = "An oversized and flowery pink sweater."
+ icon_state = "flowersweater"
+
+/obj/item/clothing/accessory/sweater/redneck
+ name = "red turtleneck"
+ desc = "A comfortable turtleneck in a dark red."
+ icon_state = "turtleneck_red"
+
+//***
+// End of sweaters
+//***
+
/obj/item/clothing/accessory/cowledvest
name = "cowled vest"
desc = "A body warmer for the 26th century."
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index 943577663f..c90d575b98 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -453,6 +453,10 @@
icon_state = "sari_green"
item_state_slots = list(slot_r_hand_str = "dress_green", slot_l_hand_str = "dress_green")
+/obj/item/clothing/under/dress/lilacdress
+ name = "lilac dress"
+ desc = "A simple black dress adorned in fake purple lilacs."
+ icon_state = "lilacdress"
/*
* wedding stuff
diff --git a/code/modules/clothing/under/shorts.dm b/code/modules/clothing/under/shorts.dm
index 4ac2ad5f2e..26a00a4a63 100644
--- a/code/modules/clothing/under/shorts.dm
+++ b/code/modules/clothing/under/shorts.dm
@@ -130,6 +130,12 @@
desc = "A piece of cloth wrapped around the waist."
icon_state = "loincloth"
+/obj/item/clothing/under/skirt/pleated
+ name = "pleated skirt"
+ desc = "A simple pleated skirt. It's like high school all over again."
+ icon_state = "pleated"
+ addblends = "pleated_a"
+
/obj/item/clothing/under/skirt/outfit
name = "black skirt"
desc = "A black skirt, very fancy!"
diff --git a/code/modules/food/drinkingglass/metaglass.dm b/code/modules/food/drinkingglass/metaglass.dm
index 0b64df0af9..1980c58873 100644
--- a/code/modules/food/drinkingglass/metaglass.dm
+++ b/code/modules/food/drinkingglass/metaglass.dm
@@ -312,7 +312,7 @@ Drinks Data
glass_icon_state = "atomicbombglass"
glass_center_of_mass = list("x"=15, "y"=7)
-/datum/reagent/ethanol/b52
+/datum/reagent/ethanol/coffee/b52
glass_icon_state = "b52glass"
/datum/reagent/ethanol/bahama_mama
diff --git a/code/modules/integrated_electronics/core/printer.dm b/code/modules/integrated_electronics/core/printer.dm
index c2c70985c5..871051a258 100644
--- a/code/modules/integrated_electronics/core/printer.dm
+++ b/code/modules/integrated_electronics/core/printer.dm
@@ -44,7 +44,7 @@
if(num < 1)
to_chat(user, span("warning", "\The [src] is too full to add more metal."))
return
- if(stack.use(num))
+ if(stack.use(max(1, round(num)))) // We don't want to create stacks that aren't whole numbers
to_chat(user, span("notice", "You add [num] sheet\s to \the [src]."))
metal += num * metal_per_sheet
interact(user)
diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm
index ff35a795b5..81557f597c 100644
--- a/code/modules/mob/living/bot/bot.dm
+++ b/code/modules/mob/living/bot/bot.dm
@@ -88,13 +88,13 @@
/mob/living/bot/attackby(var/obj/item/O, var/mob/user)
if(O.GetID())
- if(access_scanner.allowed(user) && !open && !emagged)
+ if(access_scanner.allowed(user) && !open)
locked = !locked
to_chat(user, "Controls are now [locked ? "locked." : "unlocked."]")
attack_hand(user)
- else
if(emagged)
- to_chat(user, "ERROR")
+ to_chat(user, "ERROR! SYSTEMS COMPROMISED!")
+ else
if(open)
to_chat(user, "Please close the access panel before locking it.")
else
@@ -111,7 +111,15 @@
else if(istype(O, /obj/item/weapon/weldingtool))
if(health < getMaxHealth())
if(open)
- health = min(getMaxHealth(), health + 10)
+ if(getBruteLoss() < 10)
+ bruteloss = 0
+ else
+ bruteloss = bruteloss - 10
+ if(getFireLoss() < 10)
+ fireloss = 0
+ else
+ fireloss = fireloss - 10
+ updatehealth()
user.visible_message("[user] repairs [src].","You repair [src].")
playsound(src, O.usesound, 50, 1)
else
@@ -119,6 +127,13 @@
else
to_chat(user, "[src] does not need a repair.")
return
+ else if(istype(O, /obj/item/device/assembly/prox_sensor) && emagged)
+ if(open)
+ to_chat(user, "You repair the bot's systems.")
+ emagged = 0
+ qdel(O)
+ else
+ to_chat(user, "Unable to repair with the maintenance panel closed.")
else
..()
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
index 28de4d6d93..1f211fe95b 100644
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ b/code/modules/mob/living/carbon/human/human_damage.dm
@@ -1,5 +1,6 @@
//Updates the mob's health from organs and mob damage variables
/mob/living/carbon/human/updatehealth()
+ var/huskmodifier = 1.5 // With 1.5, you need 250 burn instead of 200 to husk a human.
if(status_flags & GODMODE)
health = getMaxHealth()
@@ -17,7 +18,7 @@
health = getMaxHealth() - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute
//TODO: fix husking
- if( ((getMaxHealth() - total_burn) < config.health_threshold_dead) && stat == DEAD)
+ if( ((getMaxHealth() - total_burn) < config.health_threshold_dead * huskmodifier) && stat == DEAD)
ChangeToHusk()
return
diff --git a/code/modules/mob/living/carbon/human/species/station/station_vr.dm b/code/modules/mob/living/carbon/human/species/station/station_vr.dm
index 92819aae65..aaa29f1286 100644
--- a/code/modules/mob/living/carbon/human/species/station/station_vr.dm
+++ b/code/modules/mob/living/carbon/human/species/station/station_vr.dm
@@ -359,6 +359,7 @@
spawn_flags = SPECIES_CAN_JOIN
icobase = 'icons/mob/human_races/r_seromi_vr.dmi'
deform = 'icons/mob/human_races/r_seromi_vr.dmi'
+ icobase_tail = 1
color_mult = 1
min_age = 18
push_flags = ~HEAVY //Allows them to use micro step code.
diff --git a/code/modules/mob/living/carbon/human/species/station/traits_vr/neutral.dm b/code/modules/mob/living/carbon/human/species/station/traits_vr/neutral.dm
index 9bf2c932ec..2398a032bb 100644
--- a/code/modules/mob/living/carbon/human/species/station/traits_vr/neutral.dm
+++ b/code/modules/mob/living/carbon/human/species/station/traits_vr/neutral.dm
@@ -59,6 +59,16 @@
autohiss_exempt = list("Siik"))
excludes = list(/datum/trait/autohiss_unathi)
+/datum/trait/autohiss_awootism
+ name = "Autohiss (Disability)"
+ desc = "You can't speak r's and l's properly."
+ cost = 0
+ var_changes = list(
+ autohiss_basic_map = list(
+ "l" = list("w", "ww"),
+ "r" = list("w", "ww")
+ ))
+
/datum/trait/bloodsucker
name = "Bloodsucker"
desc = "Makes you unable to gain nutrition from anything but blood. To compenstate, you get fangs that can be used to drain blood from prey."
diff --git a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm
index 68308efc66..312d7f06db 100644
--- a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm
+++ b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_vr.dm
@@ -42,6 +42,10 @@
flags |= NOBLUDGEON //No more attack messages
files = new /datum/research/techonly(src)
+/obj/item/device/dogborg/sleeper/Destroy()
+ go_out()
+ ..()
+
/obj/item/device/dogborg/sleeper/Exit(atom/movable/O)
return 0
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index 080196f0aa..2959616130 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -153,6 +153,7 @@
/mob/living/silicon/robot/handle_regular_hud_updates()
var/fullbright = FALSE
+ var/seemeson = FALSE
if (src.stat == 2 || (XRAY in mutations) || (src.sight_mode & BORGXRAY))
src.sight |= SEE_TURFS
src.sight |= SEE_MOBS
@@ -170,6 +171,7 @@
src.see_in_dark = 8
see_invisible = SEE_INVISIBLE_MINIMUM
fullbright = TRUE
+ seemeson = TRUE
else if (src.sight_mode & BORGMATERIAL)
src.sight |= SEE_OBJS
src.see_in_dark = 8
@@ -194,6 +196,7 @@
src.see_invisible = SEE_INVISIBLE_LIVING // This is normal vision (25), setting it lower for normal vision means you don't "see" things like darkness since darkness
// has a "invisible" value of 15
plane_holder.set_vis(VIS_FULLBRIGHT,fullbright)
+ plane_holder.set_vis(VIS_MESONS,seemeson)
..()
if (src.healths)
diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station.dm b/code/modules/mob/living/silicon/robot/robot_modules/station.dm
index b820451adf..17d659fb0b 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules/station.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules/station.dm
@@ -470,6 +470,10 @@ var/global/list/robot_modules = list(
S.synths = list(metal)
src.modules += S
+ var/obj/item/stack/tile/roofing/cyborg/CT = new /obj/item/stack/tile/roofing/cyborg(src)
+ CT.synths = list(metal)
+ src.modules += CT
+
var/obj/item/stack/material/cyborg/glass/reinforced/RG = new (src)
RG.synths = list(metal, glass)
src.modules += RG
diff --git a/code/modules/modular_computers/computers/modular_computer/damage.dm b/code/modules/modular_computers/computers/modular_computer/damage.dm
index d63bf39fdf..9084bad735 100644
--- a/code/modules/modular_computers/computers/modular_computer/damage.dm
+++ b/code/modules/modular_computers/computers/modular_computer/damage.dm
@@ -16,7 +16,7 @@
H.take_damage(rand(10,30))
qdel()
-/obj/item/modular_computer/proc/take_damage(var/amount, var/component_probability, var/damage_casing = 1, var/randomize = 1)
+/obj/item/modular_computer/take_damage(var/amount, var/component_probability, var/damage_casing = 1, var/randomize = 1)
if(randomize)
// 75%-125%, rand() works with integers, apparently.
amount *= (rand(75, 125) / 100.0)
diff --git a/code/modules/modular_computers/hardware/_hardware.dm b/code/modules/modular_computers/hardware/_hardware.dm
index 90150bc547..fb73609d84 100644
--- a/code/modules/modular_computers/hardware/_hardware.dm
+++ b/code/modules/modular_computers/hardware/_hardware.dm
@@ -81,7 +81,7 @@
to_chat(user, "It seems to be slightly damaged.")
// Damages the component. Contains necessary checks. Negative damage "heals" the component.
-/obj/item/weapon/computer_hardware/proc/take_damage(var/amount)
+/obj/item/weapon/computer_hardware/take_damage(var/amount)
damage += round(amount) // We want nice rounded numbers here.
damage = between(0, damage, max_damage) // Clamp the value.
diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm
index b0aadff2a2..579e7776b7 100644
--- a/code/modules/organs/organ.dm
+++ b/code/modules/organs/organ.dm
@@ -292,7 +292,7 @@ var/list/organ_cache = list()
W.time_inflicted = world.time
//Note: external organs have their own version of this proc
-/obj/item/organ/proc/take_damage(amount, var/silent=0)
+/obj/item/organ/take_damage(amount, var/silent=0)
if(src.robotic >= ORGAN_ROBOT)
src.damage = between(0, src.damage + (amount * 0.8), max_damage)
else
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index af58edc78f..542fe3153d 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -389,6 +389,16 @@ var/global/list/light_type_cache = list()
broken()
return 1
+/obj/machinery/light/take_damage(var/damage)
+ if(!damage)
+ return
+ if(status == LIGHT_EMPTY||status == LIGHT_BROKEN)
+ return
+ if(!(status == LIGHT_OK||status == LIGHT_BURNED))
+ return
+ broken()
+ return 1
+
/obj/machinery/light/blob_act()
broken()
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index e657876b7d..7d46fcd73f 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -693,7 +693,7 @@
if (istype(in_chamber))
user.visible_message("[user] pulls the trigger.")
play_fire_sound()
- if(istype(in_chamber, /obj/item/projectile/beam/lastertag))
+ if(istype(in_chamber, /obj/item/projectile/beam/lasertag))
user.show_message("You feel rather silly, trying to commit suicide with a toy.")
mouthshoot = 0
return
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index 266df1f358..eeb8d779d2 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -1,261 +1,261 @@
-/obj/item/weapon/gun/energy/laser
- name = "laser rifle"
- desc = "A Hephaestus Industries G40E rifle, designed to kill with concentrated energy blasts. This variant has the ability to \
- switch between standard fire and a more efficent but weaker 'suppressive' fire."
- icon_state = "laser"
- item_state = "laser"
- wielded_item_state = "laser-wielded"
- fire_delay = 8
- slot_flags = SLOT_BELT|SLOT_BACK
- w_class = ITEMSIZE_LARGE
- force = 10
- origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 2)
- matter = list(DEFAULT_WALL_MATERIAL = 2000)
- projectile_type = /obj/item/projectile/beam/midlaser
-// one_handed_penalty = 30
-
- firemodes = list(
- list(mode_name="normal", fire_delay=8, projectile_type=/obj/item/projectile/beam/midlaser, charge_cost = 240),
- list(mode_name="suppressive", fire_delay=5, projectile_type=/obj/item/projectile/beam/weaklaser, charge_cost = 60),
- )
-
-/obj/item/weapon/gun/energy/laser/mounted
- self_recharge = 1
- use_external_power = 1
- one_handed_penalty = 0 // Not sure if two-handing gets checked for mounted weapons, but better safe than sorry.
-
-/obj/item/weapon/gun/energy/laser/practice
- name = "practice laser carbine"
- desc = "A modified version of the HI G40E, this one fires less concentrated energy bolts designed for target practice."
- projectile_type = /obj/item/projectile/beam/practice
- charge_cost = 48
-
- cell_type = /obj/item/weapon/cell/device
-
- firemodes = list(
- list(mode_name="normal", projectile_type=/obj/item/projectile/beam/practice, charge_cost = 48),
- list(mode_name="suppressive", projectile_type=/obj/item/projectile/beam/practice, charge_cost = 12),
- )
-
-/obj/item/weapon/gun/energy/retro
- name = "retro laser"
- icon_state = "retro"
- item_state = "retro"
- desc = "An older model of the basic lasergun. Nevertheless, it is still quite deadly and easy to maintain, making it a favorite amongst pirates and other outlaws."
- slot_flags = SLOT_BELT
- w_class = ITEMSIZE_NORMAL
- projectile_type = /obj/item/projectile/beam
- fire_delay = 10 //old technology
-
-/obj/item/weapon/gun/energy/retro/mounted
- self_recharge = 1
- use_external_power = 1
-
-/obj/item/weapon/gun/energy/retro/empty
- icon_state = "retro"
- cell_type = null
-
-
-/datum/category_item/catalogue/anomalous/precursor_a/alien_pistol
- name = "Precursor Alpha Weapon - Appendageheld Laser"
- desc = "This object strongly resembles a weapon, and if one were to pull the \
- trigger located on the handle of the object, it would fire a deadly \
- laser at whatever it was pointed at. The beam fired appears to cause too \
- much damage to whatever it would hit to have served as a long ranged repair tool, \
- therefore this object was most likely designed to be a deadly weapon. If so, this \
- has several implications towards its creators;\
-
\
- Firstly, it implies that these precursors, at some point during their development, \
- had needed to defend themselves, or otherwise had a need to utilize violence, and \
- as such created better tools to do so. It is unclear if violence was employed against \
- themselves as a form of in-fighting, or if violence was exclusive to outside species.\
-
\
- Secondly, the shape and design of the weapon implies that the creators of this \
- weapon were able to grasp objects, and be able to manipulate the trigger independently \
- from merely holding onto the weapon, making certain types of appendages like tentacles be \
- unlikely.\
-
\
- An interesting note about this weapon, when compared to contemporary energy weapons, is \
- that this gun appears to be inferior to modern laser weapons. The beam fired has less \
- of an ability to harm, and the power consumption appears to be higher than average for \
- a human-made energy side-arm. One possible explaination is that the creators of this \
- weapon, in their later years, had less of a need to optimize their capability for war, \
- and instead focused on other endeavors. Another explaination is that vast age of the weapon \
- may have caused it to degrade, yet still remain functional at a reduced capability."
- value = CATALOGUER_REWARD_MEDIUM
-
-/obj/item/weapon/gun/energy/alien
- name = "alien pistol"
- desc = "A weapon that works very similarly to a traditional energy weapon. How this came to be will likely be a mystery for the ages."
- catalogue_data = list(/datum/category_item/catalogue/anomalous/precursor_a/alien_pistol)
- icon_state = "alienpistol"
- item_state = "alienpistol"
- fire_sound = 'sound/weapons/eLuger.ogg'
- fire_delay = 10 // Handguns should be inferior to two-handed weapons. Even alien ones I suppose.
- charge_cost = 480 // Five shots.
-
- projectile_type = /obj/item/projectile/beam/cyan
- cell_type = /obj/item/weapon/cell/device/weapon/recharge/alien // Self charges.
- origin_tech = list(TECH_COMBAT = 8, TECH_MAGNET = 7)
- modifystate = "alienpistol"
-
-
-/obj/item/weapon/gun/energy/captain
- name = "antique laser gun"
- icon_state = "caplaser"
- item_state = "caplaser"
- desc = "A rare weapon, handcrafted by a now defunct specialty manufacturer on Luna for a small fortune. It's certainly aged well."
- force = 5
- slot_flags = SLOT_BELT
- w_class = ITEMSIZE_NORMAL
- projectile_type = /obj/item/projectile/beam
- origin_tech = null
- fire_delay = 10 //Old pistol
- charge_cost = 480 //to compensate a bit for self-recharging
- cell_type = /obj/item/weapon/cell/device/weapon/recharge/captain
- battery_lock = 1
-
-/obj/item/weapon/gun/energy/lasercannon
- name = "laser cannon"
- desc = "With the laser cannon, the lasing medium is enclosed in a tube lined with uranium-235 and subjected to high neutron \
- flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with small laser volumes!"
- icon_state = "lasercannon"
- item_state = null
- origin_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3, TECH_POWER = 3)
- slot_flags = SLOT_BELT|SLOT_BACK
- projectile_type = /obj/item/projectile/beam/heavylaser/cannon
- battery_lock = 1
- fire_delay = 20
- w_class = ITEMSIZE_LARGE
-// one_handed_penalty = 90 // The thing's heavy and huge.
- accuracy = 45
- charge_cost = 600
-
-/obj/item/weapon/gun/energy/lasercannon/mounted
- name = "mounted laser cannon"
- self_recharge = 1
- use_external_power = 1
- recharge_time = 10
- accuracy = 0 // Mounted cannons are just fine the way they are.
- one_handed_penalty = 0 // Not sure if two-handing gets checked for mounted weapons, but better safe than sorry.
- projectile_type = /obj/item/projectile/beam/heavylaser
- charge_cost = 400
- fire_delay = 20
-
-/obj/item/weapon/gun/energy/xray
- name = "xray laser gun"
- desc = "A high-power laser gun capable of expelling concentrated xray blasts, which are able to penetrate matter easier than \
- standard photonic beams, resulting in an effective 'anti-armor' energy weapon."
- icon_state = "xray"
- item_state = "xray"
- origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 3, TECH_MAGNET = 2)
- projectile_type = /obj/item/projectile/beam/xray
- charge_cost = 200
-
-/obj/item/weapon/gun/energy/sniperrifle
- name = "marksman energy rifle"
- desc = "The HI DMR 9E is an older design of Hephaestus Industries. A designated marksman rifle capable of shooting powerful \
- ionized beams, this is a weapon to kill from a distance."
- icon_state = "sniper"
- item_state = "sniper"
- item_state_slots = list(slot_r_hand_str = "z8carbine", slot_l_hand_str = "z8carbine") //placeholder
- origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 5, TECH_POWER = 4)
- projectile_type = /obj/item/projectile/beam/sniper
- slot_flags = SLOT_BACK
- battery_lock = 1
- charge_cost = 600
- fire_delay = 35
- force = 10
- w_class = ITEMSIZE_HUGE // So it can't fit in a backpack.
- accuracy = -45 //shooting at the hip
- scoped_accuracy = 0
-// requires_two_hands = 1
-// one_handed_penalty = 60 // The weapon itself is heavy, and the long barrel makes it hard to hold steady with just one hand.
-
-/obj/item/weapon/gun/energy/sniperrifle/verb/scope()
- set category = "Object"
- set name = "Use Scope"
- set popup_menu = 1
-
- toggle_scope(2.0)
-
-/obj/item/weapon/gun/energy/monorifle
- name = "antique mono-rifle"
- desc = "An old laser rifle. This one can only fire once before requiring recharging."
- description_fluff = "Modeled after ancient hunting rifles, this rifle was dubbed the 'Rainy Day Special' by some, due to its use as some barmens' fight-stopper of choice. One shot is all it takes, or so they say."
- icon_state = "eshotgun"
- item_state = "shotgun"
- origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 4, TECH_POWER = 3)
- projectile_type = /obj/item/projectile/beam/sniper
- slot_flags = SLOT_BACK
- charge_cost = 1300
- fire_delay = 20
- force = 8
- w_class = ITEMSIZE_LARGE
- accuracy = 10
- scoped_accuracy = 15
- var/scope_multiplier = 1.5
-
-/obj/item/weapon/gun/energy/monorifle/verb/sights()
- set category = "Object"
- set name = "Aim Down Sights"
- set popup_menu = 1
-
- toggle_scope(scope_multiplier)
-
-/obj/item/weapon/gun/energy/monorifle/combat
- name = "combat mono-rifle"
- desc = "A modernized version of the mono-rifle. This one can fire twice before requiring recharging."
- description_fluff = "A modern design produced by a company once working from Saint Columbia, based on the antique mono-rifle 'Rainy Day Special' design."
- icon_state = "ecshotgun"
- item_state = "cshotgun"
- charge_cost = 1000
- force = 12
- accuracy = 0
- scoped_accuracy = 20
-
-////////Laser Tag////////////////////
-
-/obj/item/weapon/gun/energy/lasertag
- name = "laser tag gun"
- item_state = "laser"
- desc = "Standard issue weapon of the Imperial Guard"
- origin_tech = list(TECH_COMBAT = 1, TECH_MAGNET = 2)
- matter = list(DEFAULT_WALL_MATERIAL = 2000)
- projectile_type = /obj/item/projectile/beam/lastertag/blue
- cell_type = /obj/item/weapon/cell/device/weapon/recharge
- battery_lock = 1
- var/required_vest
-
-/obj/item/weapon/gun/energy/lasertag/special_check(var/mob/living/carbon/human/M)
- if(ishuman(M))
- if(!istype(M.wear_suit, required_vest))
- M << "You need to be wearing your laser tag vest!"
- return 0
- return ..()
-
-/obj/item/weapon/gun/energy/lasertag/blue
- icon_state = "bluetag"
- item_state = "bluetag"
- projectile_type = /obj/item/projectile/beam/lastertag/blue
- required_vest = /obj/item/clothing/suit/bluetag
-
-/obj/item/weapon/gun/energy/lasertag/red
- icon_state = "redtag"
- item_state = "redtag"
- projectile_type = /obj/item/projectile/beam/lastertag/red
- required_vest = /obj/item/clothing/suit/redtag
-
-/*
- * Laser scattergun, proof of concept.
- */
-
-/obj/item/weapon/gun/energy/lasershotgun
- name = "laser scattergun"
- icon = 'icons/obj/energygun.dmi'
- item_state = "laser"
- icon_state = "scatter"
- desc = "A strange Almachi weapon, utilizing a refracting prism to turn a single laser blast into a diverging cluster."
- origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 1, TECH_MATERIAL = 4)
-
- projectile_type = /obj/item/projectile/scatter/laser
+/obj/item/weapon/gun/energy/laser
+ name = "laser rifle"
+ desc = "A Hephaestus Industries G40E rifle, designed to kill with concentrated energy blasts. This variant has the ability to \
+ switch between standard fire and a more efficent but weaker 'suppressive' fire."
+ icon_state = "laser"
+ item_state = "laser"
+ wielded_item_state = "laser-wielded"
+ fire_delay = 8
+ slot_flags = SLOT_BELT|SLOT_BACK
+ w_class = ITEMSIZE_LARGE
+ force = 10
+ origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 2)
+ matter = list(DEFAULT_WALL_MATERIAL = 2000)
+ projectile_type = /obj/item/projectile/beam/midlaser
+// one_handed_penalty = 30
+
+ firemodes = list(
+ list(mode_name="normal", fire_delay=8, projectile_type=/obj/item/projectile/beam/midlaser, charge_cost = 240),
+ list(mode_name="suppressive", fire_delay=5, projectile_type=/obj/item/projectile/beam/weaklaser, charge_cost = 60),
+ )
+
+/obj/item/weapon/gun/energy/laser/mounted
+ self_recharge = 1
+ use_external_power = 1
+ one_handed_penalty = 0 // Not sure if two-handing gets checked for mounted weapons, but better safe than sorry.
+
+/obj/item/weapon/gun/energy/laser/practice
+ name = "practice laser carbine"
+ desc = "A modified version of the HI G40E, this one fires less concentrated energy bolts designed for target practice."
+ projectile_type = /obj/item/projectile/beam/practice
+ charge_cost = 48
+
+ cell_type = /obj/item/weapon/cell/device
+
+ firemodes = list(
+ list(mode_name="normal", projectile_type=/obj/item/projectile/beam/practice, charge_cost = 48),
+ list(mode_name="suppressive", projectile_type=/obj/item/projectile/beam/practice, charge_cost = 12),
+ )
+
+/obj/item/weapon/gun/energy/retro
+ name = "retro laser"
+ icon_state = "retro"
+ item_state = "retro"
+ desc = "An older model of the basic lasergun. Nevertheless, it is still quite deadly and easy to maintain, making it a favorite amongst pirates and other outlaws."
+ slot_flags = SLOT_BELT
+ w_class = ITEMSIZE_NORMAL
+ projectile_type = /obj/item/projectile/beam
+ fire_delay = 10 //old technology
+
+/obj/item/weapon/gun/energy/retro/mounted
+ self_recharge = 1
+ use_external_power = 1
+
+/obj/item/weapon/gun/energy/retro/empty
+ icon_state = "retro"
+ cell_type = null
+
+
+/datum/category_item/catalogue/anomalous/precursor_a/alien_pistol
+ name = "Precursor Alpha Weapon - Appendageheld Laser"
+ desc = "This object strongly resembles a weapon, and if one were to pull the \
+ trigger located on the handle of the object, it would fire a deadly \
+ laser at whatever it was pointed at. The beam fired appears to cause too \
+ much damage to whatever it would hit to have served as a long ranged repair tool, \
+ therefore this object was most likely designed to be a deadly weapon. If so, this \
+ has several implications towards its creators;\
+
\
+ Firstly, it implies that these precursors, at some point during their development, \
+ had needed to defend themselves, or otherwise had a need to utilize violence, and \
+ as such created better tools to do so. It is unclear if violence was employed against \
+ themselves as a form of in-fighting, or if violence was exclusive to outside species.\
+
\
+ Secondly, the shape and design of the weapon implies that the creators of this \
+ weapon were able to grasp objects, and be able to manipulate the trigger independently \
+ from merely holding onto the weapon, making certain types of appendages like tentacles be \
+ unlikely.\
+
\
+ An interesting note about this weapon, when compared to contemporary energy weapons, is \
+ that this gun appears to be inferior to modern laser weapons. The beam fired has less \
+ of an ability to harm, and the power consumption appears to be higher than average for \
+ a human-made energy side-arm. One possible explaination is that the creators of this \
+ weapon, in their later years, had less of a need to optimize their capability for war, \
+ and instead focused on other endeavors. Another explaination is that vast age of the weapon \
+ may have caused it to degrade, yet still remain functional at a reduced capability."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/obj/item/weapon/gun/energy/alien
+ name = "alien pistol"
+ desc = "A weapon that works very similarly to a traditional energy weapon. How this came to be will likely be a mystery for the ages."
+ catalogue_data = list(/datum/category_item/catalogue/anomalous/precursor_a/alien_pistol)
+ icon_state = "alienpistol"
+ item_state = "alienpistol"
+ fire_delay = 10 // Handguns should be inferior to two-handed weapons. Even alien ones I suppose.
+ charge_cost = 480 // Five shots.
+
+ projectile_type = /obj/item/projectile/beam/cyan
+ cell_type = /obj/item/weapon/cell/device/weapon/recharge/alien // Self charges.
+ origin_tech = list(TECH_COMBAT = 8, TECH_MAGNET = 7)
+ modifystate = "alienpistol"
+
+
+/obj/item/weapon/gun/energy/captain
+ name = "antique laser gun"
+ icon_state = "caplaser"
+ item_state = "caplaser"
+ desc = "A rare weapon, handcrafted by a now defunct specialty manufacturer on Luna for a small fortune. It's certainly aged well."
+ force = 5
+ slot_flags = SLOT_BELT
+ w_class = ITEMSIZE_NORMAL
+ projectile_type = /obj/item/projectile/beam
+ origin_tech = null
+ fire_delay = 10 //Old pistol
+ charge_cost = 480 //to compensate a bit for self-recharging
+ cell_type = /obj/item/weapon/cell/device/weapon/recharge/captain
+ battery_lock = 1
+
+/obj/item/weapon/gun/energy/lasercannon
+ name = "laser cannon"
+ desc = "With the laser cannon, the lasing medium is enclosed in a tube lined with uranium-235 and subjected to high neutron \
+ flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with small laser volumes!"
+ icon_state = "lasercannon"
+ item_state = null
+ origin_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3, TECH_POWER = 3)
+ slot_flags = SLOT_BELT|SLOT_BACK
+ projectile_type = /obj/item/projectile/beam/heavylaser/cannon
+ battery_lock = 1
+ fire_delay = 20
+ w_class = ITEMSIZE_LARGE
+// one_handed_penalty = 90 // The thing's heavy and huge.
+ accuracy = 45
+ charge_cost = 600
+
+/obj/item/weapon/gun/energy/lasercannon/mounted
+ name = "mounted laser cannon"
+ self_recharge = 1
+ use_external_power = 1
+ recharge_time = 10
+ accuracy = 0 // Mounted cannons are just fine the way they are.
+ one_handed_penalty = 0 // Not sure if two-handing gets checked for mounted weapons, but better safe than sorry.
+ projectile_type = /obj/item/projectile/beam/heavylaser
+ charge_cost = 400
+ fire_delay = 20
+
+/obj/item/weapon/gun/energy/xray
+ name = "xray laser gun"
+ desc = "A high-power laser gun capable of expelling concentrated xray blasts, which are able to penetrate matter easier than \
+ standard photonic beams, resulting in an effective 'anti-armor' energy weapon."
+ icon_state = "xray"
+ item_state = "xray"
+ origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 3, TECH_MAGNET = 2)
+ projectile_type = /obj/item/projectile/beam/xray
+ charge_cost = 200
+
+/obj/item/weapon/gun/energy/sniperrifle
+ name = "marksman energy rifle"
+ desc = "The HI DMR 9E is an older design of Hephaestus Industries. A designated marksman rifle capable of shooting powerful \
+ ionized beams, this is a weapon to kill from a distance."
+ icon_state = "sniper"
+ item_state = "sniper"
+ item_state_slots = list(slot_r_hand_str = "z8carbine", slot_l_hand_str = "z8carbine") //placeholder
+ origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 5, TECH_POWER = 4)
+ projectile_type = /obj/item/projectile/beam/sniper
+ slot_flags = SLOT_BACK
+ battery_lock = 1
+ charge_cost = 600
+ fire_delay = 35
+ force = 10
+ w_class = ITEMSIZE_HUGE // So it can't fit in a backpack.
+ accuracy = -45 //shooting at the hip
+ scoped_accuracy = 0
+// requires_two_hands = 1
+// one_handed_penalty = 60 // The weapon itself is heavy, and the long barrel makes it hard to hold steady with just one hand.
+
+/obj/item/weapon/gun/energy/sniperrifle/verb/scope()
+ set category = "Object"
+ set name = "Use Scope"
+ set popup_menu = 1
+
+ toggle_scope(2.0)
+
+/obj/item/weapon/gun/energy/monorifle
+ name = "antique mono-rifle"
+ desc = "An old laser rifle. This one can only fire once before requiring recharging."
+ description_fluff = "Modeled after ancient hunting rifles, this rifle was dubbed the 'Rainy Day Special' by some, due to its use as some barmens' fight-stopper of choice. One shot is all it takes, or so they say."
+ icon_state = "eshotgun"
+ item_state = "shotgun"
+ origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 4, TECH_POWER = 3)
+ projectile_type = /obj/item/projectile/beam/sniper
+ slot_flags = SLOT_BACK
+ charge_cost = 1300
+ fire_delay = 20
+ force = 8
+ w_class = ITEMSIZE_LARGE
+ accuracy = 10
+ scoped_accuracy = 15
+ var/scope_multiplier = 1.5
+
+/obj/item/weapon/gun/energy/monorifle/verb/sights()
+ set category = "Object"
+ set name = "Aim Down Sights"
+ set popup_menu = 1
+
+ toggle_scope(scope_multiplier)
+
+/obj/item/weapon/gun/energy/monorifle/combat
+ name = "combat mono-rifle"
+ desc = "A modernized version of the mono-rifle. This one can fire twice before requiring recharging."
+ description_fluff = "A modern design produced by a company once working from Saint Columbia, based on the antique mono-rifle 'Rainy Day Special' design."
+ icon_state = "ecshotgun"
+ item_state = "cshotgun"
+ charge_cost = 1000
+ force = 12
+ accuracy = 0
+ scoped_accuracy = 20
+
+////////Laser Tag////////////////////
+
+/obj/item/weapon/gun/energy/lasertag
+ name = "laser tag gun"
+ item_state = "laser"
+ desc = "Standard issue weapon of the Imperial Guard"
+ origin_tech = list(TECH_COMBAT = 1, TECH_MAGNET = 2)
+ matter = list(DEFAULT_WALL_MATERIAL = 2000)
+ projectile_type = /obj/item/projectile/beam/lasertag/blue
+ cell_type = /obj/item/weapon/cell/device/weapon/recharge
+ battery_lock = 1
+ var/required_vest
+
+/obj/item/weapon/gun/energy/lasertag/special_check(var/mob/living/carbon/human/M)
+ if(ishuman(M))
+ if(!istype(M.wear_suit, required_vest))
+ M << "You need to be wearing your laser tag vest!"
+ return 0
+ return ..()
+
+/obj/item/weapon/gun/energy/lasertag/blue
+ icon_state = "bluetag"
+ item_state = "bluetag"
+ projectile_type = /obj/item/projectile/beam/lasertag/blue
+ required_vest = /obj/item/clothing/suit/bluetag
+
+/obj/item/weapon/gun/energy/lasertag/red
+ icon_state = "redtag"
+ item_state = "redtag"
+ projectile_type = /obj/item/projectile/beam/lasertag/red
+ required_vest = /obj/item/clothing/suit/redtag
+
+/obj/item/weapon/gun/energy/lasertag/omni
+ projectile_type = /obj/item/projectile/beam/lasertag/omni
+
+// Laser scattergun, proof of concept.
+
+/obj/item/weapon/gun/energy/lasershotgun
+ name = "laser scattergun"
+ icon = 'icons/obj/energygun.dmi'
+ item_state = "laser"
+ icon_state = "scatter"
+ desc = "A strange Almachi weapon, utilizing a refracting prism to turn a single laser blast into a diverging cluster."
+ origin_tech = list(TECH_COMBAT = 3, TECH_MAGNET = 1, TECH_MATERIAL = 4)
+
+ projectile_type = /obj/item/projectile/scatter/laser
\ No newline at end of file
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index f1a1f28e6c..ec2670c61d 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -89,6 +89,7 @@
/obj/item/projectile/beam/cyan
name = "cyan beam"
icon_state = "cyan"
+ fire_sound = 'sound/weapons/eluger.ogg'
damage = 40
light_color = "#00C6FF"
@@ -125,62 +126,52 @@
tracer_type = /obj/effect/projectile/tracer/emitter
impact_type = /obj/effect/projectile/impact/emitter
-/obj/item/projectile/beam/lastertag/blue
+/obj/item/projectile/beam/lasertag
name = "lasertag beam"
- icon_state = "bluelaser"
damage = 0
+ eyeblur = 0
no_attack_log = 1
damage_type = BURN
check_armour = "laser"
- light_color = "#0066FF"
combustion = FALSE
+/obj/item/projectile/beam/lasertag/blue
+ icon_state = "bluelaser"
+ light_color = "#0066FF"
+
muzzle_type = /obj/effect/projectile/muzzle/laser_blue
tracer_type = /obj/effect/projectile/tracer/laser_blue
impact_type = /obj/effect/projectile/impact/laser_blue
-/obj/item/projectile/beam/lastertag/blue/on_hit(var/atom/target, var/blocked = 0)
- if(istype(target, /mob/living/carbon/human))
+/obj/item/projectile/beam/lasertag/blue/on_hit(var/atom/target, var/blocked = 0)
+ if(ishuman(target))
var/mob/living/carbon/human/M = target
if(istype(M.wear_suit, /obj/item/clothing/suit/redtag))
M.Weaken(5)
return 1
-/obj/item/projectile/beam/lastertag/red
- name = "lasertag beam"
+/obj/item/projectile/beam/lasertag/red
icon_state = "laser"
- damage = 0
- no_attack_log = 1
- damage_type = BURN
- check_armour = "laser"
light_color = "#FF0D00"
- combustion = FALSE
-
-/obj/item/projectile/beam/lastertag/red/on_hit(var/atom/target, var/blocked = 0)
- if(istype(target, /mob/living/carbon/human))
+/obj/item/projectile/beam/lasertag/red/on_hit(var/atom/target, var/blocked = 0)
+ if(ishuman(target))
var/mob/living/carbon/human/M = target
if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag))
M.Weaken(5)
return 1
-/obj/item/projectile/beam/lastertag/omni//A laser tag bolt that stuns EVERYONE
- name = "lasertag beam"
+/obj/item/projectile/beam/lasertag/omni//A laser tag bolt that stuns EVERYONE
icon_state = "omnilaser"
- damage = 0
- damage_type = BURN
- check_armour = "laser"
light_color = "#00C6FF"
- combustion = FALSE
-
muzzle_type = /obj/effect/projectile/muzzle/laser_omni
tracer_type = /obj/effect/projectile/tracer/laser_omni
impact_type = /obj/effect/projectile/impact/laser_omni
-/obj/item/projectile/beam/lastertag/omni/on_hit(var/atom/target, var/blocked = 0)
- if(istype(target, /mob/living/carbon/human))
+/obj/item/projectile/beam/lasertag/omni/on_hit(var/atom/target, var/blocked = 0)
+ if(ishuman(target))
var/mob/living/carbon/human/M = target
if((istype(M.wear_suit, /obj/item/clothing/suit/bluetag))||(istype(M.wear_suit, /obj/item/clothing/suit/redtag)))
M.Weaken(5)
diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm
index d2b4dc149d..4ccd444d0e 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/reagent_dispenser.dm
@@ -158,7 +158,7 @@
message_admins("[key_name_admin(Proj.firer)] shot fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]) (JMP).")
log_game("[key_name(Proj.firer)] shot fueltank at [loc.loc.name] ([loc.x],[loc.y],[loc.z]).")
- if(!istype(Proj ,/obj/item/projectile/beam/lastertag) && !istype(Proj ,/obj/item/projectile/beam/practice) )
+ if(!istype(Proj ,/obj/item/projectile/beam/lasertag) && !istype(Proj ,/obj/item/projectile/beam/practice) )
explode()
/obj/structure/reagent_dispensers/fueltank/ex_act()
diff --git a/code/modules/shieldgen/energy_field.dm b/code/modules/shieldgen/energy_field.dm
index 65eb6dc363..5b7d7f2118 100644
--- a/code/modules/shieldgen/energy_field.dm
+++ b/code/modules/shieldgen/energy_field.dm
@@ -60,6 +60,9 @@
user.do_attack_animation(src)
user.setClickCooldown(user.get_attack_speed())
+/obj/effect/energy_field/take_damage(var/damage)
+ adjust_strength(-damage / 20)
+
/obj/effect/energy_field/attack_hand(var/mob/living/user)
impact_effect(3) // Harmless, but still produces the 'impact' effect.
..()
diff --git a/code/modules/surgery/external_repair.dm b/code/modules/surgery/external_repair.dm
index b26d803b34..e54352f536 100644
--- a/code/modules/surgery/external_repair.dm
+++ b/code/modules/surgery/external_repair.dm
@@ -9,8 +9,10 @@
req_open = 1
/datum/surgery_step/repairflesh/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- if (target.stat == DEAD) // Sorry defibs, your subjects need to have pumping fluids for these to work.
- return 0
+/* VOREStation Removal for Mlem Reasons(TM)
+ if (target.stat == DEAD) // Sorry defibs, your subjects need to have pumping fluids for these to work.
+ return 0
+*/
if (isslime(target))
return 0
if (target_zone == O_EYES || target_zone == O_MOUTH)
diff --git a/code/modules/tables/presets.dm b/code/modules/tables/presets.dm
index 06fca65138..5d568d440e 100644
--- a/code/modules/tables/presets.dm
+++ b/code/modules/tables/presets.dm
@@ -75,6 +75,15 @@
material = get_material_by_name("glass")
..()
+/obj/structure/table/borosilicate
+ icon_state = "plain_preview"
+ color = "#4D3EAC"
+ alpha = 77
+
+/obj/structure/table/borosilicate/New()
+ material = get_material_by_name("borosilicate glass")
+ ..()
+
/obj/structure/table/holotable
icon_state = "holo_preview"
color = "#EEEEEE"
diff --git a/code/modules/tables/tables.dm b/code/modules/tables/tables.dm
index 514c3b2036..c5b7bde70e 100644
--- a/code/modules/tables/tables.dm
+++ b/code/modules/tables/tables.dm
@@ -44,7 +44,7 @@ var/list/table_icon_cache = list()
health += maxhealth - old_maxhealth
-/obj/structure/table/proc/take_damage(amount)
+/obj/structure/table/take_damage(amount)
// If the table is made of a brittle material, and is *not* reinforced with a non-brittle material, damage is multiplied by TABLE_BRITTLE_MATERIAL_MULTIPLIER
if(material && material.is_brittle())
if(reinforced)
diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm
index 606735f36f..87a1b72466 100644
--- a/code/modules/vehicles/vehicle.dm
+++ b/code/modules/vehicles/vehicle.dm
@@ -424,3 +424,12 @@
new /obj/effect/decal/cleanable/blood/oil(src.loc)
spawn(1) healthcheck()
return 1
+
+/obj/vehicle/take_damage(var/damage)
+ if(!damage)
+ return
+ src.health -= damage
+ if(mechanical && prob(10))
+ new /obj/effect/decal/cleanable/blood/oil(src.loc)
+ spawn(1) healthcheck()
+ return 1
diff --git a/code/modules/vore/fluffstuff/custom_clothes_vr.dm b/code/modules/vore/fluffstuff/custom_clothes_vr.dm
index fc1fe9d0ff..2dc626b801 100644
--- a/code/modules/vore/fluffstuff/custom_clothes_vr.dm
+++ b/code/modules/vore/fluffstuff/custom_clothes_vr.dm
@@ -1848,4 +1848,15 @@ Departamental Swimsuits, for general use
icon_state = "goldenstring"
item_state = "goldenstring"
w_class = ITEMSIZE_TINY
- slot_flags = SLOT_TIE
\ No newline at end of file
+ slot_flags = SLOT_TIE
+
+//Chaoko99: Aika Hisakawa
+/obj/item/clothing/suit/fluff/blue_trimmed_coat
+ name = "blue-trimmed greatcoat"
+ desc = "A heavy, form-obscuring coat with gilded buttons and azure trim."
+ icon = 'icons/vore/custom_clothes_vr.dmi'
+ icon_state = "aika_coat"
+
+ icon_override = 'icons/vore/custom_clothes_vr.dmi'
+ item_state = "aika_coat"
+ flags_inv = HIDEJUMPSUIT | HIDETIE
\ No newline at end of file
diff --git a/code/modules/xenoarcheaology/tools/coolant_tank.dm b/code/modules/xenoarcheaology/tools/coolant_tank.dm
index df6c901517..9f5172b3de 100644
--- a/code/modules/xenoarcheaology/tools/coolant_tank.dm
+++ b/code/modules/xenoarcheaology/tools/coolant_tank.dm
@@ -11,7 +11,7 @@
/obj/structure/reagent_dispensers/coolanttank/bullet_act(var/obj/item/projectile/Proj)
if(Proj.get_structure_damage())
- if(!istype(Proj ,/obj/item/projectile/beam/lastertag) && !istype(Proj ,/obj/item/projectile/beam/practice) ) // TODO: make this not terrible
+ if(!istype(Proj ,/obj/item/projectile/beam/lasertag) && !istype(Proj ,/obj/item/projectile/beam/practice) ) // TODO: make this not terrible
explode()
/obj/structure/reagent_dispensers/coolanttank/ex_act()
diff --git a/config/custom_items.txt b/config/custom_items.txt
index 9438ff8d22..a46362b3f9 100644
--- a/config/custom_items.txt
+++ b/config/custom_items.txt
@@ -974,3 +974,10 @@ ckey: zodiacshadow
character_name: Nehi Maximus
item_path: /obj/item/device/radio/headset/fluff/zodiacshadow
}
+
+{
+ckey: chaoko99
+character_name: Aika Hisakawa
+item_path: /obj/item/clothing/suit/fluff/blue_trimmed_coat
+}
+
diff --git a/html/changelog.html b/html/changelog.html
index fab075d8ed..31766527d1 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -53,6 +53,47 @@
-->