diff --git a/.travis.yml b/.travis.yml
index fc1c93b83c..5a3b08a14a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,7 +5,7 @@ sudo: false
env:
global:
- BYOND_MAJOR="512"
- - BYOND_MINOR="1403"
+ - BYOND_MINOR="1411"
- MACRO_COUNT=4
matrix:
- TEST_DEFINE="MAP_TEST" TEST_FILE="code/_map_tests.dm" RUN="0"
diff --git a/code/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm
deleted file mode 100644
index 9f025138a1..0000000000
--- a/code/ATMOSPHERICS/pipes.dm
+++ /dev/null
@@ -1,1353 +0,0 @@
-//
-// Base type of pipes
-//
-/obj/machinery/atmospherics/pipe
-
- var/datum/gas_mixture/air_temporary // used when reconstructing a pipeline that broke
- var/datum/pipeline/parent
- var/volume = 0
-
- layer = 2.4 //under wires with their 2.44
- use_power = 0
-
- var/alert_pressure = 80*ONE_ATMOSPHERE
- //minimum pressure before check_pressure(...) should be called
-
- can_buckle = 1
- buckle_require_restraints = 1
- buckle_lying = -1
-
-/obj/machinery/atmospherics/pipe/drain_power()
- return -1
-
-/obj/machinery/atmospherics/pipe/New()
- if(istype(get_turf(src), /turf/simulated/wall) || istype(get_turf(src), /turf/simulated/shuttle/wall) || istype(get_turf(src), /turf/unsimulated/wall))
- level = 1
- ..()
-
-/obj/machinery/atmospherics/pipe/hides_under_flooring()
- return level != 2
-
-/obj/machinery/atmospherics/pipe/proc/pipeline_expansion()
- return null
-
-/obj/machinery/atmospherics/pipe/proc/check_pressure(pressure)
- //Return 1 if parent should continue checking other pipes
- //Return null if parent should stop checking other pipes. Recall: qdel(src) will by default return null
-
- return 1
-
-/obj/machinery/atmospherics/pipe/return_air()
- if(!parent)
- parent = new /datum/pipeline()
- parent.build_pipeline(src)
-
- return parent.air
-
-/obj/machinery/atmospherics/pipe/build_network()
- if(!parent)
- parent = new /datum/pipeline()
- parent.build_pipeline(src)
-
- return parent.return_network()
-
-/obj/machinery/atmospherics/pipe/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
- if(!parent)
- parent = new /datum/pipeline()
- parent.build_pipeline(src)
-
- return parent.network_expand(new_network, reference)
-
-/obj/machinery/atmospherics/pipe/return_network(obj/machinery/atmospherics/reference)
- if(!parent)
- parent = new /datum/pipeline()
- parent.build_pipeline(src)
-
- return parent.return_network(reference)
-
-/obj/machinery/atmospherics/pipe/Destroy()
- qdel_null(parent)
- if(air_temporary)
- loc.assume_air(air_temporary)
-
- . = ..()
-
-/obj/machinery/atmospherics/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
- if (istype(src, /obj/machinery/atmospherics/pipe/tank))
- return ..()
-
- if(istype(W,/obj/item/device/pipe_painter))
- return 0
-
- if (!istype(W, /obj/item/weapon/wrench))
- return ..()
- var/turf/T = src.loc
- if (level==1 && isturf(T) && !T.is_plating())
- to_chat(user, "You must remove the plating first.")
- return 1
- if(!can_unwrench())
- to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.")
- add_fingerprint(user)
- return 1
- playsound(src, W.usesound, 50, 1)
- to_chat(user, "You begin to unfasten \the [src]...")
- if (do_after(user, 40 * W.toolspeed))
- user.visible_message( \
- "\The [user] unfastens \the [src].", \
- "You have unfastened \the [src].", \
- "You hear a ratchet.")
- new /obj/item/pipe(loc, make_from=src)
- for (var/obj/machinery/meter/meter in T)
- if (meter.target == src)
- new /obj/item/pipe_meter(T)
- qdel(meter)
- qdel(src)
-
-/obj/machinery/atmospherics/pipe/proc/change_color(var/new_color)
- //only pass valid pipe colors please ~otherwise your pipe will turn invisible
- if(!pipe_color_check(new_color))
- return
-
- pipe_color = new_color
- update_icon()
-
-/obj/machinery/atmospherics/pipe/color_cache_name(var/obj/machinery/atmospherics/node)
- if(istype(src, /obj/machinery/atmospherics/pipe/tank))
- return ..()
-
- if(istype(node, /obj/machinery/atmospherics/pipe/manifold) || istype(node, /obj/machinery/atmospherics/pipe/manifold4w))
- if(pipe_color == node.pipe_color)
- return node.pipe_color
- else
- return null
- else if(istype(node, /obj/machinery/atmospherics/pipe/simple))
- return node.pipe_color
- else
- return pipe_color
-
-/obj/machinery/atmospherics/pipe/hide(var/i)
- if(istype(loc, /turf/simulated))
- invisibility = i ? 101 : 0
- update_icon()
-
-/obj/machinery/atmospherics/pipe/process()
- if(!parent) //This should cut back on the overhead calling build_network thousands of times per cycle
- ..()
- else
- . = PROCESS_KILL
-
-//
-// Simple Pipes - Just a tube, maybe bent
-//
-/obj/machinery/atmospherics/pipe/simple
- icon = 'icons/atmos/pipes.dmi'
- icon_state = ""
- var/pipe_icon = "" //what kind of pipe it is and from which dmi is the icon manager getting its icons, "" for simple pipes, "hepipe" for HE pipes, "hejunction" for HE junctions
- name = "pipe"
- desc = "A one meter section of regular pipe"
-
- volume = ATMOS_DEFAULT_VOLUME_PIPE
-
- dir = SOUTH
- initialize_directions = SOUTH|NORTH
-
- var/minimum_temperature_difference = 300
- var/thermal_conductivity = 0 //WALL_HEAT_TRANSFER_COEFFICIENT No
-
- var/maximum_pressure = 70*ONE_ATMOSPHERE
- var/fatigue_pressure = 55*ONE_ATMOSPHERE
- alert_pressure = 55*ONE_ATMOSPHERE
-
- level = 1
-
-/obj/machinery/atmospherics/pipe/simple/New()
- ..()
-
- // Pipe colors and icon states are handled by an image cache - so color and icon should
- // be null. For mapping purposes color is defined in the object definitions.
- icon = null
- alpha = 255
-
-/obj/machinery/atmospherics/pipe/simple/check_pressure(pressure)
- var/datum/gas_mixture/environment = loc.return_air()
-
- var/pressure_difference = pressure - environment.return_pressure()
-
- if(pressure_difference > maximum_pressure)
- burst()
-
- else if(pressure_difference > fatigue_pressure)
- //TODO: leak to turf, doing pfshhhhh
- if(prob(5))
- burst()
-
- else return 1
-
-/obj/machinery/atmospherics/pipe/simple/init_dir()
- switch(dir)
- if(SOUTH || NORTH)
- initialize_directions = SOUTH|NORTH
- if(EAST || WEST)
- initialize_directions = EAST|WEST
- if(NORTHEAST)
- initialize_directions = NORTH|EAST
- if(NORTHWEST)
- initialize_directions = NORTH|WEST
- if(SOUTHEAST)
- initialize_directions = SOUTH|EAST
- if(SOUTHWEST)
- initialize_directions = SOUTH|WEST
-
-/obj/machinery/atmospherics/pipe/simple/proc/burst()
- src.visible_message("\The [src] bursts!");
- playsound(src.loc, 'sound/effects/bang.ogg', 25, 1)
- var/datum/effect/effect/system/smoke_spread/smoke = new
- smoke.set_up(1,0, src.loc, 0)
- smoke.start()
- qdel(src)
-
-/obj/machinery/atmospherics/pipe/simple/proc/normalize_dir()
- if(dir==3)
- set_dir(1)
- else if(dir==12)
- set_dir(4)
-
-/obj/machinery/atmospherics/pipe/simple/Destroy()
- if(node1)
- node1.disconnect(src)
- node1 = null
- if(node2)
- node2.disconnect(src)
- node1 = null
-
- . = ..()
-
-/obj/machinery/atmospherics/pipe/simple/pipeline_expansion()
- return list(node1, node2)
-
-/obj/machinery/atmospherics/pipe/simple/change_color(var/new_color)
- ..()
- //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
- if(node1)
- node1.update_underlays()
- if(node2)
- node2.update_underlays()
-
-/obj/machinery/atmospherics/pipe/simple/update_icon(var/safety = 0)
- if(!check_icon_cache())
- return
-
- alpha = 255
-
- overlays.Cut()
-
- if(node1 && node2)
- overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "[pipe_icon]intact[icon_connect_type]")
- else
- overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "[pipe_icon]exposed[node1?1:0][node2?1:0][icon_connect_type]")
-
-/obj/machinery/atmospherics/pipe/simple/update_underlays()
- return
-
-/obj/machinery/atmospherics/pipe/simple/atmos_init()
- normalize_dir()
- var/node1_dir
- var/node2_dir
-
- for(var/direction in cardinal)
- if(direction&initialize_directions)
- if (!node1_dir)
- node1_dir = direction
- else if (!node2_dir)
- node2_dir = direction
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node1 = target
- break
- for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node2 = target
- break
-
- if(!node1 && !node2)
- qdel(src)
- return
-
- var/turf/T = loc
- if(level == 1 && !T.is_plating()) hide(1)
- update_icon()
-
-/obj/machinery/atmospherics/pipe/simple/disconnect(obj/machinery/atmospherics/reference)
- if(reference == node1)
- if(istype(node1, /obj/machinery/atmospherics/pipe))
- qdel(parent)
- node1 = null
-
- if(reference == node2)
- if(istype(node2, /obj/machinery/atmospherics/pipe))
- qdel(parent)
- node2 = null
-
- update_icon()
-
- return null
-
-/obj/machinery/atmospherics/pipe/simple/visible
- icon_state = "intact"
- level = 2
-
-/obj/machinery/atmospherics/pipe/simple/visible/scrubbers
- name = "Scrubbers pipe"
- desc = "A one meter section of scrubbers pipe"
- icon_state = "intact-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/simple/visible/supply
- name = "Air supply pipe"
- desc = "A one meter section of supply pipe"
- icon_state = "intact-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/simple/visible/yellow
- color = PIPE_COLOR_YELLOW
-
-/obj/machinery/atmospherics/pipe/simple/visible/cyan
- color = PIPE_COLOR_CYAN
-
-/obj/machinery/atmospherics/pipe/simple/visible/green
- color = PIPE_COLOR_GREEN
-
-/obj/machinery/atmospherics/pipe/simple/visible/black
- color = PIPE_COLOR_BLACK
-
-/obj/machinery/atmospherics/pipe/simple/visible/red
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/simple/visible/blue
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/simple/visible/purple
- color = PIPE_COLOR_PURPLE
-
-/obj/machinery/atmospherics/pipe/simple/hidden
- icon_state = "intact"
- level = 1
- alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game
-
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers
- name = "Scrubbers pipe"
- desc = "A one meter section of scrubbers pipe"
- icon_state = "intact-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/simple/hidden/supply
- name = "Air supply pipe"
- desc = "A one meter section of supply pipe"
- icon_state = "intact-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/simple/hidden/yellow
- color = PIPE_COLOR_YELLOW
-
-/obj/machinery/atmospherics/pipe/simple/hidden/cyan
- color = PIPE_COLOR_CYAN
-
-/obj/machinery/atmospherics/pipe/simple/hidden/green
- color = PIPE_COLOR_GREEN
-
-/obj/machinery/atmospherics/pipe/simple/hidden/black
- color = PIPE_COLOR_BLACK
-
-/obj/machinery/atmospherics/pipe/simple/hidden/red
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/simple/hidden/blue
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/simple/hidden/purple
- color = PIPE_COLOR_PURPLE
-
-/obj/machinery/atmospherics/pipe/simple/insulated
- icon = 'icons/obj/atmospherics/red_pipe.dmi'
- icon_state = "intact"
-
- minimum_temperature_difference = 10000
- thermal_conductivity = 0
- maximum_pressure = 1000*ONE_ATMOSPHERE
- fatigue_pressure = 900*ONE_ATMOSPHERE
- alert_pressure = 900*ONE_ATMOSPHERE
-
- level = 2
-
-//
-// Manifold Pipes - Three way "T" joints
-//
-/obj/machinery/atmospherics/pipe/manifold
- icon = 'icons/atmos/manifold.dmi'
- icon_state = ""
- name = "pipe manifold"
- desc = "A manifold composed of regular pipes"
-
- volume = ATMOS_DEFAULT_VOLUME_PIPE * 1.5
-
- dir = SOUTH
- initialize_directions = EAST|NORTH|WEST
-
- var/obj/machinery/atmospherics/node3
-
- level = 1
- layer = 2.4 //under wires with their 2.44
-
-/obj/machinery/atmospherics/pipe/manifold/New()
- ..()
- alpha = 255
- icon = null
-
-/obj/machinery/atmospherics/pipe/manifold/init_dir()
- switch(dir)
- if(NORTH)
- initialize_directions = EAST|SOUTH|WEST
- if(SOUTH)
- initialize_directions = WEST|NORTH|EAST
- if(EAST)
- initialize_directions = SOUTH|WEST|NORTH
- if(WEST)
- initialize_directions = NORTH|EAST|SOUTH
-
-/obj/machinery/atmospherics/pipe/manifold/pipeline_expansion()
- return list(node1, node2, node3)
-
-/obj/machinery/atmospherics/pipe/manifold/Destroy()
- if(node1)
- node1.disconnect(src)
- node1 = null
- if(node2)
- node2.disconnect(src)
- node2 = null
- if(node3)
- node3.disconnect(src)
- node3 = null
-
- . = ..()
-
-/obj/machinery/atmospherics/pipe/manifold/disconnect(obj/machinery/atmospherics/reference)
- if(reference == node1)
- if(istype(node1, /obj/machinery/atmospherics/pipe))
- qdel(parent)
- node1 = null
-
- if(reference == node2)
- if(istype(node2, /obj/machinery/atmospherics/pipe))
- qdel(parent)
- node2 = null
-
- if(reference == node3)
- if(istype(node3, /obj/machinery/atmospherics/pipe))
- qdel(parent)
- node3 = null
-
- update_icon()
-
- ..()
-
-/obj/machinery/atmospherics/pipe/manifold/change_color(var/new_color)
- ..()
- //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
- if(node1)
- node1.update_underlays()
- if(node2)
- node2.update_underlays()
- if(node3)
- node3.update_underlays()
-
-/obj/machinery/atmospherics/pipe/manifold/update_icon(var/safety = 0)
- if(!check_icon_cache())
- return
-
- alpha = 255
-
- overlays.Cut()
- overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "core" + icon_connect_type)
- overlays += icon_manager.get_atmos_icon("manifold", , , "clamps" + icon_connect_type)
- underlays.Cut()
-
- var/turf/T = get_turf(src)
- var/list/directions = list(NORTH, SOUTH, EAST, WEST)
- var/node1_direction = get_dir(src, node1)
- var/node2_direction = get_dir(src, node2)
- var/node3_direction = get_dir(src, node3)
-
- directions -= dir
-
- directions -= add_underlay(T,node1,node1_direction,icon_connect_type)
- directions -= add_underlay(T,node2,node2_direction,icon_connect_type)
- directions -= add_underlay(T,node3,node3_direction,icon_connect_type)
-
- for(var/D in directions)
- add_underlay(T,,D,icon_connect_type)
-
-
-/obj/machinery/atmospherics/pipe/manifold/update_underlays()
- ..()
- update_icon()
-
-/obj/machinery/atmospherics/pipe/manifold/atmos_init()
- var/connect_directions = (NORTH|SOUTH|EAST|WEST)&(~dir)
-
- for(var/direction in cardinal)
- if(direction&connect_directions)
- for(var/obj/machinery/atmospherics/target in get_step(src,direction))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node1 = target
- connect_directions &= ~direction
- break
- if (node1)
- break
-
-
- for(var/direction in cardinal)
- if(direction&connect_directions)
- for(var/obj/machinery/atmospherics/target in get_step(src,direction))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node2 = target
- connect_directions &= ~direction
- break
- if (node2)
- break
-
-
- for(var/direction in cardinal)
- if(direction&connect_directions)
- for(var/obj/machinery/atmospherics/target in get_step(src,direction))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node3 = target
- connect_directions &= ~direction
- break
- if (node3)
- break
-
- if(!node1 && !node2 && !node3)
- qdel(src)
- return
-
- var/turf/T = get_turf(src)
- if(level == 1 && !T.is_plating()) hide(1)
- update_icon()
-
-/obj/machinery/atmospherics/pipe/manifold/visible
- icon_state = "map"
- level = 2
-
-/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers
- name="Scrubbers pipe manifold"
- desc = "A manifold composed of scrubbers pipes"
- icon_state = "map-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold/visible/supply
- name="Air supply pipe manifold"
- desc = "A manifold composed of supply pipes"
- icon_state = "map-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/manifold/visible/yellow
- color = PIPE_COLOR_YELLOW
-
-/obj/machinery/atmospherics/pipe/manifold/visible/cyan
- color = PIPE_COLOR_CYAN
-
-/obj/machinery/atmospherics/pipe/manifold/visible/green
- color = PIPE_COLOR_GREEN
-
-/obj/machinery/atmospherics/pipe/manifold/visible/black
- color = PIPE_COLOR_BLACK
-
-/obj/machinery/atmospherics/pipe/manifold/visible/red
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold/visible/blue
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/manifold/visible/purple
- color = PIPE_COLOR_PURPLE
-
-/obj/machinery/atmospherics/pipe/manifold/hidden
- icon_state = "map"
- level = 1
- alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers
- name="Scrubbers pipe manifold"
- desc = "A manifold composed of scrubbers pipes"
- icon_state = "map-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/supply
- name="Air supply pipe manifold"
- desc = "A manifold composed of supply pipes"
- icon_state = "map-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/yellow
- color = PIPE_COLOR_YELLOW
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/cyan
- color = PIPE_COLOR_CYAN
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/green
- color = PIPE_COLOR_GREEN
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/black
- color = PIPE_COLOR_BLACK
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/red
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/blue
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/purple
- color = PIPE_COLOR_PURPLE
-
-
-//
-// 4-Way Manifold Pipes - 4 way "cross" junction
-//
-/obj/machinery/atmospherics/pipe/manifold4w
- icon = 'icons/atmos/manifold.dmi'
- icon_state = ""
- name = "4-way pipe manifold"
- desc = "A manifold composed of regular pipes"
-
- volume = ATMOS_DEFAULT_VOLUME_PIPE * 2
-
- dir = SOUTH
- initialize_directions = NORTH|SOUTH|EAST|WEST
-
- var/obj/machinery/atmospherics/node3
- var/obj/machinery/atmospherics/node4
-
- level = 1
- layer = 2.4 //under wires with their 2.44
-
-/obj/machinery/atmospherics/pipe/manifold4w/New()
- ..()
- alpha = 255
- icon = null
-
-/obj/machinery/atmospherics/pipe/manifold4w/pipeline_expansion()
- return list(node1, node2, node3, node4)
-
-/obj/machinery/atmospherics/pipe/manifold4w/Destroy()
- if(node1)
- node1.disconnect(src)
- node1 = null
- if(node2)
- node2.disconnect(src)
- node2 = null
- if(node3)
- node3.disconnect(src)
- node3 = null
- if(node4)
- node4.disconnect(src)
- node4 = null
-
- . = ..()
-
-/obj/machinery/atmospherics/pipe/manifold4w/disconnect(obj/machinery/atmospherics/reference)
- if(reference == node1)
- if(istype(node1, /obj/machinery/atmospherics/pipe))
- qdel(parent)
- node1 = null
-
- if(reference == node2)
- if(istype(node2, /obj/machinery/atmospherics/pipe))
- qdel(parent)
- node2 = null
-
- if(reference == node3)
- if(istype(node3, /obj/machinery/atmospherics/pipe))
- qdel(parent)
- node3 = null
-
- if(reference == node4)
- if(istype(node4, /obj/machinery/atmospherics/pipe))
- qdel(parent)
- node4 = null
-
- update_icon()
-
- ..()
-
-/obj/machinery/atmospherics/pipe/manifold4w/change_color(var/new_color)
- ..()
- //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
- if(node1)
- node1.update_underlays()
- if(node2)
- node2.update_underlays()
- if(node3)
- node3.update_underlays()
- if(node4)
- node4.update_underlays()
-
-/obj/machinery/atmospherics/pipe/manifold4w/update_icon(var/safety = 0)
- if(!check_icon_cache())
- return
-
- alpha = 255
-
- overlays.Cut()
- overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "4way" + icon_connect_type)
- overlays += icon_manager.get_atmos_icon("manifold", , , "clamps_4way" + icon_connect_type)
- underlays.Cut()
-
- /*
- var/list/directions = list(NORTH, SOUTH, EAST, WEST)
-
-
- directions -= add_underlay(node1)
- directions -= add_underlay(node2)
- directions -= add_underlay(node3)
- directions -= add_underlay(node4)
-
- for(var/D in directions)
- add_underlay(,D)
- */
-
- var/turf/T = get_turf(src)
- var/list/directions = list(NORTH, SOUTH, EAST, WEST)
- var/node1_direction = get_dir(src, node1)
- var/node2_direction = get_dir(src, node2)
- var/node3_direction = get_dir(src, node3)
- var/node4_direction = get_dir(src, node4)
-
- directions -= dir
-
- directions -= add_underlay(T,node1,node1_direction,icon_connect_type)
- directions -= add_underlay(T,node2,node2_direction,icon_connect_type)
- directions -= add_underlay(T,node3,node3_direction,icon_connect_type)
- directions -= add_underlay(T,node4,node4_direction,icon_connect_type)
-
- for(var/D in directions)
- add_underlay(T,,D,icon_connect_type)
-
-
-/obj/machinery/atmospherics/pipe/manifold4w/update_underlays()
- ..()
- update_icon()
-
-/obj/machinery/atmospherics/pipe/manifold4w/atmos_init()
-
- for(var/obj/machinery/atmospherics/target in get_step(src,1))
- if(target.initialize_directions & 2)
- if (check_connect_types(target,src))
- node1 = target
- break
-
- for(var/obj/machinery/atmospherics/target in get_step(src,2))
- if(target.initialize_directions & 1)
- if (check_connect_types(target,src))
- node2 = target
- break
-
- for(var/obj/machinery/atmospherics/target in get_step(src,4))
- if(target.initialize_directions & 8)
- if (check_connect_types(target,src))
- node3 = target
- break
-
- for(var/obj/machinery/atmospherics/target in get_step(src,8))
- if(target.initialize_directions & 4)
- if (check_connect_types(target,src))
- node4 = target
- break
-
- if(!node1 && !node2 && !node3 && !node4)
- qdel(src)
- return
-
- var/turf/T = get_turf(src)
- if(level == 1 && !T.is_plating()) hide(1)
- update_icon()
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible
- icon_state = "map_4way"
- level = 2
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/scrubbers
- name="4-way scrubbers pipe manifold"
- desc = "A manifold composed of scrubbers pipes"
- icon_state = "map_4way-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/supply
- name="4-way air supply pipe manifold"
- desc = "A manifold composed of supply pipes"
- icon_state = "map_4way-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow
- color = PIPE_COLOR_YELLOW
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/cyan
- color = PIPE_COLOR_CYAN
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/green
- color = PIPE_COLOR_GREEN
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/black
- color = PIPE_COLOR_BLACK
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/red
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/blue
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/purple
- color = PIPE_COLOR_PURPLE
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden
- icon_state = "map_4way"
- level = 1
- alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers
- name="4-way scrubbers pipe manifold"
- desc = "A manifold composed of scrubbers pipes"
- icon_state = "map_4way-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply
- name="4-way air supply pipe manifold"
- desc = "A manifold composed of supply pipes"
- icon_state = "map_4way-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/yellow
- color = PIPE_COLOR_YELLOW
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/cyan
- color = PIPE_COLOR_CYAN
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/green
- color = PIPE_COLOR_GREEN
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/black
- color = PIPE_COLOR_BLACK
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/red
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/blue
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/purple
- color = PIPE_COLOR_PURPLE
-
-//
-// Pipe Cap - They go on the end
-//
-/obj/machinery/atmospherics/pipe/cap
- name = "pipe endcap"
- desc = "An endcap for pipes"
- icon = 'icons/atmos/pipes.dmi'
- icon_state = ""
- level = 2
- layer = 2.4 //under wires with their 2.44
-
- volume = 35
-
- dir = SOUTH
- initialize_directions = SOUTH
-
- var/obj/machinery/atmospherics/node
-
-/obj/machinery/atmospherics/pipe/cap/init_dir()
- initialize_directions = dir
-
-/obj/machinery/atmospherics/pipe/cap/pipeline_expansion()
- return list(node)
-
-/obj/machinery/atmospherics/pipe/cap/Destroy()
- if(node)
- node.disconnect(src)
- node = null
-
- . = ..()
-
-/obj/machinery/atmospherics/pipe/cap/disconnect(obj/machinery/atmospherics/reference)
- if(reference == node)
- if(istype(node, /obj/machinery/atmospherics/pipe))
- qdel(parent)
- node = null
-
- update_icon()
-
- ..()
-
-/obj/machinery/atmospherics/pipe/cap/change_color(var/new_color)
- ..()
- //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
- if(node)
- node.update_underlays()
-
-/obj/machinery/atmospherics/pipe/cap/update_icon(var/safety = 0)
- if(!check_icon_cache())
- return
-
- alpha = 255
-
- overlays.Cut()
- overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "cap")
-
-/obj/machinery/atmospherics/pipe/cap/atmos_init()
- for(var/obj/machinery/atmospherics/target in get_step(src, dir))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node = target
- break
-
- var/turf/T = src.loc // hide if turf is not intact
- if(level == 1 && !T.is_plating()) hide(1)
- update_icon()
-
-/obj/machinery/atmospherics/pipe/cap/can_unwrench()
- return 1
-
-/obj/machinery/atmospherics/pipe/cap/visible
- level = 2
- icon_state = "cap"
-
-/obj/machinery/atmospherics/pipe/cap/visible/scrubbers
- name = "scrubbers pipe endcap"
- desc = "An endcap for scrubbers pipes"
- icon_state = "cap-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/cap/visible/supply
- name = "supply pipe endcap"
- desc = "An endcap for supply pipes"
- icon_state = "cap-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/cap/hidden
- level = 1
- icon_state = "cap"
- alpha = 128
-
-/obj/machinery/atmospherics/pipe/cap/hidden/scrubbers
- name = "scrubbers pipe endcap"
- desc = "An endcap for scrubbers pipes"
- icon_state = "cap-f-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/cap/hidden/supply
- name = "supply pipe endcap"
- desc = "An endcap for supply pipes"
- icon_state = "cap-f-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-//
-// Tanks - These are implemented as pipes with large volume
-//
-/obj/machinery/atmospherics/pipe/tank
- icon = 'icons/atmos/tank_vr.dmi' //VOREStation Edit - New Icons
- icon_state = "air_map"
-
- name = "Pressure Tank"
- desc = "A large vessel containing pressurized gas."
-
- volume = 10000 //in liters, 1 meters by 1 meters by 2 meters ~tweaked it a little to simulate a pressure tank without needing to recode them yet
- var/start_pressure = 75*ONE_ATMOSPHERE //Vorestation edit
-
- level = 1
- dir = SOUTH
- initialize_directions = SOUTH
- density = 1
-
-/obj/machinery/atmospherics/pipe/tank/New()
- icon_state = "air"
- ..()
-
-/obj/machinery/atmospherics/pipe/tank/init_dir()
- initialize_directions = dir
-
-/obj/machinery/atmospherics/pipe/tank/Destroy()
- if(node1)
- node1.disconnect(src)
- node1 = null
-
- . = ..()
-
-/obj/machinery/atmospherics/pipe/tank/pipeline_expansion()
- return list(node1)
-
-/obj/machinery/atmospherics/pipe/tank/update_underlays()
- if(..())
- underlays.Cut()
- var/turf/T = get_turf(src)
- if(!istype(T))
- return
- add_underlay(T, node1, dir)
-
-/obj/machinery/atmospherics/pipe/tank/hide()
- update_underlays()
-
-/obj/machinery/atmospherics/pipe/tank/atmos_init()
- var/connect_direction = dir
-
- for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node1 = target
- break
-
- update_underlays()
-
-/obj/machinery/atmospherics/pipe/tank/disconnect(obj/machinery/atmospherics/reference)
- if(reference == node1)
- if(istype(node1, /obj/machinery/atmospherics/pipe))
- qdel(parent)
- node1 = null
-
- update_underlays()
-
- return null
-
-/obj/machinery/atmospherics/pipe/tank/attackby(var/obj/item/W as obj, var/mob/user as mob)
- if(istype(W, /obj/item/device/pipe_painter))
- return
-
- if(istype(W, /obj/item/device/analyzer) && in_range(user, src))
- var/obj/item/device/analyzer/A = W
- A.analyze_gases(src, user)
-
-/obj/machinery/atmospherics/pipe/tank/air
- name = "Pressure Tank (Air)"
- icon_state = "air_map"
-
-/obj/machinery/atmospherics/pipe/tank/air/New()
- air_temporary = new
- air_temporary.volume = volume
- air_temporary.temperature = T20C
-
- air_temporary.adjust_multi("oxygen", (start_pressure*O2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature), \
- "nitrogen",(start_pressure*N2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
-
-
- ..()
- icon_state = "air"
-
-/obj/machinery/atmospherics/pipe/tank/oxygen
- name = "Pressure Tank (Oxygen)"
- icon_state = "o2_map"
-
-/obj/machinery/atmospherics/pipe/tank/oxygen/New()
- air_temporary = new
- air_temporary.volume = volume
- air_temporary.temperature = T20C
-
- air_temporary.adjust_gas("oxygen", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
-
- ..()
- icon_state = "o2"
-
-/obj/machinery/atmospherics/pipe/tank/nitrogen
- name = "Pressure Tank (Nitrogen)"
- icon_state = "n2_map"
- volume = 40000 //Vorestation edit
-
-/obj/machinery/atmospherics/pipe/tank/nitrogen/New()
- air_temporary = new
- air_temporary.volume = volume
- air_temporary.temperature = T20C
-
- air_temporary.adjust_gas("nitrogen", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
-
- ..()
- icon_state = "n2"
-
-/obj/machinery/atmospherics/pipe/tank/carbon_dioxide
- name = "Pressure Tank (Carbon Dioxide)"
- icon_state = "co2_map"
-
-/obj/machinery/atmospherics/pipe/tank/carbon_dioxide/New()
- air_temporary = new
- air_temporary.volume = volume
- air_temporary.temperature = T20C
-
- air_temporary.adjust_gas("carbon_dioxide", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
-
- ..()
- icon_state = "co2"
-
-/obj/machinery/atmospherics/pipe/tank/phoron
- name = "Pressure Tank (Phoron)"
- icon_state = "phoron_map"
-
-/obj/machinery/atmospherics/pipe/tank/phoron/New()
- air_temporary = new
- air_temporary.volume = volume
- air_temporary.temperature = T20C
-
- air_temporary.adjust_gas("phoron", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
-
- ..()
- icon_state = "phoron"
-
-/obj/machinery/atmospherics/pipe/tank/nitrous_oxide
- name = "Pressure Tank (Nitrous Oxide)"
- icon_state = "n2o_map"
-
-/obj/machinery/atmospherics/pipe/tank/nitrous_oxide/New()
- air_temporary = new
- air_temporary.volume = volume
- air_temporary.temperature = T0C
-
- air_temporary.adjust_gas("sleeping_agent", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
-
- ..()
- icon_state = "n2o"
-
-//
-// Vent Pipe - Unpowered vent
-//
-/obj/machinery/atmospherics/pipe/vent
- icon = 'icons/obj/atmospherics/pipe_vent.dmi'
- icon_state = "intact"
-
- name = "Vent"
- desc = "A large air vent"
-
- level = 1
-
- volume = 250
-
- dir = SOUTH
- initialize_directions = SOUTH
-
- var/build_killswitch = 1
-
-/obj/machinery/atmospherics/pipe/vent/init_dir()
- initialize_directions = dir
-
-/obj/machinery/atmospherics/pipe/vent/high_volume
- name = "Larger vent"
- volume = 1000
-
-/obj/machinery/atmospherics/pipe/vent/process()
- if(!parent)
- if(build_killswitch <= 0)
- . = PROCESS_KILL
- else
- build_killswitch--
- ..()
- return
- else
- parent.mingle_with_turf(loc, volume)
-
-/obj/machinery/atmospherics/pipe/vent/Destroy()
- if(node1)
- node1.disconnect(src)
- node1 = null
-
- . = ..()
-
-/obj/machinery/atmospherics/pipe/vent/pipeline_expansion()
- return list(node1)
-
-/obj/machinery/atmospherics/pipe/vent/update_icon()
- if(node1)
- icon_state = "intact"
-
- set_dir(get_dir(src, node1))
-
- else
- icon_state = "exposed"
-
-/obj/machinery/atmospherics/pipe/vent/atmos_init()
- var/connect_direction = dir
-
- for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node1 = target
- break
-
- update_icon()
-
-/obj/machinery/atmospherics/pipe/vent/disconnect(obj/machinery/atmospherics/reference)
- if(reference == node1)
- if(istype(node1, /obj/machinery/atmospherics/pipe))
- qdel(parent)
- node1 = null
-
- update_icon()
-
- return null
-
-/obj/machinery/atmospherics/pipe/vent/hide(var/i) //to make the little pipe section invisible, the icon changes.
- if(node1)
- icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact"
- set_dir(get_dir(src, node1))
- else
- icon_state = "exposed"
-
-//
-// Universal Pipe Adapter - Designed for connecting scrubbers, normal, and supply pipes together.
-//
-/obj/machinery/atmospherics/pipe/simple/visible/universal
- name="Universal pipe adapter"
- desc = "An adapter for regular, supply and scrubbers pipes"
- connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
- icon_state = "map_universal"
-
-/obj/machinery/atmospherics/pipe/simple/visible/universal/update_icon(var/safety = 0)
- if(!check_icon_cache())
- return
-
- alpha = 255
-
- overlays.Cut()
- overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "universal")
- underlays.Cut()
-
- if (node1)
- universal_underlays(node1)
- if(node2)
- universal_underlays(node2)
- else
- var/node1_dir = get_dir(node1,src)
- universal_underlays(,node1_dir)
- else if (node2)
- universal_underlays(node2)
- else
- universal_underlays(,dir)
- universal_underlays(dir, -180)
-
-/obj/machinery/atmospherics/pipe/simple/visible/universal/update_underlays()
- ..()
- update_icon()
-
-
-
-/obj/machinery/atmospherics/pipe/simple/hidden/universal
- name="Universal pipe adapter"
- desc = "An adapter for regular, supply and scrubbers pipes"
- connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
- icon_state = "map_universal"
-
-/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_icon(var/safety = 0)
- if(!check_icon_cache())
- return
-
- alpha = 255
-
- overlays.Cut()
- overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "universal")
- underlays.Cut()
-
- if (node1)
- universal_underlays(node1)
- if(node2)
- universal_underlays(node2)
- else
- var/node2_dir = turn(get_dir(src,node1),-180)
- universal_underlays(,node2_dir)
- else if (node2)
- universal_underlays(node2)
- var/node1_dir = turn(get_dir(src,node2),-180)
- universal_underlays(,node1_dir)
- else
- universal_underlays(,dir)
- universal_underlays(,turn(dir, -180))
-
-/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_underlays()
- ..()
- update_icon()
-
-/obj/machinery/atmospherics/proc/universal_underlays(var/obj/machinery/atmospherics/node, var/direction)
- var/turf/T = loc
- if(node)
- var/node_dir = get_dir(src,node)
- if(node.icon_connect_type == "-supply")
- add_underlay_adapter(T, , node_dir, "")
- add_underlay_adapter(T, node, node_dir, "-supply")
- add_underlay_adapter(T, , node_dir, "-scrubbers")
- else if (node.icon_connect_type == "-scrubbers")
- add_underlay_adapter(T, , node_dir, "")
- add_underlay_adapter(T, , node_dir, "-supply")
- add_underlay_adapter(T, node, node_dir, "-scrubbers")
- else
- add_underlay_adapter(T, node, node_dir, "")
- add_underlay_adapter(T, , node_dir, "-supply")
- add_underlay_adapter(T, , node_dir, "-scrubbers")
- else
- add_underlay_adapter(T, , direction, "-supply")
- add_underlay_adapter(T, , direction, "-scrubbers")
- add_underlay_adapter(T, , direction, "")
-
-/obj/machinery/atmospherics/proc/add_underlay_adapter(var/turf/T, var/obj/machinery/atmospherics/node, var/direction, var/icon_connect_type) //modified from add_underlay, does not make exposed underlays
- if(node)
- if(!T.is_plating() && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
- underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type)
- else
- underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type)
- else
- underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "retracted" + icon_connect_type)
diff --git a/code/ATMOSPHERICS/pipes/cap.dm b/code/ATMOSPHERICS/pipes/cap.dm
new file mode 100644
index 0000000000..de81c60200
--- /dev/null
+++ b/code/ATMOSPHERICS/pipes/cap.dm
@@ -0,0 +1,114 @@
+//
+// Pipe Cap - They go on the end
+//
+/obj/machinery/atmospherics/pipe/cap
+ name = "pipe endcap"
+ desc = "An endcap for pipes"
+ icon = 'icons/atmos/pipes.dmi'
+ icon_state = ""
+ level = 2
+ layer = 2.4 //under wires with their 2.44
+
+ volume = 35
+
+ dir = SOUTH
+ initialize_directions = SOUTH
+
+ var/obj/machinery/atmospherics/node
+
+/obj/machinery/atmospherics/pipe/cap/init_dir()
+ initialize_directions = dir
+
+/obj/machinery/atmospherics/pipe/cap/pipeline_expansion()
+ return list(node)
+
+/obj/machinery/atmospherics/pipe/cap/Destroy()
+ if(node)
+ node.disconnect(src)
+ node = null
+
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/cap/disconnect(obj/machinery/atmospherics/reference)
+ if(reference == node)
+ if(istype(node, /obj/machinery/atmospherics/pipe))
+ qdel(parent)
+ node = null
+
+ update_icon()
+
+ ..()
+
+/obj/machinery/atmospherics/pipe/cap/change_color(var/new_color)
+ ..()
+ //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
+ if(node)
+ node.update_underlays()
+
+/obj/machinery/atmospherics/pipe/cap/update_icon(var/safety = 0)
+ if(!check_icon_cache())
+ return
+
+ alpha = 255
+
+ overlays.Cut()
+ overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "cap")
+
+/obj/machinery/atmospherics/pipe/cap/atmos_init()
+ for(var/obj/machinery/atmospherics/target in get_step(src, dir))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node = target
+ break
+
+ var/turf/T = src.loc // hide if turf is not intact
+ if(level == 1 && !T.is_plating()) hide(1)
+ update_icon()
+
+/obj/machinery/atmospherics/pipe/cap/can_unwrench()
+ return 1
+
+/obj/machinery/atmospherics/pipe/cap/visible
+ level = 2
+ icon_state = "cap"
+
+/obj/machinery/atmospherics/pipe/cap/visible/scrubbers
+ name = "scrubbers pipe endcap"
+ desc = "An endcap for scrubbers pipes"
+ icon_state = "cap-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/cap/visible/supply
+ name = "supply pipe endcap"
+ desc = "An endcap for supply pipes"
+ icon_state = "cap-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/cap/hidden
+ level = 1
+ icon_state = "cap"
+ alpha = 128
+
+/obj/machinery/atmospherics/pipe/cap/hidden/scrubbers
+ name = "scrubbers pipe endcap"
+ desc = "An endcap for scrubbers pipes"
+ icon_state = "cap-f-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/cap/hidden/supply
+ name = "supply pipe endcap"
+ desc = "An endcap for supply pipes"
+ icon_state = "cap-f-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
diff --git a/code/ATMOSPHERICS/he_pipes.dm b/code/ATMOSPHERICS/pipes/he_pipes.dm
similarity index 96%
rename from code/ATMOSPHERICS/he_pipes.dm
rename to code/ATMOSPHERICS/pipes/he_pipes.dm
index bff838cfdd..8953739a9c 100644
--- a/code/ATMOSPHERICS/he_pipes.dm
+++ b/code/ATMOSPHERICS/pipes/he_pipes.dm
@@ -1,153 +1,155 @@
-
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging
- icon = 'icons/atmos/heat.dmi'
- icon_state = "intact"
- pipe_icon = "hepipe"
- color = "#404040"
- level = 2
- connect_types = CONNECT_TYPE_HE
- layer = 2.41
- var/initialize_directions_he
- var/surface = 2 //surface area in m^2
- var/icon_temperature = T20C //stop small changes in temperature causing an icon refresh
-
- minimum_temperature_difference = 20
- thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT
-
- buckle_lying = 1
-
- // BubbleWrap
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging/New()
- ..()
-// BubbleWrap END
- color = "#404040" //we don't make use of the fancy overlay system for colours, use this to set the default.
-
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging/init_dir()
- ..()
- initialize_directions_he = initialize_directions // The auto-detection from /pipe is good enough for a simple HE pipe
-
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging/atmos_init()
- normalize_dir()
- var/node1_dir
- var/node2_dir
-
- for(var/direction in cardinal)
- if(direction&initialize_directions_he)
- if (!node1_dir)
- node1_dir = direction
- else if (!node2_dir)
- node2_dir = direction
-
- for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node1_dir))
- if(target.initialize_directions_he & get_dir(target,src))
- node1 = target
- break
- for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node2_dir))
- if(target.initialize_directions_he & get_dir(target,src))
- node2 = target
- break
- if(!node1 && !node2)
- qdel(src)
- return
-
- update_icon()
- return
-
-
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging/process()
- if(!parent)
- ..()
- else
- var/datum/gas_mixture/pipe_air = return_air()
- if(istype(loc, /turf/simulated/))
- var/environment_temperature = 0
- if(loc:blocks_air)
- environment_temperature = loc:temperature
- else
- var/datum/gas_mixture/environment = loc.return_air()
- environment_temperature = environment.temperature
- if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference)
- parent.temperature_interact(loc, volume, thermal_conductivity)
- else if(istype(loc, /turf/space/))
- parent.radiate_heat_to_space(surface, 1)
-
- if(has_buckled_mobs())
- for(var/M in buckled_mobs)
- var/mob/living/L = M
-
- var/hc = pipe_air.heat_capacity()
- var/avg_temp = (pipe_air.temperature * hc + L.bodytemperature * 3500) / (hc + 3500)
- pipe_air.temperature = avg_temp
- L.bodytemperature = avg_temp
-
- var/heat_limit = 1000
-
- var/mob/living/carbon/human/H = L
- if(istype(H) && H.species)
- heat_limit = H.species.heat_level_3
-
- if(pipe_air.temperature > heat_limit + 1)
- L.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, BP_TORSO, used_weapon = "Excessive Heat")
-
- //fancy radiation glowing
- if(pipe_air.temperature && (icon_temperature > 500 || pipe_air.temperature > 500)) //start glowing at 500K
- if(abs(pipe_air.temperature - icon_temperature) > 10)
- icon_temperature = pipe_air.temperature
-
- var/h_r = heat2color_r(icon_temperature)
- var/h_g = heat2color_g(icon_temperature)
- var/h_b = heat2color_b(icon_temperature)
-
- if(icon_temperature < 2000) //scale up overlay until 2000K
- var/scale = (icon_temperature - 500) / 1500
- h_r = 64 + (h_r - 64)*scale
- h_g = 64 + (h_g - 64)*scale
- h_b = 64 + (h_b - 64)*scale
-
- animate(src, color = rgb(h_r, h_g, h_b), time = 20, easing = SINE_EASING)
-
-
-
-
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction
- icon = 'icons/atmos/junction.dmi'
- icon_state = "intact"
- pipe_icon = "hejunction"
- level = 2
- connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_HE
- minimum_temperature_difference = 300
- thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
-
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/init_dir()
- ..()
- switch ( dir )
- if ( SOUTH )
- initialize_directions = NORTH
- initialize_directions_he = SOUTH
- if ( NORTH )
- initialize_directions = SOUTH
- initialize_directions_he = NORTH
- if ( EAST )
- initialize_directions = WEST
- initialize_directions_he = EAST
- if ( WEST )
- initialize_directions = EAST
- initialize_directions_he = WEST
-
-
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/atmos_init()
- for(var/obj/machinery/atmospherics/target in get_step(src,initialize_directions))
- if(target.initialize_directions & get_dir(target,src))
- node1 = target
- break
- for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,initialize_directions_he))
- if(target.initialize_directions_he & get_dir(target,src))
- node2 = target
- break
-
- if(!node1&&!node2)
- qdel(src)
- return
-
- update_icon()
- return
+//
+// Heat Exchanging Pipes - Behave like simple pipes
+//
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging
+ icon = 'icons/atmos/heat.dmi'
+ icon_state = "intact"
+ pipe_icon = "hepipe"
+ color = "#404040"
+ level = 2
+ connect_types = CONNECT_TYPE_HE
+ layer = 2.41
+ var/initialize_directions_he
+ var/surface = 2 //surface area in m^2
+ var/icon_temperature = T20C //stop small changes in temperature causing an icon refresh
+
+ minimum_temperature_difference = 20
+ thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT
+
+ buckle_lying = 1
+
+ // BubbleWrap
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/New()
+ ..()
+// BubbleWrap END
+ color = "#404040" //we don't make use of the fancy overlay system for colours, use this to set the default.
+
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/init_dir()
+ ..()
+ initialize_directions_he = initialize_directions // The auto-detection from /pipe is good enough for a simple HE pipe
+
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/atmos_init()
+ normalize_dir()
+ var/node1_dir
+ var/node2_dir
+
+ for(var/direction in cardinal)
+ if(direction&initialize_directions_he)
+ if (!node1_dir)
+ node1_dir = direction
+ else if (!node2_dir)
+ node2_dir = direction
+
+ for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node1_dir))
+ if(target.initialize_directions_he & get_dir(target,src))
+ node1 = target
+ break
+ for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node2_dir))
+ if(target.initialize_directions_he & get_dir(target,src))
+ node2 = target
+ break
+ if(!node1 && !node2)
+ qdel(src)
+ return
+
+ update_icon()
+ return
+
+
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/process()
+ if(!parent)
+ ..()
+ else
+ var/datum/gas_mixture/pipe_air = return_air()
+ if(istype(loc, /turf/simulated/))
+ var/environment_temperature = 0
+ if(loc:blocks_air)
+ environment_temperature = loc:temperature
+ else
+ var/datum/gas_mixture/environment = loc.return_air()
+ environment_temperature = environment.temperature
+ if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference)
+ parent.temperature_interact(loc, volume, thermal_conductivity)
+ else if(istype(loc, /turf/space/))
+ parent.radiate_heat_to_space(surface, 1)
+
+ if(has_buckled_mobs())
+ for(var/M in buckled_mobs)
+ var/mob/living/L = M
+
+ var/hc = pipe_air.heat_capacity()
+ var/avg_temp = (pipe_air.temperature * hc + L.bodytemperature * 3500) / (hc + 3500)
+ pipe_air.temperature = avg_temp
+ L.bodytemperature = avg_temp
+
+ var/heat_limit = 1000
+
+ var/mob/living/carbon/human/H = L
+ if(istype(H) && H.species)
+ heat_limit = H.species.heat_level_3
+
+ if(pipe_air.temperature > heat_limit + 1)
+ L.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, BP_TORSO, used_weapon = "Excessive Heat")
+
+ //fancy radiation glowing
+ if(pipe_air.temperature && (icon_temperature > 500 || pipe_air.temperature > 500)) //start glowing at 500K
+ if(abs(pipe_air.temperature - icon_temperature) > 10)
+ icon_temperature = pipe_air.temperature
+
+ var/h_r = heat2color_r(icon_temperature)
+ var/h_g = heat2color_g(icon_temperature)
+ var/h_b = heat2color_b(icon_temperature)
+
+ if(icon_temperature < 2000) //scale up overlay until 2000K
+ var/scale = (icon_temperature - 500) / 1500
+ h_r = 64 + (h_r - 64)*scale
+ h_g = 64 + (h_g - 64)*scale
+ h_b = 64 + (h_b - 64)*scale
+
+ animate(src, color = rgb(h_r, h_g, h_b), time = 20, easing = SINE_EASING)
+
+//
+// Heat Exchange Junction - Interfaces HE pipes to normal pipes
+//
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction
+ icon = 'icons/atmos/junction.dmi'
+ icon_state = "intact"
+ pipe_icon = "hejunction"
+ level = 2
+ connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_HE
+ minimum_temperature_difference = 300
+ thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
+
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/init_dir()
+ ..()
+ switch ( dir )
+ if ( SOUTH )
+ initialize_directions = NORTH
+ initialize_directions_he = SOUTH
+ if ( NORTH )
+ initialize_directions = SOUTH
+ initialize_directions_he = NORTH
+ if ( EAST )
+ initialize_directions = WEST
+ initialize_directions_he = EAST
+ if ( WEST )
+ initialize_directions = EAST
+ initialize_directions_he = WEST
+
+
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/atmos_init()
+ for(var/obj/machinery/atmospherics/target in get_step(src,initialize_directions))
+ if(target.initialize_directions & get_dir(target,src))
+ node1 = target
+ break
+ for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,initialize_directions_he))
+ if(target.initialize_directions_he & get_dir(target,src))
+ node2 = target
+ break
+
+ if(!node1&&!node2)
+ qdel(src)
+ return
+
+ update_icon()
+ return
diff --git a/code/ATMOSPHERICS/pipes/manifold.dm b/code/ATMOSPHERICS/pipes/manifold.dm
new file mode 100644
index 0000000000..1b9afd9c63
--- /dev/null
+++ b/code/ATMOSPHERICS/pipes/manifold.dm
@@ -0,0 +1,244 @@
+//
+// Manifold Pipes - Three way "T" joints
+//
+/obj/machinery/atmospherics/pipe/manifold
+ icon = 'icons/atmos/manifold.dmi'
+ icon_state = ""
+ name = "pipe manifold"
+ desc = "A manifold composed of regular pipes"
+
+ volume = ATMOS_DEFAULT_VOLUME_PIPE * 1.5
+
+ dir = SOUTH
+ initialize_directions = EAST|NORTH|WEST
+
+ var/obj/machinery/atmospherics/node3
+
+ level = 1
+ layer = 2.4 //under wires with their 2.44
+
+/obj/machinery/atmospherics/pipe/manifold/New()
+ ..()
+ alpha = 255
+ icon = null
+
+/obj/machinery/atmospherics/pipe/manifold/init_dir()
+ switch(dir)
+ if(NORTH)
+ initialize_directions = EAST|SOUTH|WEST
+ if(SOUTH)
+ initialize_directions = WEST|NORTH|EAST
+ if(EAST)
+ initialize_directions = SOUTH|WEST|NORTH
+ if(WEST)
+ initialize_directions = NORTH|EAST|SOUTH
+
+/obj/machinery/atmospherics/pipe/manifold/pipeline_expansion()
+ return list(node1, node2, node3)
+
+/obj/machinery/atmospherics/pipe/manifold/Destroy()
+ if(node1)
+ node1.disconnect(src)
+ node1 = null
+ if(node2)
+ node2.disconnect(src)
+ node2 = null
+ if(node3)
+ node3.disconnect(src)
+ node3 = null
+
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/manifold/disconnect(obj/machinery/atmospherics/reference)
+ if(reference == node1)
+ if(istype(node1, /obj/machinery/atmospherics/pipe))
+ qdel(parent)
+ node1 = null
+
+ if(reference == node2)
+ if(istype(node2, /obj/machinery/atmospherics/pipe))
+ qdel(parent)
+ node2 = null
+
+ if(reference == node3)
+ if(istype(node3, /obj/machinery/atmospherics/pipe))
+ qdel(parent)
+ node3 = null
+
+ update_icon()
+
+ ..()
+
+/obj/machinery/atmospherics/pipe/manifold/change_color(var/new_color)
+ ..()
+ //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
+ if(node1)
+ node1.update_underlays()
+ if(node2)
+ node2.update_underlays()
+ if(node3)
+ node3.update_underlays()
+
+/obj/machinery/atmospherics/pipe/manifold/update_icon(var/safety = 0)
+ if(!check_icon_cache())
+ return
+
+ alpha = 255
+
+ overlays.Cut()
+ overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "core" + icon_connect_type)
+ overlays += icon_manager.get_atmos_icon("manifold", , , "clamps" + icon_connect_type)
+ underlays.Cut()
+
+ var/turf/T = get_turf(src)
+ var/list/directions = list(NORTH, SOUTH, EAST, WEST)
+ var/node1_direction = get_dir(src, node1)
+ var/node2_direction = get_dir(src, node2)
+ var/node3_direction = get_dir(src, node3)
+
+ directions -= dir
+
+ directions -= add_underlay(T,node1,node1_direction,icon_connect_type)
+ directions -= add_underlay(T,node2,node2_direction,icon_connect_type)
+ directions -= add_underlay(T,node3,node3_direction,icon_connect_type)
+
+ for(var/D in directions)
+ add_underlay(T,,D,icon_connect_type)
+
+
+/obj/machinery/atmospherics/pipe/manifold/update_underlays()
+ ..()
+ update_icon()
+
+/obj/machinery/atmospherics/pipe/manifold/atmos_init()
+ var/connect_directions = (NORTH|SOUTH|EAST|WEST)&(~dir)
+
+ for(var/direction in cardinal)
+ if(direction&connect_directions)
+ for(var/obj/machinery/atmospherics/target in get_step(src,direction))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node1 = target
+ connect_directions &= ~direction
+ break
+ if (node1)
+ break
+
+
+ for(var/direction in cardinal)
+ if(direction&connect_directions)
+ for(var/obj/machinery/atmospherics/target in get_step(src,direction))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node2 = target
+ connect_directions &= ~direction
+ break
+ if (node2)
+ break
+
+
+ for(var/direction in cardinal)
+ if(direction&connect_directions)
+ for(var/obj/machinery/atmospherics/target in get_step(src,direction))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node3 = target
+ connect_directions &= ~direction
+ break
+ if (node3)
+ break
+
+ if(!node1 && !node2 && !node3)
+ qdel(src)
+ return
+
+ var/turf/T = get_turf(src)
+ if(level == 1 && !T.is_plating()) hide(1)
+ update_icon()
+
+/obj/machinery/atmospherics/pipe/manifold/visible
+ icon_state = "map"
+ level = 2
+
+/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers
+ name="Scrubbers pipe manifold"
+ desc = "A manifold composed of scrubbers pipes"
+ icon_state = "map-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold/visible/supply
+ name="Air supply pipe manifold"
+ desc = "A manifold composed of supply pipes"
+ icon_state = "map-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/manifold/visible/yellow
+ color = PIPE_COLOR_YELLOW
+
+/obj/machinery/atmospherics/pipe/manifold/visible/cyan
+ color = PIPE_COLOR_CYAN
+
+/obj/machinery/atmospherics/pipe/manifold/visible/green
+ color = PIPE_COLOR_GREEN
+
+/obj/machinery/atmospherics/pipe/manifold/visible/black
+ color = PIPE_COLOR_BLACK
+
+/obj/machinery/atmospherics/pipe/manifold/visible/red
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold/visible/blue
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/manifold/visible/purple
+ color = PIPE_COLOR_PURPLE
+
+/obj/machinery/atmospherics/pipe/manifold/hidden
+ icon_state = "map"
+ level = 1
+ alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers
+ name="Scrubbers pipe manifold"
+ desc = "A manifold composed of scrubbers pipes"
+ icon_state = "map-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/supply
+ name="Air supply pipe manifold"
+ desc = "A manifold composed of supply pipes"
+ icon_state = "map-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/yellow
+ color = PIPE_COLOR_YELLOW
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/cyan
+ color = PIPE_COLOR_CYAN
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/green
+ color = PIPE_COLOR_GREEN
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/black
+ color = PIPE_COLOR_BLACK
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/red
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/blue
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/purple
+ color = PIPE_COLOR_PURPLE
diff --git a/code/ATMOSPHERICS/pipes/manifold4w.dm b/code/ATMOSPHERICS/pipes/manifold4w.dm
new file mode 100644
index 0000000000..ba360eefd8
--- /dev/null
+++ b/code/ATMOSPHERICS/pipes/manifold4w.dm
@@ -0,0 +1,247 @@
+//
+// 4-Way Manifold Pipes - 4 way "cross" junction
+//
+/obj/machinery/atmospherics/pipe/manifold4w
+ icon = 'icons/atmos/manifold.dmi'
+ icon_state = ""
+ name = "4-way pipe manifold"
+ desc = "A manifold composed of regular pipes"
+
+ volume = ATMOS_DEFAULT_VOLUME_PIPE * 2
+
+ dir = SOUTH
+ initialize_directions = NORTH|SOUTH|EAST|WEST
+
+ var/obj/machinery/atmospherics/node3
+ var/obj/machinery/atmospherics/node4
+
+ level = 1
+ layer = 2.4 //under wires with their 2.44
+
+/obj/machinery/atmospherics/pipe/manifold4w/New()
+ ..()
+ alpha = 255
+ icon = null
+
+/obj/machinery/atmospherics/pipe/manifold4w/pipeline_expansion()
+ return list(node1, node2, node3, node4)
+
+/obj/machinery/atmospherics/pipe/manifold4w/Destroy()
+ if(node1)
+ node1.disconnect(src)
+ node1 = null
+ if(node2)
+ node2.disconnect(src)
+ node2 = null
+ if(node3)
+ node3.disconnect(src)
+ node3 = null
+ if(node4)
+ node4.disconnect(src)
+ node4 = null
+
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/manifold4w/disconnect(obj/machinery/atmospherics/reference)
+ if(reference == node1)
+ if(istype(node1, /obj/machinery/atmospherics/pipe))
+ qdel(parent)
+ node1 = null
+
+ if(reference == node2)
+ if(istype(node2, /obj/machinery/atmospherics/pipe))
+ qdel(parent)
+ node2 = null
+
+ if(reference == node3)
+ if(istype(node3, /obj/machinery/atmospherics/pipe))
+ qdel(parent)
+ node3 = null
+
+ if(reference == node4)
+ if(istype(node4, /obj/machinery/atmospherics/pipe))
+ qdel(parent)
+ node4 = null
+
+ update_icon()
+
+ ..()
+
+/obj/machinery/atmospherics/pipe/manifold4w/change_color(var/new_color)
+ ..()
+ //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
+ if(node1)
+ node1.update_underlays()
+ if(node2)
+ node2.update_underlays()
+ if(node3)
+ node3.update_underlays()
+ if(node4)
+ node4.update_underlays()
+
+/obj/machinery/atmospherics/pipe/manifold4w/update_icon(var/safety = 0)
+ if(!check_icon_cache())
+ return
+
+ alpha = 255
+
+ overlays.Cut()
+ overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "4way" + icon_connect_type)
+ overlays += icon_manager.get_atmos_icon("manifold", , , "clamps_4way" + icon_connect_type)
+ underlays.Cut()
+
+ /*
+ var/list/directions = list(NORTH, SOUTH, EAST, WEST)
+
+
+ directions -= add_underlay(node1)
+ directions -= add_underlay(node2)
+ directions -= add_underlay(node3)
+ directions -= add_underlay(node4)
+
+ for(var/D in directions)
+ add_underlay(,D)
+ */
+
+ var/turf/T = get_turf(src)
+ var/list/directions = list(NORTH, SOUTH, EAST, WEST)
+ var/node1_direction = get_dir(src, node1)
+ var/node2_direction = get_dir(src, node2)
+ var/node3_direction = get_dir(src, node3)
+ var/node4_direction = get_dir(src, node4)
+
+ directions -= dir
+
+ directions -= add_underlay(T,node1,node1_direction,icon_connect_type)
+ directions -= add_underlay(T,node2,node2_direction,icon_connect_type)
+ directions -= add_underlay(T,node3,node3_direction,icon_connect_type)
+ directions -= add_underlay(T,node4,node4_direction,icon_connect_type)
+
+ for(var/D in directions)
+ add_underlay(T,,D,icon_connect_type)
+
+
+/obj/machinery/atmospherics/pipe/manifold4w/update_underlays()
+ ..()
+ update_icon()
+
+/obj/machinery/atmospherics/pipe/manifold4w/atmos_init()
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,1))
+ if(target.initialize_directions & 2)
+ if (check_connect_types(target,src))
+ node1 = target
+ break
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,2))
+ if(target.initialize_directions & 1)
+ if (check_connect_types(target,src))
+ node2 = target
+ break
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,4))
+ if(target.initialize_directions & 8)
+ if (check_connect_types(target,src))
+ node3 = target
+ break
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,8))
+ if(target.initialize_directions & 4)
+ if (check_connect_types(target,src))
+ node4 = target
+ break
+
+ if(!node1 && !node2 && !node3 && !node4)
+ qdel(src)
+ return
+
+ var/turf/T = get_turf(src)
+ if(level == 1 && !T.is_plating()) hide(1)
+ update_icon()
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible
+ icon_state = "map_4way"
+ level = 2
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/scrubbers
+ name="4-way scrubbers pipe manifold"
+ desc = "A manifold composed of scrubbers pipes"
+ icon_state = "map_4way-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/supply
+ name="4-way air supply pipe manifold"
+ desc = "A manifold composed of supply pipes"
+ icon_state = "map_4way-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow
+ color = PIPE_COLOR_YELLOW
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/cyan
+ color = PIPE_COLOR_CYAN
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/green
+ color = PIPE_COLOR_GREEN
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/black
+ color = PIPE_COLOR_BLACK
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/red
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/blue
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/purple
+ color = PIPE_COLOR_PURPLE
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden
+ icon_state = "map_4way"
+ level = 1
+ alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers
+ name="4-way scrubbers pipe manifold"
+ desc = "A manifold composed of scrubbers pipes"
+ icon_state = "map_4way-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply
+ name="4-way air supply pipe manifold"
+ desc = "A manifold composed of supply pipes"
+ icon_state = "map_4way-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/yellow
+ color = PIPE_COLOR_YELLOW
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/cyan
+ color = PIPE_COLOR_CYAN
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/green
+ color = PIPE_COLOR_GREEN
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/black
+ color = PIPE_COLOR_BLACK
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/red
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/blue
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/purple
+ color = PIPE_COLOR_PURPLE
diff --git a/code/ATMOSPHERICS/pipes/pipe_base.dm b/code/ATMOSPHERICS/pipes/pipe_base.dm
new file mode 100644
index 0000000000..94167e01f6
--- /dev/null
+++ b/code/ATMOSPHERICS/pipes/pipe_base.dm
@@ -0,0 +1,137 @@
+//
+// Base type of pipes
+//
+/obj/machinery/atmospherics/pipe
+
+ var/datum/gas_mixture/air_temporary // used when reconstructing a pipeline that broke
+ var/datum/pipeline/parent
+ var/volume = 0
+
+ layer = 2.4 //under wires with their 2.44
+ use_power = 0
+
+ var/alert_pressure = 80*ONE_ATMOSPHERE
+ //minimum pressure before check_pressure(...) should be called
+
+ can_buckle = 1
+ buckle_require_restraints = 1
+ buckle_lying = -1
+
+/obj/machinery/atmospherics/pipe/drain_power()
+ return -1
+
+/obj/machinery/atmospherics/pipe/New()
+ if(istype(get_turf(src), /turf/simulated/wall) || istype(get_turf(src), /turf/simulated/shuttle/wall) || istype(get_turf(src), /turf/unsimulated/wall))
+ level = 1
+ ..()
+
+/obj/machinery/atmospherics/pipe/hides_under_flooring()
+ return level != 2
+
+/obj/machinery/atmospherics/pipe/proc/pipeline_expansion()
+ return null
+
+/obj/machinery/atmospherics/pipe/proc/check_pressure(pressure)
+ //Return 1 if parent should continue checking other pipes
+ //Return null if parent should stop checking other pipes. Recall: qdel(src) will by default return null
+
+ return 1
+
+/obj/machinery/atmospherics/pipe/return_air()
+ if(!parent)
+ parent = new /datum/pipeline()
+ parent.build_pipeline(src)
+
+ return parent.air
+
+/obj/machinery/atmospherics/pipe/build_network()
+ if(!parent)
+ parent = new /datum/pipeline()
+ parent.build_pipeline(src)
+
+ return parent.return_network()
+
+/obj/machinery/atmospherics/pipe/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
+ if(!parent)
+ parent = new /datum/pipeline()
+ parent.build_pipeline(src)
+
+ return parent.network_expand(new_network, reference)
+
+/obj/machinery/atmospherics/pipe/return_network(obj/machinery/atmospherics/reference)
+ if(!parent)
+ parent = new /datum/pipeline()
+ parent.build_pipeline(src)
+
+ return parent.return_network(reference)
+
+/obj/machinery/atmospherics/pipe/Destroy()
+ qdel_null(parent)
+ if(air_temporary)
+ loc.assume_air(air_temporary)
+
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
+ if (istype(src, /obj/machinery/atmospherics/pipe/tank))
+ return ..()
+
+ if(istype(W,/obj/item/device/pipe_painter))
+ return 0
+
+ if (!istype(W, /obj/item/weapon/wrench))
+ return ..()
+ var/turf/T = src.loc
+ if (level==1 && isturf(T) && !T.is_plating())
+ to_chat(user, "You must remove the plating first.")
+ return 1
+ if(!can_unwrench())
+ to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.")
+ add_fingerprint(user)
+ return 1
+ playsound(src, W.usesound, 50, 1)
+ to_chat(user, "You begin to unfasten \the [src]...")
+ if (do_after(user, 40 * W.toolspeed))
+ user.visible_message( \
+ "\The [user] unfastens \the [src].", \
+ "You have unfastened \the [src].", \
+ "You hear a ratchet.")
+ new /obj/item/pipe(loc, make_from=src)
+ for (var/obj/machinery/meter/meter in T)
+ if (meter.target == src)
+ new /obj/item/pipe_meter(T)
+ qdel(meter)
+ qdel(src)
+
+/obj/machinery/atmospherics/pipe/proc/change_color(var/new_color)
+ //only pass valid pipe colors please ~otherwise your pipe will turn invisible
+ if(!pipe_color_check(new_color))
+ return
+
+ pipe_color = new_color
+ update_icon()
+
+/obj/machinery/atmospherics/pipe/color_cache_name(var/obj/machinery/atmospherics/node)
+ if(istype(src, /obj/machinery/atmospherics/pipe/tank))
+ return ..()
+
+ if(istype(node, /obj/machinery/atmospherics/pipe/manifold) || istype(node, /obj/machinery/atmospherics/pipe/manifold4w))
+ if(pipe_color == node.pipe_color)
+ return node.pipe_color
+ else
+ return null
+ else if(istype(node, /obj/machinery/atmospherics/pipe/simple))
+ return node.pipe_color
+ else
+ return pipe_color
+
+/obj/machinery/atmospherics/pipe/hide(var/i)
+ if(istype(loc, /turf/simulated))
+ invisibility = i ? 101 : 0
+ update_icon()
+
+/obj/machinery/atmospherics/pipe/process()
+ if(!parent) //This should cut back on the overhead calling build_network thousands of times per cycle
+ ..()
+ else
+ . = PROCESS_KILL
diff --git a/code/ATMOSPHERICS/pipes/simple.dm b/code/ATMOSPHERICS/pipes/simple.dm
new file mode 100644
index 0000000000..f676c1ac38
--- /dev/null
+++ b/code/ATMOSPHERICS/pipes/simple.dm
@@ -0,0 +1,257 @@
+//
+// Simple Pipes - Just a tube, maybe bent
+//
+/obj/machinery/atmospherics/pipe/simple
+ icon = 'icons/atmos/pipes.dmi'
+ icon_state = ""
+ var/pipe_icon = "" //what kind of pipe it is and from which dmi is the icon manager getting its icons, "" for simple pipes, "hepipe" for HE pipes, "hejunction" for HE junctions
+ name = "pipe"
+ desc = "A one meter section of regular pipe"
+
+ volume = ATMOS_DEFAULT_VOLUME_PIPE
+
+ dir = SOUTH
+ initialize_directions = SOUTH|NORTH
+
+ var/minimum_temperature_difference = 300
+ var/thermal_conductivity = 0 //WALL_HEAT_TRANSFER_COEFFICIENT No
+
+ var/maximum_pressure = 70*ONE_ATMOSPHERE
+ var/fatigue_pressure = 55*ONE_ATMOSPHERE
+ alert_pressure = 55*ONE_ATMOSPHERE
+
+ level = 1
+
+/obj/machinery/atmospherics/pipe/simple/New()
+ ..()
+
+ // Pipe colors and icon states are handled by an image cache - so color and icon should
+ // be null. For mapping purposes color is defined in the object definitions.
+ icon = null
+ alpha = 255
+
+/obj/machinery/atmospherics/pipe/simple/check_pressure(pressure)
+ var/datum/gas_mixture/environment = loc.return_air()
+
+ var/pressure_difference = pressure - environment.return_pressure()
+
+ if(pressure_difference > maximum_pressure)
+ burst()
+
+ else if(pressure_difference > fatigue_pressure)
+ //TODO: leak to turf, doing pfshhhhh
+ if(prob(5))
+ burst()
+
+ else return 1
+
+/obj/machinery/atmospherics/pipe/simple/init_dir()
+ switch(dir)
+ if(SOUTH || NORTH)
+ initialize_directions = SOUTH|NORTH
+ if(EAST || WEST)
+ initialize_directions = EAST|WEST
+ if(NORTHEAST)
+ initialize_directions = NORTH|EAST
+ if(NORTHWEST)
+ initialize_directions = NORTH|WEST
+ if(SOUTHEAST)
+ initialize_directions = SOUTH|EAST
+ if(SOUTHWEST)
+ initialize_directions = SOUTH|WEST
+
+/obj/machinery/atmospherics/pipe/simple/proc/burst()
+ src.visible_message("\The [src] bursts!");
+ playsound(src.loc, 'sound/effects/bang.ogg', 25, 1)
+ var/datum/effect/effect/system/smoke_spread/smoke = new
+ smoke.set_up(1,0, src.loc, 0)
+ smoke.start()
+ qdel(src)
+
+/obj/machinery/atmospherics/pipe/simple/proc/normalize_dir()
+ if(dir==3)
+ set_dir(1)
+ else if(dir==12)
+ set_dir(4)
+
+/obj/machinery/atmospherics/pipe/simple/Destroy()
+ if(node1)
+ node1.disconnect(src)
+ node1 = null
+ if(node2)
+ node2.disconnect(src)
+ node1 = null
+
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/simple/pipeline_expansion()
+ return list(node1, node2)
+
+/obj/machinery/atmospherics/pipe/simple/change_color(var/new_color)
+ ..()
+ //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
+ if(node1)
+ node1.update_underlays()
+ if(node2)
+ node2.update_underlays()
+
+/obj/machinery/atmospherics/pipe/simple/update_icon(var/safety = 0)
+ if(!check_icon_cache())
+ return
+
+ alpha = 255
+
+ overlays.Cut()
+
+ if(node1 && node2)
+ overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "[pipe_icon]intact[icon_connect_type]")
+ else
+ overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "[pipe_icon]exposed[node1?1:0][node2?1:0][icon_connect_type]")
+
+/obj/machinery/atmospherics/pipe/simple/update_underlays()
+ return
+
+/obj/machinery/atmospherics/pipe/simple/atmos_init()
+ normalize_dir()
+ var/node1_dir
+ var/node2_dir
+
+ for(var/direction in cardinal)
+ if(direction&initialize_directions)
+ if (!node1_dir)
+ node1_dir = direction
+ else if (!node2_dir)
+ node2_dir = direction
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node1 = target
+ break
+ for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node2 = target
+ break
+
+ if(!node1 && !node2)
+ qdel(src)
+ return
+
+ var/turf/T = loc
+ if(level == 1 && !T.is_plating()) hide(1)
+ update_icon()
+
+/obj/machinery/atmospherics/pipe/simple/disconnect(obj/machinery/atmospherics/reference)
+ if(reference == node1)
+ if(istype(node1, /obj/machinery/atmospherics/pipe))
+ qdel(parent)
+ node1 = null
+
+ if(reference == node2)
+ if(istype(node2, /obj/machinery/atmospherics/pipe))
+ qdel(parent)
+ node2 = null
+
+ update_icon()
+
+ return null
+
+/obj/machinery/atmospherics/pipe/simple/visible
+ icon_state = "intact"
+ level = 2
+
+/obj/machinery/atmospherics/pipe/simple/visible/scrubbers
+ name = "Scrubbers pipe"
+ desc = "A one meter section of scrubbers pipe"
+ icon_state = "intact-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/simple/visible/supply
+ name = "Air supply pipe"
+ desc = "A one meter section of supply pipe"
+ icon_state = "intact-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/simple/visible/yellow
+ color = PIPE_COLOR_YELLOW
+
+/obj/machinery/atmospherics/pipe/simple/visible/cyan
+ color = PIPE_COLOR_CYAN
+
+/obj/machinery/atmospherics/pipe/simple/visible/green
+ color = PIPE_COLOR_GREEN
+
+/obj/machinery/atmospherics/pipe/simple/visible/black
+ color = PIPE_COLOR_BLACK
+
+/obj/machinery/atmospherics/pipe/simple/visible/red
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/simple/visible/blue
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/simple/visible/purple
+ color = PIPE_COLOR_PURPLE
+
+/obj/machinery/atmospherics/pipe/simple/hidden
+ icon_state = "intact"
+ level = 1
+ alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game
+
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers
+ name = "Scrubbers pipe"
+ desc = "A one meter section of scrubbers pipe"
+ icon_state = "intact-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/simple/hidden/supply
+ name = "Air supply pipe"
+ desc = "A one meter section of supply pipe"
+ icon_state = "intact-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/simple/hidden/yellow
+ color = PIPE_COLOR_YELLOW
+
+/obj/machinery/atmospherics/pipe/simple/hidden/cyan
+ color = PIPE_COLOR_CYAN
+
+/obj/machinery/atmospherics/pipe/simple/hidden/green
+ color = PIPE_COLOR_GREEN
+
+/obj/machinery/atmospherics/pipe/simple/hidden/black
+ color = PIPE_COLOR_BLACK
+
+/obj/machinery/atmospherics/pipe/simple/hidden/red
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/simple/hidden/blue
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/simple/hidden/purple
+ color = PIPE_COLOR_PURPLE
+
+/obj/machinery/atmospherics/pipe/simple/insulated
+ icon = 'icons/obj/atmospherics/red_pipe.dmi'
+ icon_state = "intact"
+
+ minimum_temperature_difference = 10000
+ thermal_conductivity = 0
+ maximum_pressure = 1000*ONE_ATMOSPHERE
+ fatigue_pressure = 900*ONE_ATMOSPHERE
+ alert_pressure = 900*ONE_ATMOSPHERE
+
+ level = 2
diff --git a/code/ATMOSPHERICS/pipes/tank.dm b/code/ATMOSPHERICS/pipes/tank.dm
new file mode 100644
index 0000000000..07ce8d5b71
--- /dev/null
+++ b/code/ATMOSPHERICS/pipes/tank.dm
@@ -0,0 +1,161 @@
+//
+// Tanks - These are implemented as pipes with large volume
+//
+/obj/machinery/atmospherics/pipe/tank
+ icon = 'icons/atmos/tank_vr.dmi' //VOREStation Edit - New Icons
+ icon_state = "air_map"
+
+ name = "Pressure Tank"
+ desc = "A large vessel containing pressurized gas."
+
+ volume = 10000 //in liters, 1 meters by 1 meters by 2 meters ~tweaked it a little to simulate a pressure tank without needing to recode them yet
+ var/start_pressure = 75*ONE_ATMOSPHERE //Vorestation edit
+
+ level = 1
+ dir = SOUTH
+ initialize_directions = SOUTH
+ density = 1
+
+/obj/machinery/atmospherics/pipe/tank/New()
+ icon_state = "air"
+ ..()
+
+/obj/machinery/atmospherics/pipe/tank/init_dir()
+ initialize_directions = dir
+
+/obj/machinery/atmospherics/pipe/tank/Destroy()
+ if(node1)
+ node1.disconnect(src)
+ node1 = null
+
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/tank/pipeline_expansion()
+ return list(node1)
+
+/obj/machinery/atmospherics/pipe/tank/update_underlays()
+ if(..())
+ underlays.Cut()
+ var/turf/T = get_turf(src)
+ if(!istype(T))
+ return
+ add_underlay(T, node1, dir)
+
+/obj/machinery/atmospherics/pipe/tank/hide()
+ update_underlays()
+
+/obj/machinery/atmospherics/pipe/tank/atmos_init()
+ var/connect_direction = dir
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node1 = target
+ break
+
+ update_underlays()
+
+/obj/machinery/atmospherics/pipe/tank/disconnect(obj/machinery/atmospherics/reference)
+ if(reference == node1)
+ if(istype(node1, /obj/machinery/atmospherics/pipe))
+ qdel(parent)
+ node1 = null
+
+ update_underlays()
+
+ return null
+
+/obj/machinery/atmospherics/pipe/tank/attackby(var/obj/item/W as obj, var/mob/user as mob)
+ if(istype(W, /obj/item/device/pipe_painter))
+ return
+
+ if(istype(W, /obj/item/device/analyzer) && in_range(user, src))
+ var/obj/item/device/analyzer/A = W
+ A.analyze_gases(src, user)
+
+/obj/machinery/atmospherics/pipe/tank/air
+ name = "Pressure Tank (Air)"
+ icon_state = "air_map"
+
+/obj/machinery/atmospherics/pipe/tank/air/New()
+ air_temporary = new
+ air_temporary.volume = volume
+ air_temporary.temperature = T20C
+
+ air_temporary.adjust_multi("oxygen", (start_pressure*O2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature), \
+ "nitrogen",(start_pressure*N2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
+
+
+ ..()
+ icon_state = "air"
+
+/obj/machinery/atmospherics/pipe/tank/oxygen
+ name = "Pressure Tank (Oxygen)"
+ icon_state = "o2_map"
+
+/obj/machinery/atmospherics/pipe/tank/oxygen/New()
+ air_temporary = new
+ air_temporary.volume = volume
+ air_temporary.temperature = T20C
+
+ air_temporary.adjust_gas("oxygen", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
+
+ ..()
+ icon_state = "o2"
+
+/obj/machinery/atmospherics/pipe/tank/nitrogen
+ name = "Pressure Tank (Nitrogen)"
+ icon_state = "n2_map"
+ volume = 40000 //Vorestation edit
+
+/obj/machinery/atmospherics/pipe/tank/nitrogen/New()
+ air_temporary = new
+ air_temporary.volume = volume
+ air_temporary.temperature = T20C
+
+ air_temporary.adjust_gas("nitrogen", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
+
+ ..()
+ icon_state = "n2"
+
+/obj/machinery/atmospherics/pipe/tank/carbon_dioxide
+ name = "Pressure Tank (Carbon Dioxide)"
+ icon_state = "co2_map"
+
+/obj/machinery/atmospherics/pipe/tank/carbon_dioxide/New()
+ air_temporary = new
+ air_temporary.volume = volume
+ air_temporary.temperature = T20C
+
+ air_temporary.adjust_gas("carbon_dioxide", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
+
+ ..()
+ icon_state = "co2"
+
+/obj/machinery/atmospherics/pipe/tank/phoron
+ name = "Pressure Tank (Phoron)"
+ icon_state = "phoron_map"
+
+/obj/machinery/atmospherics/pipe/tank/phoron/New()
+ air_temporary = new
+ air_temporary.volume = volume
+ air_temporary.temperature = T20C
+
+ air_temporary.adjust_gas("phoron", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
+
+ ..()
+ icon_state = "phoron"
+
+/obj/machinery/atmospherics/pipe/tank/nitrous_oxide
+ name = "Pressure Tank (Nitrous Oxide)"
+ icon_state = "n2o_map"
+
+/obj/machinery/atmospherics/pipe/tank/nitrous_oxide/New()
+ air_temporary = new
+ air_temporary.volume = volume
+ air_temporary.temperature = T0C
+
+ air_temporary.adjust_gas("sleeping_agent", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
+
+ ..()
+ icon_state = "n2o"
diff --git a/code/ATMOSPHERICS/pipes/universal.dm b/code/ATMOSPHERICS/pipes/universal.dm
new file mode 100644
index 0000000000..1017751aa1
--- /dev/null
+++ b/code/ATMOSPHERICS/pipes/universal.dm
@@ -0,0 +1,102 @@
+//
+// Universal Pipe Adapter - Designed for connecting scrubbers, normal, and supply pipes together.
+//
+/obj/machinery/atmospherics/pipe/simple/visible/universal
+ name="Universal pipe adapter"
+ desc = "An adapter for regular, supply and scrubbers pipes"
+ connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
+ icon_state = "map_universal"
+
+/obj/machinery/atmospherics/pipe/simple/visible/universal/update_icon(var/safety = 0)
+ if(!check_icon_cache())
+ return
+
+ alpha = 255
+
+ overlays.Cut()
+ overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "universal")
+ underlays.Cut()
+
+ if (node1)
+ universal_underlays(node1)
+ if(node2)
+ universal_underlays(node2)
+ else
+ var/node1_dir = get_dir(node1,src)
+ universal_underlays(,node1_dir)
+ else if (node2)
+ universal_underlays(node2)
+ else
+ universal_underlays(,dir)
+ universal_underlays(dir, -180)
+
+/obj/machinery/atmospherics/pipe/simple/visible/universal/update_underlays()
+ ..()
+ update_icon()
+
+
+
+/obj/machinery/atmospherics/pipe/simple/hidden/universal
+ name="Universal pipe adapter"
+ desc = "An adapter for regular, supply and scrubbers pipes"
+ connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
+ icon_state = "map_universal"
+
+/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_icon(var/safety = 0)
+ if(!check_icon_cache())
+ return
+
+ alpha = 255
+
+ overlays.Cut()
+ overlays += icon_manager.get_atmos_icon("pipe", , pipe_color, "universal")
+ underlays.Cut()
+
+ if (node1)
+ universal_underlays(node1)
+ if(node2)
+ universal_underlays(node2)
+ else
+ var/node2_dir = turn(get_dir(src,node1),-180)
+ universal_underlays(,node2_dir)
+ else if (node2)
+ universal_underlays(node2)
+ var/node1_dir = turn(get_dir(src,node2),-180)
+ universal_underlays(,node1_dir)
+ else
+ universal_underlays(,dir)
+ universal_underlays(,turn(dir, -180))
+
+/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_underlays()
+ ..()
+ update_icon()
+
+/obj/machinery/atmospherics/proc/universal_underlays(var/obj/machinery/atmospherics/node, var/direction)
+ var/turf/T = loc
+ if(node)
+ var/node_dir = get_dir(src,node)
+ if(node.icon_connect_type == "-supply")
+ add_underlay_adapter(T, , node_dir, "")
+ add_underlay_adapter(T, node, node_dir, "-supply")
+ add_underlay_adapter(T, , node_dir, "-scrubbers")
+ else if (node.icon_connect_type == "-scrubbers")
+ add_underlay_adapter(T, , node_dir, "")
+ add_underlay_adapter(T, , node_dir, "-supply")
+ add_underlay_adapter(T, node, node_dir, "-scrubbers")
+ else
+ add_underlay_adapter(T, node, node_dir, "")
+ add_underlay_adapter(T, , node_dir, "-supply")
+ add_underlay_adapter(T, , node_dir, "-scrubbers")
+ else
+ add_underlay_adapter(T, , direction, "-supply")
+ add_underlay_adapter(T, , direction, "-scrubbers")
+ add_underlay_adapter(T, , direction, "")
+
+/obj/machinery/atmospherics/proc/add_underlay_adapter(var/turf/T, var/obj/machinery/atmospherics/node, var/direction, var/icon_connect_type) //modified from add_underlay, does not make exposed underlays
+ if(node)
+ if(!T.is_plating() && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
+ underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type)
+ else
+ underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type)
+ else
+ underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "retracted" + icon_connect_type)
diff --git a/code/ATMOSPHERICS/pipes/vent.dm b/code/ATMOSPHERICS/pipes/vent.dm
new file mode 100644
index 0000000000..74eebb29a1
--- /dev/null
+++ b/code/ATMOSPHERICS/pipes/vent.dm
@@ -0,0 +1,83 @@
+//
+// Vent Pipe - Unpowered vent
+//
+/obj/machinery/atmospherics/pipe/vent
+ icon = 'icons/obj/atmospherics/pipe_vent.dmi'
+ icon_state = "intact"
+
+ name = "Vent"
+ desc = "A large air vent"
+
+ level = 1
+
+ volume = 250
+
+ dir = SOUTH
+ initialize_directions = SOUTH
+
+ var/build_killswitch = 1
+
+/obj/machinery/atmospherics/pipe/vent/init_dir()
+ initialize_directions = dir
+
+/obj/machinery/atmospherics/pipe/vent/high_volume
+ name = "Larger vent"
+ volume = 1000
+
+/obj/machinery/atmospherics/pipe/vent/process()
+ if(!parent)
+ if(build_killswitch <= 0)
+ . = PROCESS_KILL
+ else
+ build_killswitch--
+ ..()
+ return
+ else
+ parent.mingle_with_turf(loc, volume)
+
+/obj/machinery/atmospherics/pipe/vent/Destroy()
+ if(node1)
+ node1.disconnect(src)
+ node1 = null
+
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/vent/pipeline_expansion()
+ return list(node1)
+
+/obj/machinery/atmospherics/pipe/vent/update_icon()
+ if(node1)
+ icon_state = "intact"
+
+ set_dir(get_dir(src, node1))
+
+ else
+ icon_state = "exposed"
+
+/obj/machinery/atmospherics/pipe/vent/atmos_init()
+ var/connect_direction = dir
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node1 = target
+ break
+
+ update_icon()
+
+/obj/machinery/atmospherics/pipe/vent/disconnect(obj/machinery/atmospherics/reference)
+ if(reference == node1)
+ if(istype(node1, /obj/machinery/atmospherics/pipe))
+ qdel(parent)
+ node1 = null
+
+ update_icon()
+
+ return null
+
+/obj/machinery/atmospherics/pipe/vent/hide(var/i) //to make the little pipe section invisible, the icon changes.
+ if(node1)
+ icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact"
+ set_dir(get_dir(src, node1))
+ else
+ icon_state = "exposed"
diff --git a/code/ZAS/Turf.dm b/code/ZAS/Turf.dm
index a309cd3a08..f61d1cf4fc 100644
--- a/code/ZAS/Turf.dm
+++ b/code/ZAS/Turf.dm
@@ -6,9 +6,9 @@
/turf/simulated/proc/update_graphic(list/graphic_add = null, list/graphic_remove = null)
if(LAZYLEN(graphic_add))
- overlays += graphic_add
+ add_overlay(graphic_add, priority = TRUE)
if(LAZYLEN(graphic_remove))
- overlays -= graphic_remove
+ cut_overlay(graphic_remove, priority = TRUE)
/turf/proc/update_air_properties()
var/block = c_airblock(src)
diff --git a/code/__defines/atmos.dm b/code/__defines/atmos.dm
index bd9175aab1..13964a6f80 100644
--- a/code/__defines/atmos.dm
+++ b/code/__defines/atmos.dm
@@ -21,8 +21,6 @@
#define HUMAN_NEEDED_OXYGEN (MOLES_CELLSTANDARD * BREATH_PERCENTAGE * 0.16)
#define HUMAN_HEAT_CAPACITY 280000 //J/K For 80kg person
-#define SOUND_MINIMUM_PRESSURE 10
-
#define PRESSURE_DAMAGE_COEFFICIENT 4 // The amount of pressure damage someone takes is equal to (pressure / HAZARD_HIGH_PRESSURE)*PRESSURE_DAMAGE_COEFFICIENT, with the maximum of MAX_PRESSURE_DAMAGE.
#define MAX_HIGH_PRESSURE_DAMAGE 4 // This used to be 20... I got this much random rage for some retarded decision by polymorph?! Polymorph now lies in a pool of blood with a katana jammed in his spleen. ~Errorage --PS: The katana did less than 20 damage to him :(
#define LOW_PRESSURE_DAMAGE 2 // The amount of damage someone takes when in a low pressure area. (The pressure threshold is so low that it doesn't make sense to do any calculations, so it just applies this flat value).
diff --git a/code/__defines/sound.dm b/code/__defines/sound.dm
new file mode 100644
index 0000000000..6fae2fadcb
--- /dev/null
+++ b/code/__defines/sound.dm
@@ -0,0 +1,56 @@
+//max channel is 1024. Only go lower from here, because byond tends to pick the first availiable channel to play sounds on
+#define CHANNEL_LOBBYMUSIC 1024
+#define CHANNEL_ADMIN 1023
+#define CHANNEL_VOX 1022
+#define CHANNEL_JUKEBOX 1021
+#define CHANNEL_HEARTBEAT 1020 //sound channel for heartbeats
+#define CHANNEL_AMBIENCE_FORCED 1019
+#define CHANNEL_AMBIENCE 1018
+#define CHANNEL_BUZZ 1017
+#define CHANNEL_BICYCLE 1016
+
+//THIS SHOULD ALWAYS BE THE LOWEST ONE!
+//KEEP IT UPDATED
+
+#define CHANNEL_HIGHEST_AVAILABLE 1015
+
+#define SOUND_MINIMUM_PRESSURE 10
+#define FALLOFF_SOUNDS 0.5
+
+//Sound environment defines. Reverb preset for sounds played in an area, see sound datum reference for more.
+#define GENERIC 0
+#define PADDED_CELL 1
+#define ROOM 2
+#define BATHROOM 3
+#define LIVINGROOM 4
+#define STONEROOM 5
+#define AUDITORIUM 6
+#define CONCERT_HALL 7
+#define CAVE 8
+#define ARENA 9
+#define HANGAR 10
+#define CARPETED_HALLWAY 11
+#define HALLWAY 12
+#define STONE_CORRIDOR 13
+#define ALLEY 14
+#define FOREST 15
+#define CITY 16
+#define MOUNTAINS 17
+#define QUARRY 18
+#define PLAIN 19
+#define PARKING_LOT 20
+#define SEWER_PIPE 21
+#define UNDERWATER 22
+#define DRUGGED 23
+#define DIZZY 24
+#define PSYCHOTIC 25
+
+#define STANDARD_STATION STONEROOM
+#define LARGE_ENCLOSED HANGAR
+#define SMALL_ENCLOSED BATHROOM
+#define TUNNEL_ENCLOSED CAVE
+#define LARGE_SOFTFLOOR CARPETED_HALLWAY
+#define MEDIUM_SOFTFLOOR LIVINGROOM
+#define SMALL_SOFTFLOOR ROOM
+#define ASTEROID CAVE
+#define SPACE UNDERWATER
diff --git a/code/__defines/species_languages.dm b/code/__defines/species_languages.dm
index 5cfb5f37d0..cf60bbc602 100644
--- a/code/__defines/species_languages.dm
+++ b/code/__defines/species_languages.dm
@@ -45,6 +45,9 @@
#define LANGUAGE_OCCULT "Occult"
#define LANGUAGE_CHANGELING "Changeling"
#define LANGUAGE_VOX "Vox-Pidgin"
+#define LANGUAGE_TERMINUS "Terminus"
+#define LANGUAGE_SKRELLIANFAR "High Skrellian"
+#define LANGUAGE_MINBUS "Minbus"
// Language flags.
#define WHITELISTED 1 // Language is available if the speaker is whitelisted.
diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm
index b11cd33d32..11a22d5938 100644
--- a/code/_helpers/unsorted.dm
+++ b/code/_helpers/unsorted.dm
@@ -803,7 +803,6 @@ proc/GaussRandRound(var/sigma,var/roundto)
var/old_dir1 = T.dir
var/old_icon_state1 = T.icon_state
var/old_icon1 = T.icon
- var/old_overlays = T.overlays.Copy()
var/old_underlays = T.underlays.Copy()
var/old_decals = T.decals ? T.decals.Copy() : null
@@ -811,11 +810,9 @@ proc/GaussRandRound(var/sigma,var/roundto)
X.set_dir(old_dir1)
X.icon_state = old_icon_state1
X.icon = old_icon1
- X.overlays = old_overlays
+ X.copy_overlays(T, TRUE)
X.underlays = old_underlays
X.decals = old_decals
- if(old_decals)
- X.apply_decals()
//Move the air from source to dest
var/turf/simulated/ST = T
@@ -841,14 +838,10 @@ proc/GaussRandRound(var/sigma,var/roundto)
if(shuttlework)
var/turf/simulated/shuttle/SS = T
SS.landed_holder.leave_turf()
-
else if(turftoleave)
T.ChangeTurf(turftoleave)
- T.apply_decals()
-
else
T.ChangeTurf(get_base_turf_by_area(T))
- T.apply_decals()
refined_src -= T
refined_trg -= B
diff --git a/code/_macros_vr.dm b/code/_macros_vr.dm
new file mode 100644
index 0000000000..daa1123574
--- /dev/null
+++ b/code/_macros_vr.dm
@@ -0,0 +1,2 @@
+#define isbelly(A) istype(A, /obj/belly)
+#define isstorage(A) istype(A, /obj/item/weapon/storage)
\ No newline at end of file
diff --git a/code/controllers/subsystems/bellies_vr.dm b/code/controllers/subsystems/bellies_vr.dm
new file mode 100644
index 0000000000..faaa297ca3
--- /dev/null
+++ b/code/controllers/subsystems/bellies_vr.dm
@@ -0,0 +1,41 @@
+#define SSBELLIES_PROCESSED 1
+#define SSBELLIES_IGNORED 2
+
+//
+// Bellies subsystem - Process vore bellies
+//
+
+SUBSYSTEM_DEF(bellies)
+ name = "Bellies"
+ priority = 5
+ wait = 1 SECONDS
+ flags = SS_KEEP_TIMING|SS_NO_INIT
+ runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME
+
+ var/static/list/belly_list = list()
+ var/list/currentrun = list()
+ var/ignored_bellies = 0
+
+/datum/controller/subsystem/bellies/stat_entry()
+ ..("#: [belly_list.len] | P: [ignored_bellies]")
+
+/datum/controller/subsystem/bellies/fire(resumed = 0)
+ if (!resumed)
+ ignored_bellies = 0
+ src.currentrun = belly_list.Copy()
+
+ //cache for sanic speed (lists are references anyways)
+ var/list/currentrun = src.currentrun
+ var/times_fired = src.times_fired
+ while(currentrun.len)
+ var/obj/belly/B = currentrun[currentrun.len]
+ currentrun.len--
+
+ if(QDELETED(B))
+ belly_list -= B
+ else
+ if(B.process_belly(times_fired,wait) == SSBELLIES_IGNORED)
+ ignored_bellies++
+
+ if (MC_TICK_CHECK)
+ return
diff --git a/code/controllers/subsystems/floor_decals.dm b/code/controllers/subsystems/floor_decals.dm
deleted file mode 100644
index 39e4515d0d..0000000000
--- a/code/controllers/subsystems/floor_decals.dm
+++ /dev/null
@@ -1,28 +0,0 @@
-//
-// Floor Decals Initialization Subsystem
-// This is part of the giant decal hack that works around a BYOND bug where DreamDaemon will crash if you
-// update overlays on turfs too much.
-// The master_controller on Polaris used to init decals prior to initializing areas (which initilized turfs)
-// Now that we switched to subsystems we still want to do the same thing, so this takes care of it.
-//
-SUBSYSTEM_DEF(floor_decals)
- name = "Floor Decals"
- init_order = INIT_ORDER_DECALS
- flags = SS_NO_FIRE
-
-/datum/controller/subsystem/floor_decals/Initialize(timeofday)
- if(floor_decals_initialized)
- return ..()
- to_world_log("Initializing Floor Decals")
- admin_notice("Initializing Floor Decals", R_DEBUG)
- var/list/turfs_with_decals = list()
- for(var/obj/effect/floor_decal/D in world)
- var/T = D.add_to_turf_decals()
- if(T) turfs_with_decals |= T
- CHECK_TICK
- for(var/item in turfs_with_decals)
- var/turf/T = item
- if(T.decals) T.apply_decals()
- CHECK_TICK
- floor_decals_initialized = TRUE
- return ..()
diff --git a/code/controllers/subsystems/overlays.dm b/code/controllers/subsystems/overlays.dm
index 6d7581e126..352102e175 100644
--- a/code/controllers/subsystems/overlays.dm
+++ b/code/controllers/subsystems/overlays.dm
@@ -11,6 +11,8 @@ SUBSYSTEM_DEF(overlays)
var/list/overlay_icon_state_caches // Cache thing
var/list/overlay_icon_cache // Cache thing
+var/global/image/appearance_bro = new() // Temporarily super-global because of BYOND init order dumbness.
+
/datum/controller/subsystem/overlays/PreInit()
overlay_icon_state_caches = list()
overlay_icon_cache = list()
@@ -90,7 +92,7 @@ SUBSYSTEM_DEF(overlays)
icon_cache[icon] = .
/atom/proc/build_appearance_list(old_overlays)
- var/static/image/appearance_bro = new()
+ // var/static/image/appearance_bro = new() // Moved to be superglobal due to BYOND insane init order stupidness.
var/list/new_overlays = list()
if (!islist(old_overlays))
old_overlays = list(old_overlays)
diff --git a/code/controllers/subsystems/transcore_vr.dm b/code/controllers/subsystems/transcore_vr.dm
index f98bf6d2c0..4958d87f3d 100644
--- a/code/controllers/subsystems/transcore_vr.dm
+++ b/code/controllers/subsystems/transcore_vr.dm
@@ -152,9 +152,7 @@ SUBSYSTEM_DEF(transcore)
// Send a past-due notification to the medical radio channel.
/datum/controller/subsystem/transcore/proc/notify(var/name)
ASSERT(name)
- var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset/heads/captain(null)
- a.autosay("[name] is past-due for a mind backup. This will be the only notification.", "TransCore Oversight", "Medical")
- qdel(a)
+ global_announcer.autosay("[name] is past-due for a mind backup. This will be the only notification.", "TransCore Oversight", "Medical")
// Called from mind_record to add itself to the transcore.
/datum/controller/subsystem/transcore/proc/add_backup(var/datum/transhuman/mind_record/MR)
@@ -187,10 +185,8 @@ SUBSYSTEM_DEF(transcore)
// Moves all mind records from the databaes into the disk and shuts down all backup canary processing.
/datum/controller/subsystem/transcore/proc/core_dump(var/obj/item/weapon/disk/transcore/disk)
ASSERT(disk)
- var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset/heads/captain(null)
- a.autosay("An emergency core dump has been initiated!", "TransCore Oversight", "Command")
- a.autosay("An emergency core dump has been initiated!", "TransCore Oversight", "Medical")
- qdel(a)
+ global_announcer.autosay("An emergency core dump has been initiated!", "TransCore Oversight", "Command")
+ global_announcer.autosay("An emergency core dump has been initiated!", "TransCore Oversight", "Medical")
disk.stored += backed_up
backed_up.Cut()
diff --git a/code/datums/helper_datums/teleport_vr.dm b/code/datums/helper_datums/teleport_vr.dm
index cbae240cff..1cb73d6ad9 100644
--- a/code/datums/helper_datums/teleport_vr.dm
+++ b/code/datums/helper_datums/teleport_vr.dm
@@ -1,22 +1,13 @@
/datum/teleport/proc/try_televore()
- var/datum/belly/target_belly
-
- //Destination is a living thing
- target_belly = check_belly(destination)
-
- //Destination has a living thing on it
- if(!target_belly)
- for(var/mob/living/M in get_turf(destination))
- if(M.vore_organs.len)
- var/I = M.vore_organs[1]
- target_belly = M.vore_organs[I]
-
- if(target_belly)
- teleatom.forceMove(destination.loc)
+ //Destination is in a belly
+ if(isbelly(destination.loc))
+ var/obj/belly/B = destination.loc
+
+ teleatom.forceMove(get_turf(B)) //So we can splash the sound and sparks and everything.
playSpecials(destination,effectout,soundout)
- target_belly.internal_contents |= teleatom
- playsound(destination, target_belly.vore_sound, 100, 1)
+ teleatom.forceMove(B)
return 1
//No fun!
- return 0
\ No newline at end of file
+ return 0
+
\ No newline at end of file
diff --git a/code/datums/supplypacks/robotics.dm b/code/datums/supplypacks/robotics.dm
index 3e861e354b..d9f20c5aa6 100644
--- a/code/datums/supplypacks/robotics.dm
+++ b/code/datums/supplypacks/robotics.dm
@@ -116,14 +116,6 @@
containername = "Robolimb blueprints (Bishop)"
access = access_robotics
-/datum/supply_packs/robotics/robolimbs/veymed
- name = "Vey-Med robolimb blueprints"
- contains = list(/obj/item/weapon/disk/limb/veymed)
- cost = 70
- containertype = /obj/structure/closet/crate/secure/science
- containername = "Robolimb blueprints (Vey-Med)"
- access = access_robotics
-
/datum/supply_packs/robotics/mecha_ripley
name = "Circuit Crate (\"Ripley\" APLU)"
contains = list(
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index ae21bf8093..0902bd3871 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -260,26 +260,26 @@ var/list/mob/living/forced_ambiance_list = new
// If we previously were in an area with force-played ambiance, stop it.
if(L in forced_ambiance_list)
- L << sound(null, channel = 1)
+ L << sound(null, channel = CHANNEL_AMBIENCE_FORCED)
forced_ambiance_list -= L
if(!L.client.ambience_playing)
L.client.ambience_playing = 1
- L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = 2)
+ L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_AMBIENCE)
if(forced_ambience)
if(forced_ambience.len)
forced_ambiance_list |= L
var/sound/chosen_ambiance = pick(forced_ambience)
if(!istype(chosen_ambiance))
- chosen_ambiance = sound(chosen_ambiance, repeat = 1, wait = 0, volume = 25, channel = 1)
+ chosen_ambiance = sound(chosen_ambiance, repeat = 1, wait = 0, volume = 25, channel = CHANNEL_AMBIENCE_FORCED)
L << chosen_ambiance
else
L << sound(null, channel = 1)
else if(src.ambience.len && prob(35))
if((world.time >= L.client.played + 600))
var/sound = pick(ambience)
- L << sound(sound, repeat = 0, wait = 0, volume = 25, channel = 1)
+ L << sound(sound, repeat = 0, wait = 0, volume = 25, channel = CHANNEL_AMBIENCE)
L.client.played = world.time
/area/proc/gravitychange(var/gravitystate = 0, var/area/A)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 0cd09b8a57..3ae19b1e4f 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -296,3 +296,7 @@
/atom/movable/proc/adjust_scale(new_scale)
icon_scale = new_scale
update_transform()
+
+// Stub for now, override with better things.
+/atom/movable/proc/drop_location()
+ return loc
\ No newline at end of file
diff --git a/code/game/machinery/adv_med_vr.dm b/code/game/machinery/adv_med_vr.dm
index 68185bcf46..6c11b6cf34 100644
--- a/code/game/machinery/adv_med_vr.dm
+++ b/code/game/machinery/adv_med_vr.dm
@@ -12,9 +12,9 @@
var/livingprey = 0
var/objectprey = 0
- for(var/I in H.vore_organs)
- var/datum/belly/B = H.vore_organs[I]
- for(var/C in B.internal_contents)
+ for(var/belly in H.vore_organs)
+ var/obj/belly/B = belly
+ for(var/C in B)
if(ishuman(C))
humanprey++
else if(isliving(C))
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index 76eafc2a05..6a435ef388 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -824,7 +824,7 @@ FIRE ALARM
alarms_hidden = TRUE
/obj/machinery/firealarm/update_icon()
- overlays.Cut()
+ cut_overlays()
if(panel_open)
set_light(0)
@@ -847,8 +847,7 @@ FIRE ALARM
if("blue") set_light(l_range = 2, l_power = 0.5, l_color = "#1024A9")
if("red") set_light(l_range = 4, l_power = 2, l_color = "#ff0000")
if("delta") set_light(l_range = 4, l_power = 2, l_color = "#FF6633")
-
- overlays += image('icons/obj/monitors.dmi', "overlay_[seclevel]")
+ add_overlay("overlay_[seclevel]")
/obj/machinery/firealarm/fire_act(datum/gas_mixture/air, temperature, volume)
if(detecting)
diff --git a/code/game/machinery/kitchen/gibber.dm b/code/game/machinery/kitchen/gibber.dm
index 9b6b503237..ceea16ec3b 100644
--- a/code/game/machinery/kitchen/gibber.dm
+++ b/code/game/machinery/kitchen/gibber.dm
@@ -225,13 +225,12 @@
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
operating = 0
- for (var/obj/thing in contents)
- // Todo: unify limbs and internal organs
+ for (var/obj/item/thing in contents)
// There's a chance that the gibber will fail to destroy some evidence.
- if((istype(thing,/obj/item/organ) || istype(thing,/obj/item/organ)) && prob(80))
+ if(istype(thing,/obj/item/organ) && prob(80))
qdel(thing)
continue
- thing.loc = get_turf(thing) // Drop it onto the turf for throwing.
+ thing.forceMove(get_turf(thing)) // Drop it onto the turf for throwing.
thing.throw_at(get_edge_target_turf(src,gib_throw_dir),rand(0,3),emagged ? 100 : 50) // Being pelted with bits of meat and bone would hurt.
update_icon()
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index b5e98dab70..3b05f4e27c 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -1112,8 +1112,8 @@
/obj/item/toy/plushie/kitten = 2,
/obj/item/toy/plushie/lizard = 2,
/obj/item/toy/plushie/spider = 2,
- /obj/item/toy/plushie/farwa = 2)
- // /obj/item/weapon/storage/trinketbox = 2 (readding later due to conflict)
+ /obj/item/toy/plushie/farwa = 2,
+ /obj/item/weapon/storage/trinketbox = 2)
prices = list(/obj/item/weapon/storage/fancy/heartbox = 15,
/obj/item/toy/bouquet = 10,
/obj/item/toy/bouquet/fake = 3,
diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm
index ef4e196309..eb3ac7cb12 100644
--- a/code/game/objects/items/devices/radio/intercom.dm
+++ b/code/game/objects/items/devices/radio/intercom.dm
@@ -50,6 +50,12 @@
name = "entertainment intercom"
frequency = ENT_FREQ
+/obj/item/device/radio/intercom/omni
+ name = "global announcer"
+/obj/item/device/radio/intercom/omni/initialize()
+ channels = radiochannels.Copy()
+ return ..()
+
/obj/item/device/radio/intercom/New()
..()
processing_objects += src
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 89f10c8140..d408a033f7 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -53,14 +53,13 @@ var/global/list/default_medbay_channels = list(
var/const/FREQ_LISTENING = 1
var/list/internal_channels
-/obj/item/device/radio
var/datum/radio_frequency/radio_connection
var/list/datum/radio_frequency/secure_radio_connections = new
- proc/set_frequency(new_frequency)
- radio_controller.remove_object(src, frequency)
- frequency = new_frequency
- radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT)
+/obj/item/device/radio/proc/set_frequency(new_frequency)
+ radio_controller.remove_object(src, frequency)
+ frequency = new_frequency
+ radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT)
/obj/item/device/radio/New()
..()
diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index 225ac96012..f10767a49c 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -213,8 +213,10 @@
R.add_language(LANGUAGE_UNATHI, 1)
R.add_language(LANGUAGE_SIIK, 1)
R.add_language(LANGUAGE_SKRELLIAN, 1)
+ R.add_language(LANGUAGE_SKRELLIANFAR, 0)
R.add_language(LANGUAGE_GUTTER, 1)
R.add_language(LANGUAGE_SCHECHI, 1)
R.add_language(LANGUAGE_ROOTLOCAL, 1)
+ R.add_language(LANGUAGE_TERMINUS, 1)
return 1
diff --git a/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm b/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm
index b3605c6b1f..256d2c8582 100644
--- a/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm
+++ b/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm
@@ -10,7 +10,7 @@
/obj/fiftyspawner/wood/sif
name = "stack of alien wood"
- type_to_spawn = /obj/item/stack/tile/sifwood
+ type_to_spawn = /obj/item/stack/tile/wood/sif
/obj/fiftyspawner/carpet
name = "stack of carpet"
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index f31a3a6edf..bc93d20bb5 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -37,9 +37,6 @@
flags = 0
origin_tech = list(TECH_BIO = 1)
no_variants = FALSE
-
-/obj/item/stack/tile/grass/fifty
- amount = 50
/*
* Wood
*/
@@ -55,23 +52,11 @@
flags = 0
no_variants = FALSE
-/obj/item/stack/tile/sifwood
+/obj/item/stack/tile/wood/sif
name = "alien wood tile"
singular_name = "alien wood tile"
desc = "An easy to fit wooden floor tile. It's blue!"
icon_state = "tile-sifwood"
- force = 1.0
- throwforce = 1.0
- throw_speed = 5
- throw_range = 20
- flags = 0
- no_variants = FALSE
-
-/obj/item/stack/tile/wood/fifty
- amount = 50
-
-/obj/item/stack/tile/sifwood/fifty
- amount = 50
/obj/item/stack/tile/wood/cyborg
name = "wood floor tile synthesizer"
diff --git a/code/game/objects/items/trash_vr.dm b/code/game/objects/items/trash_vr.dm
index 38c434b973..942b571aa5 100644
--- a/code/game/objects/items/trash_vr.dm
+++ b/code/game/objects/items/trash_vr.dm
@@ -12,10 +12,7 @@
if(H.species.trashcan == 1)
playsound(H.loc,'sound/items/eatfood.ogg', rand(10,50), 1)
user.drop_item()
- var/belly = H.vore_selected
- var/datum/belly/selected = H.vore_organs[belly]
- forceMove(H)
- selected.internal_contents |= src
+ forceMove(H.vore_selected)
to_chat(H, "You can taste the flavor of garbage. Wait what?")
return
@@ -24,10 +21,7 @@
if(R.module.type == /obj/item/weapon/robot_module/robot/scrubpup) // You can now feed the trash borg yay.
playsound(R.loc,'sound/items/eatfood.ogg', rand(10,50), 1)
user.drop_item()
- var/belly = R.vore_selected
- var/datum/belly/selected = R.vore_organs[belly]
- forceMove(R)
- selected.internal_contents |= src // Too many hoops and obstacles to stick it into the sleeper module.
+ forceMove(R.vore_selected)
R.visible_message("[user] feeds [R] with [src]!")
return
..()
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm
index 84a17ac9d1..64d6252a2f 100644
--- a/code/game/objects/items/weapons/storage/boxes.dm
+++ b/code/game/objects/items/weapons/storage/boxes.dm
@@ -96,7 +96,8 @@
name = "box of syringes"
desc = "A box full of syringes."
icon_state = "syringe"
- starts_with = list(/obj/item/weapon/reagent_containers/syringe = 7)
+ can_hold = list(/obj/item/weapon/reagent_containers/syringe) //VOREStation Edit
+ starts_with = list(/obj/item/weapon/reagent_containers/syringe = 20) //VOREStation Edit
/obj/item/weapon/storage/box/syringegun
name = "box of syringe gun cartridges"
diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm
index 6bddb28769..799169bad5 100644
--- a/code/game/objects/items/weapons/storage/storage.dm
+++ b/code/game/objects/items/weapons/storage/storage.dm
@@ -674,7 +674,6 @@
/*
* Trinket Box - READDING SOON
*/
-/*
/obj/item/weapon/storage/trinketbox
name = "trinket box"
desc = "A box that can hold small trinkets, such as a ring."
@@ -724,5 +723,4 @@
..()
if(open && contents.len)
var/display_item = contents[1]
- to_chat(user, "\The [src] contains \the [display_item]!")
- */
\ No newline at end of file
+ to_chat(user, "\The [src] contains \the [display_item]!")
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/syndie.dm b/code/game/objects/items/weapons/syndie.dm
index 5406b05a26..3ba85b0bfc 100644
--- a/code/game/objects/items/weapons/syndie.dm
+++ b/code/game/objects/items/weapons/syndie.dm
@@ -13,9 +13,9 @@
desc = "A small wrapped package."
w_class = ITEMSIZE_NORMAL
- var/devastate = 0
- var/heavy_impact = 1
- var/light_impact = 2
+ var/devastate = 1
+ var/heavy_impact = 2
+ var/light_impact = 4
var/flash_range = 5
var/size = "small" /*Used for the icon, this one will make c-4small_0 for the off state.*/
@@ -24,7 +24,7 @@
item_state = "radio"
desc = "A mysterious package, it's quite heavy."
devastate = 1
- heavy_impact = 2
+ heavy_impact = 3
light_impact = 5
flash_range = 7
size = "large"
diff --git a/code/game/objects/random/random_vr.dm b/code/game/objects/random/random_vr.dm
index 7b7b25379f..2a68c1496f 100644
--- a/code/game/objects/random/random_vr.dm
+++ b/code/game/objects/random/random_vr.dm
@@ -199,3 +199,11 @@
T = get_step_rand(this_mob) || T
if(T)
this_mob.forceMove(T)
+
+//Just overriding this here, no more super medkit so those can be reserved for PoIs and such
+/obj/random/firstaid/item_to_spawn()
+ return pick(prob(4);/obj/item/weapon/storage/firstaid/regular,
+ prob(3);/obj/item/weapon/storage/firstaid/toxin,
+ prob(3);/obj/item/weapon/storage/firstaid/o2,
+ prob(2);/obj/item/weapon/storage/firstaid/adv,
+ prob(3);/obj/item/weapon/storage/firstaid/fire)
diff --git a/code/game/objects/structures/crates_lockers/closets/egg_vr.dm b/code/game/objects/structures/crates_lockers/closets/egg_vr.dm
index d1c37221cf..b47a49c4b5 100644
--- a/code/game/objects/structures/crates_lockers/closets/egg_vr.dm
+++ b/code/game/objects/structures/crates_lockers/closets/egg_vr.dm
@@ -18,13 +18,6 @@
src.dump_contents()
qdel(src)
-/obj/structure/closet/secure_closet/egg/dump_contents()
- var/datum/belly/belly = check_belly(src)
- if(belly)
- for(var/atom/movable/M in src)
- belly.internal_contents |= M
- return ..()
-
/obj/structure/closet/secure_closet/egg/unathi
name = "unathi egg"
desc = "Some species of Unathi apparently lay soft-shelled eggs!"
diff --git a/code/game/sound.dm b/code/game/sound.dm
index 0a440db1c4..12d0e5ed8c 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -1,107 +1,50 @@
-//Sound environment defines. Reverb preset for sounds played in an area, see sound datum reference for more.
-#define GENERIC 0
-#define PADDED_CELL 1
-#define ROOM 2
-#define BATHROOM 3
-#define LIVINGROOM 4
-#define STONEROOM 5
-#define AUDITORIUM 6
-#define CONCERT_HALL 7
-#define CAVE 8
-#define ARENA 9
-#define HANGAR 10
-#define CARPETED_HALLWAY 11
-#define HALLWAY 12
-#define STONE_CORRIDOR 13
-#define ALLEY 14
-#define FOREST 15
-#define CITY 16
-#define MOUNTAINS 17
-#define QUARRY 18
-#define PLAIN 19
-#define PARKING_LOT 20
-#define SEWER_PIPE 21
-#define UNDERWATER 22
-#define DRUGGED 23
-#define DIZZY 24
-#define PSYCHOTIC 25
-
-#define STANDARD_STATION STONEROOM
-#define LARGE_ENCLOSED HANGAR
-#define SMALL_ENCLOSED BATHROOM
-#define TUNNEL_ENCLOSED CAVE
-#define LARGE_SOFTFLOOR CARPETED_HALLWAY
-#define MEDIUM_SOFTFLOOR LIVINGROOM
-#define SMALL_SOFTFLOOR ROOM
-#define ASTEROID CAVE
-#define SPACE UNDERWATER
-
-var/list/shatter_sound = list('sound/effects/Glassbr1.ogg','sound/effects/Glassbr2.ogg','sound/effects/Glassbr3.ogg')
-var/list/explosion_sound = list('sound/effects/Explosion1.ogg','sound/effects/Explosion2.ogg','sound/effects/Explosion3.ogg','sound/effects/Explosion4.ogg','sound/effects/Explosion5.ogg','sound/effects/Explosion6.ogg')
-var/list/spark_sound = list('sound/effects/sparks1.ogg','sound/effects/sparks2.ogg','sound/effects/sparks3.ogg','sound/effects/sparks5.ogg','sound/effects/sparks6.ogg','sound/effects/sparks7.ogg')
-var/list/rustle_sound = list('sound/effects/rustle1.ogg','sound/effects/rustle2.ogg','sound/effects/rustle3.ogg','sound/effects/rustle4.ogg','sound/effects/rustle5.ogg')
-var/list/punch_sound = list('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg')
-var/list/clown_sound = list('sound/effects/clownstep1.ogg','sound/effects/clownstep2.ogg')
-var/list/swing_hit_sound = list('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg')
-var/list/hiss_sound = list('sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg')
-var/list/page_sound = list('sound/effects/pageturn1.ogg', 'sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg')
-var/list/fracture_sound = list('sound/effects/bonebreak1.ogg','sound/effects/bonebreak2.ogg','sound/effects/bonebreak3.ogg','sound/effects/bonebreak4.ogg')
-var/list/casing_sound = list ('sound/weapons/casingfall1.ogg','sound/weapons/casingfall2.ogg','sound/weapons/casingfall3.ogg')
-var/list/keyboard_sound = list ('sound/effects/keyboard/keyboard1.ogg','sound/effects/keyboard/keyboard2.ogg','sound/effects/keyboard/keyboard3.ogg', 'sound/effects/keyboard/keyboard4.ogg')
-var/list/mechstep_sound = list('sound/mecha/mechstep1.ogg', 'sound/mecha/mechstep2.ogg')
-var/list/bodyfall_sound = list('sound/effects/bodyfall1.ogg','sound/effects/bodyfall2.ogg','sound/effects/bodyfall3.ogg','sound/effects/bodyfall4.ogg')
-var/list/can_sound = list('sound/effects/can_open1.ogg','sound/effects/can_open2.ogg','sound/effects/can_open3.ogg','sound/effects/can_open4.ogg')
-var/list/geiger_sound = list('sound/items/geiger1.ogg', 'sound/items/geiger2.ogg', 'sound/items/geiger3.ogg', 'sound/items/geiger4.ogg', 'sound/items/geiger5.ogg')
-var/list/geiger_weak_sound = list('sound/items/geiger_weak1.ogg', 'sound/items/geiger_weak2.ogg', 'sound/items/geiger_weak3.ogg', 'sound/items/geiger_weak4.ogg')
-
-//var/list/gun_sound = list('sound/weapons/Gunshot.ogg', 'sound/weapons/Gunshot2.ogg','sound/weapons/Gunshot3.ogg','sound/weapons/Gunshot4.ogg')
-
-/proc/playsound(var/atom/source, soundin, vol as num, vary, extrarange as num, falloff, var/is_global, var/frequency)
-
- soundin = get_sfx(soundin) // same sound for everyone
-
+/proc/playsound(atom/source, soundin, vol as num, vary, extrarange as num, falloff, is_global, frequency = null, channel = 0, pressure_affected = TRUE, ignore_walls = TRUE, preference = null)
if(isarea(source))
- error("[source] is an area and is trying to make the sound: [soundin]")
+ throw EXCEPTION("playsound(): source is an area")
return
- frequency = isnull(frequency) ? get_rand_frequency() : frequency // Same frequency for everybody
var/turf/turf_source = get_turf(source)
+ //allocate a channel if necessary now so its the same for everyone
+ channel = channel || open_sound_channel()
+
// Looping through the player list has the added bonus of working for mobs inside containers
- for (var/P in player_list)
+ var/sound/S = sound(get_sfx(soundin))
+ var/maxdistance = (world.view + extrarange) * 3
+ var/list/listeners = player_list
+ if(!ignore_walls) //these sounds don't carry through walls
+ listeners = listeners & hearers(maxdistance,turf_source)
+ for(var/P in listeners)
var/mob/M = P
if(!M || !M.client)
continue
+ var/turf/T = get_turf(M)
+ var/distance = get_dist(T, turf_source)
- var/distance = get_dist(M, turf_source)
- if(distance <= (world.view + extrarange) * 3)
- var/turf/T = get_turf(M)
-
+ if(distance <= maxdistance)
if(T && T.z == turf_source.z)
- M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, is_global)
+ M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, is_global, channel, pressure_affected, S)
-var/const/FALLOFF_SOUNDS = 0.5
+/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff, is_global, channel = 0, pressure_affected = TRUE, sound/S, preference)
+ if(!client || ear_deaf > 0)
+ return
+ if(preference && !client.is_preference_enabled(preference))
+ return
-/mob/proc/playsound_local(var/turf/turf_source, soundin, vol as num, vary, frequency, falloff, is_global)
- if(!src.client || ear_deaf > 0) return
- soundin = get_sfx(soundin)
+ if(!S)
+ S = sound(get_sfx(soundin))
- var/sound/S = sound(soundin)
S.wait = 0 //No queue
- S.channel = 0 //Any channel
+ S.channel = channel || open_sound_channel()
S.volume = vol
- S.environment = -1
- if (vary)
+
+ if(vary)
if(frequency)
S.frequency = frequency
else
S.frequency = get_rand_frequency()
- //sound volume falloff with pressure
- var/pressure_factor = 1.0
-
if(isturf(turf_source))
- // 3D sounds, the technology is here!
var/turf/T = get_turf(src)
//sound volume falloff with distance
@@ -109,24 +52,32 @@ var/const/FALLOFF_SOUNDS = 0.5
S.volume -= max(distance - world.view, 0) * 2 //multiplicative falloff to add on top of natural audio falloff.
- var/datum/gas_mixture/hearer_env = T.return_air()
- var/datum/gas_mixture/source_env = turf_source.return_air()
+ //Atmosphere affects sound
+ var/pressure_factor = 1
+ if(pressure_affected)
+ var/datum/gas_mixture/hearer_env = T.return_air()
+ var/datum/gas_mixture/source_env = turf_source.return_air()
- if (hearer_env && source_env)
- var/pressure = min(hearer_env.return_pressure(), source_env.return_pressure())
+ if(hearer_env && source_env)
+ var/pressure = min(hearer_env.return_pressure(), source_env.return_pressure())
+ if(pressure < ONE_ATMOSPHERE)
+ pressure_factor = max((pressure - SOUND_MINIMUM_PRESSURE)/(ONE_ATMOSPHERE - SOUND_MINIMUM_PRESSURE), 0)
+ else //space
+ pressure_factor = 0
- if (pressure < ONE_ATMOSPHERE)
- pressure_factor = max((pressure - SOUND_MINIMUM_PRESSURE)/(ONE_ATMOSPHERE - SOUND_MINIMUM_PRESSURE), 0)
- else //in space
- pressure_factor = 0
+ if(distance <= 1)
+ pressure_factor = max(pressure_factor, 0.15) //touching the source of the sound
- if (distance <= 1)
- pressure_factor = max(pressure_factor, 0.15) //hearing through contact
+ S.volume *= pressure_factor
+ //End Atmosphere affecting sound
- S.volume *= pressure_factor
+ //Don't bother with doing anything below.
+ if(S.volume <= 0)
+ return //No sound
- if (S.volume <= 0)
- return //no volume means no sound
+ //Apply a sound environment.
+ if(!is_global)
+ S.environment = get_sound_env(pressure_factor)
var/dx = turf_source.x - T.x // Hearing from the right/left
S.x = dx
@@ -136,34 +87,27 @@ var/const/FALLOFF_SOUNDS = 0.5
S.y = 1
S.falloff = (falloff ? falloff : FALLOFF_SOUNDS)
- if(!is_global)
-
- if(istype(src,/mob/living/))
- var/mob/living/M = src
- if (M.hallucination)
- S.environment = PSYCHOTIC
- else if (M.druggy)
- S.environment = DRUGGED
- else if (M.drowsyness)
- S.environment = DIZZY
- else if (M.confused)
- S.environment = DIZZY
- else if (M.sleeping)
- S.environment = UNDERWATER
- else if (pressure_factor < 0.5)
- S.environment = SPACE
- else
- var/area/A = get_area(src)
- S.environment = A.sound_env
-
- else if (pressure_factor < 0.5)
- S.environment = SPACE
- else
- var/area/A = get_area(src)
- S.environment = A.sound_env
-
src << S
+/proc/sound_to_playing_players(sound, volume = 100, vary)
+ sound = get_sfx(sound)
+ for(var/M in player_list)
+ if(ismob(M) && !isnewplayer(M))
+ var/mob/MO = M
+ MO.playsound_local(get_turf(MO), sound, volume, vary, pressure_affected = FALSE)
+
+/proc/open_sound_channel()
+ var/static/next_channel = 1 //loop through the available 1024 - (the ones we reserve) channels and pray that its not still being used
+ . = ++next_channel
+ if(next_channel > CHANNEL_HIGHEST_AVAILABLE)
+ next_channel = 1
+
+/mob/proc/stop_sound_channel(chan)
+ src << sound(null, repeat = 0, wait = 0, channel = chan)
+
+/proc/get_rand_frequency()
+ return rand(32000, 55000) //Frequency stuff only works with 45kbps oggs.
+
/client/proc/playtitlemusic()
if(!ticker || !all_lobby_tracks.len || !media) return
if(is_preference_enabled(/datum/client_preference/play_lobby_music))
@@ -171,25 +115,26 @@ var/const/FALLOFF_SOUNDS = 0.5
media.push_music(T.url, world.time, 0.85)
to_chat(src,"Lobby music: [T.title] by [T.artist].")
-/proc/get_rand_frequency()
- return rand(32000, 55000) //Frequency stuff only works with 45kbps oggs.
-
/proc/get_sfx(soundin)
if(istext(soundin))
switch(soundin)
- if ("shatter") soundin = pick(shatter_sound)
- if ("explosion") soundin = pick(explosion_sound)
- if ("sparks") soundin = pick(spark_sound)
- if ("rustle") soundin = pick(rustle_sound)
- if ("punch") soundin = pick(punch_sound)
- if ("clownstep") soundin = pick(clown_sound)
- if ("swing_hit") soundin = pick(swing_hit_sound)
- if ("hiss") soundin = pick(hiss_sound)
- if ("pageturn") soundin = pick(page_sound)
- if ("fracture") soundin = pick(fracture_sound)
- if ("canopen") soundin = pick(can_sound)
- if ("mechstep") soundin = pick(mechstep_sound)
- //if ("gunshot") soundin = pick(gun_sound)
- if("geiger") soundin = pick(geiger_sound)
- if("geiger_weak") soundin = pick(geiger_weak_sound)
+ if ("shatter") soundin = pick('sound/effects/Glassbr1.ogg','sound/effects/Glassbr2.ogg','sound/effects/Glassbr3.ogg')
+ if ("explosion") soundin = pick('sound/effects/Explosion1.ogg','sound/effects/Explosion2.ogg','sound/effects/Explosion3.ogg','sound/effects/Explosion4.ogg','sound/effects/Explosion5.ogg','sound/effects/Explosion6.ogg')
+ if ("sparks") soundin = pick('sound/effects/sparks1.ogg','sound/effects/sparks2.ogg','sound/effects/sparks3.ogg','sound/effects/sparks5.ogg','sound/effects/sparks6.ogg','sound/effects/sparks7.ogg')
+ if ("rustle") soundin = pick('sound/effects/rustle1.ogg','sound/effects/rustle2.ogg','sound/effects/rustle3.ogg','sound/effects/rustle4.ogg','sound/effects/rustle5.ogg')
+ if ("punch") soundin = pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg')
+ if ("clownstep") soundin = pick('sound/effects/clownstep1.ogg','sound/effects/clownstep2.ogg')
+ if ("swing_hit") soundin = pick('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg')
+ if ("hiss") soundin = pick('sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg')
+ if ("pageturn") soundin = pick('sound/effects/pageturn1.ogg', 'sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg')
+ if ("fracture") soundin = pick('sound/effects/bonebreak1.ogg','sound/effects/bonebreak2.ogg','sound/effects/bonebreak3.ogg','sound/effects/bonebreak4.ogg')
+ if ("canopen") soundin = pick('sound/effects/can_open1.ogg','sound/effects/can_open2.ogg','sound/effects/can_open3.ogg','sound/effects/can_open4.ogg')
+ if ("mechstep") soundin = pick('sound/mecha/mechstep1.ogg', 'sound/mecha/mechstep2.ogg')
+ if ("geiger") soundin = pick('sound/items/geiger1.ogg', 'sound/items/geiger2.ogg', 'sound/items/geiger3.ogg', 'sound/items/geiger4.ogg', 'sound/items/geiger5.ogg')
+ if ("geiger_weak") soundin = pick('sound/items/geiger_weak1.ogg', 'sound/items/geiger_weak2.ogg', 'sound/items/geiger_weak3.ogg', 'sound/items/geiger_weak4.ogg')
return soundin
+
+//Are these even used?
+var/list/casing_sound = list ('sound/weapons/casingfall1.ogg','sound/weapons/casingfall2.ogg','sound/weapons/casingfall3.ogg')
+var/list/keyboard_sound = list ('sound/effects/keyboard/keyboard1.ogg','sound/effects/keyboard/keyboard2.ogg','sound/effects/keyboard/keyboard3.ogg', 'sound/effects/keyboard/keyboard4.ogg')
+var/list/bodyfall_sound = list('sound/effects/bodyfall1.ogg','sound/effects/bodyfall2.ogg','sound/effects/bodyfall3.ogg','sound/effects/bodyfall4.ogg')
diff --git a/code/game/turfs/flooring/flooring.dm b/code/game/turfs/flooring/flooring.dm
index e7d3ff5926..1affecf04f 100644
--- a/code/game/turfs/flooring/flooring.dm
+++ b/code/game/turfs/flooring/flooring.dm
@@ -1,5 +1,10 @@
var/list/flooring_types
+/proc/populate_flooring_types()
+ flooring_types = list()
+ for (var/flooring_path in typesof(/decl/flooring))
+ flooring_types["[flooring_path]"] = new flooring_path
+
/proc/get_flooring_data(var/flooring_path)
if(!flooring_types)
flooring_types = list()
@@ -285,22 +290,12 @@ var/list/flooring_types
'sound/effects/footstep/wood4.ogg',
'sound/effects/footstep/wood5.ogg'))
-/decl/flooring/sifwood
+/decl/flooring/wood/sif
name = "alien wooden floor"
desc = "Polished alien wood planks."
icon = 'icons/turf/flooring/wood.dmi'
icon_base = "sifwood"
- has_damage_range = 6
- damage_temperature = T0C+200
- descriptor = "planks"
- build_type = /obj/item/stack/tile/sifwood
- flags = TURF_CAN_BREAK | TURF_IS_FRAGILE | TURF_REMOVE_SCREWDRIVER
- footstep_sounds = list("human" = list(
- 'sound/effects/footstep/wood1.ogg',
- 'sound/effects/footstep/wood2.ogg',
- 'sound/effects/footstep/wood3.ogg',
- 'sound/effects/footstep/wood4.ogg',
- 'sound/effects/footstep/wood5.ogg'))
+ build_type = /obj/item/stack/tile/wood/sif
/decl/flooring/reinforced
name = "reinforced floor"
diff --git a/code/game/turfs/flooring/flooring_decals.dm b/code/game/turfs/flooring/flooring_decals.dm
index 84a243e35f..ea9a7f77fb 100644
--- a/code/game/turfs/flooring/flooring_decals.dm
+++ b/code/game/turfs/flooring/flooring_decals.dm
@@ -14,17 +14,29 @@ var/list/floor_decals = list()
if(newcolour) color = newcolour
..(newloc)
-// Hack to workaround byond crash bug
/obj/effect/floor_decal/initialize()
- if(!floor_decals_initialized || !loc || QDELETED(src))
- return
add_to_turf_decals()
- var/turf/T = get_turf(src)
- if(T) //VOREStation Edit
- T.apply_decals()
initialized = TRUE
return INITIALIZE_HINT_QDEL
+// This is a separate proc from initialize() to facilitiate its caching and other stuff. Look into it someday.
+/obj/effect/floor_decal/proc/add_to_turf_decals()
+ if(supplied_dir)
+ set_dir(supplied_dir) // TODO - Why can't this line be done in initialize/New()?
+ var/turf/T = get_turf(src)
+ if(istype(T, /turf/simulated/floor) || istype(T, /turf/unsimulated/floor) || istype(T, /turf/simulated/shuttle/floor))
+ var/cache_key = "[alpha]-[color]-[dir]-[icon_state]-[T.layer]"
+ var/image/I = floor_decals[cache_key]
+ if(!I)
+ I = image(icon = icon, icon_state = icon_state, dir = dir)
+ I.layer = T.layer
+ I.color = color
+ I.alpha = alpha
+ floor_decals[cache_key] = I
+ LAZYADD(T.decals, I) // Add to its decals list (so it remembers to re-apply after it cuts overlays)
+ T.add_overlay(I) // Add to its current overlays too.
+ return T
+
/obj/effect/floor_decal/reset
name = "reset marker"
diff --git a/code/game/turfs/flooring/flooring_premade.dm b/code/game/turfs/flooring/flooring_premade.dm
index cde55e50e3..106ba48422 100644
--- a/code/game/turfs/flooring/flooring_premade.dm
+++ b/code/game/turfs/flooring/flooring_premade.dm
@@ -68,11 +68,11 @@
icon_state = "wood"
initial_flooring = /decl/flooring/wood
-/turf/simulated/floor/sifwood
+/turf/simulated/floor/wood/sif
name = "alien wooden floor"
icon = 'icons/turf/flooring/wood.dmi'
icon_state = "sifwood"
- initial_flooring = /decl/flooring/sifwood
+ initial_flooring = /decl/flooring/wood/sif
/turf/simulated/floor/grass
name = "grass patch"
@@ -230,9 +230,8 @@
oxygen = 0
nitrogen = 0
-/turf/simulated/floor/reinforced/n20/New()
- ..()
- sleep(-1)
+/turf/simulated/floor/reinforced/n20/initialize()
+ . = ..()
if(!air) make_air()
air.adjust_gas("sleeping_agent", ATMOSTANK_NITROUSOXIDE)
@@ -412,11 +411,11 @@
. = ..()
/turf/snow/update_icon()
- overlays.Cut()
+ cut_overlays()
for(var/d in crossed_dirs)
var/amt = crossed_dirs[d]
for(var/i in 1 to amt)
- overlays += icon(icon, "footprint[i]", text2num(d))
+ add_overlay(image(icon, "footprint[i]", text2num(d)))
//**** Here ends snow ****
\ No newline at end of file
diff --git a/code/game/turfs/flooring/turf_overlay_holder.dm b/code/game/turfs/flooring/turf_overlay_holder.dm
deleted file mode 100644
index c12f727a0b..0000000000
--- a/code/game/turfs/flooring/turf_overlay_holder.dm
+++ /dev/null
@@ -1,95 +0,0 @@
-//
-// Initialize floor decals! Woo! This is crazy.
-//
-
-var/global/floor_decals_initialized = FALSE
-
-// The Turf Decal Holder
-// Since it is unsafe to add overlays to turfs, we hold them here for now.
-// Since I want this object to basically not exist, I am modeling it in part after lighting_overlay
-/atom/movable/turf_overlay_holder
- name = "turf overlay holder"
- density = 0
- simulated = 0
- anchored = 1
- layer = TURF_LAYER
- icon = null
- icon_state = null
- mouse_opacity = 0
- // auto_init = 0
-
-/atom/movable/turf_overlay_holder/initialize()
- // doesn't need special init
- initialized = TRUE
- return INITIALIZE_HINT_NORMAL
-
-/atom/movable/turf_overlay_holder/New(var/atom/newloc)
- ..()
- verbs.Cut()
- var/turf/T = loc
- T.overlay_holder = src
-
-/atom/movable/turf_overlay_holder/Destroy()
- if(loc)
- var/turf/T = loc
- if(T.overlay_holder == src)
- T.overlay_holder = null
- . = ..()
-
-// Variety of overrides so the overlays don't get affected by weird things.
-/atom/movable/turf_overlay_holder/ex_act()
- return
-
-/atom/movable/turf_overlay_holder/singularity_act()
- return
-
-/atom/movable/turf_overlay_holder/singularity_pull()
- return
-
-/atom/movable/turf_overlay_holder/forceMove()
- return 0 //should never move
-
-/atom/movable/turf_overlay_holder/Move()
- return 0
-
-/atom/movable/turf_overlay_holder/throw_at()
- return 0
-
-/obj/effect/floor_decal/proc/add_to_turf_decals()
- if(src.supplied_dir) src.set_dir(src.supplied_dir)
- var/turf/T = get_turf(src)
- if(istype(T, /turf/simulated/floor) || istype(T, /turf/unsimulated/floor) || istype(T, /turf/simulated/shuttle/floor))
- var/cache_key = "[src.alpha]-[src.color]-[src.dir]-[src.icon_state]-[T.layer]"
- var/image/I = floor_decals[cache_key]
- if(!I)
- I = image(icon = src.icon, icon_state = src.icon_state, dir = src.dir)
- I.layer = T.layer
- I.color = src.color
- I.alpha = src.alpha
- floor_decals[cache_key] = I
- if(!T.decals) T.decals = list()
- //world.log << "About to add img:\ref[I] onto decals at turf:\ref[T] ([T.x],[T.y],[T.z]) which has appearance:\ref[T.appearance] and decals.len=[T.decals.len]"
- T.decals += I
- return T
- // qdel(D)
- src.loc = null
- src.tag = null
-
-// Changes to turf to let us do this
-/turf
- var/atom/movable/turf_overlay_holder/overlay_holder = null
-
-// After a turf change, destroy the old overlay holder since we will have lost access to it.
-/turf/post_change()
- var/atom/movable/turf_overlay_holder/TOH = locate(/atom/movable/turf_overlay_holder, src)
- if(TOH)
- qdel(TOH)
- ..()
-
-/turf/proc/apply_decals()
- if(decals)
- if(!overlay_holder)
- overlay_holder = new(src)
- overlay_holder.overlays = src.decals
- else if(overlay_holder)
- overlay_holder.overlays.Cut()
diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm
index 789ec20a17..e156588937 100644
--- a/code/game/turfs/simulated.dm
+++ b/code/game/turfs/simulated.dm
@@ -21,16 +21,15 @@
spawn(0)
wet = wet_val
if(wet_overlay)
- overlays -= wet_overlay
- wet_overlay = null
- wet_overlay = image('icons/effects/water.dmi',src,"wet_floor")
- overlays += wet_overlay
+ cut_overlay(wet_overlay)
+ wet_overlay = image('icons/effects/water.dmi', icon_state = "wet_floor")
+ add_overlay(wet_overlay)
sleep(800)
if(wet == 2)
sleep(3200)
wet = 0
if(wet_overlay)
- overlays -= wet_overlay
+ cut_overlay(wet_overlay)
wet_overlay = null
/turf/simulated/proc/freeze_floor()
@@ -38,14 +37,14 @@
return
wet = 3 // icy
if(wet_overlay)
- overlays -= wet_overlay
+ cut_overlay(wet_overlay)
wet_overlay = null
wet_overlay = image('icons/turf/overlays.dmi',src,"snowfloor")
- overlays += wet_overlay
+ add_overlay(wet_overlay)
spawn(5 MINUTES)
wet = 0
if(wet_overlay)
- overlays -= wet_overlay
+ cut_overlay(wet_overlay)
wet_overlay = null
/turf/simulated/clean_blood()
diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm
index f906335819..9f3a8e67b0 100644
--- a/code/game/turfs/simulated/floor.dm
+++ b/code/game/turfs/simulated/floor.dm
@@ -60,7 +60,7 @@
//This proc auto corrects the grass tiles' siding.
/turf/simulated/floor/proc/make_plating(var/place_product, var/defer_icon_update)
- overlays.Cut()
+ cut_overlays()
// VOREStation Edit - We are flooring switching to plating, swap out old_decals for decals.
if(flooring)
var/tmp/list/underfloor_decals = old_decals
diff --git a/code/game/turfs/simulated/floor_attackby.dm b/code/game/turfs/simulated/floor_attackby.dm
index ef36121b12..5602eac320 100644
--- a/code/game/turfs/simulated/floor_attackby.dm
+++ b/code/game/turfs/simulated/floor_attackby.dm
@@ -4,40 +4,15 @@
return 0
if(flooring)
- if(istype(C, /obj/item/weapon/crowbar))
- if(broken || burnt)
- to_chat(user, "You remove the broken [flooring.descriptor].")
- make_plating()
- else if(flooring.flags & TURF_IS_FRAGILE)
- to_chat(user, "You forcefully pry off the [flooring.descriptor], destroying them in the process.")
- make_plating()
- else if(flooring.flags & TURF_REMOVE_CROWBAR)
- to_chat(user, "You lever off the [flooring.descriptor].")
- make_plating(1)
- else
- return
- playsound(src, C.usesound, 80, 1)
- return
- else if(istype(C, /obj/item/weapon/screwdriver) && (flooring.flags & TURF_REMOVE_SCREWDRIVER))
- if(broken || burnt)
- return
- to_chat(user, "You unscrew and remove the [flooring.descriptor].")
- make_plating(1)
- playsound(src, C.usesound, 80, 1)
- return
- else if(istype(C, /obj/item/weapon/wrench) && (flooring.flags & TURF_REMOVE_WRENCH))
- to_chat(user, "You unwrench and remove the [flooring.descriptor].")
- make_plating(1)
- playsound(src, C.usesound, 80, 1)
- return
- else if(istype(C, /obj/item/weapon/shovel) && (flooring.flags & TURF_REMOVE_SHOVEL))
- to_chat(user, "You shovel off the [flooring.descriptor].")
- make_plating(1)
- playsound(src, 'sound/items/Deconstruct.ogg', 80, 1)
+ if(istype(C, /obj/item/weapon))
+ try_deconstruct_tile(C, user)
return
else if(istype(C, /obj/item/stack/cable_coil))
to_chat(user, "You must remove the [flooring.descriptor] first.")
return
+ else if(istype(C, /obj/item/stack/tile))
+ try_replace_tile(C, user)
+ return
else
if(istype(C, /obj/item/stack/cable_coil))
@@ -87,4 +62,48 @@
burnt = null
broken = null
else
- to_chat(user, "You need more welding fuel to complete this task.")
\ No newline at end of file
+ to_chat(user, "You need more welding fuel to complete this task.")
+
+/turf/simulated/floor/proc/try_deconstruct_tile(obj/item/weapon/W as obj, mob/user as mob)
+ if(istype(W, /obj/item/weapon/crowbar))
+ if(broken || burnt)
+ to_chat(user, "You remove the broken [flooring.descriptor].")
+ make_plating()
+ else if(flooring.flags & TURF_IS_FRAGILE)
+ to_chat(user, "You forcefully pry off the [flooring.descriptor], destroying them in the process.")
+ make_plating()
+ else if(flooring.flags & TURF_REMOVE_CROWBAR)
+ to_chat(user, "You lever off the [flooring.descriptor].")
+ make_plating(1)
+ else
+ return 0
+ playsound(src, W.usesound, 80, 1)
+ return 1
+ else if(istype(W, /obj/item/weapon/screwdriver) && (flooring.flags & TURF_REMOVE_SCREWDRIVER))
+ if(broken || burnt)
+ return 0
+ to_chat(user, "You unscrew and remove the [flooring.descriptor].")
+ make_plating(1)
+ playsound(src, W.usesound, 80, 1)
+ return 1
+ else if(istype(W, /obj/item/weapon/wrench) && (flooring.flags & TURF_REMOVE_WRENCH))
+ to_chat(user, "You unwrench and remove the [flooring.descriptor].")
+ make_plating(1)
+ playsound(src, W.usesound, 80, 1)
+ return 1
+ else if(istype(W, /obj/item/weapon/shovel) && (flooring.flags & TURF_REMOVE_SHOVEL))
+ to_chat(user, "You shovel off the [flooring.descriptor].")
+ make_plating(1)
+ playsound(src, 'sound/items/Deconstruct.ogg', 80, 1)
+ return 1
+ return 0
+
+/turf/simulated/floor/proc/try_replace_tile(obj/item/stack/tile/T as obj, mob/user as mob)
+ if(T.type == flooring.build_type)
+ return
+ var/obj/item/weapon/W = user.is_holding_item_of_type(/obj/item/weapon)
+ if(!try_deconstruct_tile(W, user))
+ return
+ if(flooring)
+ return
+ attackby(T, user)
\ No newline at end of file
diff --git a/code/game/turfs/simulated/floor_icon.dm b/code/game/turfs/simulated/floor_icon.dm
index 940a170cdb..1faf198ced 100644
--- a/code/game/turfs/simulated/floor_icon.dm
+++ b/code/game/turfs/simulated/floor_icon.dm
@@ -15,7 +15,7 @@ var/image/no_ceiling_image = null
if(lava)
return
- overlays.Cut()
+ cut_overlays()
if(flooring)
// Set initial icon and strings.
@@ -38,17 +38,17 @@ var/image/no_ceiling_image = null
var/turf/simulated/floor/T = get_step(src, step_dir)
if(!istype(T) || !T.flooring || T.flooring.name != flooring.name)
has_border |= step_dir
- overlays |= get_flooring_overlay("[flooring.icon_base]-edge-[step_dir]", "[flooring.icon_base]_edges", step_dir)
+ add_overlay(get_flooring_overlay("[flooring.icon_base]-edge-[step_dir]", "[flooring.icon_base]_edges", step_dir))
// There has to be a concise numerical way to do this but I am too noob.
if((has_border & NORTH) && (has_border & EAST))
- overlays |= get_flooring_overlay("[flooring.icon_base]-edge-[NORTHEAST]", "[flooring.icon_base]_edges", NORTHEAST)
+ add_overlay(get_flooring_overlay("[flooring.icon_base]-edge-[NORTHEAST]", "[flooring.icon_base]_edges", NORTHEAST))
if((has_border & NORTH) && (has_border & WEST))
- overlays |= get_flooring_overlay("[flooring.icon_base]-edge-[NORTHWEST]", "[flooring.icon_base]_edges", NORTHWEST)
+ add_overlay(get_flooring_overlay("[flooring.icon_base]-edge-[NORTHWEST]", "[flooring.icon_base]_edges", NORTHWEST))
if((has_border & SOUTH) && (has_border & EAST))
- overlays |= get_flooring_overlay("[flooring.icon_base]-edge-[SOUTHEAST]", "[flooring.icon_base]_edges", SOUTHEAST)
+ add_overlay(get_flooring_overlay("[flooring.icon_base]-edge-[SOUTHEAST]", "[flooring.icon_base]_edges", SOUTHEAST))
if((has_border & SOUTH) && (has_border & WEST))
- overlays |= get_flooring_overlay("[flooring.icon_base]-edge-[SOUTHWEST]", "[flooring.icon_base]_edges", SOUTHWEST)
+ add_overlay(get_flooring_overlay("[flooring.icon_base]-edge-[SOUTHWEST]", "[flooring.icon_base]_edges", SOUTHWEST))
if(flooring.flags & TURF_HAS_CORNERS)
// As above re: concise numerical way to do this.
@@ -56,37 +56,36 @@ var/image/no_ceiling_image = null
if(!(has_border & EAST))
var/turf/simulated/floor/T = get_step(src, NORTHEAST)
if(!(istype(T) && T.flooring && T.flooring.name == flooring.name))
- overlays |= get_flooring_overlay("[flooring.icon_base]-corner-[NORTHEAST]", "[flooring.icon_base]_corners", NORTHEAST)
+ add_overlay(get_flooring_overlay("[flooring.icon_base]-corner-[NORTHEAST]", "[flooring.icon_base]_corners", NORTHEAST))
if(!(has_border & WEST))
var/turf/simulated/floor/T = get_step(src, NORTHWEST)
if(!(istype(T) && T.flooring && T.flooring.name == flooring.name))
- overlays |= get_flooring_overlay("[flooring.icon_base]-corner-[NORTHWEST]", "[flooring.icon_base]_corners", NORTHWEST)
+ add_overlay(get_flooring_overlay("[flooring.icon_base]-corner-[NORTHWEST]", "[flooring.icon_base]_corners", NORTHWEST))
if(!(has_border & SOUTH))
if(!(has_border & EAST))
var/turf/simulated/floor/T = get_step(src, SOUTHEAST)
if(!(istype(T) && T.flooring && T.flooring.name == flooring.name))
- overlays |= get_flooring_overlay("[flooring.icon_base]-corner-[SOUTHEAST]", "[flooring.icon_base]_corners", SOUTHEAST)
+ add_overlay(get_flooring_overlay("[flooring.icon_base]-corner-[SOUTHEAST]", "[flooring.icon_base]_corners", SOUTHEAST))
if(!(has_border & WEST))
var/turf/simulated/floor/T = get_step(src, SOUTHWEST)
if(!(istype(T) && T.flooring && T.flooring.name == flooring.name))
- overlays |= get_flooring_overlay("[flooring.icon_base]-corner-[SOUTHWEST]", "[flooring.icon_base]_corners", SOUTHWEST)
+ add_overlay(get_flooring_overlay("[flooring.icon_base]-corner-[SOUTHWEST]", "[flooring.icon_base]_corners", SOUTHWEST))
- // Hack workaround to byond crash bug
- //if(decals && decals.len)
- //overlays |= decals
- apply_decals()
+ // Re-apply floor decals
+ if(LAZYLEN(decals))
+ add_overlay(decals)
if(is_plating() && !(isnull(broken) && isnull(burnt))) //temp, todo
icon = 'icons/turf/flooring/plating.dmi'
icon_state = "dmg[rand(1,4)]"
else if(flooring)
if(!isnull(broken) && (flooring.flags & TURF_CAN_BREAK))
- overlays |= get_flooring_overlay("[flooring.icon_base]-broken-[broken]","broken[broken]") // VOREStation Edit - Eris overlays
+ add_overlay(get_flooring_overlay("[flooring.icon_base]-broken-[broken]","broken[broken]")) // VOREStation Edit - Eris overlays
if(!isnull(burnt) && (flooring.flags & TURF_CAN_BURN))
- overlays |= get_flooring_overlay("[flooring.icon_base]-burned-[burnt]","burned[burnt]") // VOREStation Edit - Eris overlays
+ add_overlay(get_flooring_overlay("[flooring.icon_base]-burned-[burnt]","burned[burnt]")) // VOREStation Edit - Eris overlays
if(weather_overlay)
- overlays += weather_overlay
+ add_overlay(weather_overlay)
if(update_neighbors)
for(var/turf/simulated/floor/F in range(src, 1))
@@ -97,7 +96,7 @@ var/image/no_ceiling_image = null
// Show 'ceilingless' overlay.
var/turf/above = GetAbove(src)
if(above && isopenspace(above) && !istype(src, /turf/simulated/floor/outdoors)) // This won't apply to outdoor turfs since its assumed they don't have a ceiling anyways.
- overlays |= no_ceiling_image
+ add_overlay(no_ceiling_image)
/turf/simulated/floor/proc/get_flooring_overlay(var/cache_key, var/icon_base, var/icon_dir = 0)
if(!flooring_cache[cache_key])
diff --git a/code/game/turfs/simulated/floor_types.dm b/code/game/turfs/simulated/floor_types.dm
index 07c686df99..3c4856cf00 100644
--- a/code/game/turfs/simulated/floor_types.dm
+++ b/code/game/turfs/simulated/floor_types.dm
@@ -15,17 +15,19 @@
var/list/decals
New(var/location = null, var/turf/simulated/shuttle/turf)
+ ..(null)
my_turf = turf
/obj/landed_holder/proc/land_on(var/turf/T)
//Gather destination information
- var/old_dest_type = T.type
- var/old_dest_dir = T.dir
- var/old_dest_icon_state = T.icon_state
- var/old_dest_icon = T.icon
- var/list/old_dest_overlays = T.overlays.Copy()
- var/list/old_dest_underlays = T.underlays.Copy()
- var/list/old_dest_decals = T.decals ? T.decals.Copy() : null
+ var/obj/landed_holder/new_holder = new(null)
+ new_holder.turf_type = T.type
+ new_holder.dir = T.dir
+ new_holder.icon = T.icon
+ new_holder.icon_state = T.icon_state
+ new_holder.copy_overlays(T, TRUE)
+ new_holder.underlays = T.underlays.Copy()
+ new_holder.decals = T.decals ? T.decals.Copy() : null
//Set the destination to be like us
T.Destroy()
@@ -33,7 +35,7 @@
new_dest.set_dir(my_turf.dir)
new_dest.icon_state = my_turf.icon_state
new_dest.icon = my_turf.icon
- new_dest.overlays = my_turf.overlays
+ new_dest.copy_overlays(my_turf, TRUE)
new_dest.underlays = my_turf.underlays
new_dest.decals = my_turf.decals
//Shuttle specific stuff
@@ -43,18 +45,9 @@
new_dest.join_flags = my_turf.join_flags
new_dest.join_group = my_turf.join_group
- if(new_dest.decals)
- new_dest.apply_decals()
-
- //Tell the new turf about what was there before
- new_dest.landed_holder = new(turf = new_dest)
- new_dest.landed_holder.turf_type = old_dest_type
- new_dest.landed_holder.dir = old_dest_dir
- new_dest.landed_holder.icon = old_dest_icon
- new_dest.landed_holder.icon_state = old_dest_icon_state
- new_dest.landed_holder.overlays = old_dest_overlays
- new_dest.landed_holder.underlays = old_dest_underlays
- new_dest.landed_holder.decals = old_dest_decals
+ // Associate the holder with the new turf.
+ new_holder.my_turf = new_dest
+ new_dest.landed_holder = new_holder
//Update underlays if necessary (interior corners won't have changed).
if(new_dest.takes_underlays && !new_dest.interior_corner)
@@ -70,11 +63,9 @@
new_source.set_dir(dir)
new_source.icon_state = icon_state
new_source.icon = icon
- new_source.overlays = overlays
+ new_source.copy_overlays(src, TRUE)
new_source.underlays = underlays
new_source.decals = decals
- if(new_source.decals)
- new_source.apply_decals()
else
new_source = my_turf.ChangeTurf(get_base_turf_by_area(my_turf),,1)
diff --git a/code/game/turfs/simulated/outdoors/outdoors.dm b/code/game/turfs/simulated/outdoors/outdoors.dm
index 13d983a9e1..cd358b7d5e 100644
--- a/code/game/turfs/simulated/outdoors/outdoors.dm
+++ b/code/game/turfs/simulated/outdoors/outdoors.dm
@@ -44,7 +44,9 @@ var/list/outdoor_turfs = list()
planet_controller.unallocateTurf(src)
else // This is happening during map gen, if there's no planet_controller (hopefully).
outdoor_turfs -= src
- qdel(weather_overlay)
+ if(weather_overlay)
+ cut_overlay(weather_overlay)
+ qdel_null(weather_overlay)
update_icon()
/turf/simulated/post_change()
@@ -67,15 +69,14 @@ var/list/outdoor_turfs = list()
var/image/I = image(icon = 'icons/turf/outdoors_edge.dmi', icon_state = "[T.get_edge_icon_state()]-edge", dir = checkdir)
I.plane = 0
turf_edge_cache[cache_key] = I
- overlays += turf_edge_cache[cache_key]
+ add_overlay(turf_edge_cache[cache_key])
/turf/simulated/proc/get_edge_icon_state()
return icon_state
/turf/simulated/floor/outdoors/update_icon()
- overlays.Cut()
- update_icon_edge()
..()
+ update_icon_edge()
/turf/simulated/floor/outdoors/mud
name = "mud"
diff --git a/code/game/turfs/simulated/outdoors/snow.dm b/code/game/turfs/simulated/outdoors/snow.dm
index 8e60c925e5..9926c4704a 100644
--- a/code/game/turfs/simulated/outdoors/snow.dm
+++ b/code/game/turfs/simulated/outdoors/snow.dm
@@ -17,10 +17,9 @@
. = ..()
/turf/simulated/floor/outdoors/snow/update_icon()
- overlays.Cut()
..()
for(var/d in crossed_dirs)
- overlays += image(icon = 'icons/turf/outdoors.dmi', icon_state = "snow_footprints", dir = text2num(d))
+ add_overlay(image(icon = 'icons/turf/outdoors.dmi', icon_state = "snow_footprints", dir = text2num(d)))
/turf/simulated/floor/outdoors/snow/attackby(var/obj/item/W, var/mob/user)
if(istype(W, /obj/item/weapon/shovel))
diff --git a/code/game/turfs/simulated/wall_icon.dm b/code/game/turfs/simulated/wall_icon.dm
index 2dac063723..b8a0980de4 100644
--- a/code/game/turfs/simulated/wall_icon.dm
+++ b/code/game/turfs/simulated/wall_icon.dm
@@ -47,36 +47,36 @@
if(!damage_overlays[1]) //list hasn't been populated
generate_overlays()
- overlays.Cut()
+ cut_overlays()
var/image/I
if(!density)
I = image('icons/turf/wall_masks.dmi', "[material.icon_base]fwall_open")
I.color = material.icon_colour
- overlays += I
+ add_overlay(I)
return
for(var/i = 1 to 4)
I = image('icons/turf/wall_masks.dmi', "[material.icon_base][wall_connections[i]]", dir = 1<<(i-1))
I.color = material.icon_colour
- overlays += I
+ add_overlay(I)
if(reinf_material)
if(construction_stage != null && construction_stage < 6)
I = image('icons/turf/wall_masks.dmi', "reinf_construct-[construction_stage]")
I.color = reinf_material.icon_colour
- overlays += I
+ add_overlay(I)
else
if("[reinf_material.icon_reinf]0" in icon_states('icons/turf/wall_masks.dmi'))
// Directional icon
for(var/i = 1 to 4)
I = image('icons/turf/wall_masks.dmi', "[reinf_material.icon_reinf][wall_connections[i]]", dir = 1<<(i-1))
I.color = reinf_material.icon_colour
- overlays += I
+ add_overlay(I)
else
I = image('icons/turf/wall_masks.dmi', reinf_material.icon_reinf)
I.color = reinf_material.icon_colour
- overlays += I
+ add_overlay(I)
if(damage != 0)
var/integrity = material.integrity
@@ -87,7 +87,7 @@
if(overlay > damage_overlays.len)
overlay = damage_overlays.len
- overlays += damage_overlays[overlay]
+ add_overlay(damage_overlays[overlay])
return
/turf/simulated/wall/proc/generate_overlays()
diff --git a/code/game/turfs/simulated/wall_types.dm b/code/game/turfs/simulated/wall_types.dm
index 6118c2741f..7fefbf8a3c 100644
--- a/code/game/turfs/simulated/wall_types.dm
+++ b/code/game/turfs/simulated/wall_types.dm
@@ -230,15 +230,7 @@
/turf/simulated/shuttle/wall/voidcraft/update_icon()
if(stripe_color)
- overlays = list() //VOREStation Edit - Another place with overlay nonsense.
+ cut_overlays()
var/image/I = image(icon = src.icon, icon_state = "o_[icon_state]")
I.color = stripe_color
- //VOREStation Add - Shenanigans around this because of the bullshit byond bug
- var/pre_overlays = overlays.len
- overlays.Add(I)
- var/post_overlays = overlays.len
- if(post_overlays != (pre_overlays + 1))
- world.log << "Corrupted overlays on [x],[y],[z] voidcraft wall"
- new type(src)
- return
- //VOREStation Add End
+ add_overlay(I)
diff --git a/code/game/turfs/simulated/wall_types_vr.dm b/code/game/turfs/simulated/wall_types_vr.dm
index 90d389bf53..4d939c2004 100644
--- a/code/game/turfs/simulated/wall_types_vr.dm
+++ b/code/game/turfs/simulated/wall_types_vr.dm
@@ -26,7 +26,7 @@
var/list/flesh_overlay_cache = list()
/turf/simulated/flesh/update_icon(var/update_neighbors)
- overlays.Cut()
+ cut_overlays()
if(density)
icon = 'icons/turf/stomach_vr.dmi'
@@ -37,7 +37,7 @@ var/list/flesh_overlay_cache = list()
var/place_dir = turn(direction, 180)
if(!flesh_overlay_cache["flesh_side_[place_dir]"])
flesh_overlay_cache["flesh_side_[place_dir]"] = image('icons/turf/stomach_vr.dmi', "flesh_side", dir = place_dir)
- T.overlays += flesh_overlay_cache["flesh_side_[place_dir]"]
+ add_overlay(flesh_overlay_cache["flesh_side_[place_dir]"])
if(update_neighbors)
for(var/direction in alldirs)
diff --git a/code/game/turfs/simulated/water.dm b/code/game/turfs/simulated/water.dm
index a47578f102..e4b762d733 100644
--- a/code/game/turfs/simulated/water.dm
+++ b/code/game/turfs/simulated/water.dm
@@ -16,7 +16,6 @@
update_icon()
/turf/simulated/floor/water/update_icon()
- overlays.Cut()
..() // To get the edges.
icon_state = water_state
var/image/floorbed_sprite = image(icon = 'icons/turf/outdoors.dmi', icon_state = under_state)
@@ -129,16 +128,16 @@ var/list/shoreline_icon_cache = list()
// Water sprites are really annoying, so let BYOND sort it out.
/turf/simulated/floor/water/shoreline/update_icon()
underlays.Cut()
- overlays.Cut()
+ cut_overlays()
..() // Get the underlay first.
var/cache_string = "[initial(icon_state)]_[water_state]_[dir]"
if(cache_string in shoreline_icon_cache) // Check to see if an icon already exists.
- overlays += shoreline_icon_cache[cache_string]
+ add_overlay(shoreline_icon_cache[cache_string])
else // If not, make one, but only once.
var/icon/shoreline_water = icon(src.icon, "shoreline_water", src.dir)
var/icon/shoreline_subtract = icon(src.icon, "[initial(icon_state)]_subtract", src.dir)
shoreline_water.Blend(shoreline_subtract,ICON_SUBTRACT)
shoreline_icon_cache[cache_string] = shoreline_water
- overlays += shoreline_icon_cache[cache_string]
+ add_overlay(shoreline_icon_cache[cache_string])
diff --git a/code/game/turfs/snow/snow.dm b/code/game/turfs/snow/snow.dm
index b09275ca41..a8ccd5b63b 100644
--- a/code/game/turfs/snow/snow.dm
+++ b/code/game/turfs/snow/snow.dm
@@ -26,12 +26,12 @@
. = ..()
/turf/snow/update_icon()
- overlays.Cut()
+ cut_overlays()
for(var/d in crossed_dirs)
var/amt = crossed_dirs[d]
for(var/i in 1 to amt)
- overlays += icon(icon, "footprint[i]", text2num(d))
+ add_overlay(image(icon, "footprint[i]", text2num(d)))
/turf/snow/snow2
name = "snow"
diff --git a/code/game/turfs/space/cracked_asteroid.dm b/code/game/turfs/space/cracked_asteroid.dm
index b9f43af82e..dae0d5a129 100644
--- a/code/game/turfs/space/cracked_asteroid.dm
+++ b/code/game/turfs/space/cracked_asteroid.dm
@@ -10,7 +10,8 @@
/turf/space/cracked_asteroid/is_space() // So people don't start floating when standing on it.
return FALSE
-/turf/space/cracked_asteroid/New()
- ..()
- spawn(2 SECONDS)
- overlays.Cut()
\ No newline at end of file
+// u wot m8? ~Leshana
+// /turf/space/cracked_asteroid/New()
+// ..()
+// spawn(2 SECONDS)
+// overlays.Cut()
diff --git a/code/game/turfs/unsimulated/beach.dm b/code/game/turfs/unsimulated/beach.dm
index 57dee24951..28cebacb8a 100644
--- a/code/game/turfs/unsimulated/beach.dm
+++ b/code/game/turfs/unsimulated/beach.dm
@@ -17,7 +17,7 @@
/turf/unsimulated/beach/water/New()
..()
- overlays += image("icon"='icons/misc/beach.dmi',"icon_state"="water2","layer"=MOB_LAYER+0.1)
+ add_overlay(image("icon"='icons/misc/beach.dmi',"icon_state"="water2","layer"=MOB_LAYER+0.1))
/turf/simulated/floor/beach
name = "Beach"
@@ -56,4 +56,4 @@
/turf/simulated/floor/beach/water/New()
..()
- overlays += image("icon"='icons/misc/beach.dmi',"icon_state"="water5","layer"=MOB_LAYER+0.1)
+ add_overlay(image("icon"='icons/misc/beach.dmi',"icon_state"="water5","layer"=MOB_LAYER+0.1))
diff --git a/code/global.dm b/code/global.dm
index a65e010c03..efb58b3318 100644
--- a/code/global.dm
+++ b/code/global.dm
@@ -184,7 +184,7 @@ var/static/list/scarySounds = list(
var/max_explosion_range = 14
// Announcer intercom, because too much stuff creates an intercom for one message then hard del()s it.
-var/global/obj/item/device/radio/intercom/global_announcer = new /obj/item/device/radio/intercom{channels=list("Engineering")}(null)
+var/global/obj/item/device/radio/intercom/omni/global_announcer = new /obj/item/device/radio/intercom/omni(null)
var/list/station_departments = list("Command", "Medical", "Engineering", "Science", "Security", "Cargo", "Civilian")
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 4eefda8d1d..9a5ac33c22 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -380,7 +380,7 @@ proc/admin_notice(var/message, var/rights)
if(3)
dat+={"
Creating new Feed Message...
-
Receiving Channel: [src.admincaster_feed_channel.channel_name]
" //MARK
+
Receiving Channel: [src.admincaster_feed_channel.channel_name]
Message Author: [src.admincaster_signature]
Message Body: [src.admincaster_feed_message.body]
Submit
Cancel
@@ -677,10 +677,7 @@ var/datum/announcement/minor/admin_min_announcer = new
set desc = "Send an intercom message, like an arrivals announcement."
if(!check_rights(0)) return
- //This is basically how death alarms do it
- var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset/omni(null)
-
- var/channel = input("Channel for message:","Channel", null) as null|anything in (list("Common") + a.keyslot2.channels) // + a.keyslot1.channels
+ var/channel = input("Channel for message:","Channel", null) as null|anything in radiochannels
if(channel) //They picked a channel
var/sender = input("Name of sender (max 75):", "Announcement", "Announcement Computer") as null|text
@@ -691,11 +688,94 @@ var/datum/announcement/minor/admin_min_announcer = new
if(message) //They put a message
message = sanitize(message, 500, extra = 0)
- a.autosay("[message]", "[sender]", "[channel == "Common" ? null : channel]") //Common is a weird case, as it's not a "channel", it's just talking into a radio without a channel set.
+ global_announcer.autosay("[message]", "[sender]", "[channel == "Common" ? null : channel]") //Common is a weird case, as it's not a "channel", it's just talking into a radio without a channel set.
log_admin("Intercom: [key_name(usr)] : [sender]:[message]")
- qdel(a)
+
feedback_add_details("admin_verb","IN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+/datum/admins/proc/intercom_convo()
+ set category = "Fun"
+ set name = "Intercom Convo"
+ set desc = "Send an intercom conversation, like several uses of the Intercom Msg verb."
+ set waitfor = FALSE //Why bother? We have some sleeps. You can leave tho!
+ if(!check_rights(0)) return
+
+ var/channel = input("Channel for message:","Channel", null) as null|anything in radiochannels
+
+ if(!channel) //They picked a channel
+ return
+
+ to_chat(usr,"Intercom Convo Directions
Start the conversation with the sender, a pipe (|), and then the message on one line. Then hit enter to \
+ add another line, and type a (whole) number of seconds to pause between that message, and the next message, then repeat the message syntax up to 20 times. For example:
\
+ --- --- ---
\
+ Some Guy|Hello guys, what's up?
\
+ 5
\
+ Other Guy|Hey, good to see you.
\
+ 5
\
+ Some Guy|Yeah, you too.
\
+ --- --- ---
\
+ The above will result in those messages playing, with a 5 second gap between each. Maximum of 20 messages allowed.")
+
+ var/list/decomposed
+ var/message = input(usr,"See your chat box for instructions. Keep a copy elsewhere in case it is rejected when you click OK.", "Input Conversation", "") as null|message
+
+ if(!message)
+ return
+
+ //Split on pipe or \n
+ decomposed = splittext(message,regex("\\||$","m"))
+ decomposed += "0" //Tack on a final 0 sleep to make 3-per-message evenly
+
+ //Time to find how they screwed up.
+ //Wasn't the right length
+ if((decomposed.len) % 3) //+1 to accomidate the lack of a wait time for the last message
+ to_chat(usr,"You passed [decomposed.len] segments (senders+messages+pauses). You must pass a multiple of 3, minus 1 (no pause after the last message). That means a sender and message on every other line (starting on the first), separated by a pipe character (|), and a number every other line that is a pause in seconds.")
+ return
+
+ //Too long a conversation
+ if((decomposed.len / 3) > 20)
+ to_chat(usr,"This conversation is too long! 20 messages maximum, please.")
+ return
+
+ //Missed some sleeps, or sanitized to nothing.
+ for(var/i = 1; i < decomposed.len; i++)
+
+ //Sanitize sender
+ var/clean_sender = sanitize(decomposed[i])
+ if(!clean_sender)
+ to_chat(usr,"One part of your conversation was not able to be sanitized. It was the sender of the [(i+2)/3]\th message.")
+ return
+ decomposed[i] = clean_sender
+
+ //Sanitize message
+ var/clean_message = sanitize(decomposed[++i])
+ if(!clean_message)
+ to_chat(usr,"One part of your conversation was not able to be sanitized. It was the body of the [(i+2)/3]\th message.")
+ return
+ decomposed[i] = clean_message
+
+ //Sanitize wait time
+ var/clean_time = text2num(decomposed[++i])
+ if(!isnum(clean_time))
+ to_chat(usr,"One part of your conversation was not able to be sanitized. It was the wait time after the [(i+2)/3]\th message.")
+ return
+ if(clean_time > 60)
+ to_chat(usr,"Max 60 second wait time between messages for sanity's sake please.")
+ return
+ decomposed[i] = clean_time
+
+ log_admin("Intercom convo started by: [key_name(usr)] : [sanitize(message)]")
+ feedback_add_details("admin_verb","IN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+ //Sanitized AND we still have a chance to send it? Wow!
+ if(LAZYLEN(decomposed))
+ for(var/i = 1; i < decomposed.len; i++)
+ var/this_sender = decomposed[i]
+ var/this_message = decomposed[++i]
+ var/this_wait = decomposed[++i]
+ global_announcer.autosay("[this_message]", "[this_sender]", "[channel == "Common" ? null : channel]") //Common is a weird case, as it's not a "channel", it's just talking into a radio without a channel set.
+ sleep(this_wait SECONDS)
+
/datum/admins/proc/toggleooc()
set category = "Server"
set desc="Globally Toggles OOC"
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index bbd10a20dc..59a787a2ae 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -26,6 +26,7 @@ var/list/admin_verbs_admin = list(
/datum/admins/proc/toggleguests, //toggles whether guests can join the current game,
/datum/admins/proc/announce, //priority announce something to all clients.,
/datum/admins/proc/intercom, //send a fake intercom message, like an arrivals announcement,
+ /datum/admins/proc/intercom_convo, //send a fake intercom conversation, like an ATC exchange,
/client/proc/colorooc, //allows us to set a custom colour for everythign we say in ooc,
/client/proc/admin_ghost, //allows us to ghost/reenter body at will,
/client/proc/toggle_view_range, //changes how far we can see,
diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm
index e624d2df05..cb110d4e86 100644
--- a/code/modules/admin/view_variables/view_variables.dm
+++ b/code/modules/admin/view_variables/view_variables.dm
@@ -143,7 +143,12 @@
vtext = "\ref[C] - [C] ([C.type])"
else if(islist(value))
var/list/L = value
- vtext = "/list ([L.len])"
+ var/removed = 0
+ if(varname == "contents")
+ var/list/original = value
+ L = original.Copy() //We'll take a copy to manipulate
+ removed = D.view_variables_filter_contents(L)
+ vtext = "/list ([L.len]+[removed]H)"
if(!(varname in view_variables_dont_expand) && L.len > 0 && L.len < 100)
extra = ""
var/index = 1
@@ -158,3 +163,21 @@
vtext = "[value]"
return "- [ecm][varname] = [vtext][extra]
"
+
+//Allows us to mask out some contents when it's not necessary to show them
+//For example, organs on humans, as the organs are stored in other lists which will also be present
+//So there's really no need to list them twice.
+/datum/proc/view_variables_filter_contents(list/L)
+ return 0 //Return how many items you removed.
+
+/mob/living/carbon/human/view_variables_filter_contents(list/L)
+ . = ..()
+ L -= ability_master
+ .++
+
+/mob/living/carbon/human/view_variables_filter_contents(list/L)
+ . = ..()
+ var/len_before = L.len
+ L -= organs
+ L -= internal_organs
+ . += len_before - L.len
diff --git a/code/modules/client/preference_setup/global/setting_datums.dm b/code/modules/client/preference_setup/global/setting_datums.dm
index 2f251398d1..222813460b 100644
--- a/code/modules/client/preference_setup/global/setting_datums.dm
+++ b/code/modules/client/preference_setup/global/setting_datums.dm
@@ -86,7 +86,18 @@ var/list/_client_preferences_by_type
preference_mob.stop_all_music()
else
preference_mob.update_music()
-
+//VOREStation Add - Need to put it here because it should be ordered riiiight here.
+/datum/client_preference/eating_noises
+ description = "Eating Noises"
+ key = "EATING_NOISES"
+ enabled_description = "Noisy"
+ disabled_description = "Silent"
+/datum/client_preference/digestion_noises
+ description = "Digestion Noises"
+ key = "DIGEST_NOISES"
+ enabled_description = "Noisy"
+ disabled_description = "Silent"
+//VOREStation Add End
/datum/client_preference/ghost_ears
description ="Ghost ears"
key = "CHAT_GHOSTEARS"
diff --git a/code/modules/client/preference_setup/loadout/loadout_xeno.dm b/code/modules/client/preference_setup/loadout/loadout_xeno.dm
index 7e4a082ff7..666f348515 100644
--- a/code/modules/client/preference_setup/loadout/loadout_xeno.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_xeno.dm
@@ -147,4 +147,17 @@
display_name = "cloth footwraps"
path = /obj/item/clothing/shoes/footwraps
sort_category = "Xenowear"
- cost = 1
\ No newline at end of file
+ cost = 1
+
+/datum/gear/uniform/cohesionsuits
+ display_name = "cohesion suit selection (Promethean)"
+ path = /obj/item/clothing/under/cohesion
+ sort_category = "Xenowear"
+
+/datum/gear/uniform/cohesionsuits/New()
+ ..()
+ var/list/cohesionsuits = list()
+ for(var/cohesionsuit in (typesof(/obj/item/clothing/under/cohesion)))
+ var/obj/item/clothing/under/cohesion/cohesion_type = cohesionsuit
+ cohesionsuits[initial(cohesion_type.name)] = cohesion_type
+ gear_tweaks += new/datum/gear_tweak/path(sortAssoc(cohesionsuits))
\ No newline at end of file
diff --git a/code/modules/clothing/clothing_accessories.dm b/code/modules/clothing/clothing_accessories.dm
index de4556036b..57c292f1e3 100644
--- a/code/modules/clothing/clothing_accessories.dm
+++ b/code/modules/clothing/clothing_accessories.dm
@@ -1,11 +1,9 @@
/obj/item/clothing/proc/can_attach_accessory(obj/item/clothing/accessory/A)
- var/obj/item/clothing/accessory/attach = A
- if(src.valid_accessory_slots && (attach.slot in src.valid_accessory_slots))
- if(accessories.len && restricted_accessory_slots && (attach.slot in restricted_accessory_slots))
+ if(src.valid_accessory_slots && (A.slot in src.valid_accessory_slots))
+ if(accessories.len && restricted_accessory_slots && (A.slot in restricted_accessory_slots))
for(var/obj/item/clothing/accessory/AC in accessories)
- if (AC.slot == attach.slot)
+ if (AC.slot == A.slot)
return FALSE
- return TRUE
return TRUE
else
return FALSE
diff --git a/code/modules/clothing/spacesuits/rig/modules/utility_vr.dm b/code/modules/clothing/spacesuits/rig/modules/utility_vr.dm
index 167a0ce6c5..83456629a1 100644
--- a/code/modules/clothing/spacesuits/rig/modules/utility_vr.dm
+++ b/code/modules/clothing/spacesuits/rig/modules/utility_vr.dm
@@ -83,12 +83,8 @@
var/username = FindNameFromID(H) || "Unknown"
var/message = "[username] has overridden [A] (airlock) in \the [get_area(A)] at [A.x],[A.y],[A.z] with \the [src]."
- var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset/heads/captain(null)
- a.icon = icon
- a.icon_state = icon_state
- a.autosay(message, "Security Subsystem", "Command")
- a.autosay(message, "Security Subsystem", "Security")
- qdel(a)
+ global_announcer.autosay(message, "Security Subsystem", "Command")
+ global_announcer.autosay(message, "Security Subsystem", "Security")
return 1
/obj/item/rig_module/rescue_pharm
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index b9a462dabb..d45a584e2c 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -816,4 +816,30 @@
/obj/item/clothing/under/explorer
desc = "A green uniform for operating in hazardous environments."
name = "explorer's jumpsuit"
- icon_state = "explorer"
\ No newline at end of file
+ icon_state = "explorer"
+
+/obj/item/clothing/under/cohesion
+ name = "black cohesion suit"
+ desc = "A plain black cohesion suit intended to assist Prometheans in maintaining their form and prevent direct skin exposure."
+ icon_state = "cohesionsuit"
+ rolled_sleeves = -1 // defeats the purpose!!!
+
+/obj/item/clothing/under/cohesion/striped
+ name = "red striped cohesion suit"
+ desc = "A black cohesion suit with red stripes intended to assist Prometheans in maintaining their form and prevent direct skin exposure."
+ icon_state = "cohesionsuit_striped"
+
+/obj/item/clothing/under/cohesion/decal
+ name = "purple decaled cohesion suit"
+ desc = "A white cohesion suit with purple decals intended to assist Prometheans in maintaining their form and prevent direct skin exposure."
+ icon_state = "cohesionsuit_decal"
+
+/obj/item/clothing/under/cohesion/pattern
+ name = "blue patterned cohesion suit"
+ desc = "A white cohesion suit with blue patterns intended to assist Prometheans in maintaining their form and prevent direct skin exposure."
+ icon_state = "cohesionsuit_pattern"
+
+/obj/item/clothing/under/cohesion/hazard
+ name = "hazard cohesion suit"
+ desc = "An orange cohesion suit with yellow hazard stripes intended to assist Prometheans in maintaining their form and prevent direct skin exposure."
+ icon_state = "cohesionsuit_hazard"
\ No newline at end of file
diff --git a/code/modules/clothing/under/miscellaneous_vr.dm b/code/modules/clothing/under/miscellaneous_vr.dm
index db3165e9c9..a0fef4879b 100644
--- a/code/modules/clothing/under/miscellaneous_vr.dm
+++ b/code/modules/clothing/under/miscellaneous_vr.dm
@@ -1,21 +1,5 @@
/obj/item/clothing/var/hides_bulges = FALSE // OwO wats this?
-/mob/living/carbon/human/proc/show_pudge()
- //A uniform could hide it.
- if(istype(w_uniform,/obj/item/clothing))
- var/obj/item/clothing/under = w_uniform
- if(under.hides_bulges)
- return FALSE
-
- //We return as soon as we find one, no need for 'else' really.
- if(istype(wear_suit,/obj/item/clothing))
- var/obj/item/clothing/suit = wear_suit
- if(suit.hides_bulges)
- return FALSE
-
-
- return TRUE
-
/obj/item/clothing/under/permit
name = "public nudity permit"
desc = "This permit entitles the bearer to conduct their duties without a uniform. Normally issued to furred crewmembers or those with nothing to hide."
diff --git a/code/modules/holodeck/HolodeckObjects.dm b/code/modules/holodeck/HolodeckObjects.dm
index 09b525114b..c7f8f275bf 100644
--- a/code/modules/holodeck/HolodeckObjects.dm
+++ b/code/modules/holodeck/HolodeckObjects.dm
@@ -107,7 +107,7 @@
/turf/simulated/floor/holofloor/desert/New()
..()
if(prob(10))
- overlays += "asteroid[rand(0,9)]"
+ add_overlay("asteroid[rand(0,9)]")
/obj/structure/holostool
name = "stool"
diff --git a/code/modules/hydroponics/seed_storage_vr.dm b/code/modules/hydroponics/seed_storage_vr.dm
index 078191f508..6d9d373b78 100644
--- a/code/modules/hydroponics/seed_storage_vr.dm
+++ b/code/modules/hydroponics/seed_storage_vr.dm
@@ -19,6 +19,7 @@
/obj/item/seeds/limeseed = 3,
/obj/item/seeds/mtearseed = 2,
/obj/item/seeds/orangeseed = 3,
+ /obj/item/seeds/onionseed = 3,
/obj/item/seeds/peanutseed = 3,
/obj/item/seeds/plumpmycelium = 3,
/obj/item/seeds/poppyseed = 3,
diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm
index e8252d4581..6e75d97a0d 100644
--- a/code/modules/materials/material_recipes.dm
+++ b/code/modules/materials/material_recipes.dm
@@ -186,6 +186,6 @@
/material/wood/sif/generate_recipes()
..()
- recipes += new/datum/stack_recipe("alien wood floor tile", /obj/item/stack/tile/sifwood, 1, 4, 20)
+ recipes += new/datum/stack_recipe("alien wood floor tile", /obj/item/stack/tile/wood/sif, 1, 4, 20)
recipes -= new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20)
recipes -= new/datum/stack_recipe("wooden chair", /obj/structure/bed/chair/wood, 3, time = 10, one_per_turf = 1, on_floor = 1)
diff --git a/code/modules/mob/language/generic.dm b/code/modules/mob/language/generic.dm
index e3cb043565..d1e2eab309 100644
--- a/code/modules/mob/language/generic.dm
+++ b/code/modules/mob/language/generic.dm
@@ -42,7 +42,7 @@
// Galactic common languages (systemwide accepted standards).
/datum/language/trader
name = LANGUAGE_TRADEBAND
- desc = "Maintained by the various trading cartels in major systems, this elegant, structured language is used for bartering and bargaining."
+ desc = "Maintained by the various trading cartels in major systems, this elegant, structured language is used for bartering and bargaining." //VOREstation Edit
speech_verb = "enunciates"
colour = "say_quote"
key = "2"
@@ -53,10 +53,22 @@
"nt","ti","us","it","en","at","tu","te","ri","es","et","ra","ta","an","ni","li","on","or","se",
"am","ae","ia","di","ue","em","ar","ui","st","si","de","ci","iu","ne","pe","co","os","ur","ru")
+/datum/language/terminus
+ name = LANGUAGE_TERMINUS
+ desc = "A soft language spoken by the people of the sparsely populated, socially-conscious Precursors' Crypt region."
+ speech_verb = "mentions"
+ exclaim_verb = "insinuates"
+ colour = "terminus"
+ key = "4"
+ flags = WHITELISTED
+ syllables = list ("die", "en", "skei", "van", "son", "der", "aar", "ch", "op", "ruk", "aa", "be", "ne", "het",
+ "ek", "ras", "ver", "zan", "das", "waa", "geb", "vol", "lu", "min", "breh", "rus", "stv", "ee", "goe", "sk",
+ "la", "ver", "we", "ge", "luk", "an", "ar", "at", "es", "et", "bel", "du", "jaa", "ch", "kk", "gh", "ll", "uu", "wat")
+
// Criminal language.
/datum/language/gutter
name = LANGUAGE_GUTTER
- desc = "There is no true language named Gutter. 'Gutter' is a catchall term for a collection of unofficial SolCom dialects that has somehow managed to spread across the stars."
+ desc = "Gutter originated as a Thieves' Cant of sorts during the early colonization era. The language eventually spread from the cartels and triads to the disenfranchised people of the Bowl."
speech_verb = "growls"
colour = "rough"
key = "3"
diff --git a/code/modules/mob/language/outsider.dm b/code/modules/mob/language/outsider.dm
index 0a721e6f56..b1932bb3ba 100644
--- a/code/modules/mob/language/outsider.dm
+++ b/code/modules/mob/language/outsider.dm
@@ -92,7 +92,7 @@
speech_verb = "hisses"
ask_verb = "hisses"
exclaim_verb = "hisses"
- key = "4"
+ key = "u"
flags = RESTRICTED
syllables = list("sss","sSs","SSS")
@@ -115,3 +115,18 @@
return 1
return 0
+
+//for your antag purposes.
+/datum/language/minbus
+ name = LANGUAGE_MINBUS
+ desc = "The Powers That Be have seen it fit to grace you with a special language that sounds like Russian for some reason."
+ speech_verb = "says"
+ ask_verb = "asks"
+ exclaim_verb = "shouts"
+ colour = "deadsay"
+ key = "r"
+ machine_understands = 0
+ flags = RESTRICTED
+ syllables = list("rus","zem","ave","groz","ski","ska","ven","konst","pol","lin","svy",
+ "danya","da","mied","zan","das","krem","myka","cyka","blyat","to","st","no","na","ni",
+ "ko","ne","en","po","ra","li","on","byl","cto","eni","ost","ol","ego","ver","stv","pro")
\ No newline at end of file
diff --git a/code/modules/mob/language/station.dm b/code/modules/mob/language/station.dm
index 8e638fce80..0538e390cb 100644
--- a/code/modules/mob/language/station.dm
+++ b/code/modules/mob/language/station.dm
@@ -85,6 +85,20 @@
flags = WHITELISTED
syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix")
+/datum/language/skrellfar
+ name = LANGUAGE_SKRELLIANFAR
+ desc = "The most common language among the Skrellian Far Kingdoms. Has an even higher than usual concentration of inaudible phonemes."
+ speech_verb = "warbles"
+ ask_verb = "warbles"
+ exclaim_verb = "sings"
+ whisper_verb = "hums"
+ colour = "skrellfar"
+ key = "p"
+ space_chance = 30
+ flags = WHITELISTED
+ syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix", "...", "oo", "q", "nq", "x", "xq", "ll", "...", "...", "...") //should sound like there's holes in it
+
+
/datum/language/human
name = LANGUAGE_SOL_COMMON
desc = "A bastardized hybrid of many languages, including Chinese, English, French, and more; it is the common language of the Sol system."
@@ -114,7 +128,7 @@
/datum/language/machine
name = LANGUAGE_EAL
- desc = "An efficient language of encoded tones developed by synthetics and cyborgs."
+ desc = "An efficient language of encoded tones developed by positronics."
speech_verb = "whistles"
ask_verb = "chirps"
exclaim_verb = "whistles loudly"
@@ -244,4 +258,4 @@
"tod", "ser", "su", "no", "nue", "el",
"ad", "al", "an", "ar", "as", "ci", "co", "de", "do", "el", "en", "er", "es", "ie", "in", "la", "lo", "me", "na",
"no", "nt", "or", "os", "pa", "qu", "ra", "re", "ro", "se", "st", "ta", "te", "to", "ue", "un",
-"tod", "ser", "su", "no", "nue", "el")
+"tod", "ser", "su", "no", "nue", "el")
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/carbon/brain/brain.dm
index efe2abc497..7165c36fa8 100644
--- a/code/modules/mob/living/carbon/brain/brain.dm
+++ b/code/modules/mob/living/carbon/brain/brain.dm
@@ -8,6 +8,7 @@
use_me = 0 //Can't use the me verb, it's a freaking immobile brain
icon = 'icons/obj/surgery.dmi'
icon_state = "brain1"
+ no_vore = TRUE //VOREStation Edit - PLEASE. lol.
New()
var/datum/reagents/R = new/datum/reagents(1000)
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index bedb652f38..36e3853295 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -302,7 +302,7 @@
msg += attempt_vr(src,"examine_bellies",args) //VOREStation Code
msg += attempt_vr(src,"examine_pickup_size",args) //VOREStation Code
msg += attempt_vr(src,"examine_step_size",args) //VOREStation Code
- msg += attempt_vr(src,"nif_examine",args) //VOREStation Code
+ msg += attempt_vr(src,"examine_nif",args) //VOREStation Code
if(mSmallsize in mutations)
msg += "[T.He] [T.is] small halfling!\n"
diff --git a/code/modules/mob/living/carbon/human/examine_vr.dm b/code/modules/mob/living/carbon/human/examine_vr.dm
index 9d86241dd1..d976dc50b1 100644
--- a/code/modules/mob/living/carbon/human/examine_vr.dm
+++ b/code/modules/mob/living/carbon/human/examine_vr.dm
@@ -107,17 +107,6 @@
message = "[t_He] [t_is] so absolutely stuffed that you aren't sure how it's possible to move. [t_He] can't seem to swell any bigger. The surface of [t_his] belly looks sorely strained!\n"
return message
-/mob/living/carbon/human/proc/examine_bellies()
- if(!show_pudge()) //Some clothing or equipment can hide this.
- return ""
-
- var/message = ""
- for (var/I in src.vore_organs)
- var/datum/belly/B = vore_organs[I]
- message += B.get_examine_msg()
-
- return message
-
//For OmniHUD records access for appropriate models
/proc/hasHUD_vr(mob/living/carbon/human/H, hudtype)
if(H.nif)
@@ -141,23 +130,18 @@
return FALSE
-/mob/living/carbon/human/proc/examine_pickup_size(mob/living/carbon/human/H)
+/mob/living/carbon/human/proc/examine_pickup_size(mob/living/H)
var/message = ""
- if(isliving(src) && (H.get_effective_size() - src.get_effective_size()) >= 0.50)
+ if(istype(H) && (H.get_effective_size() - src.get_effective_size()) >= 0.50)
message = "They are small enough that you could easily pick them up!\n"
return message
-
-/mob/living/carbon/human/proc/examine_step_size(mob/living/carbon/human/H)
+/mob/living/carbon/human/proc/examine_step_size(mob/living/H)
var/message = ""
- if(isliving(src) && (H.get_effective_size() - src.get_effective_size()) >= 0.75)
+ if(istype(H) && (H.get_effective_size() - src.get_effective_size()) >= 0.75)
message = "They are small enough that you could easily trample them!\n"
return message
-/mob/living/carbon/human/proc/nif_examine(mob/living/carbon/human/H)
- var/message = ""
- if(!src.nif || src.conceal_nif || !src.nif_examine) //Do they have a nif, do they have the NIF concealed, and do they have a NIF examine message?
- return "" //If so, no message.
- else
- message += "[src.nif_examine]\n"
- return message
+/mob/living/carbon/human/proc/examine_nif(mob/living/carbon/human/H)
+ if(nif && nif.examine_msg) //If you have one set, anyway.
+ return "[nif.examine_msg]\n"
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index fec1390f67..f92c8a8741 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -66,7 +66,8 @@
list_body = null
LAZYCLEARLIST(list_huds)
list_huds = null
- if(nif) qdel_null(nif) //VOREStation Add
+ qdel_null(nif) //VOREStation Add
+ qdel_null_list(vore_organs) //VOREStation Add
return ..()
/mob/living/carbon/human/Stat()
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index 58e9dc8339..ec4f50e120 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -43,7 +43,7 @@
var/obj/item/organ/external/E = get_organ(organ_name)
if(!E || E.is_stump())
tally += 4
- else if(E.splinted)
+ else if(E.splinted && E.splinted.loc != E)
tally += 0.5
else if(E.status & ORGAN_BROKEN)
tally += 1.5
@@ -55,7 +55,7 @@
var/obj/item/organ/external/E = get_organ(organ_name)
if(!E || E.is_stump())
tally += 4
- else if(E.splinted)
+ else if(E.splinted && E.splinted.loc != E)
tally += 0.5
else if(E.status & ORGAN_BROKEN)
tally += 1.5
diff --git a/code/modules/mob/living/carbon/human/human_species_vr.dm b/code/modules/mob/living/carbon/human/human_species_vr.dm
index 596de6a1fa..52ca3f0426 100644
--- a/code/modules/mob/living/carbon/human/human_species_vr.dm
+++ b/code/modules/mob/living/carbon/human/human_species_vr.dm
@@ -1,3 +1,6 @@
+/mob/living/carbon/human/dummy
+ no_vore = TRUE //Dummies don't need bellies.
+
/mob/living/carbon/human/sergal/New(var/new_loc)
h_style = "Sergal Plain"
..(new_loc, "Sergal")
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index f60a5d6708..947b844ad2 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -319,7 +319,7 @@ This saves us from having to call add_fingerprint() any time something is put in
for(var/obj/item/clothing/C in worn_clothing)
if(istype(W, /obj/item/clothing/accessory))
var/obj/item/clothing/accessory/A = W
- if(C.attempt_attach_accessory(A))
+ if(C.attempt_attach_accessory(A, src))
return
else
src << "You are trying to equip this item to an unsupported inventory slot. How the heck did you manage that? Stop it..."
diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans.dm b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
index d709a1db3e..e01fe608d3 100644
--- a/code/modules/mob/living/carbon/human/species/station/prometheans.dm
+++ b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
@@ -156,9 +156,9 @@ VOREStation Removal End */
H.adjustFireLoss(-heal_rate)
H.adjustOxyLoss(-heal_rate)
H.adjustToxLoss(-heal_rate)
- else
+/* else //VOREStation Edit Start.
H.adjustToxLoss(2*heal_rate) // Doubled because 0.5 is miniscule, and fire_stacks are capped in both directions
-
+*/ //VOREStation Edit End
/datum/species/shapeshifter/promethean/get_blood_colour(var/mob/living/carbon/human/H)
return (H ? rgb(H.r_skin, H.g_skin, H.b_skin) : ..())
diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm b/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm
index 8baa490800..70ab7f577b 100644
--- a/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm
+++ b/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm
@@ -9,6 +9,7 @@
mob_size = MOB_MEDIUM
num_alternate_languages = 1 //Let's at least give them one
appearance_flags = HAS_SKIN_COLOR | HAS_EYE_COLOR | HAS_HAIR_COLOR | RADIATION_GLOWS | HAS_UNDERWEAR
+ trashcan = 1 //They have goopy bodies. They can just dissolve things within them.
inherent_verbs = list(
/mob/living/carbon/human/proc/shapeshifter_select_shape,
/mob/living/carbon/human/proc/shapeshifter_select_colour,
@@ -20,7 +21,8 @@
/mob/living/carbon/human/proc/succubus_drain,
/mob/living/carbon/human/proc/succubus_drain_finalize,
/mob/living/carbon/human/proc/succubus_drain_lethal,
- /mob/living/carbon/human/proc/slime_feed
+ /mob/living/carbon/human/proc/slime_feed,
+ /mob/living/proc/eat_trash
)
diff --git a/code/modules/mob/living/carbon/human/species/station/station.dm b/code/modules/mob/living/carbon/human/species/station/station.dm
index 702002f98d..1b6a13e3a3 100644
--- a/code/modules/mob/living/carbon/human/species/station/station.dm
+++ b/code/modules/mob/living/carbon/human/species/station/station.dm
@@ -10,7 +10,7 @@
worlds tumultous at best."
num_alternate_languages = 3
species_language = LANGUAGE_SOL_COMMON
- secondary_langs = list(LANGUAGE_SOL_COMMON)
+ secondary_langs = list(LANGUAGE_SOL_COMMON, LANGUAGE_TERMINUS)
name_language = null // Use the first-name last-name generator rather than a language scrambler
min_age = 18
max_age = 130
diff --git a/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm b/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm
index d4fd1d9dc2..6860b99aa9 100644
--- a/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm
+++ b/code/modules/mob/living/carbon/human/species/station/station_special_abilities_vr.dm
@@ -606,9 +606,6 @@
C.absorbing_prey = 0
return
-
-
-
/mob/living/carbon/human/proc/succubus_drain_finalize()
set name = "Drain/Feed Finalization"
set desc = "Toggle to allow for draining to be prolonged. Turn this on to make it so prey will be knocked out/die while being drained, or you will feed yourself to the prey's selected stomach if you're feeding them. Can be toggled at any time."
@@ -618,110 +615,134 @@
C.drain_finalized = !C.drain_finalized
to_chat(C, "You will [C.drain_finalized?"now":"not"] finalize draining/feeding.")
-/mob/living/carbon/human/proc/shred_limb() //If you're looking at this, nothing but pain and suffering lies below.
+
+//Test to see if we can shred a mob. Some child override needs to pass us a target. We'll return it if you can.
+/mob/living/var/vore_shred_time = 45 SECONDS
+/mob/living/proc/can_shred(var/mob/living/carbon/human/target)
+ //Needs to have organs to be able to shred them.
+ if(!istype(target))
+ to_chat(src,"You can't shred that type of creature.")
+ return FALSE
+ //Needs to be capable (replace with incapacitated call?)
+ if(stat || paralysis || stunned || weakened || lying || restrained() || buckled)
+ to_chat(src,"You cannot do that in your current state!")
+ return FALSE
+ //Needs to be adjacent, at the very least.
+ if(!Adjacent(target))
+ to_chat(src,"You must be next to your target.")
+ return FALSE
+ //Cooldown on abilities
+ if(last_special > world.time)
+ to_chat(src,"You can't perform an ability again so soon!")
+ return FALSE
+
+ return target
+
+//Human test for shreddability, returns the mob if they can be shredded.
+/mob/living/carbon/human/vore_shred_time = 10 SECONDS
+/mob/living/carbon/human/can_shred()
+ //Humans need a grab
+ var/obj/item/weapon/grab/G = get_active_hand()
+ if(!istype(G))
+ to_chat(src,"You have to have a very strong grip on someone first!")
+ return FALSE
+ if(G.state != GRAB_NECK)
+ to_chat(src,"You must have a tighter grip to severely damage this creature!")
+ return FALSE
+
+ return ..(G.affecting)
+
+//PAIs don't need a grab or anything
+/mob/living/silicon/pai/can_shred(var/mob/living/carbon/human/target)
+ if(!target)
+ var/list/choices = list()
+ for(var/mob/living/carbon/human/M in oviewers(1))
+ choices += M
+
+ if(!choices.len)
+ to_chat(src,"There's nobody nearby to use this on.")
+
+ target = input(src,"Who do you wish to target?","Damage/Remove Prey's Organ") as null|anything in choices
+ if(!istype(target))
+ return FALSE
+
+ return ..(target)
+
+/mob/living/proc/shred_limb()
set name = "Damage/Remove Prey's Organ"
set desc = "Severely damages prey's organ. If the limb is already severely damaged, it will be torn off."
set category = "Abilities"
- if(!ishuman(src))
- return //If you're not a human you don't have permission to do this.
- if(last_special > world.time)
+ //can_shred() will return a mob we can shred, if we can shred any.
+ var/mob/living/carbon/human/T = can_shred()
+ if(!istype(T))
+ return //Silent, because can_shred does messages.
+
+ //Let them pick any of the target's external organs
+ var/obj/item/organ/external/T_ext = input(src,"What do you wish to severely damage?") as null|anything in T.organs //D for destroy.
+ if(!T_ext) //Picking something here is critical.
return
-
- if(stat || paralysis || stunned || weakened || lying || restrained() || buckled)
- to_chat(src, "You cannot severely damage anything in your current state!")
- return
-
- var/mob/living/carbon/human/C = src
- var/obj/item/weapon/grab/G = src.get_active_hand()
- if(!istype(G))
- to_chat(C, "We must be grabbing a creature in our active hand to severely damage them.")
- return
-
- var/mob/living/carbon/human/T = G.affecting
- if(!istype(T)) //Are they a mob?
- to_chat(C, "\The [T] is not able to be severely damaged!")
- return
-
- if(G.state != GRAB_NECK)
- to_chat(C, "You must have a tighter grip to severely damage this creature.")
- return
-
- if(!T || !C || C.stat)
- return
-
- if(!Adjacent(T))
- return
-
- var/list/choices2 = list()
- for(var/obj/item/organ/O in T.organs) //External organs
- choices2 += O
-
- var/obj/item/organ/external/D = input(C,"What do you wish to severely damage?") as null|anything in choices2 //D for destroy.
- if(D.vital)
- if(alert("Are you sure you wish to severely damage their [D]? It most likely will kill the prey...",,"Yes", "No") != "Yes")
+ if(T_ext.vital)
+ if(alert("Are you sure you wish to severely damage their [T_ext]? It will likely kill [T]...",,"Yes", "No") != "Yes")
return //If they reconsider, don't continue.
- var/list/choices3 = list()
- for(var/obj/item/organ/internal/I in D.internal_organs) //Look for the internal organ in the organ being shreded.
- choices3 += I
+ //Any internal organ, if there are any
+ var/obj/item/organ/internal/T_int = input(src,"Do you wish to severely damage an internal organ, as well? If not, click 'cancel'") as null|anything in T_ext.internal_organs
+ if(T_int && T_int.vital)
+ if(alert("Are you sure you wish to severely damage their [T_int]? It will likely kill [T]...",,"Yes", "No") != "Yes")
+ return //If they reconsider, don't continue.
- var/obj/item/organ/internal/P = input(C,"Do you wish to severely damage an internal organ, as well? If not, click 'cancel'") as null|anything in choices3
+ //And a belly, if they want
+ var/obj/belly/B = input(src,"Do you wish to swallow the organ if you tear if out? If not, click 'cancel'") as null|anything in vore_organs
- var/eat_limb = input(C,"Do you wish to swallow the organ if you tear if out? If so, select which stomach.") as null|anything in C.vore_organs //EXTREMELY EFFICIENT
-
- if(last_special > world.time)
+ if(can_shred(T) != T)
+ to_chat(src,"Looks like you lost your chance...")
return
- if(stat || paralysis || stunned || weakened || lying || restrained() || buckled)
- to_chat(C, "You cannot shred in your current state.")
- return
+ last_special = world.time + vore_shred_time
+ visible_message("[src] appears to be preparing to do something to [T]!") //Let everyone know that bad times are ahead
- last_special = world.time + 100 //10 seconds.
- C.visible_message("[C] appears to be preparing to do something to [T]!") //Let everyone know that bad times are head
+ if(do_after(src, vore_shred_time, T)) //Ten seconds. You have to be in a neckgrab for this, so you're already in a bad position.
+ if(can_shred(T) != T)
+ to_chat(src,"Looks like you lost your chance...")
+ return
+
+ //Removing an internal organ
+ if(T_int && T_int.damage >= 25) //Internal organ and it's been severely damaged
+ T.apply_damage(15, BRUTE, T_ext) //Damage the external organ they're going through.
+ T_int.removed()
+ if(B)
+ T_int.forceMove(B) //Move to pred's gut
+ visible_message("[src] severely damages [T_int.name] of [T]!")
+ else
+ T_int.forceMove(T.loc)
+ visible_message("[src] severely damages [T_ext.name] of [T], resulting in their [T_int.name] coming out!","You tear out [T]'s [T_int.name]!")
- if(do_after(C, 100, T)) //Ten seconds. You have to be in a neckgrab for this, so you're already in a bad position.
- if(!Adjacent(T)) return
- if(P && P.damage >= 25) //Internal organ and it's been severely damage
- T.apply_damage(15, BRUTE, D) //Damage the external organ they're going through.
- P.removed()
- P.forceMove(T.loc) //Move to where prey is.
- log_and_message_admins("tore out [P] of [T].", C)
- if(eat_limb)
- var/datum/belly/S = C.vore_organs[eat_limb]
- P.forceMove(C) //Move to pred's gut
- S.internal_contents |= P //Add to pred's gut.
- C.visible_message("[C] severely damages [D] of [T]!") // Same as below, but (pred) damages the (right hand) of (person)
- to_chat(C, "[P] of [T] moves into your [S]!") //Quietly eat their internal organ! Comes out "The (right hand) of (person) moves into your (stomach)
- playsound(C, S.vore_sound, 70, 1)
- log_and_message_admins("tore out and ate [P] of [T].", C)
+ //Removing an external organ
+ else if(!T_int && (T_ext.damage >= 25 || T_ext.brute_dam >= 25))
+ T_ext.droplimb(1,DROPLIMB_EDGE) //Clean cut so it doesn't kill the prey completely.
+
+ //Is it groin/chest? You can't remove those.
+ if(T_ext.cannot_amputate)
+ T.apply_damage(25, BRUTE, T_ext)
+ visible_message("[src] severely damages [T]'s [T_ext.name]!")
+ else if(B)
+ T_ext.forceMove(B)
+ visible_message("[src] swallows [T]'s [T_ext.name] into their [lowertext(B.name)]!")
else
- log_and_message_admins("tore out [P] of [T].", C)
- C.visible_message("[C] severely damages [D] of [T], resulting in their [P] coming out!")
- else if(!P && (D.damage >= 25 || D.brute_dam >= 25)) //Not targeting an internal organ & external organ has been severely damaged already.
- D.droplimb(1,DROPLIMB_EDGE) //Clean cut so it doesn't kill the prey completely.
- if(D.cannot_amputate) //Is it groin/chest? You can't remove those.
- T.apply_damage(25, BRUTE, D)
- C.visible_message("[C] severely damage [T]'s [D]!") //Keep it vague. Let the /me's do the talking.
- log_and_message_admins("shreded [T]'s [D].", C)
- return
- if(eat_limb)
- var/datum/belly/S = C.vore_organs[eat_limb]
- D.forceMove(C) //Move to pred's gut
- S.internal_contents |= D //Add to pred's gut.
- C.visible_message("[C] swallows [D] of [T] into their [S]!","You swallow [D] of [T]!")
- playsound(C, S.vore_sound, 70, 1)
- to_chat(C, "Their [D] moves into your [S]!")
- log_and_message_admins("tore off and ate [D] of [T].", C)
- else
- C.visible_message("[C] tears off [D] of [T]!","You tear out [D] of [T]!") //Will come out "You tear out (the right foot) of (person)
- log_and_message_admins("tore off [T]'s [D].", C)
- else //Not targeting an internal organ w/ > 25 damage , and the limb doesn't have < 25 damage.
- if(P)
- P.damage = 25 //Internal organs can only take damage, not brute damage.
- T.apply_damage(25, BRUTE, D)
- C.visible_message("[C] severely damages [D] of [T]!") //Keep it vague. Let the /me's do the talking.
- log_and_message_admins("shreded [D] of [T].", C)
+ T_ext.forceMove(T.loc)
+ visible_message("[src] tears off [T]'s [T_ext.name]!","You tear off [T]'s [T_ext.name]!")
+
+ //Not targeting an internal organ w/ > 25 damage , and the limb doesn't have < 25 damage.
+ else
+ if(T_int)
+ T_int.damage = 25 //Internal organs can only take damage, not brute damage.
+ T.apply_damage(25, BRUTE, T_ext)
+ visible_message("[src] severely damages [T]'s [T_ext.name]!")
+
+ src.attack_log += text("\[[time_stamp()]\] Shred_limb'd [T.real_name] ([T.ckey])")
+ T.attack_log += text("\[[time_stamp()]\] [src.real_name] ([src.ckey]) shred_limb'd me")
+ msg_admin_attack("[src.real_name] ([src.ckey]) shredded (shred_limb) [T.real_name] ([T.ckey]) (JMP)")
/mob/living/proc/flying_toggle()
set name = "Toggle Flight"
diff --git a/code/modules/mob/living/carbon/human/species/station/station_special_vr.dm b/code/modules/mob/living/carbon/human/species/station/station_special_vr.dm
index cdfebdbd04..56a35acc96 100644
--- a/code/modules/mob/living/carbon/human/species/station/station_special_vr.dm
+++ b/code/modules/mob/living/carbon/human/species/station/station_special_vr.dm
@@ -28,7 +28,7 @@
/mob/living/carbon/human/proc/succubus_drain_finalize,
/mob/living/carbon/human/proc/succubus_drain_lethal,
/mob/living/carbon/human/proc/bloodsuck,
- /mob/living/carbon/human/proc/shred_limb,
+ /mob/living/proc/shred_limb,
/mob/living/proc/flying_toggle,
/mob/living/proc/start_wings_hovering) //Xenochimera get all the special verbs since they can't select traits.
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 4ca556be13..6c14187035 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
@@ -32,7 +32,7 @@
spawn_flags = SPECIES_CAN_JOIN
appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR
- inherent_verbs = list(/mob/living/carbon/human/proc/shred_limb)
+ inherent_verbs = list(/mob/living/proc/shred_limb)
flesh_color = "#AFA59E"
base_color = "#777777"
@@ -76,7 +76,7 @@
secondary_langs = list(LANGUAGE_SKRELLIAN)
name_language = LANGUAGE_SKRELLIAN
color_mult = 1
- inherent_verbs = list(/mob/living/carbon/human/proc/shred_limb)
+ inherent_verbs = list(/mob/living/proc/shred_limb)
min_age = 18
max_age = 110
@@ -120,7 +120,7 @@
secondary_langs = list(LANGUAGE_BIRDSONG)
name_language = LANGUAGE_BIRDSONG
color_mult = 1
- inherent_verbs = list(/mob/living/carbon/human/proc/shred_limb,/mob/living/proc/flying_toggle,/mob/living/proc/start_wings_hovering)
+ inherent_verbs = list(/mob/living/proc/shred_limb,/mob/living/proc/flying_toggle,/mob/living/proc/start_wings_hovering)
min_age = 18
max_age = 110
@@ -182,7 +182,7 @@
"You feel uncomfortably warm.",
"Your overheated skin itches."
)
- inherent_verbs = list(/mob/living/carbon/human/proc/shred_limb)
+ inherent_verbs = list(/mob/living/proc/shred_limb)
/datum/species/fl_zorren
name = "Flatland Zorren"
@@ -213,7 +213,7 @@
flesh_color = "#AFA59E"
base_color = "#333333"
color_mult = 1
- inherent_verbs = list(/mob/living/carbon/human/proc/shred_limb)
+ inherent_verbs = list(/mob/living/proc/shred_limb)
heat_discomfort_strings = list(
"Your fur prickles in the heat.",
@@ -239,7 +239,7 @@
// gluttonous = 1
num_alternate_languages = 3
color_mult = 1
- inherent_verbs = list(/mob/living/carbon/human/proc/shred_limb)
+ inherent_verbs = list(/mob/living/proc/shred_limb)
blurb = "Vulpkanin are a species of sharp-witted canine-pideds residing on the planet Altam just barely within the \
dual-star Vazzend system. Their politically de-centralized society and independent natures have led them to become a species and \
@@ -293,7 +293,7 @@
"You feel uncomfortably warm.",
"Your chitin feels hot."
)
- inherent_verbs = list(/mob/living/carbon/human/proc/shred_limb)
+ inherent_verbs = list(/mob/living/proc/shred_limb)
/datum/species/unathi
spawn_flags = SPECIES_CAN_JOIN //Species_can_join is the only spawn flag all the races get, so that none of them will be whitelist only if whitelist is enabled.
@@ -302,7 +302,7 @@
tail_animation = 'icons/mob/species/unathi/tail_vr.dmi'
color_mult = 1
min_age = 18
- inherent_verbs = list(/mob/living/carbon/human/proc/shred_limb)
+ inherent_verbs = list(/mob/living/proc/shred_limb)
/datum/species/tajaran
spawn_flags = SPECIES_CAN_JOIN
@@ -312,7 +312,7 @@
color_mult = 1
min_age = 18
gluttonous = 0 //Moving this here so I don't have to fix this conflict every time polaris glances at station.dm
- inherent_verbs = list(/mob/living/carbon/human/proc/shred_limb)
+ inherent_verbs = list(/mob/living/proc/shred_limb)
/datum/species/skrell
spawn_flags = SPECIES_CAN_JOIN
@@ -338,7 +338,7 @@
inherent_verbs = list(
/mob/living/carbon/human/proc/sonar_ping,
/mob/living/proc/hide,
- /mob/living/carbon/human/proc/shred_limb,
+ /mob/living/proc/shred_limb,
/mob/living/proc/toggle_pass_table
)
@@ -359,7 +359,7 @@
min_age = 18
icobase = 'icons/mob/human_races/r_vox_old.dmi'
deform = 'icons/mob/human_races/r_def_vox_old.dmi'
- inherent_verbs = list(/mob/living/carbon/human/proc/shred_limb)
+ inherent_verbs = list(/mob/living/proc/shred_limb)
datum/species/harpy
name = "Rapala"
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 7349bafa02..e5287dc96b 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
@@ -87,7 +87,7 @@
/datum/trait/hard_vore/apply(var/datum/species/S,var/mob/living/carbon/human/H)
..(S,H)
- H.verbs |= /mob/living/carbon/human/proc/shred_limb
+ H.verbs |= /mob/living/proc/shred_limb
/datum/trait/trashcan
name = "Trash Can"
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 922923d5f2..76d497734a 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -29,8 +29,6 @@
//Random events (vomiting etc)
handle_random_events()
- attempt_vr(src,"handle_internal_contents",args) //VOREStation Code
-
. = 1
//Chemicals in the body, this is moved over here so that blood can be added after death
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 3f46e1812a..3ca6f129b0 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -1212,3 +1212,18 @@ default behaviour is:
item.throw_at(target, throw_range, item.throw_speed, src)
+
+/mob/living/get_sound_env(var/pressure_factor)
+ if (hallucination)
+ return PSYCHOTIC
+ else if (druggy)
+ return DRUGGED
+ else if (drowsyness)
+ return DIZZY
+ else if (confused)
+ return DIZZY
+ else if (sleeping)
+ return UNDERWATER
+ else
+ return ..()
+
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index b16cf888dd..b67f4cd185 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -151,12 +151,14 @@ var/list/ai_verbs_default = list(
add_language(LANGUAGE_UNATHI, 1)
add_language(LANGUAGE_SIIK, 1)
add_language(LANGUAGE_SKRELLIAN, 1)
+ add_language(LANGUAGE_SKRELLIANFAR, 0)
add_language(LANGUAGE_TRADEBAND, 1)
add_language(LANGUAGE_GUTTER, 1)
add_language(LANGUAGE_EAL, 1)
add_language(LANGUAGE_SCHECHI, 1)
add_language(LANGUAGE_SIGN, 1)
add_language(LANGUAGE_ROOTLOCAL, 1)
+ add_language(LANGUAGE_TERMINUS, 1)
if(!safety)//Only used by AIize() to successfully spawn an AI.
if (!B)//If there is no player/brain inside.
diff --git a/code/modules/mob/living/silicon/pai/examine.dm b/code/modules/mob/living/silicon/pai/examine.dm
index 0d4d73bbe7..876b9aacf1 100644
--- a/code/modules/mob/living/silicon/pai/examine.dm
+++ b/code/modules/mob/living/silicon/pai/examine.dm
@@ -7,7 +7,7 @@
if(!src.client) msg += "\nIt appears to be in stand-by mode.\n" //afk
if(UNCONSCIOUS) msg += "\nIt doesn't seem to be responding.\n"
if(DEAD) msg += "\nIt looks completely unsalvageable.\n"
- msg += attempt_vr(src,"examine_bellies_pai",args) //VOREStation Edit
+ msg += attempt_vr(src,"examine_bellies",args) //VOREStation Edit
// VOREStation Edit: Start
if(ooc_notes)
diff --git a/code/modules/mob/living/silicon/pai/life.dm b/code/modules/mob/living/silicon/pai/life.dm
index 92e430b6a5..f483921b81 100644
--- a/code/modules/mob/living/silicon/pai/life.dm
+++ b/code/modules/mob/living/silicon/pai/life.dm
@@ -21,7 +21,6 @@
src << "Communication circuit reinitialized. Speech and messaging functionality restored."
handle_statuses()
- handle_internal_contents() //VOREStation edit
if(health <= 0)
death(null,"gives one shrill beep before falling lifeless.")
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index df86b24c00..0ad35e7fae 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -99,6 +99,7 @@
add_language(LANGUAGE_TRADEBAND, 1)
add_language(LANGUAGE_GUTTER, 1)
add_language(LANGUAGE_EAL, 1)
+ add_language(LANGUAGE_TERMINUS, 1)
add_language(LANGUAGE_SIGN, 0)
verbs += /mob/living/silicon/pai/proc/choose_chassis
@@ -298,7 +299,7 @@
if(istype(T)) T.visible_message("[src] folds outwards, expanding into a mobile form.")
verbs += /mob/living/silicon/pai/proc/pai_nom //VOREStation edit
verbs += /mob/living/proc/set_size //VOREStation edit
- verbs += /mob/living/silicon/pai/proc/shred_limb //VORREStation edit
+ verbs += /mob/living/proc/shred_limb //VORREStation edit
/mob/living/silicon/pai/verb/fold_up()
set category = "pAI Commands"
@@ -389,9 +390,7 @@
if(src.loc == card)
return
- for(var/I in vore_organs) //VOREStation edit. Release all their stomach contents. Don't want them to be in the PAI when they fold or weird things might happen.
- var/datum/belly/B = vore_organs[I] //VOREStation edit
- B.release_all_contents() //VOREStation edit
+ release_vore_contents() //VOREStation Add
var/turf/T = get_turf(src)
if(istype(T)) T.visible_message("[src] neatly folds inwards, compacting down to a rectangular card.")
diff --git a/code/modules/mob/living/silicon/pai/pai_vr.dm b/code/modules/mob/living/silicon/pai/pai_vr.dm
index 8350e4764b..c5de247595 100644
--- a/code/modules/mob/living/silicon/pai/pai_vr.dm
+++ b/code/modules/mob/living/silicon/pai/pai_vr.dm
@@ -13,13 +13,12 @@
/mob/living/silicon/pai/proc/update_fullness_pai() //Determines if they have something in their stomach. Copied and slightly modified.
var/new_people_eaten = 0
- for(var/I in vore_organs)
- var/datum/belly/B = vore_organs[I]
- for(var/mob/living/M in B.internal_contents)
+ for(var/belly in vore_organs)
+ var/obj/belly/B = belly
+ for(var/mob/living/M in B)
new_people_eaten += M.size_multiplier
people_eaten = min(1, new_people_eaten)
-
/mob/living/silicon/pai/update_icon() //Some functions cause this to occur, such as resting
..()
update_fullness_pai()
@@ -43,114 +42,3 @@
icon_state = "[chassis]_full"
else if(people_eaten && resting)
icon_state = "[chassis]_rest_full"
-
-/mob/living/silicon/pai/proc/examine_bellies_pai()
-
- var/message = ""
- for (var/I in src.vore_organs)
- var/datum/belly/B = vore_organs[I]
- message += B.get_examine_msg()
-
- return message
-
-
-
-//PAI Remove Limb code
-/mob/living/silicon/pai/proc/shred_limb()
- set name = "Damage/Remove Prey's Organ"
- set desc = "Severely damages prey's organ. If the limb is already severely damaged, it will be torn off."
- set category = "Abilities"
- if(!ispAI(src))
- return //If you're not a pai you don't have permission to do this.
- var/mob/living/silicon/pai/C = src
-
- if(last_special > world.time)
- return
-
- var/list/choices = list()
- for(var/mob/living/carbon/human/M in view(1,src))
- if(!istype(M,/mob/living/silicon) && Adjacent(M))
- choices += M
- choices -= src
-
- var/mob/living/carbon/human/T = input(src,"Who do you wish to target?") as null|anything in choices
-
- if(!T || !src || src.stat) return
-
- if(!Adjacent(T)) return
-
- if(last_special > world.time) return
-
- if(stat || paralysis || stunned || weakened || lying || restrained() || buckled)
- src << "You cannot target in your current state."
- return
-
- var/list/choices2 = list()
- for(var/obj/item/organ/O in T.organs) //External organs
- choices2 += O
-
- var/obj/item/organ/external/D = input(C,"What do you wish to severely damage?") as null|anything in choices2 //D for destroy.
- if(D.vital)
- if(alert("Are you sure you wish to severely damage their [D]? It most likely will kill the prey...",,"Yes", "No") != "Yes")
- return //If they reconsider, don't continue.
-
- var/list/choices3 = list()
- for(var/obj/item/organ/internal/I in D.internal_organs) //Look for the internal organ in the organ being shreded.
- choices3 += I
-
- var/obj/item/organ/internal/P = input(C,"Do you wish to severely damage an internal organ, as well? If not, click 'cancel'") as null|anything in choices3
-
- var/eat_limb = input(C,"Do you wish to swallow the organ if you tear if out? If so, select which stomach.") as null|anything in C.vore_organs //EXTREMELY EFFICIENT
-
- if(last_special > world.time)
- return
-
- if(stat || paralysis || stunned || weakened || lying || restrained() || buckled)
- to_chat(C, "You cannot shred in your current state.")
- return
-
- last_special = world.time + 450 //45 seconds.
- C.visible_message("[C] appears to be preparing to do something to [T]!") //Let everyone know that bad times are head
-
- if(do_after(C, 450, T)) //Fourty-Five seconds. You don't need a neckgrab for this, so it's going to take a long while.
- if(!Adjacent(T)) return
- if(P && P.damage >= 25) //Internal organ and it's been severely damage
- T.apply_damage(15, BRUTE, D) //Damage the external organ they're going through.
- P.removed()
- P.forceMove(T.loc) //Move to where prey is.
- log_and_message_admins("tore out [P] of [T].", C)
- if(eat_limb)
- var/datum/belly/S = C.vore_organs[eat_limb]
- P.forceMove(C) //Move to pred's gut
- S.internal_contents |= P //Add to pred's gut.
- C.visible_message("[C] severely damages [D] of [T]!") // Same as below, but (pred) damages the (right hand) of (person)
- to_chat(C, "[P] of [T] moves into your [S]!") //Quietly eat their internal organ! Comes out "The (right hand) of (person) moves into your (stomach)
- playsound(C, S.vore_sound, 70, 1)
- log_and_message_admins("tore out and ate [P] of [T].", C)
- else
- log_and_message_admins("tore out [P] of [T].", C)
- C.visible_message("[C] severely damages [D] of [T], resulting in their [P] coming out!")
- else if(!P && (D.damage >= 25 || D.brute_dam >= 25)) //Not targeting an internal organ & external organ has been severely damaged already.
- D.droplimb(1,DROPLIMB_EDGE) //Clean cut so it doesn't kill the prey completely.
- if(D.cannot_amputate) //Is it groin/chest? You can't remove those.
- T.apply_damage(25, BRUTE, D)
- C.visible_message("[C] severely damage [T]'s [D]!") //Keep it vague. Let the /me's do the talking.
- log_and_message_admins("shreded [T]'s [D].", C)
- return
- if(eat_limb)
- var/datum/belly/S = C.vore_organs[eat_limb]
- D.forceMove(C) //Move to pred's gut
- S.internal_contents |= D //Add to pred's gut.
- C.visible_message("[C] swallows [D] of [T] into their [S]!","You swallow [D] of [T]!")
- playsound(C, S.vore_sound, 70, 1)
- to_chat(C, "Their [D] moves into your [S]!")
- log_and_message_admins("tore off and ate [D] of [T].", C)
- else
- C.visible_message("[C] tears off [D] of [T]!","You tear out [D] of [T]!") //Will come out "You tear out (the right foot) of (person)
- log_and_message_admins("tore off [T]'s [D].", C)
- else //Not targeting an internal organ w/ > 25 damage , and the limb doesn't have < 25 damage.
- if(P)
- P.damage = 25 //Internal organs can only take damage, not brute damage.
- T.apply_damage(25, BRUTE, D)
- C.visible_message("[C] severely damages [D] of [T]!") //Keep it vague. Let the /me's do the talking.
- log_and_message_admins("shreded [D] of [T].", C)
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 8a36ef87f1..6d4cfbe976 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
@@ -527,15 +527,12 @@
hearer << deathsound
T << deathsound
if(is_vore_predator(T))
- for (var/bellytype in T.vore_organs)
- var/datum/belly/belly = T.vore_organs[bellytype]
- for (var/obj/thing in belly.internal_contents)
- thing.loc = src
- belly.internal_contents -= thing
- for (var/mob/subprey in belly.internal_contents)
- subprey.loc = src
- belly.internal_contents -= subprey
- to_chat(subprey, "As [T] melts away around you, you find yourself in [hound]'s [name]")
+ for(var/belly in T.vore_organs)
+ var/obj/belly/B = belly
+ for(var/atom/movable/thing in B)
+ thing.forceMove(src)
+ if(ismob(thing))
+ to_chat(thing, "As [T] melts away around you, you find yourself in [hound]'s [name]")
for(var/obj/item/I in T)
if(istype(I,/obj/item/organ/internal/mmi_holder/posibrain))
var/obj/item/organ/internal/mmi_holder/MMI = I
diff --git a/code/modules/mob/living/silicon/robot/examine_vr.dm b/code/modules/mob/living/silicon/robot/examine_vr.dm
index fba3791795..89d1522b8c 100644
--- a/code/modules/mob/living/silicon/robot/examine_vr.dm
+++ b/code/modules/mob/living/silicon/robot/examine_vr.dm
@@ -1,8 +1,8 @@
/mob/living/silicon/robot/proc/examine_bellies_borg()
var/message = ""
- for (var/I in src.vore_organs)
- var/datum/belly/B = vore_organs[I]
+ for(var/belly in vore_organs)
+ var/obj/belly/B = belly
message += B.get_examine_msg()
return message
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm
index fd8164b01c..48455c3844 100644
--- a/code/modules/mob/living/silicon/robot/inventory.dm
+++ b/code/modules/mob/living/silicon/robot/inventory.dm
@@ -256,3 +256,9 @@
/mob/living/silicon/robot/put_in_hands(var/obj/item/W) // No hands.
W.loc = get_turf(src)
return 1
+
+/mob/living/silicon/robot/is_holding_item_of_type(typepath)
+ for(var/obj/item/I in list(module_state_1, module_state_2, module_state_3))
+ if(istype(I, typepath))
+ return I
+ return FALSE
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index aa1cf2d271..6c70e1b4b0 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -24,7 +24,6 @@
process_killswitch()
process_locks()
process_queued_alarms()
- handle_internal_contents() //VOREStation Edit
update_canmove()
/mob/living/silicon/robot/proc/clamp_values()
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 8f1d7c3257..2ec46478a4 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules/station.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules/station.dm
@@ -23,7 +23,7 @@ var/global/list/robot_modules = list(
var/hide_on_manifest = 0
var/channels = list()
var/networks = list()
- var/languages = list(LANGUAGE_SOL_COMMON = 1, LANGUAGE_TRADEBAND = 1, LANGUAGE_UNATHI = 0, LANGUAGE_SIIK = 0, LANGUAGE_SKRELLIAN = 0, LANGUAGE_GUTTER = 0, LANGUAGE_SCHECHI = 0, "Sagaru" = 0, "Birdsong" = 0, "Canilunzt" = 0, LANGUAGE_SIGN = 0)
+ var/languages = list(LANGUAGE_SOL_COMMON = 1, LANGUAGE_TRADEBAND = 1, LANGUAGE_UNATHI = 0, LANGUAGE_SIIK = 0, LANGUAGE_SKRELLIAN = 0, LANGUAGE_GUTTER = 0, LANGUAGE_SCHECHI = 0, "Sagaru" = 0, "Birdsong" = 0, "Canilunzt" = 0, LANGUAGE_SIGN = 0, LANGUAGE_TERMINUS = 1)
var/sprites = list()
var/can_be_pushed = 1
var/no_slip = 0
@@ -51,6 +51,8 @@ var/global/list/robot_modules = list(
if(R.radio)
R.radio.recalculateChannels()
+ vr_add_sprites() //Vorestation Edit: For vorestation only sprites
+
R.set_module_sprites(sprites)
R.choose_icon(R.module_sprites.len + 1, R.module_sprites)
@@ -578,11 +580,13 @@ var/global/list/robot_modules = list(
LANGUAGE_UNATHI = 1,
LANGUAGE_SIIK = 1,
LANGUAGE_SKRELLIAN = 1,
+ LANGUAGE_SKRELLIANFAR = 0,
LANGUAGE_ROOTLOCAL = 0,
LANGUAGE_TRADEBAND = 1,
LANGUAGE_GUTTER = 1,
LANGUAGE_SCHECHI = 1,
LANGUAGE_EAL = 1,
+ LANGUAGE_TERMINUS = 1,
LANGUAGE_SIGN = 0
)
diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm b/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm
index 71f50f6714..274754a562 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm
@@ -14,6 +14,7 @@
LANGUAGE_DAEMON = 0,
LANGUAGE_ENOCHIAN = 0
)
+ var/vr_sprites = list()
/obj/item/weapon/robot_module/robot/clerical
languages = list(
@@ -47,6 +48,10 @@
/obj/item/weapon/robot_module/proc/vr_new() // Any Global modules, just add them before the return (This will also affect all the borgs in this file)
return
+/obj/item/weapon/robot_module/proc/vr_add_sprites() // Adds sprites from this file into list of avialible ones for global modules
+ sprites += vr_sprites
+ return
+
/obj/item/weapon/robot_module/robot/medical/surgeon/vr_new() //Surgeon Bot
src.modules += new /obj/item/device/sleevemate(src) //Lets them scan people.
. = ..() //Any Global vore modules will come from here
@@ -55,6 +60,42 @@
src.modules += new /obj/item/device/sleevemate(src) //Lets them scan people.
. = ..() //Any Global vore modules will come from here
+/obj/item/weapon/robot_module/robot/medical/crisis //Allows Crisis module to use Handy sprite
+ vr_sprites = list(
+ "Handy" = "handy-med"
+ )
+
+/obj/item/weapon/robot_module/robot/clerical/butler //VR Handy sprites
+ vr_sprites = list(
+ "Handy - Service" = "handy-service",
+ "Handy - Hydro" = "handy-hydro"
+ )
+
+/obj/item/weapon/robot_module/robot/clerical/general //VR Handy sprites
+ vr_sprites = list(
+ "Handy" = "handy-clerk"
+ )
+
+/obj/item/weapon/robot_module/robot/janitor //VR Handy sprites
+ vr_sprites = list(
+ "Handy" = "handy-janitor"
+ )
+
+/obj/item/weapon/robot_module/robot/security/general //VR Handy sprites
+ vr_sprites = list(
+ "Handy" = "handy-sec"
+ )
+
+/obj/item/weapon/robot_module/robot/miner //VR Handy sprites
+ vr_sprites = list(
+ "Handy" = "handy-miner"
+ )
+
+/obj/item/weapon/robot_module/robot/standard //VR Handy sprites
+ vr_sprites = list(
+ "Handy" = "handy-standard"
+ )
+
/obj/item/weapon/robot_module/robot/knine
name = "k9 robot module"
sprites = list(
diff --git a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm
index b3b88074b0..1575516d91 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm
@@ -9,11 +9,13 @@
LANGUAGE_UNATHI = 0,
LANGUAGE_SIIK = 0,
LANGUAGE_SKRELLIAN = 0,
+ LANGUAGE_SKRELLIANFAR = 0,
LANGUAGE_ROOTLOCAL = 0,
LANGUAGE_GUTTER = 1,
LANGUAGE_SCHECHI = 0,
LANGUAGE_EAL = 1,
- LANGUAGE_SIGN = 0
+ LANGUAGE_SIGN = 0,
+ LANGUAGE_TERMINUS = 1
)
sprites = list(
"Cerberus" = "syndie_bloodhound",
diff --git a/code/modules/mob/living/silicon/robot/robot_vr.dm b/code/modules/mob/living/silicon/robot/robot_vr.dm
index 6bf2f77c0d..2dd54a1e06 100644
--- a/code/modules/mob/living/silicon/robot/robot_vr.dm
+++ b/code/modules/mob/living/silicon/robot/robot_vr.dm
@@ -6,6 +6,17 @@
var/pounce_cooldown_time = 40
var/leap_at
var/dogborg = FALSE
+ var/original_icon = 'icons/mob/robots.dmi'
+ var/vr_icons = list(
+ "handy-hydro",
+ "handy-service",
+ "handy-clerk",
+ "handy-janitor",
+ "handy-miner",
+ "handy-standard",
+ "handy-sec"
+ ) //List of all used sprites that are in robots_vr.dmi
+
/mob/living/silicon/robot/verb/robot_nom(var/mob/living/T in living_mobs(1))
set name = "Robot Nom"
@@ -17,6 +28,7 @@
return feed_grabbed_to_self(src,T)
/mob/living/silicon/robot/updateicon()
+ vr_sprite_check()
..()
if(dogborg == TRUE && stat == CONSCIOUS)
if(sleeper_g == TRUE)
@@ -70,3 +82,10 @@
cleaned_human << "[src] cleans your face!"
return
return
+
+/mob/living/silicon/robot/proc/vr_sprite_check()
+ if((icon_state in vr_icons) && (icon == 'icons/mob/robots.dmi'))
+ original_icon = icon
+ icon = 'icons/mob/robots_vr.dmi'
+ else if(!(icon_state in vr_icons))
+ icon = original_icon
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/animals/cat_vr.dm b/code/modules/mob/living/simple_animal/animals/cat_vr.dm
index f4c2644ad6..b2d5c73e5c 100644
--- a/code/modules/mob/living/simple_animal/animals/cat_vr.dm
+++ b/code/modules/mob/living/simple_animal/animals/cat_vr.dm
@@ -1,8 +1,8 @@
/mob/living/simple_animal/cat/fluff/Runtime/init_belly()
..()
- var/datum/belly/B = vore_organs[vore_selected]
+ var/obj/belly/B = vore_selected
B.name = "Stomach"
- B.inside_flavor = "The slimy wet insides of Runtime! Not quite as clean as the cat on the outside."
+ B.desc = "The slimy wet insides of Runtime! Not quite as clean as the cat on the outside."
B.emote_lists[DM_HOLD] = list(
"Runtime's stomach kneads gently on you and you're fairly sure you can hear her start purring.",
diff --git a/code/modules/mob/living/simple_animal/animals/fish_vr.dm b/code/modules/mob/living/simple_animal/animals/fish_vr.dm
index 406171d3f2..d1d74ec60e 100644
--- a/code/modules/mob/living/simple_animal/animals/fish_vr.dm
+++ b/code/modules/mob/living/simple_animal/animals/fish_vr.dm
@@ -11,9 +11,9 @@
/mob/living/simple_animal/fish/koi/poisonous/Life()
..()
- var/datum/belly/why = check_belly(src)
- if(why && prob(10))
- sting(why.owner)
+ if(isbelly(loc) && prob(10))
+ var/obj/belly/B = loc
+ sting(B.owner)
/mob/living/simple_animal/fish/koi/poisonous/react_to_attack(var/atom/A)
if(isliving(A) && Adjacent(A))
diff --git a/code/modules/mob/living/simple_animal/animals/fox_vr.dm b/code/modules/mob/living/simple_animal/animals/fox_vr.dm
index 8a2bcdf390..65938cb249 100644
--- a/code/modules/mob/living/simple_animal/animals/fox_vr.dm
+++ b/code/modules/mob/living/simple_animal/animals/fox_vr.dm
@@ -40,9 +40,9 @@
/mob/living/simple_animal/fox/init_belly()
..()
- var/datum/belly/B = vore_organs[vore_selected]
+ var/obj/belly/B = vore_selected
B.name = "Stomach"
- B.inside_flavor = "Slick foxguts. Cute on the outside, slimy on the inside!"
+ B.desc = "Slick foxguts. Cute on the outside, slimy on the inside!"
B.emote_lists[DM_HOLD] = list(
"The foxguts knead and churn around you harmlessly.",
@@ -187,9 +187,9 @@
/mob/living/simple_animal/fox/fluff/Renault/init_belly()
..()
- var/datum/belly/B = vore_organs[vore_selected]
+ var/obj/belly/B = vore_selected
B.name = "Stomach"
- B.inside_flavor = "Slick foxguts. They seem somehow more regal than perhaps other foxes!"
+ B.desc = "Slick foxguts. They seem somehow more regal than perhaps other foxes!"
B.emote_lists[DM_HOLD] = list(
"Renault's stomach walls squeeze around you more tightly for a moment, before relaxing, as if testing you a bit.",
diff --git a/code/modules/mob/living/simple_animal/animals/slime.dm b/code/modules/mob/living/simple_animal/animals/slime.dm
index f7d23771a3..d3a8b1df0c 100644
--- a/code/modules/mob/living/simple_animal/animals/slime.dm
+++ b/code/modules/mob/living/simple_animal/animals/slime.dm
@@ -1,4 +1,4 @@
-/mob/living/simple_animal/slime
+/mob/living/simple_animal/old_slime
name = "pet slime"
desc = "A lovable, domesticated slime."
icon = 'icons/mob/slimes.dmi'
@@ -19,14 +19,14 @@
var/colour = "grey"
-/mob/living/simple_animal/slime/science
+/mob/living/simple_animal/old_slime/science
name = "Kendrick"
colour = "rainbow"
icon_state = "rainbow baby slime"
icon_living = "rainbow baby slime"
icon_dead = "rainbow baby slime dead"
-/mob/living/simple_animal/slime/science/initialize()
+/mob/living/simple_animal/old_slime/science/initialize()
. = ..()
overlays.Cut()
overlays += "aslime-:33"
@@ -56,12 +56,12 @@
overlays += "aslime-:33"
/mob/living/simple_animal/adultslime/death()
- var/mob/living/simple_animal/slime/S1 = new /mob/living/simple_animal/slime (src.loc)
+ var/mob/living/simple_animal/old_slime/S1 = new /mob/living/simple_animal/old_slime (src.loc)
S1.icon_state = "[src.colour] baby slime"
S1.icon_living = "[src.colour] baby slime"
S1.icon_dead = "[src.colour] baby slime dead"
S1.colour = "[src.colour]"
- var/mob/living/simple_animal/slime/S2 = new /mob/living/simple_animal/slime (src.loc)
+ var/mob/living/simple_animal/old_slime/S2 = new /mob/living/simple_animal/old_slime (src.loc)
S2.icon_state = "[src.colour] baby slime"
S2.icon_living = "[src.colour] baby slime"
S2.icon_dead = "[src.colour] baby slime dead"
diff --git a/code/modules/mob/living/simple_animal/simple_animal_vr.dm b/code/modules/mob/living/simple_animal/simple_animal_vr.dm
index 669726c537..8aa585cbb3 100644
--- a/code/modules/mob/living/simple_animal/simple_animal_vr.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal_vr.dm
@@ -33,11 +33,9 @@
if(!IsAdvancedToolUser())
verbs |= /mob/living/simple_animal/proc/animal_nom
-// Release belly contents beforey being gc'd!
+// Release belly contents before being gc'd!
/mob/living/simple_animal/Destroy()
- for(var/I in vore_organs)
- var/datum/belly/B = vore_organs[I]
- B.release_all_contents(include_absorbed = TRUE) // When your stomach is empty
+ release_vore_contents()
prey_excludes.Cut()
. = ..()
@@ -49,9 +47,9 @@
// Update fullness based on size & quantity of belly contents
/mob/living/simple_animal/proc/update_fullness()
var/new_fullness = 0
- for(var/I in vore_organs)
- var/datum/belly/B = vore_organs[I]
- for(var/mob/living/M in B.internal_contents)
+ for(var/belly in vore_organs)
+ var/obj/belly/B = belly
+ for(var/mob/living/M in B)
new_fullness += M.size_multiplier
new_fullness = round(new_fullness, 1) // Because intervals of 0.25 are going to make sprite artists cry.
vore_fullness = min(vore_capacity, new_fullness)
@@ -137,10 +135,8 @@
stop_automated_movement = 0
/mob/living/simple_animal/death()
- for(var/I in vore_organs)
- var/datum/belly/B = vore_organs[I]
- B.release_all_contents(include_absorbed = TRUE) // When your stomach is empty
- ..() // then you have my permission to die.
+ release_vore_contents()
+ . = ..()
// Simple animals have only one belly. This creates it (if it isn't already set up)
/mob/living/simple_animal/proc/init_belly()
@@ -149,10 +145,11 @@
if(no_vore) //If it can't vore, let's not give it a stomach.
return
- var/datum/belly/B = new /datum/belly(src)
+ var/obj/belly/B = new /obj/belly(src)
+ vore_selected = B
B.immutable = 1
B.name = vore_stomach_name ? vore_stomach_name : "stomach"
- B.inside_flavor = vore_stomach_flavor ? vore_stomach_flavor : "Your surroundings are warm, soft, and slimy. Makes sense, considering you're inside \the [name]."
+ B.desc = vore_stomach_flavor ? vore_stomach_flavor : "Your surroundings are warm, soft, and slimy. Makes sense, considering you're inside \the [name]."
B.digest_mode = vore_default_mode
B.escapable = vore_escape_chance > 0
B.escapechance = vore_escape_chance
@@ -161,7 +158,6 @@
B.human_prey_swallow_time = swallowTime
B.nonhuman_prey_swallow_time = swallowTime
B.vore_verb = "swallow"
- // TODO - Customizable per mob
B.emote_lists[DM_HOLD] = list( // We need more that aren't repetitive. I suck at endo. -Ace
"The insides knead at you gently for a moment.",
"The guts glorp wetly around you as some air shifts.",
@@ -192,9 +188,7 @@
"The juices pooling beneath you sizzle against your sore skin.",
"The churning walls slowly pulverize you into meaty nutrients.",
"The stomach glorps and gurgles as it tries to work you into slop.")
- src.vore_organs[B.name] = B
- src.vore_selected = B.name
-
+
/mob/living/simple_animal/Bumped(var/atom/movable/AM, yes)
if(ismob(AM))
var/mob/tmob = AM
diff --git a/code/modules/mob/living/simple_animal/vore/otie.dm b/code/modules/mob/living/simple_animal/vore/otie.dm
index 3500a5b3ad..885f625fe2 100644
--- a/code/modules/mob/living/simple_animal/vore/otie.dm
+++ b/code/modules/mob/living/simple_animal/vore/otie.dm
@@ -184,27 +184,20 @@
if(ai_inactive)//No autobarf on player control.
return
if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/donut) && istype(src, /mob/living/simple_animal/otie/security))
- user << "The guard pup accepts your offer for their catch."
- for(var/I in vore_organs)
- var/datum/belly/B = vore_organs[I]
- B.release_all_contents()
- return
- if(prob(2)) //Small chance to get prey out from non-sec oties.
- for(var/I in vore_organs)
- var/datum/belly/B = vore_organs[I]
- B.release_all_contents()
- return
+ to_chat(user,"The guard pup accepts your offer for their catch.")
+ release_vore_contents()
+ else if(prob(2)) //Small chance to get prey out from non-sec oties.
+ to_chat(user,"The pup accepts your offer for their catch.")
+ release_vore_contents()
return
- ..()
+ . = ..()
/mob/living/simple_animal/otie/security/feed_grabbed_to_self(var/mob/living/user, var/mob/living/prey) // Make the gut start out safe for bellybrigging.
- var/datum/belly/B = user.vore_selected
- var/datum/belly/belly_target = user.vore_organs[B]
if(ishuman(target_mob))
- belly_target.digest_mode = DM_HOLD
+ vore_selected.digest_mode = DM_HOLD
if(istype(prey,/mob/living/simple_animal/mouse))
- belly_target.digest_mode = DM_DIGEST
- ..()
+ vore_selected.digest_mode = DM_DIGEST
+ . = ..()
/mob/living/simple_animal/otie/security/proc/check_threat(var/mob/living/M)
if(!M || !ishuman(M) || M.stat == DEAD || src == M)
diff --git a/code/modules/mob/living/simple_animal/vore/shadekin/ability_procs.dm b/code/modules/mob/living/simple_animal/vore/shadekin/ability_procs.dm
index f14901a63d..91bd07db29 100644
--- a/code/modules/mob/living/simple_animal/vore/shadekin/ability_procs.dm
+++ b/code/modules/mob/living/simple_animal/vore/shadekin/ability_procs.dm
@@ -21,7 +21,7 @@
ability_flags &= ~AB_PHASE_SHIFTED
name = real_name
for(var/belly in vore_organs)
- var/datum/belly/B = vore_organs[belly]
+ var/obj/belly/B = belly
B.escapable = initial(B.escapable)
overlays.Cut()
@@ -43,13 +43,9 @@
var/list/potentials = living_mobs(0)
if(potentials.len)
var/mob/living/target = pick(potentials)
- var/datum/belly/B = vore_organs[vore_selected]
- if(istype(target) && istype(B))
- target.forceMove(src)
- B.internal_contents |= target
- playsound(src, B.vore_sound, 100, 1)
- to_chat(target,"\The [src] phases in around you, [B.vore_verb]ing you into their [B.name]!")
- to_chat(src,"Your [B.name] has a new occupant!")
+ if(istype(target) && vore_selected)
+ target.forceMove(vore_selected)
+ to_chat(target,"\The [src] phases in around you, [vore_selected.vore_verb]ing you into their [vore_selected.name]!")
// Do this after the potential vore, so we get the belly
update_icon()
@@ -79,7 +75,7 @@
name = "Something"
for(var/belly in vore_organs)
- var/datum/belly/B = vore_organs[belly]
+ var/obj/belly/B = belly
B.escapable = FALSE
overlays.Cut()
diff --git a/code/modules/mob/living/simple_animal/vore/shadekin/shadekin.dm b/code/modules/mob/living/simple_animal/vore/shadekin/shadekin.dm
index 5594a6f1bc..2a2085d8e4 100644
--- a/code/modules/mob/living/simple_animal/vore/shadekin/shadekin.dm
+++ b/code/modules/mob/living/simple_animal/vore/shadekin/shadekin.dm
@@ -130,10 +130,11 @@
if(no_vore) //If it can't vore, let's not give it a stomach.
return
- var/datum/belly/B = new /datum/belly(src)
+ var/obj/belly/B = new /obj/belly(src)
+ vore_selected = B
B.immutable = 1
B.name = vore_stomach_name ? vore_stomach_name : "stomach"
- B.inside_flavor = vore_stomach_flavor ? vore_stomach_flavor : "Your surroundings are warm, soft, and slimy. Makes sense, considering you're inside \the [name]."
+ B.desc = vore_stomach_flavor ? vore_stomach_flavor : "Your surroundings are warm, soft, and slimy. Makes sense, considering you're inside \the [name]."
B.digest_mode = vore_default_mode
B.escapable = vore_escape_chance > 0
B.escapechance = vore_escape_chance
@@ -186,14 +187,6 @@
"The chaos of being digested fades as you’re snuffed out by a harsh clench! You’re steadily broken down into a thick paste, processed and absorbed by the predator!"
)
- src.vore_organs[B.name] = B
- src.vore_selected = B.name
-
-
-
-
-
-
/mob/living/simple_animal/shadekin/Life()
. = ..()
if(ability_flags & AB_PHASE_SHIFTED)
diff --git a/code/modules/mob/living/simple_animal/vore/zz_vore_overrides.dm b/code/modules/mob/living/simple_animal/vore/zz_vore_overrides.dm
index 2f2868faab..863b7da41e 100644
--- a/code/modules/mob/living/simple_animal/vore/zz_vore_overrides.dm
+++ b/code/modules/mob/living/simple_animal/vore/zz_vore_overrides.dm
@@ -228,8 +228,8 @@
// Override stuff for holodeck carp to make them not digest when set to safe!
/mob/living/simple_animal/hostile/carp/holodeck/set_safety(var/safe)
. = ..()
- for(var/I in vore_organs)
- var/datum/belly/B = vore_organs[I]
+ for(var/belly in vore_organs)
+ var/obj/belly/B = belly
B.digest_mode = safe ? DM_HOLD : vore_default_mode
B.digestchance = safe ? 0 : vore_digest_chance
B.absorbchance = safe ? 0 : vore_absorb_chance
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index e3b0f20504..1ad998a1f1 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -527,10 +527,10 @@
for(var/name in H.organs_by_name)
var/obj/item/organ/external/e = H.organs_by_name[name]
if(e && H.lying)
- if(((e.status & ORGAN_BROKEN && !(e.splinted)) || e.status & ORGAN_BLEEDING) && (H.getBruteLoss() + H.getFireLoss() >= 100))
+ if((e.status & ORGAN_BROKEN && (!e.splinted || (e.splinted && e.splinted in e.contents && prob(30))) || e.status & ORGAN_BLEEDING) && (H.getBruteLoss() + H.getFireLoss() >= 100))
return 1
break
- return 0
+ return 0
/mob/MouseDrop(mob/M as mob)
..()
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index a7b965d74f..21752e05d1 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -627,3 +627,11 @@ var/global/image/backplane
backplane.mouse_opacity = 0
return TRUE
+
+/mob/proc/get_sound_env(var/pressure_factor)
+ if (pressure_factor < 0.5)
+ return SPACE
+ else
+ var/area/A = get_area(src)
+ return A.sound_env
+
\ No newline at end of file
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 9d30ef7244..06f6a128d5 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -89,6 +89,7 @@
add_language(LANGUAGE_EAL, 1)
add_language(LANGUAGE_SCHECHI, 1)
add_language(LANGUAGE_SIGN, 1)
+ add_language(LANGUAGE_TERMINUS, 1)
// Lorefolks say it may be so.
if(O.client && O.client.prefs)
diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf.dm
index d52f16706b..ae44c58412 100644
--- a/code/modules/multiz/turf.dm
+++ b/code/modules/multiz/turf.dm
@@ -73,7 +73,7 @@
* Update icon and overlays of open space to be that of the turf below, plus any visible objects on that turf.
*/
/turf/simulated/open/update_icon()
- overlays = list() // Edit - Overlays are being crashy when modified.
+ cut_overlays() // Edit - Overlays are being crashy when modified.
update_icon_edge()// Add - Get grass into open spaces and whatnot.
var/turf/below = GetBelow(src)
if(below)
@@ -86,12 +86,7 @@
bottom_turf.plane = src.plane
bottom_turf.color = below.color
underlays = list(bottom_turf)
- // Hack workaround to byond crash bug - Include the magic overlay holder object.
- overlays += below.overlays
- // if(below.overlay_holder)
- // overlays += (below.overlays + below.overlay_holder.overlays)
- // else
- // overlays += below.overlays
+ copy_overlays(below)
// get objects (not mobs, they are handled by /obj/zshadow)
var/list/o_img = list()
@@ -104,16 +99,10 @@
temp2.overlays += O.overlays
// TODO Is pixelx/y needed?
o_img += temp2
- var/overlays_pre = overlays.len
- overlays += o_img
- var/overlays_post = overlays.len
- if(overlays_post != (overlays_pre + o_img.len)) //Here we go!
- world.log << "Corrupted openspace turf at [x],[y],[z] being replaced. Pre: [overlays_pre], Post: [overlays_post]"
- new /turf/simulated/open(src)
- return //Let's get out of here.
+ add_overlay(o_img)
if(!below_is_open)
- overlays += over_OS_darkness
+ add_overlay(over_OS_darkness)
return 0
return PROCESS_KILL
diff --git a/code/modules/nifsoft/nif.dm b/code/modules/nifsoft/nif.dm
index 614ce79d4c..da4594d557 100644
--- a/code/modules/nifsoft/nif.dm
+++ b/code/modules/nifsoft/nif.dm
@@ -32,7 +32,8 @@ You can also set the stat of a NIF to NIF_TEMPFAIL without any issues to disable
var/tmp/list/nifsofts[TOTAL_NIF_SOFTWARE] // All our nifsofts
var/tmp/list/nifsofts_life = list() // Ones that want to be talked to on life()
var/owner // Owner character name
-
+ var/examine_msg //Message shown on examine.
+
var/tmp/vision_flags = 0 // Flags implants set for faster lookups
var/tmp/health_flags = 0
var/tmp/combat_flags = 0
@@ -69,6 +70,12 @@ You can also set the stat of a NIF to NIF_TEMPFAIL without any issues to disable
//Put loaded data here if we loaded any
save_data = islist(load_data) ? load_data.Copy() : list()
+ var/saved_examine_msg = save_data["examine_msg"]
+
+ //If it's an empty string, they want it blank. If null, it's never been saved, give default.
+ if(isnull(saved_examine_msg))
+ saved_examine_msg = "There's a certain spark to their eyes."
+ examine_msg = saved_examine_msg
//If given a human on spawn (probably from persistence)
if(ishuman(newloc))
@@ -110,6 +117,7 @@ You can also set the stat of a NIF to NIF_TEMPFAIL without any issues to disable
human = H
human.nif = src
stat = NIF_INSTALLING
+ H.verbs |= /mob/living/carbon/human/proc/set_nif_examine
return TRUE
return FALSE
@@ -138,6 +146,7 @@ You can also set the stat of a NIF to NIF_TEMPFAIL without any issues to disable
SC.brainmobs = list()
stat = NIF_PREINSTALL
vis_update()
+ H.verbs |= /mob/living/carbon/human/proc/set_nif_examine
H.nif = null
human = null
install_done = null
@@ -572,3 +581,25 @@ You can also set the stat of a NIF to NIF_TEMPFAIL without any issues to disable
playsound(T,'sound/effects/slime_squish.ogg',50,1)
else
return ..()
+
+/mob/living/carbon/human/proc/set_nif_examine()
+ set name = "NIF Appearance"
+ set desc = "If your NIF alters your appearance in some way, describe it here."
+ set category = "OOC"
+
+ if(!nif)
+ verbs -= /mob/living/carbon/human/proc/set_nif_examine
+ to_chat(src,"You don't have a NIF, not sure why this was here.")
+ return
+
+ var/new_flavor = sanitize(input(src,"Describe how your NIF alters your appearance, like glowy eyes or metal plate on your head, etc. Be sensible. Clear this for no examine text. 128ch max.","Describe NIF", nif.examine_msg) as null|text, max_length = 128)
+ //They clicked cancel or meanwhile lost their NIF
+ if(!nif || isnull(new_flavor))
+ return //No changes
+ //Sanitize or user cleaned it entirely
+ if(!new_flavor)
+ nif.examine_msg = ""
+ nif.save_data["examine_msg"] = ""
+ else
+ nif.examine_msg = new_flavor
+ nif.save_data["examine_msg"] = new_flavor
diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm
index 6c8d9c631a..df11357e8b 100644
--- a/code/modules/organs/organ_external.dm
+++ b/code/modules/organs/organ_external.dm
@@ -545,7 +545,7 @@ This function completely restores a damaged organ to perfect condition.
//external organs handle brokenness a bit differently when it comes to damage. Instead brute_dam is checked inside process()
//this also ensures that an external organ cannot be "broken" without broken_description being set.
/obj/item/organ/external/is_broken()
- return ((status & ORGAN_CUT_AWAY) || ((status & ORGAN_BROKEN) && !(splinted)))
+ return ((status & ORGAN_CUT_AWAY) || (status & ORGAN_BROKEN) && (!splinted || (splinted && splinted in src.contents && prob(30))))
//Determines if we even need to process this organ.
/obj/item/organ/external/proc/need_process()
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index f844ac0475..7cf68c5d39 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -427,6 +427,14 @@
return
if(istype(A, /obj/structure/foamedmetal)) //Turrets can detect through foamed metal, but will have to blast through it. Similar to windows, if someone runs behind it, a person should probably just not shoot.
return
+ if(istype(A, /obj/structure/girder)) //They see you there.
+ return
+ if(istype(A, /obj/structure/door_assembly)) //And through there.
+ return
+ if(istype(A, /obj/structure)) //Unanchored things you can shove around will still keep the turret or other firing at your position. Aim intent still functions.
+ var/obj/structure/S = A
+ if(!S.anchored)
+ return
if(istype(A, /mob/living) || istype(A, /obj/mecha) || istype(A, /obj/vehicle))
result = 2 //We hit someone, return 1!
return
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm
index 1073949fe1..072022cc29 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm
@@ -168,19 +168,19 @@
L.ExtinguishMob()
L.adjust_fire_stacks(-(amount / 5))
remove_self(needed)
-
+/* //VOREStation Edit Start. Stops slimes from dying from water. Fixes fuel affect_ingest, too.
/datum/reagent/water/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
if(alien == IS_SLIME)
M.adjustToxLoss(6 * removed)
else
..()
-/datum/reagent/fuel/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed)
+/datum/reagent/water/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed)
if(alien == IS_SLIME)
M.adjustToxLoss(6 * removed)
else
..()
-
+*/ //VOREStation Edit End.
/datum/reagent/fuel
name = "Welding fuel"
id = "fuel"
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm
index c554959435..9b15c07b70 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm
@@ -319,6 +319,8 @@
M.update_inv_wear_mask(0)
if(ishuman(M))
var/mob/living/carbon/human/H = M
+ if(alien == IS_SLIME)
+ M.adjustToxLoss(rand(5, 10))
if(H.head)
if(H.head.clean_blood())
H.update_inv_head(0)
@@ -336,6 +338,14 @@
return
M.clean_blood()
+/datum/reagent/space_cleaner/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed)
+ if(alien == IS_SLIME)
+ M.adjustToxLoss(6 * removed)
+ else
+ M.adjustToxLoss(3 * removed)
+ if(prob(5))
+ M.vomit()
+
/datum/reagent/lube // TODO: spraying on borgs speeds them up
name = "Space Lube"
id = "lube"
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Vore_vr.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Vore_vr.dm
index 75886783ae..84360e128f 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Vore_vr.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Vore_vr.dm
@@ -80,9 +80,9 @@
M.make_dizzy(1)
M.adjustHalLoss(2)
- for(var/I in M.vore_organs)
- var/datum/belly/B = M.vore_organs[I]
- for(var/atom/movable/A in B.internal_contents)
+ for(var/belly in M.vore_organs)
+ var/obj/belly/B = belly
+ for(var/atom/movable/A in B)
if(isliving(A))
var/mob/living/P = A
if(P.absorbed)
@@ -90,8 +90,6 @@
if(prob(5))
playsound(M, 'sound/effects/splat.ogg', 50, 1)
B.release_specific_contents(A)
- return
-
/datum/reagent/unsorbitol
name = "Unsorbitol"
@@ -109,13 +107,13 @@
M.confused = max(M.confused, 20)
M.hallucination += 15
- for(var/I in M.vore_organs)
- var/datum/belly/B = M.vore_organs[I]
+ for(var/belly in M.vore_organs)
+ var/obj/belly/B = belly
if(B.digest_mode == DM_ABSORB) //Turn off absorbing on bellies
B.digest_mode = DM_HOLD
- for(var/mob/living/P in B.internal_contents)
+ for(var/mob/living/P in B)
if(!P.absorbed)
continue
@@ -123,7 +121,6 @@
playsound(M, 'sound/vore/schlorp.ogg', 50, 1)
P.absorbed = 0
M.visible_message("Something spills into [M]'s [lowertext(B.name)]!")
- return
//Special toxins for solargrubs
diff --git a/code/modules/reagents/reagent_containers/food/z_custom_food_vr.dm b/code/modules/reagents/reagent_containers/food/z_custom_food_vr.dm
index a1a7f0194b..79ca83ddab 100644
--- a/code/modules/reagents/reagent_containers/food/z_custom_food_vr.dm
+++ b/code/modules/reagents/reagent_containers/food/z_custom_food_vr.dm
@@ -48,8 +48,10 @@ var/global/ingredientLimit = 20000
return*/
user.drop_item()
I.forceMove(src)
-
- S.reagents.trans_to(src,S.reagents.total_volume)
+
+ if(S.reagents)
+ S.reagents.trans_to(src,S.reagents.total_volume)
+
ingredients += S
if(src.addTop)
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index b9191b4329..b4ccda29ec 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -160,8 +160,9 @@
return
var/mob/living/carbon/human/H = target
+ var/obj/item/organ/external/affected //VOREStation Edit - Moved this outside this if
if(istype(H))
- var/obj/item/organ/external/affected = H.get_organ(user.zone_sel.selecting)
+ affected = H.get_organ(user.zone_sel.selecting) //VOREStation Edit - See above comment.
if(!affected)
to_chat(user, "\The [H] is missing that limb!")
return
@@ -202,6 +203,7 @@
if(ismob(target))
var/contained = reagentlist()
trans = reagents.trans_to_mob(target, amount_per_transfer_from_this, CHEM_BLOOD)
+ dirty(target,affected) //VOREStation Add
admin_inject_log(user, target, src, contained, trans)
else
trans = reagents.trans_to_obj(target, amount_per_transfer_from_this)
@@ -214,7 +216,7 @@
update_icon()
return
-
+/* VOREStation Edit - See syringes_vr.dm
/obj/item/weapon/reagent_containers/syringe/update_icon()
overlays.Cut()
@@ -241,7 +243,7 @@
filling.color = reagents.get_color()
overlays += filling
-
+*/
/obj/item/weapon/reagent_containers/syringe/proc/syringestab(mob/living/carbon/target as mob, mob/living/carbon/user as mob)
if(istype(target, /mob/living/carbon/human))
diff --git a/code/modules/reagents/reagent_containers/syringes_vr.dm b/code/modules/reagents/reagent_containers/syringes_vr.dm
new file mode 100644
index 0000000000..1c6fb55fe8
--- /dev/null
+++ b/code/modules/reagents/reagent_containers/syringes_vr.dm
@@ -0,0 +1,119 @@
+#define SYRINGE_CAPPED 10
+
+/obj/item/weapon/reagent_containers/syringe
+ icon = 'icons/goonstation/objects/syringe_vr.dmi'
+ mode = SYRINGE_CAPPED //Override
+ var/used = FALSE
+ var/dirtiness = 0
+ var/list/targets
+ var/list/datum/disease2/disease/viruses
+
+/obj/item/weapon/reagent_containers/syringe/initialize()
+ . = ..()
+ update_icon()
+
+/obj/item/weapon/reagent_containers/syringe/Destroy()
+ qdel_null_list(viruses)
+ targets.Cut()
+ return ..()
+
+/obj/item/weapon/reagent_containers/syringe/process()
+ dirtiness = min(dirtiness + targets.len,75)
+ if(dirtiness >= 75)
+ processing_objects -= src
+ return 1
+
+/obj/item/weapon/reagent_containers/syringe/proc/dirty(var/mob/living/carbon/human/target, var/obj/item/organ/external/eo)
+ if(!ishuman(loc))
+ return //Avoid borg syringe problems.
+ LAZYINITLIST(targets)
+
+ //We can't keep a mob reference, that's a bad idea, so instead name+ref should suffice.
+ var/hash = md5(target.real_name + "\ref[target]")
+
+ //Just once!
+ targets |= hash
+
+ //Grab any viruses they have
+ if(LAZYLEN(target.virus2.len))
+ LAZYINITLIST(viruses)
+ var/datum/disease2/disease/virus = pick(target.virus2.len)
+ viruses[hash] = virus.getcopy()
+
+ //Dirtiness should be very low if you're the first injectee. If you're spam-injecting 4 people in a row around you though,
+ //This gives the last one a 30% chance of infection.
+ if(prob(dirtiness+(targets.len-1)*10))
+ log_and_message_admins("[loc] infected [target]'s [eo.name] with \the [src].")
+ infect_limb(eo)
+
+ //75% chance to spread a virus if we have one
+ if(LAZYLEN(viruses) && prob(75))
+ var/old_hash = pick(viruses)
+ if(hash != old_hash) //Same virus you already had?
+ var/datum/disease2/disease/virus = viruses[old_hash]
+ infect_virus2(target,virus.getcopy())
+
+ if(!used)
+ processing_objects |= src
+
+/obj/item/weapon/reagent_containers/syringe/proc/infect_limb(var/obj/item/organ/external/eo)
+ src = null
+ var/weakref/limb_ref = weakref(eo)
+ spawn(rand(5 MINUTES,10 MINUTES))
+ var/obj/item/organ/external/found_limb = limb_ref.resolve()
+ if(istype(found_limb))
+ eo.germ_level += INFECTION_LEVEL_ONE+30
+
+//Allow for capped syringe mode
+/obj/item/weapon/reagent_containers/syringe/attack_self(mob/user as mob)
+ switch(mode)
+ if(SYRINGE_CAPPED)
+ mode = SYRINGE_DRAW
+ to_chat(user,"You uncap the syringe.")
+ if(SYRINGE_DRAW)
+ mode = SYRINGE_INJECT
+ if(SYRINGE_INJECT)
+ mode = SYRINGE_DRAW
+ if(SYRINGE_BROKEN)
+ return
+ update_icon()
+
+//Allow for capped syringes
+/obj/item/weapon/reagent_containers/syringe/update_icon()
+ cut_overlays(src)
+
+ var/matrix/tf = matrix()
+ if(isstorage(loc))
+ tf.Turn(-90) //Vertical for storing compact-ly
+ tf.Translate(-3,0) //Could do this with pixel_x but let's just update the appearance once.
+ transform = tf
+
+ if(mode == SYRINGE_BROKEN)
+ icon_state = "broken"
+ return
+
+ if(mode == SYRINGE_CAPPED)
+ icon_state = "capped"
+ return
+
+ var/list/new_overlays = list()
+ var/rounded_vol = round(reagents.total_volume, round(reagents.maximum_volume / 3))
+ if(reagents.total_volume)
+ filling = image(icon, src, "filler[rounded_vol]")
+ filling.color = reagents.get_color()
+ new_overlays += filling
+
+ if(ismob(loc))
+ var/injoverlay
+ switch(mode)
+ if (SYRINGE_DRAW)
+ injoverlay = "draw"
+ if (SYRINGE_INJECT)
+ injoverlay = "inject"
+ new_overlays += injoverlay
+
+ add_overlay(new_overlays)
+ icon_state = "[rounded_vol]"
+ item_state = "syringe_[rounded_vol]"
+
+#undef SYRINGE_CAPPED
diff --git a/code/modules/vore/eating/belly_dat_vr.dm b/code/modules/vore/eating/belly_dat_vr.dm
new file mode 100644
index 0000000000..19befd3035
--- /dev/null
+++ b/code/modules/vore/eating/belly_dat_vr.dm
@@ -0,0 +1,162 @@
+// // // // // // // // // // // //
+// // // LEGACY USE ONLY!! // // //
+// // // // // // // // // // // //
+
+// These have been REPLACED by the object-based bellies. These remain here,
+// so that people can load save files from prior times, and the Copy() proc can
+// convert their belly to a new object-based one.
+
+/datum/belly
+ var/name // Name of this location
+ var/inside_flavor // Flavor text description of inside sight/sound/smells/feels.
+ var/vore_sound = 'sound/vore/gulp.ogg' // Sound when ingesting someone
+ var/vore_verb = "ingest" // Verb for eating with this in messages
+ var/human_prey_swallow_time = 100 // Time in deciseconds to swallow /mob/living/carbon/human
+ var/nonhuman_prey_swallow_time = 30 // Time in deciseconds to swallow anything else
+ var/emoteTime = 600 // How long between stomach emotes at prey
+ var/digest_brute = 2 // Brute damage per tick in digestion mode
+ var/digest_burn = 3 // Burn damage per tick in digestion mode
+ var/digest_tickrate = 3 // Modulus this of air controller tick number to iterate gurgles on
+ var/immutable = 0 // Prevents this belly from being deleted
+ var/escapable = 0 // Belly can be resisted out of at any time
+ var/escapetime = 60 SECONDS // Deciseconds, how long to escape this belly
+ var/digestchance = 0 // % Chance of stomach beginning to digest if prey struggles
+ var/absorbchance = 0 // % Chance of stomach beginning to absorb if prey struggles
+ var/escapechance = 0 // % Chance of prey beginning to escape if prey struggles.
+ var/transferchance = 0 // % Chance of prey being
+ var/can_taste = 0 // If this belly prints the flavor of prey when it eats someone.
+ var/bulge_size = 0.25 // The minimum size the prey has to be in order to show up on examine.
+ var/shrink_grow_size = 1 // This horribly named variable determines the minimum/maximum size it will shrink/grow prey to.
+ var/datum/belly/transferlocation = null // Location that the prey is released if they struggle and get dropped off.
+
+ var/tmp/digest_mode = DM_HOLD // Whether or not to digest. Default to not digest.
+ var/tmp/list/digest_modes = list(DM_HOLD,DM_DIGEST,DM_ITEMWEAK,DM_STRIPDIGEST,DM_HEAL,DM_ABSORB,DM_DRAIN,DM_UNABSORB,DM_SHRINK,DM_GROW,DM_SIZE_STEAL,DM_DIGEST_NUMB) // Possible digest modes
+ var/tmp/list/transform_modes = list(DM_TRANSFORM_MALE,DM_TRANSFORM_FEMALE,DM_TRANSFORM_KEEP_GENDER,DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR,DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR_EGG,DM_TRANSFORM_REPLICA,DM_TRANSFORM_REPLICA_EGG,DM_TRANSFORM_KEEP_GENDER_EGG,DM_TRANSFORM_MALE_EGG,DM_TRANSFORM_FEMALE_EGG, DM_EGG)
+ var/tmp/mob/living/owner // The mob whose belly this is.
+ var/tmp/list/internal_contents = list() // People/Things you've eaten into this belly!
+ var/tmp/emotePend = FALSE // If there's already a spawned thing counting for the next emote
+ var/tmp/list/items_preserved = list() // Stuff that wont digest.
+ var/list/slots = list(slot_back,slot_handcuffed,slot_l_store,slot_r_store,slot_wear_mask,slot_l_hand,slot_r_hand,slot_wear_id,slot_glasses,slot_gloves,slot_head,slot_shoes,slot_belt,slot_wear_suit,slot_w_uniform,slot_s_store,slot_l_ear,slot_r_ear)
+
+
+ // Don't forget to watch your commas at the end of each line if you change these.
+ var/list/struggle_messages_outside = list(
+ "%pred's %belly wobbles with a squirming meal.",
+ "%pred's %belly jostles with movement.",
+ "%pred's %belly briefly swells outward as someone pushes from inside.",
+ "%pred's %belly fidgets with a trapped victim.",
+ "%pred's %belly jiggles with motion from inside.",
+ "%pred's %belly sloshes around.",
+ "%pred's %belly gushes softly.",
+ "%pred's %belly lets out a wet squelch.")
+
+ var/list/struggle_messages_inside = list(
+ "Your useless squirming only causes %pred's slimy %belly to squelch over your body.",
+ "Your struggles only cause %pred's %belly to gush softly around you.",
+ "Your movement only causes %pred's %belly to slosh around you.",
+ "Your motion causes %pred's %belly to jiggle.",
+ "You fidget around inside of %pred's %belly.",
+ "You shove against the walls of %pred's %belly, making it briefly swell outward.",
+ "You jostle %pred's %belly with movement.",
+ "You squirm inside of %pred's %belly, making it wobble around.")
+
+ var/list/digest_messages_owner = list(
+ "You feel %prey's body succumb to your digestive system, which breaks it apart into soft slurry.",
+ "You hear a lewd glorp as your %belly muscles grind %prey into a warm pulp.",
+ "Your %belly lets out a rumble as it melts %prey into sludge.",
+ "You feel a soft gurgle as %prey's body loses form in your %belly. They're nothing but a soft mass of churning slop now.",
+ "Your %belly begins gushing %prey's remains through your system, adding some extra weight to your thighs.",
+ "Your %belly begins gushing %prey's remains through your system, adding some extra weight to your rump.",
+ "Your %belly begins gushing %prey's remains through your system, adding some extra weight to your belly.",
+ "Your %belly groans as %prey falls apart into a thick soup. You can feel their remains soon flowing deeper into your body to be absorbed.",
+ "Your %belly kneads on every fiber of %prey, softening them down into mush to fuel your next hunt.",
+ "Your %belly churns %prey down into a hot slush. You can feel the nutrients coursing through your digestive track with a series of long, wet glorps.")
+
+ var/list/digest_messages_prey = list(
+ "Your body succumbs to %pred's digestive system, which breaks you apart into soft slurry.",
+ "%pred's %belly lets out a lewd glorp as their muscles grind you into a warm pulp.",
+ "%pred's %belly lets out a rumble as it melts you into sludge.",
+ "%pred feels a soft gurgle as your body loses form in their %belly. You're nothing but a soft mass of churning slop now.",
+ "%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's thighs.",
+ "%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's rump.",
+ "%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's belly.",
+ "%pred's %belly groans as you fall apart into a thick soup. Your remains soon flow deeper into %pred's body to be absorbed.",
+ "%pred's %belly kneads on every fiber of your body, softening you down into mush to fuel their next hunt.",
+ "%pred's %belly churns you down into a hot slush. Your nutrient-rich remains course through their digestive track with a series of long, wet glorps.")
+
+ var/list/examine_messages = list(
+ "They have something solid in their %belly!",
+ "It looks like they have something in their %belly!")
+
+ //Mostly for being overridden on precreated bellies on mobs. Could be VV'd into
+ //a carbon's belly if someone really wanted. No UI for carbons to adjust this.
+ //List has indexes that are the digestion mode strings, and keys that are lists of strings.
+ var/tmp/list/emote_lists = list()
+
+//OLD: This only exists for legacy conversion purposes
+//It's called whenever an old datum-style belly is loaded
+/datum/belly/proc/copy(obj/belly/new_belly)
+
+ //// Non-object variables
+ new_belly.name = name
+ new_belly.desc = inside_flavor
+ new_belly.vore_sound = vore_sound
+ new_belly.vore_verb = vore_verb
+ new_belly.human_prey_swallow_time = human_prey_swallow_time
+ new_belly.nonhuman_prey_swallow_time = nonhuman_prey_swallow_time
+ new_belly.emote_time = emoteTime
+ new_belly.digest_brute = digest_brute
+ new_belly.digest_burn = digest_burn
+ new_belly.digest_tickrate = digest_tickrate
+ new_belly.immutable = immutable
+ new_belly.can_taste = can_taste
+ new_belly.escapable = escapable
+ new_belly.escapetime = escapetime
+ new_belly.digestchance = digestchance
+ new_belly.absorbchance = absorbchance
+ new_belly.escapechance = escapechance
+ new_belly.transferchance = transferchance
+ new_belly.transferlocation = transferlocation
+ new_belly.bulge_size = bulge_size
+ new_belly.shrink_grow_size = shrink_grow_size
+
+ //// Object-holding variables
+ //struggle_messages_outside - strings
+ new_belly.struggle_messages_outside.Cut()
+ for(var/I in struggle_messages_outside)
+ new_belly.struggle_messages_outside += I
+
+ //struggle_messages_inside - strings
+ new_belly.struggle_messages_inside.Cut()
+ for(var/I in struggle_messages_inside)
+ new_belly.struggle_messages_inside += I
+
+ //digest_messages_owner - strings
+ new_belly.digest_messages_owner.Cut()
+ for(var/I in digest_messages_owner)
+ new_belly.digest_messages_owner += I
+
+ //digest_messages_prey - strings
+ new_belly.digest_messages_prey.Cut()
+ for(var/I in digest_messages_prey)
+ new_belly.digest_messages_prey += I
+
+ //examine_messages - strings
+ new_belly.examine_messages.Cut()
+ for(var/I in examine_messages)
+ new_belly.examine_messages += I
+
+ //emote_lists - index: digest mode, key: list of strings
+ new_belly.emote_lists.Cut()
+ for(var/K in emote_lists)
+ new_belly.emote_lists[K] = list()
+ for(var/I in emote_lists[K])
+ new_belly.emote_lists[K] += I
+
+ return new_belly
+
+// // // // // // // // // // // //
+// // // LEGACY USE ONLY!! // // //
+// // // // // // // // // // // //
+// See top of file! //
+// // // // // // // // // // // //
\ No newline at end of file
diff --git a/code/modules/vore/eating/belly_vr.dm b/code/modules/vore/eating/belly_obj_vr.dm
similarity index 62%
rename from code/modules/vore/eating/belly_vr.dm
rename to code/modules/vore/eating/belly_obj_vr.dm
index b8f98922a1..01f21b4124 100644
--- a/code/modules/vore/eating/belly_vr.dm
+++ b/code/modules/vore/eating/belly_obj_vr.dm
@@ -1,6 +1,8 @@
+#define VORE_SOUND_FALLOFF 0.05
+
//
-// The belly object is what holds onto a mob while they're inside a predator.
-// It takes care of altering the pred's decription, digesting the prey, relaying struggles etc.
+// Belly system 2.0, now using objects instead of datums because EH at datums.
+// How many times have I rewritten bellies and vore now? -Aro
//
// If you change what variables are on this, then you need to update the copy() proc.
@@ -8,16 +10,16 @@
//
// Parent type of all the various "belly" varieties.
//
-/datum/belly
- var/name // Name of this location
- var/inside_flavor // Flavor text description of inside sight/sound/smells/feels.
+/obj/belly
+ name = "belly" // Name of this location
+ desc = "It's a belly! You're in it!" // Flavor text description of inside sight/sound/smells/feels.
var/vore_sound = 'sound/vore/gulp.ogg' // Sound when ingesting someone
var/vore_verb = "ingest" // Verb for eating with this in messages
var/human_prey_swallow_time = 100 // Time in deciseconds to swallow /mob/living/carbon/human
var/nonhuman_prey_swallow_time = 30 // Time in deciseconds to swallow anything else
- var/emoteTime = 600 // How long between stomach emotes at prey
+ var/emote_time = 60 SECONDS // How long between stomach emotes at prey
var/digest_brute = 2 // Brute damage per tick in digestion mode
- var/digest_burn = 3 // Burn damage per tick in digestion mode
+ var/digest_burn = 2 // Burn damage per tick in digestion mode
var/digest_tickrate = 3 // Modulus this of air controller tick number to iterate gurgles on
var/immutable = 0 // Prevents this belly from being deleted
var/escapable = 0 // Belly can be resisted out of at any time
@@ -29,20 +31,21 @@
var/can_taste = 0 // If this belly prints the flavor of prey when it eats someone.
var/bulge_size = 0.25 // The minimum size the prey has to be in order to show up on examine.
var/shrink_grow_size = 1 // This horribly named variable determines the minimum/maximum size it will shrink/grow prey to.
- var/datum/belly/transferlocation = null // Location that the prey is released if they struggle and get dropped off.
+ var/transferlocation // Location that the prey is released if they struggle and get dropped off.
+ var/release_sound = TRUE // Boolean for now, maybe replace with something else later
+
+ //I don't think we've ever altered these lists. making them static until someone actually overrides them somewhere.
+ var/tmp/static/list/digest_modes = list(DM_HOLD,DM_DIGEST,DM_ITEMWEAK,DM_STRIPDIGEST,DM_HEAL,DM_ABSORB,DM_DRAIN,DM_UNABSORB,DM_SHRINK,DM_GROW,DM_SIZE_STEAL,DM_DIGEST_NUMB) // Possible digest modes
+ var/tmp/static/list/transform_modes = list(DM_TRANSFORM_MALE,DM_TRANSFORM_FEMALE,DM_TRANSFORM_KEEP_GENDER,DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR,DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR_EGG,DM_TRANSFORM_REPLICA,DM_TRANSFORM_REPLICA_EGG,DM_TRANSFORM_KEEP_GENDER_EGG,DM_TRANSFORM_MALE_EGG,DM_TRANSFORM_FEMALE_EGG, DM_EGG)
+ var/tmp/static/list/slots = list(slot_back,slot_handcuffed,slot_l_store,slot_r_store,slot_wear_mask,slot_l_hand,slot_r_hand,slot_wear_id,slot_glasses,slot_gloves,slot_head,slot_shoes,slot_belt,slot_wear_suit,slot_w_uniform,slot_s_store,slot_l_ear,slot_r_ear)
- var/tmp/digest_mode = DM_HOLD // Whether or not to digest. Default to not digest.
- var/tmp/list/digest_modes = list(DM_HOLD,DM_DIGEST,DM_ITEMWEAK,DM_STRIPDIGEST,DM_HEAL,DM_ABSORB,DM_DRAIN,DM_UNABSORB,DM_SHRINK,DM_GROW,DM_SIZE_STEAL,DM_DIGEST_NUMB) // Possible digest modes
- var/tmp/list/transform_modes = list(DM_TRANSFORM_MALE,DM_TRANSFORM_FEMALE,DM_TRANSFORM_KEEP_GENDER,DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR,DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR_EGG,DM_TRANSFORM_REPLICA,DM_TRANSFORM_REPLICA_EGG,DM_TRANSFORM_KEEP_GENDER_EGG,DM_TRANSFORM_MALE_EGG,DM_TRANSFORM_FEMALE_EGG, DM_EGG)
var/tmp/mob/living/owner // The mob whose belly this is.
- var/tmp/list/internal_contents = list() // People/Things you've eaten into this belly!
- var/tmp/is_full // Flag for if digested remeans are present. (for disposal messages)
- var/tmp/emotePend = FALSE // If there's already a spawned thing counting for the next emote
- var/tmp/list/items_preserved = list() // Stuff that wont digest.
- var/tmp/list/checked_slots = list() // Checked gear slots for strip digest.
- var/list/slots = list(slot_back,slot_handcuffed,slot_l_store,slot_r_store,slot_wear_mask,slot_l_hand,slot_r_hand,slot_wear_id,slot_glasses,slot_gloves,slot_head,slot_shoes,slot_belt,slot_wear_suit,slot_w_uniform,slot_s_store,slot_l_ear,slot_r_ear)
-
-
+ var/tmp/digest_mode = DM_HOLD // Current mode the belly is set to from digest_modes (+transform_modes if human)
+ var/tmp/next_process = 0 // Waiting for this SSbellies times_fired to process again.
+ var/tmp/list/items_preserved = list() // Stuff that wont digest so we shouldn't process it again.
+ var/tmp/next_emote = 0 // When we're supposed to print our next emote, as a belly controller tick #
+ var/tmp/recent_sound = FALSE // Prevent audio spam
+
// Don't forget to watch your commas at the end of each line if you change these.
var/list/struggle_messages_outside = list(
"%pred's %belly wobbles with a squirming meal.",
@@ -97,56 +100,77 @@
//List has indexes that are the digestion mode strings, and keys that are lists of strings.
var/tmp/list/emote_lists = list()
-// Constructor that sets the owning mob
-/datum/belly/New(var/mob/living/owning_mob)
- owner = owning_mob
+/obj/belly/initialize()
+ . = ..()
+ //If not, we're probably just in a prefs list or something.
+ if(isliving(loc))
+ owner = loc
+ owner.vore_organs |= src
+ SSbellies.belly_list += src
-// Toggle digestion on/off and notify user of the new setting.
-// If multiple digestion modes are avaliable (i.e. unbirth) then user should be prompted.
-/datum/belly/proc/toggle_digestion()
- return
+/obj/belly/Destroy()
+ SSbellies.belly_list -= src
+ if(owner)
+ owner.vore_organs -= src
+ owner = null
+ . = ..()
-// Checks if any mobs are present inside the belly
-// return True if the belly is empty.
-/datum/belly/proc/is_empty()
- return internal_contents.len == 0
+// Called whenever an atom enters this belly
+/obj/belly/Entered(var/atom/movable/thing,var/atom/OldLoc)
+ if(OldLoc in contents)
+ return //Someone dropping something (or being stripdigested)
+ //Generic entered message
+ to_chat(owner,"[thing] slides into your [lowertext(name)].")
+
+ //Sound w/ antispam flag setting
+ if(vore_sound && !recent_sound)
+ playsound(src, vore_sound, vol = 100, vary = 1, falloff = VORE_SOUND_FALLOFF, preference = /datum/client_preference/eating_noises)
+ recent_sound = TRUE
+
+ //Messages if it's a mob
+ if(isliving(thing))
+ var/mob/living/M = thing
+ if(desc)
+ to_chat(M, "[desc]")
+ var/taste
+ if(can_taste && (taste = M.get_taste_message(FALSE)))
+ to_chat(owner, "[M] tastes of [taste].")
+
// Release all contents of this belly into the owning mob's location.
// If that location is another mob, contents are transferred into whichever of its bellies the owning mob is in.
// Returns the number of mobs so released.
-/datum/belly/proc/release_all_contents(var/include_absorbed = FALSE)
- if (internal_contents.len == 0)
- return 0
- for (var/M in internal_contents)
- if(istype(M,/mob/living))
- var/mob/living/ML = M
- if(ML.absorbed && !include_absorbed)
+/obj/belly/proc/release_all_contents(var/include_absorbed = FALSE)
+ var/atom/destination = drop_location()
+ var/count = 0
+ for(var/thing in contents)
+ var/atom/movable/AM = thing
+ if(isliving(AM))
+ var/mob/living/L = AM
+ if(L.absorbed && !include_absorbed)
continue
- ML.absorbed = FALSE
+ L.absorbed = FALSE
- var/atom/movable/AM = M
- AM.forceMove(owner.loc) // Move the belly contents into the same location as belly's owner.
- internal_contents -= AM // Remove from the belly contents
- var/datum/belly/B = check_belly(owner) // This makes sure that the mob behaves properly if released into another mob
- if(B)
- B.internal_contents += AM
+ AM.forceMove(destination) // Move the belly contents into the same location as belly's owner.
+ count++
items_preserved.Cut()
- checked_slots.Cut()
owner.visible_message("[owner] expels everything from their [lowertext(name)]!")
owner.update_icons()
- return 1
+ if(release_sound)
+ playsound(src, 'sound/effects/splat.ogg', vol = 100, vary = 1, falloff = VORE_SOUND_FALLOFF, preference = /datum/client_preference/eating_noises)
+ return count
// Release a specific atom from the contents of this belly into the owning mob's location.
// If that location is another mob, the atom is transferred into whichever of its bellies the owning mob is in.
// Returns the number of atoms so released.
-/datum/belly/proc/release_specific_contents(var/atom/movable/M)
- if (!(M in internal_contents))
+/obj/belly/proc/release_specific_contents(var/atom/movable/M)
+ if (!(M in contents))
return 0 // They weren't in this belly anyway
- M.forceMove(owner.loc) // Move the belly contents into the same location as belly's owner.
- src.internal_contents -= M // Remove from the belly contents
- if(M in items_preserved)
- src.items_preserved -= M
+ M.forceMove(drop_location()) // Move the belly contents into the same location as belly's owner.
+ items_preserved -= M
+ if(release_sound)
+ playsound(src, 'sound/effects/splat.ogg', vol = 100, vary = 1, falloff = VORE_SOUND_FALLOFF, preference = /datum/client_preference/eating_noises)
if(istype(M,/mob/living))
var/mob/living/ML = M
@@ -156,17 +180,12 @@
if(ishuman(M) && ishuman(OW))
var/mob/living/carbon/human/Prey = M
var/mob/living/carbon/human/Pred = OW
- // TODO - If we ever find a way to share reagent containers, un-share them here
var/absorbed_count = 2 //Prey that we were, plus the pred gets a portion
- for(var/mob/living/P in internal_contents)
+ for(var/mob/living/P in contents)
if(P.absorbed)
absorbed_count++
Pred.bloodstr.trans_to(Prey, Pred.reagents.total_volume / absorbed_count)
- var/datum/belly/B = check_belly(owner)
- if(B)
- B.internal_contents += M
-
owner.visible_message("[owner] expels [M] from their [lowertext(name)]!")
owner.update_icons()
return 1
@@ -174,38 +193,32 @@
// Actually perform the mechanics of devouring the tasty prey.
// The purpose of this method is to avoid duplicate code, and ensure that all necessary
// steps are taken.
-/datum/belly/proc/nom_mob(var/mob/prey, var/mob/user)
+/obj/belly/proc/nom_mob(var/mob/prey, var/mob/user)
if(owner.stat == DEAD)
return
if (prey.buckled)
prey.buckled.unbuckle_mob()
- prey.forceMove(owner)
- internal_contents |= prey
+ prey.forceMove(src)
owner.updateVRPanel()
- for(var/mob/living/M in internal_contents)
+
+ for(var/mob/living/M in contents)
M.updateVRPanel()
- if(inside_flavor)
- prey << "[inside_flavor]"
-
- for(var/obj/item/weapon/storage/S in prey)
- S.hide_from(owner)
-
// Get the line that should show up in Examine message if the owner of this belly
// is examined. By making this a proc, we not only take advantage of polymorphism,
// but can easily make the message vary based on how many people are inside, etc.
// Returns a string which shoul be appended to the Examine output.
-/datum/belly/proc/get_examine_msg()
- if(internal_contents.len && examine_messages.len)
+/obj/belly/proc/get_examine_msg()
+ if(contents.len && examine_messages.len)
var/formatted_message
var/raw_message = pick(examine_messages)
var/total_bulge = 0
formatted_message = replacetext(raw_message,"%belly",lowertext(name))
formatted_message = replacetext(formatted_message,"%pred",owner)
- formatted_message = replacetext(formatted_message,"%prey",english_list(internal_contents))
- for(var/mob/living/P in internal_contents)
+ formatted_message = replacetext(formatted_message,"%prey",english_list(contents))
+ for(var/mob/living/P in contents)
if(!P.absorbed) //This is required first, in case there's a person absorbed and not absorbed in a stomach.
total_bulge += P.size_multiplier
if(total_bulge >= bulge_size && bulge_size != 0)
@@ -216,7 +229,7 @@
// The next function gets the messages set on the belly, in human-readable format.
// This is useful in customization boxes and such. The delimiter right now is \n\n so
// in message boxes, this looks nice and is easily delimited.
-/datum/belly/proc/get_messages(var/type, var/delim = "\n\n")
+/obj/belly/proc/get_messages(var/type, var/delim = "\n\n")
ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em")
var/list/raw_messages
@@ -238,18 +251,18 @@
// The next function sets the messages on the belly, from human-readable var
// replacement strings and linebreaks as delimiters (two \n\n by default).
// They also sanitize the messages.
-/datum/belly/proc/set_messages(var/raw_text, var/type, var/delim = "\n\n")
+/obj/belly/proc/set_messages(var/raw_text, var/type, var/delim = "\n\n")
ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em")
var/list/raw_list = text2list(html_encode(raw_text),delim)
if(raw_list.len > 10)
raw_list.Cut(11)
- log_debug("[owner] tried to set [name] with 11+ messages")
+ log_debug("[owner] tried to set [lowertext(name)] with 11+ messages")
for(var/i = 1, i <= raw_list.len, i++)
if(length(raw_list[i]) > 160 || length(raw_list[i]) < 10) //160 is fudged value due to htmlencoding increasing the size
raw_list.Cut(i,i)
- log_debug("[owner] tried to set [name] with >121 or <10 char message")
+ log_debug("[owner] tried to set [lowertext(name)] with >121 or <10 char message")
else
raw_list[i] = readd_quotes(raw_list[i])
//Also fix % sign for var replacement
@@ -275,45 +288,36 @@
// Called from the process_Life() methods of bellies that digest prey.
// Default implementation calls M.death() and removes from internal contents.
// Indigestable items are removed, and M is deleted.
-/datum/belly/proc/digestion_death(var/mob/living/M)
- is_full = 1
+/obj/belly/proc/digestion_death(var/mob/living/M)
//M.death(1) // "Stop it he's already dead..." Basically redundant and the reason behind screaming mouse carcasses.
if(M.ckey)
- message_admins("[key_name(owner)] has digested [key_name(M)] in their [name] ([owner ? "JMP" : "null"])")
- internal_contents -= M
+ message_admins("[key_name(owner)] has digested [key_name(M)] in their [lowertext(name)] ([owner ? "JMP" : "null"])")
// If digested prey is also a pred... anyone inside their bellies gets moved up.
if(is_vore_predator(M))
- for(var/bellytype in M.vore_organs)
- var/datum/belly/belly = M.vore_organs[bellytype]
- for (var/obj/thing in belly.internal_contents)
- thing.loc = owner
- internal_contents += thing
- for (var/mob/subprey in belly.internal_contents)
- subprey.loc = owner
- internal_contents += subprey
- subprey << "As [M] melts away around you, you find yourself in [owner]'s [name]"
+ for(var/belly in M.vore_organs)
+ var/obj/belly/B = belly
+ for(var/thing in B)
+ var/atom/movable/AM = thing
+ AM.forceMove(owner.loc)
+ if(isliving(AM))
+ to_chat(AM,"As [M] melts away around you, you find yourself in [owner]'s [lowertext(name)]")
//Drop all items into the belly.
if(config.items_survive_digestion)
- var/mob/living/carbon/human/H = M
- if(!H)
- H = owner
- for(var/obj/item/W in H)
+ for(var/obj/item/W in M)
if(istype(W,/obj/item/organ/internal/mmi_holder/posibrain))
var/obj/item/organ/internal/mmi_holder/MMI = W
var/atom/movable/brain = MMI.removed()
if(brain)
- H.remove_from_mob(brain,owner)
- brain.forceMove(owner)
+ M.remove_from_mob(brain,owner)
+ brain.forceMove(src)
items_preserved += brain
- internal_contents += brain
for(var/slot in slots)
var/obj/item/thingy = M.get_equipped_item(slot = slot)
if(thingy)
M.unEquip(thingy,force = TRUE)
- thingy.forceMove(owner)
- internal_contents |= thingy
+ thingy.forceMove(src)
//Reagent transfer
if(ishuman(owner))
@@ -331,10 +335,10 @@
qdel(M)
// Handle a mob being absorbed
-/datum/belly/proc/absorb_living(var/mob/living/M)
+/obj/belly/proc/absorb_living(var/mob/living/M)
M.absorbed = 1
- M << "[owner]'s [name] absorbs your body, making you part of them."
- owner << "Your [name] absorbs [M]'s body, making them part of you."
+ to_chat(M,"[owner]'s [lowertext(name)] absorbs your body, making you part of them.")
+ to_chat(owner,"Your [lowertext(name)] absorbs [M]'s body, making them part of you.")
if(ishuman(M) && ishuman(owner))
var/mob/living/carbon/human/Prey = M
@@ -348,55 +352,68 @@
// problems when A absorbs B, and then C absorbs A, resulting in B holding onto an invalid reagent container.
//This is probably already the case, but for sub-prey, it won't be.
- M.forceMove(owner)
+ if(M.loc != src)
+ M.forceMove(src)
//Seek out absorbed prey of the prey, absorb them too.
//This in particular will recurse oddly because if there is absorbed prey of prey of prey...
//it will just move them up one belly. This should never happen though since... when they were
//absobred, they should have been absorbed as well!
- for(var/I in M.vore_organs)
- var/datum/belly/B = M.vore_organs[I]
- for(var/mob/living/Mm in B.internal_contents)
+ for(var/belly in M.vore_organs)
+ var/obj/belly/B = belly
+ for(var/mob/living/Mm in B)
if(Mm.absorbed)
- internal_contents += Mm
- B.internal_contents -= Mm
absorb_living(Mm)
+ //Update owner
+ owner.updateVRPanel()
+
//Digest a single item
//Receives a return value from digest_act that's how much nutrition
//the item should be worth
-/datum/belly/proc/digest_item(var/obj/item/item)
- var/digested = item.digest_act(internal_contents, owner)
+/obj/belly/proc/digest_item(var/obj/item/item)
+ var/digested = item.digest_act(src, owner)
if(!digested)
items_preserved |= item
else
- internal_contents -= item
owner.nutrition += (5 * digested)
if(isrobot(owner))
var/mob/living/silicon/robot/R = owner
R.cell.charge += (50 * digested)
+//Determine where items should fall out of us into.
+//Typically just to the owner's location.
+/obj/belly/drop_location()
+ //Should be the case 99.99% of the time
+ if(owner)
+ return owner.loc
+ //Sketchy fallback for safety, put them somewhere safe.
+ else
+ log_debug("[src] (\ref[src]) doesn't have an owner, and dropped someone at a latespawn point!")
+ var/fallback = pick(latejoin)
+ return get_turf(fallback)
+
//Handle a mob struggling
// Called from /mob/living/carbon/relaymove()
-/datum/belly/proc/relay_resist(var/mob/living/R)
- if (!(R in internal_contents))
- return // User is not in this belly, or struggle too soon.
+/obj/belly/proc/relay_resist(var/mob/living/R)
+ if (!(R in contents))
+ return // User is not in this belly
R.setClickCooldown(50)
if(owner.stat) //If owner is stat (dead, KO) we can actually escape
- R << "You attempt to climb out of \the [name]. (This will take around [escapetime/10] seconds.)"
- owner << "Someone is attempting to climb out of your [name]!"
+ to_chat(R,"You attempt to climb out of \the [lowertext(name)]. (This will take around [escapetime/10] seconds.)")
+ to_chat(owner,"Someone is attempting to climb out of your [lowertext(name)]!")
if(do_after(R, escapetime, owner, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED))
- if((owner.stat || escapable) && (R in internal_contents)) //Can still escape?
+ if((owner.stat || escapable) && (R.loc == src)) //Can still escape?
release_specific_contents(R)
return
- else if(!(R in internal_contents)) //Aren't even in the belly. Quietly fail.
+ else if(R.loc != src) //Aren't even in the belly. Quietly fail.
return
else //Belly became inescapable or mob revived
- R << "Your attempt to escape [name] has failed!"
- owner << "The attempt to escape from your [name] has failed!"
+ to_chat(R,"Your attempt to escape [lowertext(name)] has failed!")
+ to_chat(owner,"The attempt to escape from your [lowertext(name)] has failed!")
return
return
var/struggle_outer_message = pick(struggle_messages_outside)
@@ -415,112 +432,96 @@
for(var/mob/M in hearers(4, owner))
M.show_message(struggle_outer_message, 2) // hearable
- R << struggle_user_message
+ to_chat(R,struggle_user_message)
var/strpick = pick(struggle_sounds)
var/strsound = struggle_sounds[strpick]
- playsound(R.loc, strsound, 50, 1)
+ playsound(src, strsound, vary = 1, vol = 100, falloff = VORE_SOUND_FALLOFF, preference = /datum/client_preference/digestion_noises)
if(escapable) //If the stomach has escapable enabled.
if(prob(escapechance)) //Let's have it check to see if the prey escapes first.
- R << "You start to climb out of \the [name]."
- owner << "Someone is attempting to climb out of your [name]!"
+ to_chat(R,"You start to climb out of \the [lowertext(name)].")
+ to_chat(owner,"Someone is attempting to climb out of your [lowertext(name)]!")
if(do_after(R, escapetime))
- if((escapable) && (R in internal_contents) && !R.absorbed) //Does the owner still have escapable enabled?
+ if((escapable) && (R.loc == src) && !R.absorbed) //Does the owner still have escapable enabled?
release_specific_contents(R)
- R << "You climb out of \the [name]."
- owner << "[R] climbs out of your [name]!"
+ to_chat(R,"You climb out of \the [lowertext(name)].")
+ to_chat(owner,"[R] climbs out of your [lowertext(name)]!")
for(var/mob/M in hearers(4, owner))
- M.show_message("[R] climbs out of [owner]'s [name]!", 2)
+ M.show_message("[R] climbs out of [owner]'s [lowertext(name)]!", 2)
return
- else if(!(R in internal_contents)) //Aren't even in the belly. Quietly fail.
+ else if(!(R.loc == src)) //Aren't even in the belly. Quietly fail.
return
else //Belly became inescapable.
- R << "Your attempt to escape [name] has failed!"
- owner << "The attempt to escape from your [name] has failed!"
+ to_chat(R,"Your attempt to escape [lowertext(name)] has failed!")
+ to_chat(owner,"The attempt to escape from your [lowertext(name)] has failed!")
return
- else if(prob(transferchance) && istype(transferlocation)) //Next, let's have it see if they end up getting into an even bigger mess then when they started.
- var/location_found = 0
- var/name_found = 0
- for(var/I in owner.vore_organs)
- var/datum/belly/B = owner.vore_organs[I]
- if(B == transferlocation)
- location_found = 1
+ else if(prob(transferchance) && transferlocation) //Next, let's have it see if they end up getting into an even bigger mess then when they started.
+ var/obj/belly/dest_belly
+ for(var/belly in owner.vore_organs)
+ var/obj/belly/B = belly
+ if(B.name == transferlocation)
+ dest_belly = B
break
- if(!location_found)
- for(var/I in owner.vore_organs)
- var/datum/belly/B = owner.vore_organs[I]
- if(B.name == transferlocation.name)
- name_found = 1
- transferlocation = B
- break
-
- if(!location_found && !name_found)
- to_chat(owner, "Something went wrong with your belly transfer settings.")
+ if(!dest_belly)
+ to_chat(owner, "Something went wrong with your belly transfer settings. Your [lowertext(name)] has had it's transfer chance and transfer location cleared as a precaution.")
+ transferchance = 0
transferlocation = null
return
- R << "Your attempt to escape [name] has failed and your struggles only results in you sliding into [owner]'s [transferlocation]!"
- owner << "Someone slid into your [transferlocation] due to their struggling inside your [name]!"
- transfer_contents(R, transferlocation)
+ to_chat(R,"Your attempt to escape [lowertext(name)] has failed and your struggles only results in you sliding into [owner]'s [transferlocation]!")
+ to_chat(owner,"Someone slid into your [transferlocation] due to their struggling inside your [lowertext(name)]!")
+ transfer_contents(R, dest_belly)
return
else if(prob(absorbchance) && digest_mode != DM_ABSORB) //After that, let's have it run the absorb chance.
- R << "In response to your struggling, \the [name] begins to cling more tightly..."
- owner << "You feel your [name] start to cling onto its contents..."
+ to_chat(R,"In response to your struggling, \the [lowertext(name)] begins to cling more tightly...")
+ to_chat(owner,"You feel your [lowertext(name)] start to cling onto its contents...")
digest_mode = DM_ABSORB
return
else if(prob(digestchance) && digest_mode != DM_ITEMWEAK && digest_mode != DM_DIGEST) //Finally, let's see if it should run the digest chance.
- R << "In response to your struggling, \the [name] begins to get more active..."
- owner << "You feel your [name] beginning to become active!"
+ to_chat(R,"In response to your struggling, \the [lowertext(name)] begins to get more active...")
+ to_chat(owner,"You feel your [lowertext(name)] beginning to become active!")
digest_mode = DM_ITEMWEAK
return
else if(prob(digestchance) && digest_mode == DM_ITEMWEAK) //Oh god it gets even worse if you fail twice!
- R << "In response to your struggling, \the [name] begins to get even more active!"
- owner << "You feel your [name] beginning to become even more active!"
+ to_chat(R,"In response to your struggling, \the [lowertext(name)] begins to get even more active!")
+ to_chat(owner,"You feel your [lowertext(name)] beginning to become even more active!")
digest_mode = DM_DIGEST
return
else //Nothing interesting happened.
- R << "You make no progress in escaping [owner]'s [name]."
- owner << "Your prey appears to be unable to make any progress in escaping your [name]."
+ to_chat(R,"You make no progress in escaping [owner]'s [lowertext(name)].")
+ to_chat(owner,"Your prey appears to be unable to make any progress in escaping your [lowertext(name)].")
return
//Transfers contents from one belly to another
-/datum/belly/proc/transfer_contents(var/atom/movable/content, var/datum/belly/target, silent = 0)
- if(!(content in internal_contents))
+/obj/belly/proc/transfer_contents(var/atom/movable/content, var/obj/belly/target, silent = 0)
+ if(!(content in src) || !istype(target))
return
- internal_contents -= content
- target.internal_contents += content
- if(isliving(content))
- var/mob/living/M = content
- if(target.inside_flavor)
- to_chat(M, "[target.inside_flavor]")
- if(target.can_taste && M.get_taste_message(0))
- to_chat(owner, "[M] tastes of [M.get_taste_message(0)].")
+ content.forceMove(target)
if(!silent)
- for(var/mob/hearer in range(1,owner))
- hearer << sound(target.vore_sound,volume=80)
+ playsound(src, target.vore_sound, vol = 100, vary = 1, falloff = VORE_SOUND_FALLOFF, preference = /datum/client_preference/digestion_noises)
owner.updateVRPanel()
- for(var/mob/living/M in internal_contents)
+ for(var/mob/living/M in contents)
M.updateVRPanel()
// Belly copies and then returns the copy
// Needs to be updated for any var changes
-/datum/belly/proc/copy(mob/new_owner)
- var/datum/belly/dupe = new /datum/belly(new_owner)
+/obj/belly/proc/copy(mob/new_owner)
+ var/obj/belly/dupe = new /obj/belly(new_owner)
//// Non-object variables
dupe.name = name
- dupe.inside_flavor = inside_flavor
+ dupe.desc = desc
dupe.vore_sound = vore_sound
dupe.vore_verb = vore_verb
dupe.human_prey_swallow_time = human_prey_swallow_time
dupe.nonhuman_prey_swallow_time = nonhuman_prey_swallow_time
- dupe.emoteTime = emoteTime
+ dupe.emote_time = emote_time
dupe.digest_brute = digest_brute
dupe.digest_burn = digest_burn
dupe.digest_tickrate = digest_tickrate
diff --git a/code/modules/vore/eating/bellymodes_vr.dm b/code/modules/vore/eating/bellymodes_vr.dm
index b7adbf91d8..36a85490f8 100644
--- a/code/modules/vore/eating/bellymodes_vr.dm
+++ b/code/modules/vore/eating/bellymodes_vr.dm
@@ -1,41 +1,48 @@
// Process the predator's effects upon the contents of its belly (i.e digestion/transformation etc)
-// Called from /mob/living/Life() proc.
-/datum/belly/proc/process_Life()
+/obj/belly/proc/process_belly(var/times_fired,var/wait) //Passed by controller
+ if((times_fired < next_process) || !contents.len)
+ recent_sound = FALSE
+ return SSBELLIES_IGNORED
+
+ if(loc != owner)
+ if(istype(owner))
+ loc = owner
+ else
+ qdel(src)
+ return SSBELLIES_PROCESSED
+
+ next_process = times_fired + (6 SECONDS/wait) //Set up our next process time.
+ var/play_sound //Potential sound to play at the end to avoid code duplication.
/////////////////////////// Auto-Emotes ///////////////////////////
- if((digest_mode in emote_lists) && !emotePend)
- emotePend = TRUE
-
- spawn(emoteTime)
- var/list/EL = emote_lists[digest_mode]
- for(var/mob/living/M in internal_contents)
- if(M.digestable || !(digest_mode == DM_DIGEST || digest_mode == DM_DIGEST_NUMB || digest_mode == DM_ITEMWEAK)) // don't give digesty messages to indigestible people
- M << "[pick(EL)]"
- src.emotePend = FALSE
+ if(contents.len && next_emote <= times_fired)
+ next_emote = times_fired + round(emote_time/wait,1)
+ var/list/EL = emote_lists[digest_mode]
+ for(var/mob/living/M in contents)
+ if(M.digestable || !(digest_mode == DM_DIGEST || digest_mode == DM_DIGEST_NUMB || digest_mode == DM_ITEMWEAK)) // don't give digesty messages to indigestible people
+ to_chat(M,"[pick(EL)]")
/////////////////////////// Exit Early ////////////////////////////
- var/list/touchable_items = internal_contents - items_preserved
+ var/list/touchable_items = contents - items_preserved
if(!length(touchable_items))
- return
+ return SSBELLIES_PROCESSED
//////////////////////// Absorbed Handling ////////////////////////
- for(var/mob/living/M in internal_contents)
+ for(var/mob/living/M in contents)
if(M.absorbed)
M.Weaken(5)
///////////////////////////// DM_HOLD /////////////////////////////
if(digest_mode == DM_HOLD)
- return //Pretty boring, huh
+ return SSBELLIES_PROCESSED //Pretty boring, huh
//////////////////////////// DM_DIGEST ////////////////////////////
else if(digest_mode == DM_DIGEST || digest_mode == DM_DIGEST_NUMB || digest_mode == DM_ITEMWEAK)
/*if(prob(50)) //Was SO OFTEN. AAAA.
- var/churnsound = pick(digestion_sounds)
- for(var/mob/hearer in range(1,owner))
- hearer << sound(churnsound,volume=80)*/
-
- for (var/mob/living/M in internal_contents)
+ play_sound = pick(digestion_sounds)
+
+ for (var/mob/living/M in contents)
//Pref protection!
if (!M.digestable || M.absorbed)
continue
@@ -55,12 +62,10 @@
digest_alert_prey = replacetext(digest_alert_prey,"%belly",lowertext(name))
//Send messages
- owner << "" + digest_alert_owner + ""
- M << "" + digest_alert_prey + ""
+ to_chat(owner,"" + digest_alert_owner + "")
+ to_chat(M,"" + digest_alert_prey + "")
- var/deathsound = pick(death_sounds)
- for(var/mob/hearer in range(1,owner))
- hearer << deathsound
+ play_sound = pick(death_sounds)
digestion_death(M)
owner.update_icons()
continue
@@ -71,19 +76,18 @@
H.bloodstr.add_reagent("numbenzyme",10)
// Deal digestion damage (and feed the pred)
- if(!(M.status_flags & GODMODE))
- M.adjustBruteLoss(digest_brute)
- M.adjustFireLoss(digest_burn)
+ M.adjustBruteLoss(digest_brute)
+ M.adjustFireLoss(digest_burn)
- var/offset = (1 + ((M.weight - 137) / 137)) // 130 pounds = .95 140 pounds = 1.02
- var/difference = owner.size_multiplier / M.size_multiplier
- if(isrobot(owner))
- var/mob/living/silicon/robot/R = owner
- R.cell.charge += 20*(digest_brute+digest_burn)
- if(offset) // If any different than default weight, multiply the % of offset.
- owner.nutrition += offset*(2*(digest_brute+digest_burn)/difference) // 9.5 nutrition per digestion tick if they're 130 pounds and it's same size. 10.2 per digestion tick if they're 140 and it's same size. Etc etc.
- else
- owner.nutrition += 2*(digest_brute+digest_burn)/difference
+ var/offset = (1 + ((M.weight - 137) / 137)) // 130 pounds = .95 140 pounds = 1.02
+ var/difference = owner.size_multiplier / M.size_multiplier
+ if(isrobot(owner))
+ var/mob/living/silicon/robot/R = owner
+ R.cell.charge += 20*(digest_brute+digest_burn)
+ if(offset) // If any different than default weight, multiply the % of offset.
+ owner.nutrition += offset*(2*(digest_brute+digest_burn)/difference) // 9.5 nutrition per digestion tick if they're 130 pounds and it's same size. 10.2 per digestion tick if they're 140 and it's same size. Etc etc.
+ else
+ owner.nutrition += 2*(digest_brute+digest_burn)/difference
M.updateVRPanel()
//Contaminate or gurgle items
@@ -93,28 +97,25 @@
if(istype(T,/obj/item/weapon/reagent_containers/food) || istype(T,/obj/item/weapon/holder) || istype(T,/obj/item/organ))
digest_item(T)
else
- T.gurgle_contaminate(internal_contents, owner)
+ T.gurgle_contaminate(contents, owner)
items_preserved |= T
else
digest_item(T)
owner.updateVRPanel()
- return
//////////////////////////// DM_STRIPDIGEST ////////////////////////////
else if(digest_mode == DM_STRIPDIGEST) // Only gurgle the gear off your prey.
if(prob(50))
- var/churnsound = pick(digestion_sounds)
- for(var/mob/hearer in range(1,owner))
- hearer << sound(churnsound,volume=80)
+ play_sound = pick(digestion_sounds)
// Handle loose items first.
var/obj/item/T = pick(touchable_items)
if(istype(T))
digest_item(T)
- for(var/mob/living/carbon/human/M in internal_contents)
+ for(var/mob/living/carbon/human/M in contents)
if (M.absorbed)
continue
for(var/slot in slots)
@@ -122,22 +123,19 @@
if(thingy)
M.unEquip(thingy,force = TRUE)
thingy.forceMove(owner)
- internal_contents |= thingy
+ contents |= thingy
digest_item(T)
M.updateVRPanel()
owner.updateVRPanel()
- return
//////////////////////////// DM_ABSORB ////////////////////////////
else if(digest_mode == DM_ABSORB)
- for (var/mob/living/M in internal_contents)
+ for (var/mob/living/M in contents)
/*if(prob(10)) //Less often than gurgles. People might leave this on forever.
- var/absorbsound = pick(digestion_sounds)
- M << sound(absorbsound,volume=80)
- owner << sound(absorbsound,volume=80)*/
+ play_sound = pick(digestion_sounds)
if(M.absorbed)
continue
@@ -149,48 +147,36 @@
else if(M.nutrition < 100) //When they're finally drained.
absorb_living(M)
- return
-
-
-
//////////////////////////// DM_UNABSORB ////////////////////////////
else if(digest_mode == DM_UNABSORB)
- for (var/mob/living/M in internal_contents)
+ for (var/mob/living/M in contents)
if(M.absorbed && owner.nutrition >= 100)
M.absorbed = 0
- M << "You suddenly feel solid again "
- owner << "You feel like a part of you is missing."
+ to_chat(M,"You suddenly feel solid again ")
+ to_chat(owner,"You feel like a part of you is missing.")
owner.nutrition -= 100
- return
-
//////////////////////////// DM_DRAIN ////////////////////////////
else if(digest_mode == DM_DRAIN)
- for (var/mob/living/M in internal_contents)
+ for (var/mob/living/M in contents)
/*if(prob(10)) //Less often than gurgles. People might leave this on forever.
- var/drainsound = pick(digestion_sounds)
- M << sound(drainsound,volume=80)
- owner << sound(drainsound,volume=80)*/
+ play_sound = pick(digestion_sounds)
if(M.nutrition >= 100) //Drain them until there's no nutrients left.
var/oldnutrition = (M.nutrition * 0.05)
M.nutrition = (M.nutrition * 0.95)
owner.nutrition += oldnutrition
- return
- return
//////////////////////////// DM_SHRINK ////////////////////////////
else if(digest_mode == DM_SHRINK)
- for (var/mob/living/M in internal_contents)
+ for (var/mob/living/M in contents)
if(prob(10)) //Infinite gurgles!
- var/shrinksound = pick(digestion_sounds)
- M << sound(shrinksound,volume=80)
- owner << sound(shrinksound,volume=80)
+ play_sound = pick(digestion_sounds)
if(M.size_multiplier > shrink_grow_size) //Shrink until smol.
M.resize(M.size_multiplier-0.01) //Shrink by 1% per tick.
@@ -198,34 +184,27 @@
var/oldnutrition = (M.nutrition * 0.05)
M.nutrition = (M.nutrition * 0.95)
owner.nutrition += oldnutrition
- return
- return
//////////////////////////// DM_GROW ////////////////////////////
else if(digest_mode == DM_GROW)
- for (var/mob/living/M in internal_contents)
+ for (var/mob/living/M in contents)
if(prob(10))
- var/growsound = pick(digestion_sounds)
- M << sound(growsound,volume=80)
- owner << sound(growsound,volume=80)
+ play_sound = pick(digestion_sounds)
if(M.size_multiplier < shrink_grow_size) //Grow until large.
M.resize(M.size_multiplier+0.01) //Grow by 1% per tick.
if(M.nutrition >= 100)
owner.nutrition = (owner.nutrition * 0.95)
- return
//////////////////////////// DM_SIZE_STEAL ////////////////////////////
else if(digest_mode == DM_SIZE_STEAL)
- for (var/mob/living/M in internal_contents)
+ for (var/mob/living/M in contents)
if(prob(10))
- var/growsound = pick(digestion_sounds)
- M << sound(growsound,volume=80)
- owner << sound(growsound,volume=80)
+ play_sound = pick(digestion_sounds)
if(M.size_multiplier > shrink_grow_size && owner.size_multiplier < 2) //Grow until either pred is large or prey is small.
owner.resize(owner.size_multiplier+0.01) //Grow by 1% per tick.
@@ -234,16 +213,13 @@
var/oldnutrition = (M.nutrition * 0.05)
M.nutrition = (M.nutrition * 0.95)
owner.nutrition += oldnutrition
- return
///////////////////////////// DM_HEAL /////////////////////////////
else if(digest_mode == DM_HEAL)
/*if(prob(50)) //Wet heals!
- var/healsound = pick(digestion_sounds)
- for(var/mob/hearer in range(1,owner))
- hearer << sound(healsound,volume=80)*/
+ play_sound = pick(digestion_sounds)
- for (var/mob/living/M in internal_contents)
+ for (var/mob/living/M in contents)
if(M.stat != DEAD)
if(owner.nutrition > 90 && (M.health < M.maxHealth))
M.adjustBruteLoss(-5)
@@ -254,11 +230,10 @@
else if(owner.nutrition > 90 && (M.nutrition <= 400))
owner.nutrition -= 1
M.nutrition += 1
- return
///////////////////////////// DM_TRANSFORM_HAIR_AND_EYES /////////////////////////////
else if(digest_mode == DM_TRANSFORM_HAIR_AND_EYES && ishuman(owner))
- for (var/mob/living/carbon/human/P in internal_contents)
+ for (var/mob/living/carbon/human/P in contents)
if(P.stat == DEAD)
continue
@@ -272,10 +247,9 @@
change_eyes(P)
change_hair(P,1)
- return
///////////////////////////// DM_TRANSFORM_MALE /////////////////////////////
else if(digest_mode == DM_TRANSFORM_MALE && ishuman(owner))
- for (var/mob/living/carbon/human/P in internal_contents)
+ for (var/mob/living/carbon/human/P in contents)
if(P.stat == DEAD)
continue
@@ -297,12 +271,9 @@
if(check_gender(P,MALE))
change_gender(P,MALE,1)
- return
-
-
///////////////////////////// DM_TRANSFORM_FEMALE /////////////////////////////
else if(digest_mode == DM_TRANSFORM_FEMALE && ishuman(owner))
- for (var/mob/living/carbon/human/P in internal_contents)
+ for (var/mob/living/carbon/human/P in contents)
if(P.stat == DEAD)
continue
@@ -324,11 +295,9 @@
if(check_gender(P,FEMALE))
change_gender(P,FEMALE,1)
- return
-
///////////////////////////// DM_TRANSFORM_KEEP_GENDER /////////////////////////////
else if(digest_mode == DM_TRANSFORM_KEEP_GENDER && ishuman(owner))
- for (var/mob/living/carbon/human/P in internal_contents)
+ for (var/mob/living/carbon/human/P in contents)
if(P.stat == DEAD)
continue
@@ -346,11 +315,9 @@
change_hair(P)
change_skin(P,1)
- return
-
///////////////////////////// DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR /////////////////////////////
else if(digest_mode == DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR && ishuman(owner))
- for (var/mob/living/carbon/human/P in internal_contents)
+ for (var/mob/living/carbon/human/P in contents)
if(P.stat == DEAD)
continue
@@ -366,11 +333,9 @@
change_wing_nocolor(P)
change_species(P,1)
- return
-
///////////////////////////// DM_TRANSFORM_REPLICA /////////////////////////////
else if(digest_mode == DM_TRANSFORM_REPLICA && ishuman(owner))
- for (var/mob/living/carbon/human/P in internal_contents)
+ for (var/mob/living/carbon/human/P in contents)
if(P.stat == DEAD)
continue
@@ -395,11 +360,9 @@
change_wing(P)
change_species(P,1)
- return
-
///////////////////////////// DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR_EGG /////////////////////////////
else if(digest_mode == DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR_EGG && ishuman(owner))
- for (var/mob/living/carbon/human/P in internal_contents)
+ for (var/mob/living/carbon/human/P in contents)
if(P.stat == DEAD)
continue
@@ -413,11 +376,9 @@
if(!P.absorbed)
put_in_egg(P,1)
- return
-
///////////////////////////// DM_TRANSFORM_KEEP_GENDER_EGG /////////////////////////////
else if(digest_mode == DM_TRANSFORM_KEEP_GENDER_EGG && ishuman(owner))
- for (var/mob/living/carbon/human/P in internal_contents)
+ for (var/mob/living/carbon/human/P in contents)
if(P.stat == DEAD)
continue
@@ -433,11 +394,9 @@
if(!P.absorbed)
put_in_egg(P,1)
- return
-
///////////////////////////// DM_TRANSFORM_REPLICA_EGG /////////////////////////////
else if(digest_mode == DM_TRANSFORM_REPLICA_EGG && ishuman(owner))
- for (var/mob/living/carbon/human/P in internal_contents)
+ for (var/mob/living/carbon/human/P in contents)
if(P.stat == DEAD)
continue
@@ -460,11 +419,9 @@
if(!P.absorbed)
put_in_egg(P,1)
- return
-
///////////////////////////// DM_TRANSFORM_MALE_EGG /////////////////////////////
else if(digest_mode == DM_TRANSFORM_MALE_EGG && ishuman(owner))
- for (var/mob/living/carbon/human/P in internal_contents)
+ for (var/mob/living/carbon/human/P in contents)
if(P.stat == DEAD)
continue
@@ -484,11 +441,9 @@
if(!P.absorbed)
put_in_egg(P,1)
- return
-
///////////////////////////// DM_TRANSFORM_FEMALE_EGG /////////////////////////////
else if(digest_mode == DM_TRANSFORM_FEMALE_EGG && ishuman(owner))
- for (var/mob/living/carbon/human/P in internal_contents)
+ for (var/mob/living/carbon/human/P in contents)
if(P.stat == DEAD)
continue
@@ -508,12 +463,14 @@
if(!P.absorbed)
put_in_egg(P,1)
- return
-
///////////////////////////// DM_EGG /////////////////////////////
else if(digest_mode == DM_EGG && ishuman(owner))
- for (var/mob/living/carbon/human/P in internal_contents)
+ for (var/mob/living/carbon/human/P in contents)
if(P.absorbed || P.stat == DEAD)
continue
put_in_egg(P,1)
+
+ if(play_sound)
+ playsound(src, play_sound, vol = 100, vary = 1, falloff = VORE_SOUND_FALLOFF, ignore_walls = FALSE, preference = /datum/client_preference/digestion_noises)
+ return SSBELLIES_PROCESSED
diff --git a/code/modules/vore/eating/contaminate_vr.dm b/code/modules/vore/eating/contaminate_vr.dm
index 38dc808b2b..1505472b1d 100644
--- a/code/modules/vore/eating/contaminate_vr.dm
+++ b/code/modules/vore/eating/contaminate_vr.dm
@@ -5,7 +5,7 @@ var/image/gurgled_overlay = image('icons/effects/sludgeoverlay_vr.dmi')
var/cleanname
var/cleandesc
-/obj/item/proc/gurgle_contaminate(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/proc/gurgle_contaminate(var/atom/movable/item_storage = null)
if(!can_gurgle())
return FALSE
@@ -18,7 +18,7 @@ var/image/gurgled_overlay = image('icons/effects/sludgeoverlay_vr.dmi')
name = "[gurgleflavor] [cleanname]"
desc = "[cleandesc] It seems to be covered in ominously foul residue and needs a wash."
for(var/obj/item/O in contents)
- gurgle_contaminate(internal_contents, item_storage)
+ gurgle_contaminate(item_storage)
return TRUE
/obj/item/proc/can_gurgle()
@@ -93,34 +93,34 @@ var/image/gurgled_overlay = image('icons/effects/sludgeoverlay_vr.dmi')
//////////////
// Special handling of gurgle_contaminate
//////////////
-/obj/item/weapon/card/id/gurgle_contaminate(var/list/internal_contents = null, var/atom/movable/item_storage = null)
- digest_act(internal_contents, item_storage) //Digesting these anyway
+/obj/item/weapon/card/id/gurgle_contaminate(var/atom/movable/item_storage = null)
+ digest_act(item_storage) //Digesting these anyway
return TRUE
-/obj/item/weapon/reagent_containers/food/gurgle_contaminate(var/list/internal_contents = null, var/atom/movable/item_storage = null)
- digest_act(internal_contents, item_storage)
+/obj/item/weapon/reagent_containers/food/gurgle_contaminate(var/atom/movable/item_storage = null)
+ digest_act(item_storage)
return TRUE
-/obj/item/weapon/holder/gurgle_contaminate(var/list/internal_contents = null, var/atom/movable/item_storage = null)
- digest_act(internal_contents, item_storage)
+/obj/item/weapon/holder/gurgle_contaminate(var/atom/movable/item_storage = null)
+ digest_act(item_storage)
return TRUE
-/obj/item/organ/gurgle_contaminate(var/list/internal_contents = null, var/atom/movable/item_storage = null)
- digest_act(internal_contents, item_storage)
+/obj/item/organ/gurgle_contaminate(var/atom/movable/item_storage = null)
+ digest_act(item_storage)
return TRUE
-/obj/item/weapon/cell/gurgle_contaminate(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/weapon/cell/gurgle_contaminate(var/atom/movable/item_storage = null)
if(!gurgled)
//Don't make them wet, just drain
var/obj/item/weapon/cell/C = src
C.charge = 0
return TRUE
-/obj/item/weapon/storage/box/gurgle_contaminate(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/weapon/storage/box/gurgle_contaminate(var/atom/movable/item_storage = null)
if((. = ..()))
name = "soggy [cleanname]"
desc = "This soggy box is about to fall apart any time."
-/obj/item/device/pda/gurgle_contaminate(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/device/pda/gurgle_contaminate(var/atom/movable/item_storage = null)
if((. = ..()))
desc = "This device seems completely unresponsive while drenched with sludge. Perhaps you could still wash it."
diff --git a/code/modules/vore/eating/digest_act_vr.dm b/code/modules/vore/eating/digest_act_vr.dm
index a789c886e7..78512bf09c 100644
--- a/code/modules/vore/eating/digest_act_vr.dm
+++ b/code/modules/vore/eating/digest_act_vr.dm
@@ -3,20 +3,15 @@
//return non-negative integer: Amount of nutrition/charge gained (scaled to nutrition, other end can multiply for charge scale).
// Ye default implementation.
-/obj/item/proc/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/proc/digest_act(var/atom/movable/item_storage = null)
for(var/obj/item/O in contents)
if(istype(O,/obj/item/weapon/storage/internal)) //Dump contents from dummy pockets.
for(var/obj/item/SO in O)
- if(internal_contents)
- internal_contents |= SO
if(item_storage)
SO.forceMove(item_storage)
qdel(O)
- else
- if(internal_contents)
- internal_contents |= O
- if(item_storage)
- O.forceMove(item_storage)
+ else if(item_storage)
+ O.forceMove(item_storage)
qdel(src)
return w_class
@@ -24,82 +19,75 @@
/////////////
// Some indigestible stuff
/////////////
-/obj/item/weapon/hand_tele/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/weapon/hand_tele/digest_act(...)
return FALSE
-/obj/item/weapon/card/id/gold/captain/spare/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/weapon/card/id/gold/captain/spare/digest_act(...)
return FALSE
-/obj/item/device/aicard/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/device/aicard/digest_act(...)
return FALSE
-/obj/item/device/paicard/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/device/paicard/digest_act(...)
return FALSE
-/obj/item/weapon/gun/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/weapon/gun/digest_act(...)
return FALSE
-/obj/item/weapon/pinpointer/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/weapon/pinpointer/digest_act(...)
return FALSE
-/obj/item/blueprints/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/blueprints/digest_act(...)
return FALSE
-/obj/item/weapon/disk/nuclear/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/weapon/disk/nuclear/digest_act(...)
return FALSE
-/obj/item/device/perfect_tele_beacon/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/device/perfect_tele_beacon/digest_act(...)
return FALSE //Sorta important to not digest your own beacons.
/////////////
// Some special treatment
/////////////
//PDAs need to lose their ID to not take it with them, so we can get a digested ID
-/obj/item/device/pda/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/device/pda/digest_act(var/atom/movable/item_storage = null)
if(id)
id = null
- /* Doesn't appear to be necessary anymore.
- if(item_storage)
- id.forceMove(item_storage)
- if(internal_contents)
- internal_contents |= id
- */
-
. = ..()
-/obj/item/weapon/card/id/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/weapon/card/id/digest_act(var/atom/movable/item_storage = null)
desc = "A partially digested card that has seen better days. Much of it's data has been destroyed."
icon = 'icons/obj/card_vr.dmi'
icon_state = "digested"
access = list() // No access
return FALSE
-/obj/item/weapon/reagent_containers/food/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
- if(ishuman(item_storage))
- var/mob/living/carbon/human/H = item_storage
- reagents.trans_to_holder(H.ingested, (reagents.total_volume * 0.3), 1, 0)
-
- else if(isrobot(item_storage))
- var/mob/living/silicon/robot/R = item_storage
- R.cell.charge += 150
+/obj/item/weapon/reagent_containers/food/digest_act(var/atom/movable/item_storage = null)
+ if(isbelly(item_storage))
+ var/obj/belly/B = item_storage
+ if(ishuman(B.owner))
+ var/mob/living/carbon/human/H = B.owner
+ reagents.trans_to_holder(H.ingested, (reagents.total_volume * 0.3), 1, 0)
+ else if(isrobot(B.owner))
+ var/mob/living/silicon/robot/R = B.owner
+ R.cell.charge += 150
. = ..()
-/obj/item/weapon/holder/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/weapon/holder/digest_act(var/atom/movable/item_storage = null)
for(var/mob/living/M in contents)
- if(internal_contents)
- internal_contents |= M
if(item_storage)
M.forceMove(item_storage)
held_mob = null
. = ..()
-/obj/item/organ/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/organ/digest_act(var/atom/movable/item_storage = null)
if((. = ..()))
. += 70 //Organs give a little more
-/obj/item/weapon/storage/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/weapon/storage/digest_act(var/atom/movable/item_storage = null)
for(var/obj/item/I in contents)
I.screen_loc = null
- .=..()
+
+ . = ..()
/////////////
// Some more complicated stuff
/////////////
-/obj/item/device/mmi/digital/posibrain/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/device/mmi/digital/posibrain/digest_act(var/atom/movable/item_storage = null)
//Replace this with a VORE setting so all types of posibrains can/can't be digested on a whim
return FALSE
diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm
index ed9fe0ae16..4b7fabc1d1 100644
--- a/code/modules/vore/eating/living_vr.dm
+++ b/code/modules/vore/eating/living_vr.dm
@@ -2,7 +2,7 @@
/mob/living
var/digestable = 1 // Can the mob be digested inside a belly?
var/allowmobvore = 1 // Will simplemobs attempt to eat the mob?
- var/vore_selected // Default to no vore capability.
+ var/obj/belly/vore_selected // Default to no vore capability.
var/list/vore_organs = list() // List of vore containers inside a mob
var/absorbed = 0 // If a mob is absorbed into another
var/weight = 137 // Weight for mobs for weightgain system
@@ -15,8 +15,6 @@
var/vore_taste = null // What the character tastes like
var/no_vore = 0 // If the character/mob can vore.
var/openpanel = 0 // Is the vore panel open?
- var/conceal_nif = 0 // Do they wish to conceal their NIF from examine?
- var/nif_examine = "There's a certain spark to their eyes" //The examine text of their NIF. This is the default placeholder.
var/noisy = 0 // Toggle audible hunger.
var/absorbing_prey = 0 // Determines if the person is using the succubus drain or not. See station_special_abilities_vr.
var/drain_finalized = 0 // Determines if the succubus drain will be KO'd/absorbed. Can be toggled on at any time.
@@ -28,13 +26,10 @@
/hook/living_new/proc/vore_setup(mob/living/M)
M.verbs += /mob/living/proc/escapeOOC
M.verbs += /mob/living/proc/lick
- if(M.no_vore) //If the mob isn's supposed to have a stomach, let's not give it an insidepanel so it can make one for itself, or a stomach.
- M << "The creature that you are can not eat others."
+ if(M.no_vore) //If the mob isn't supposed to have a stomach, let's not give it an insidepanel so it can make one for itself, or a stomach.
return 1
M.verbs += /mob/living/proc/insidePanel
- //M.appearance_flags |= PIXEL_SCALE // Moved to 02_size.dm
-
//Tries to load prefs if a client is present otherwise gives freebie stomach
if(!M.vore_organs || !M.vore_organs.len)
spawn(20) //Wait a couple of seconds to make sure copy_to or whatever has gone
@@ -42,7 +37,7 @@
if(M.client && M.client.prefs_vr)
if(!M.copy_from_prefs_vr())
- M << "ERROR: You seem to have saved VOREStation prefs, but they couldn't be loaded."
+ to_chat(M,"ERROR: You seem to have saved VOREStation prefs, but they couldn't be loaded.")
return 0
if(M.vore_organs && M.vore_organs.len)
M.vore_selected = M.vore_organs[1]
@@ -50,35 +45,25 @@
if(!M.vore_organs || !M.vore_organs.len)
if(!M.vore_organs)
M.vore_organs = list()
- var/datum/belly/B = new /datum/belly(M)
+ var/obj/belly/B = new /obj/belly(M)
+ M.vore_selected = B
B.immutable = 1
B.name = "Stomach"
- B.inside_flavor = "It appears to be rather warm and wet. Makes sense, considering it's inside \the [M.name]."
+ B.desc = "It appears to be rather warm and wet. Makes sense, considering it's inside \the [M.name]."
B.can_taste = 1
- M.vore_organs[B.name] = B
- M.vore_selected = B.name
-
- //Simple_animal gets emotes. move this to that hook instead?
- if(istype(src,/mob/living/simple_animal))
- B.emote_lists[DM_HOLD] = list(
- "The insides knead at you gently for a moment.",
- "The guts glorp wetly around you as some air shifts.",
- "Your predator takes a deep breath and sighs, shifting you somewhat.",
- "The stomach squeezes you tight for a moment, then relaxes.",
- "During a moment of quiet, breathing becomes the most audible thing.",
- "The warm slickness surrounds and kneads on you.")
-
- B.emote_lists[DM_DIGEST] = list(
- "The caustic acids eat away at your form.",
- "The acrid air burns at your lungs.",
- "Without a thought for you, the stomach grinds inwards painfully.",
- "The guts treat you like food, squeezing to press more acids against you.",
- "The onslaught against your body doesn't seem to be letting up; you're food now.",
- "The insides work on you like they would any other food.")
-
+
//Return 1 to hook-caller
return 1
+//
+// Hide vore organs in contents
+//
+/mob/living/view_variables_filter_contents(list/L)
+ . = ..()
+ var/len_before = L.len
+ L -= vore_organs
+ . += len_before - L.len
+
//
// Handle being clicked, perhaps with something to devour
//
@@ -139,15 +124,13 @@
else if(istype(I,/obj/item/device/radio/beacon))
var/confirm = alert(user, "[src == user ? "Eat the beacon?" : "Feed the beacon to [src]?"]", "Confirmation", "Yes!", "Cancel")
if(confirm == "Yes!")
- var/bellychoice = input("Which belly?","Select A Belly") in src.vore_organs
- var/datum/belly/B = src.vore_organs[bellychoice]
- src.visible_message("[user] is trying to stuff a beacon into [src]'s [bellychoice]!","[user] is trying to stuff a beacon into you!")
+ var/obj/belly/B = input("Which belly?","Select A Belly") as null|anything in vore_organs
+ if(!istype(B))
+ return 1
+ visible_message("[user] is trying to stuff a beacon into [src]'s [lowertext(B.name)]!","[user] is trying to stuff a beacon into you!")
if(do_after(user,30,src))
user.drop_item()
- I.loc = src
- B.internal_contents |= I
- src.visible_message("[src] is fed the beacon!","You're fed the beacon!")
- playsound(src, B.vore_sound, 100, 1)
+ I.forceMove(B)
return 1
else
return 1 //You don't get to hit someone 'later'
@@ -160,48 +143,15 @@
/mob/living/proc/vore_process_resist()
//Are we resisting from inside a belly?
- var/datum/belly/B = check_belly(src)
- if(B)
- spawn() B.relay_resist(src)
+ if(isbelly(loc))
+ var/obj/belly/B = loc
+ B.relay_resist(src)
return TRUE //resist() on living does this TRUE thing.
-
+
//Other overridden resists go here
-
return 0
-
-//
-// Proc for updating vore organs and digestion/healing/absorbing
-//
-/mob/living/proc/handle_internal_contents()
- if(air_master.current_cycle%3 != 1)
- return //The accursed timer
-
- for (var/I in vore_organs)
- var/datum/belly/B = vore_organs[I]
- if(B.internal_contents.len)
- B.process_Life() //AKA 'do bellymodes_vr.dm'
-
- if(noisy > 0 && nutrition < 100 && prob(10))
- var/growlsound = pick(hunger_sounds)
- if(nutrition < 50)
- for(var/mob/hearer in range(1,src))
- hearer << sound(growlsound,volume=80)
- else
- for(var/mob/hearer in range(1,src))
- hearer << sound(growlsound,volume=35)
-
- if(air_master.current_cycle%90 != 1) return //Occasionally do supercleanups.
- for (var/I in vore_organs)
- var/datum/belly/B = vore_organs[I]
- if(B.internal_contents.len)
- listclearnulls(B.internal_contents)
- for(var/atom/movable/M in B.internal_contents)
- if(M.loc != src)
- B.internal_contents -= M
- log_debug("Had to remove [M] from belly [B] in [src]")
-
//
// Verb for saving vore preferences to save file
//
@@ -227,7 +177,7 @@
/mob/living/proc/copy_to_prefs_vr()
if(!client || !client.prefs_vr)
- src << "You attempted to save your vore prefs but somehow you're in this character without a client.prefs_vr variable. Tell a dev."
+ to_chat(src,"You attempted to save your vore prefs but somehow you're in this character without a client.prefs_vr variable. Tell a dev.")
return 0
var/datum/vore_preferences/P = client.prefs_vr
@@ -236,8 +186,6 @@
P.allowmobvore = src.allowmobvore
P.belly_prefs = src.vore_organs
P.vore_taste = src.vore_taste
- P.nif_examine = src.nif_examine
- P.conceal_nif = src.conceal_nif
P.can_be_drop_prey = src.can_be_drop_prey
P.can_be_drop_pred = src.can_be_drop_pred
@@ -248,26 +196,79 @@
//
/mob/living/proc/copy_from_prefs_vr()
if(!client || !client.prefs_vr)
- src << "You attempted to apply your vore prefs but somehow you're in this character without a client.prefs_vr variable. Tell a dev."
+ to_chat(src,"You attempted to apply your vore prefs but somehow you're in this character without a client.prefs_vr variable. Tell a dev.")
return 0
var/datum/vore_preferences/P = client.prefs_vr
- src.digestable = P.digestable
- src.allowmobvore = P.allowmobvore
- src.vore_organs = list()
- src.vore_taste = P.vore_taste
- src.nif_examine = P.nif_examine
- src.conceal_nif = P.conceal_nif
- src.can_be_drop_prey = P.can_be_drop_prey
- src.can_be_drop_pred = P.can_be_drop_pred
+ vore_organs = list()
+ digestable = P.digestable
+ allowmobvore = P.allowmobvore
+ vore_taste = P.vore_taste
+ can_be_drop_prey = P.can_be_drop_prey
+ can_be_drop_pred = P.can_be_drop_pred
+ var/force_save = FALSE
for(var/I in P.belly_prefs)
- var/datum/belly/Bp = P.belly_prefs[I]
- src.vore_organs[Bp.name] = Bp.copy(src)
+ if(isbelly(I)) //Belly system 2.0
+ var/obj/belly/saved = I
+ saved.copy(src)
+ else if(istext(I)) //Belly name for old datum system
+ force_save = TRUE
+ log_debug("[src] had legacy belly [I], converting.")
+ var/datum/belly/Bp = P.belly_prefs[I]
+ var/obj/belly/new_belly = new(src)
+ Bp.copy(new_belly) //Rewritten to convert to a 2.0 belly
+
+ if(force_save)
+ save_vore_prefs()
return 1
+//
+// Release everything in every vore organ
+//
+/mob/living/proc/release_vore_contents(var/include_absorbed = TRUE)
+ for(var/belly in vore_organs)
+ var/obj/belly/B = belly
+ B.release_all_contents(include_absorbed)
+
+//
+// Returns examine messages for bellies
+//
+/mob/living/proc/examine_bellies()
+ if(!show_pudge()) //Some clothing or equipment can hide this.
+ return ""
+
+ var/message = ""
+ for (var/belly in vore_organs)
+ var/obj/belly/B = belly
+ message += B.get_examine_msg()
+
+ return message
+
+//
+// Whether or not people can see our belly messages
+//
+/mob/living/proc/show_pudge()
+ return TRUE //Can override if you want.
+
+/mob/living/carbon/human/show_pudge()
+ //A uniform could hide it.
+ if(istype(w_uniform,/obj/item/clothing))
+ var/obj/item/clothing/under = w_uniform
+ if(under.hides_bulges)
+ return FALSE
+
+ //We return as soon as we find one, no need for 'else' really.
+ if(istype(wear_suit,/obj/item/clothing))
+ var/obj/item/clothing/suit = wear_suit
+ if(suit.hides_bulges)
+ return FALSE
+
+
+ return ..()
+
//
// Clearly super important. Obviously.
//
@@ -315,48 +316,35 @@
set name = "OOC Escape"
set category = "OOC"
- //You're in an animal!
- if(istype(src.loc,/mob/living/simple_animal))
- var/mob/living/simple_animal/pred = src.loc
- var/confirm = alert(src, "You're in a mob. Don't use this as a trick to get out of hostile animals. This is for escaping from preference-breaking and if you're otherwise unable to escape from endo. If you are in more than one pred, use this more than once.", "Confirmation", "Okay", "Cancel")
- if(confirm == "Okay")
- for(var/I in pred.vore_organs)
- var/datum/belly/B = pred.vore_organs[I]
- B.release_specific_contents(src)
-
- for(var/mob/living/simple_animal/SA in range(10))
- SA.prey_excludes += src
- spawn(18000)
- if(src && SA)
- SA.prey_excludes -= src
-
- message_admins("[key_name(src)] used the OOC escape button to get out of [key_name(pred)] (MOB) ([pred ? "JMP" : "null"])")
- pred.update_icons()
-
- //You're in a PC!
- else if(istype(src.loc,/mob/living))
- var/mob/living/carbon/pred = src.loc
- var/confirm = alert(src, "You're in a player-character. This is for escaping from preference-breaking or if your predator disconnects/AFKs. If you are in more than one pred. If your preferences were being broken, please admin-help as well.", "Confirmation", "Okay", "Cancel")
- if(confirm == "Okay")
- for(var/O in pred.vore_organs)
- var/datum/belly/CB = pred.vore_organs[O]
- CB.internal_contents -= src //Clean them if we can, otherwise it will get GC'd by the vore code later.
- src.forceMove(get_turf(loc))
- message_admins("[key_name(src)] used the OOC escape button to get out of [key_name(pred)] (PC) ([pred ? "JMP" : "null"])")
+ //You're in a belly!
+ if(isbelly(loc))
+ var/obj/belly/B = loc
+ var/confirm = alert(src, "You're in a mob. Don't use this as a trick to get out of hostile animals. This is for escaping from preference-breaking and if you're otherwise unable to escape from endo (pred AFK for a long time).", "Confirmation", "Okay", "Cancel")
+ if(!confirm == "Okay" || loc != B)
+ return
+ //Actual escaping
+ forceMove(get_turf(src)) //Just move me up to the turf, let's not cascade through bellies, there's been a problem, let's just leave.
+ for(var/mob/living/simple_animal/SA in range(10))
+ SA.prey_excludes[src] = world.time
+ log_and_message_admins("[key_name(src)] used the OOC escape button to get out of [key_name(B.owner)] ([B.owner ? "JMP" : "null"])")
+
+ if(isanimal(B.owner))
+ var/mob/living/simple_animal/SA = B.owner
+ SA.update_icons()
//You're in a dogborg!
- else if(istype(src.loc, /obj/item/device/dogborg/sleeper))
- var/mob/living/silicon/pred = src.loc.loc //Thing holding the belly!
- var/obj/item/device/dogborg/sleeper/belly = src.loc //The belly!
+ else if(istype(loc, /obj/item/device/dogborg/sleeper))
+ var/mob/living/silicon/pred = loc.loc //Thing holding the belly!
+ var/obj/item/device/dogborg/sleeper/belly = loc //The belly!
var/confirm = alert(src, "You're in a dogborg sleeper. This is for escaping from preference-breaking or if your predator disconnects/AFKs. If your preferences were being broken, please admin-help as well.", "Confirmation", "Okay", "Cancel")
- if(confirm == "Okay")
- message_admins("[key_name(src)] used the OOC escape button to get out of [key_name(pred)] (BORG) ([pred ? "JMP" : "null"])")
- belly.go_out(src) //Just force-ejects from the borg as if they'd clicked the eject button.
-
-
+ if(!confirm == "Okay" || loc != belly)
+ return
+ //Actual escaping
+ log_and_message_admins("[key_name(src)] used the OOC escape button to get out of [key_name(pred)] (BORG) ([pred ? "JMP" : "null"])")
+ belly.go_out(src) //Just force-ejects from the borg as if they'd clicked the eject button.
else
- src << "You aren't inside anyone, you clod."
+ to_chat(src,"You aren't inside anyone, though, is the thing.")
//
// Eating procs depending on who clicked what
@@ -384,14 +372,13 @@
//
// Master vore proc that actually does vore procedures
//
-/mob/living/proc/perform_the_nom(var/mob/living/user, var/mob/living/prey, var/mob/living/pred, var/belly)
+/mob/living/proc/perform_the_nom(var/mob/living/user, var/mob/living/prey, var/mob/living/pred, var/obj/belly/belly, var/delay)
//Sanity
- if(!user || !prey || !pred || !belly || !(belly in pred.vore_organs))
- log_debug("[user] attempted to feed [prey] to [pred], via [belly] but it went wrong.")
+ if(!user || !prey || !pred || !istype(belly) || !(belly in pred.vore_organs))
+ log_debug("[user] attempted to feed [prey] to [pred], via [lowertext(belly.name)] but it went wrong.")
return
// The belly selected at the time of noms
- var/datum/belly/belly_target = pred.vore_organs[belly]
var/attempt_msg = "ERROR: Vore message couldn't be created. Notify a dev. (at)"
var/success_msg = "ERROR: Vore message couldn't be created. Notify a dev. (sc)"
@@ -404,17 +391,17 @@
// Prepare messages
if(user == pred) //Feeding someone to yourself
- attempt_msg = text("[] is attemping to [] [] into their []!",pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
- success_msg = text("[] manages to [] [] into their []!",pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
+ attempt_msg = text("[] is attemping to [] [] into their []!",pred,lowertext(belly.vore_verb),prey,lowertext(belly.name))
+ success_msg = text("[] manages to [] [] into their []!",pred,lowertext(belly.vore_verb),prey,lowertext(belly.name))
else //Feeding someone to another person
- attempt_msg = text("[] is attempting to make [] [] [] into their []!",user,pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
- success_msg = text("[] manages to make [] [] [] into their []!",user,pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
+ attempt_msg = text("[] is attempting to make [] [] [] into their []!",user,pred,lowertext(belly.vore_verb),prey,lowertext(belly.name))
+ success_msg = text("[] manages to make [] [] [] into their []!",user,pred,lowertext(belly.vore_verb),prey,lowertext(belly.name))
// Announce that we start the attempt!
user.visible_message(attempt_msg)
// Now give the prey time to escape... return if they did
- var/swallow_time = istype(prey, /mob/living/carbon/human) ? belly_target.human_prey_swallow_time : belly_target.nonhuman_prey_swallow_time
+ var/swallow_time = delay || istype(prey, /mob/living/carbon/human) ? belly.human_prey_swallow_time : belly.nonhuman_prey_swallow_time
//Timer and progress bar
if(!do_after(user, swallow_time, prey))
@@ -422,16 +409,14 @@
// If we got this far, nom successful! Announce it!
user.visible_message(success_msg)
- if(belly_target.vore_sound)
- playsound(user, belly_target.vore_sound, 100, 1)
// Actually shove prey into the belly.
- belly_target.nom_mob(prey, user)
+ belly.nom_mob(prey, user)
user.update_icons()
// Flavor handling
- if(belly_target.can_taste && prey.get_taste_message(0))
- to_chat(belly_target.owner, "[prey] tastes of [prey.get_taste_message(0)].")
+ if(belly.can_taste && prey.get_taste_message(FALSE))
+ to_chat(belly.owner, "[prey] tastes of [prey.get_taste_message(FALSE)].")
// Inform Admins
if (pred == user)
@@ -444,10 +429,10 @@
// Magical pred-air breathing for inside preds
// overrides a proc defined on atom called by breathe.dm
//
-/mob/living/return_air()
+/obj/belly/return_air()
return return_air_for_internal_lifeform()
-/mob/living/return_air_for_internal_lifeform()
+/obj/belly/return_air_for_internal_lifeform()
//Free air until someone wants to code processing it for reals from predbreaths
var/datum/gas_mixture/belly_air/air = new(1000)
return air
@@ -464,108 +449,54 @@
"oxygen" = 21,
"nitrogen" = 79)
+// Procs for micros stuffed into boots and the like to escape from them
/mob/living/proc/escape_clothes(obj/item/clothing/C)
- ASSERT(src.loc == C)
+ ASSERT(loc == C)
if(ishuman(C.loc)) //In a /mob/living/carbon/human
var/mob/living/carbon/human/H = C.loc
if(H.shoes == C) //Being worn
- src << " You start to climb around the larger creature's feet and ankles!"
- H << "Something is trying to climb out of your [C]!"
+ to_chat(src," You start to climb around the larger creature's feet and ankles!")
+ to_chat(H,"Something is trying to climb out of your [C]!")
var/original_loc = H.loc
for(var/escape_time = 100,escape_time > 0,escape_time--)
if(H.loc != original_loc)
- src << "You're pinned back underfoot!"
- H << "You pin the escapee back underfoot!"
+ to_chat(src,"You're pinned back underfoot!")
+ to_chat(H,"You pin the escapee back underfoot!")
return
if(src.loc != C)
return
sleep(1)
- src << "You manage to escape \the [C]!"
- H << "Somone has climbed out of your [C]!"
- src.loc = H.loc
- var/datum/belly/B = check_belly(H)
- if(B)
- B.internal_contents |= src
- return
+ to_chat(src,"You manage to escape \the [C]!")
+ to_chat(H,"Somone has climbed out of your [C]!")
+ forceMove(H.loc)
+
else //Being held by a human
- src << "You start to climb out of \the [C]!"
- H << "Something is trying to climb out of your [C]!"
+ to_chat(src,"You start to climb out of \the [C]!")
+ to_chat(H,"Something is trying to climb out of your [C]!")
for(var/escape_time = 60,escape_time > 0,escape_time--)
if(H.shoes == C)
- src << "You're pinned underfoot!"
- H << "You pin the escapee underfoot!"
+ to_chat(src,"You're pinned underfoot!")
+ to_chat(H,"You pin the escapee underfoot!")
return
if(src.loc != C)
return
sleep(1)
- src << "You manage to escape \the [C]!"
- H << "Somone has climbed out of your [C]!"
- src.loc = H.loc
- var/datum/belly/B = check_belly(H)
- if(B)
- B.internal_contents |= src
- return
+ to_chat(src,"You manage to escape \the [C]!")
+ to_chat(H,"Somone has climbed out of your [C]!")
+ forceMove(H.loc)
- src << "You start to climb out of \the [C]!"
+ to_chat(src,"You start to climb out of \the [C]!")
sleep(50)
- if(src.loc == C)
- src << "You climb out of \the [C]!"
- src.loc = C.loc
- var/datum/belly/B
- if(check_belly(C)) B = check_belly(C)
- if(check_belly(C.loc)) B = check_belly(C.loc)
- if(B)
- B.internal_contents |= src
- return
+ if(loc == C)
+ to_chat(src,"You climb out of \the [C]!")
+ forceMove(C.loc)
return
/mob/living/proc/feed_grabbed_to_self_falling_nom(var/mob/living/user, var/mob/living/prey)
var/belly = user.vore_selected
- return perform_the_falling_nom(user, prey, user, belly)
-
-/mob/living/proc/perform_the_falling_nom(var/mob/living/user, var/mob/living/prey, var/mob/living/pred, var/belly) //For dropnoms and slime feeding. This is so a nom can be performed instantly.
- //Sanity
- belly = pred.vore_selected
- if(!user || !prey || !pred || !belly || !(belly in pred.vore_organs))
- log_debug("[user] attempted to feed [prey] to [pred], via [belly] but it went wrong.")
- return
-
- // The belly selected at the time of noms
- var/datum/belly/belly_target = pred.vore_organs[belly]
- var/success_msg = "ERROR: Vore message couldn't be created. Notify a dev. (sc)"
-
- //Final distance check. Time has passed, menus have come and gone. Can't use do_after adjacent because doesn't behave for held micros
- var/user_to_pred = get_dist(get_turf(user),get_turf(pred))
- var/user_to_prey = get_dist(get_turf(user),get_turf(prey))
-
- if(user_to_pred > 1 || user_to_prey > 1)
- return 0
-
- // Prepare messages
- if(user == pred) //Feeding someone to yourself
- success_msg = text("[] manages to [] [] into their []!",pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
- else //Feeding someone to another person. This shouldn't happen.
- success_msg = text("[] manages to make [] [] [] into their []!",user,pred,lowertext(belly_target.vore_verb),prey,lowertext(belly_target.name))
-
- user.visible_message(success_msg)
- if(belly_target.vore_sound)
- playsound(user, belly_target.vore_sound, 100, 1)
-
- // Actually shove prey into the belly.
- belly_target.nom_mob(prey, user)
- user.update_icons()
-
- // Flavor handling
- if(belly_target.can_taste && prey.get_taste_message(0))
- to_chat(belly_target.owner, "[prey] tastes of [prey.get_taste_message(0)].")
-
- // Inform Admins
- if (pred == user)
- msg_admin_attack("[key_name(pred)] ate [key_name(prey)] via dropnom/slime feeding!. ([pred ? "JMP" : "null"])")
- else
- msg_admin_attack("[key_name(user)] forced [key_name(pred)] to eat [key_name(prey)] via dropnoms/slime feeding!! ([pred ? "JMP" : "null"])")
+ return perform_the_nom(user, prey, user, belly, delay = 1) //1/10th of a second is probably fine.
/mob/living/proc/glow_toggle()
set name = "Glow (Toggle)"
@@ -594,18 +525,20 @@
set category = "Abilities"
set desc = "Consume held garbage."
+ if(!vore_selected)
+ to_chat(src,"You either don't have a belly selected, or don't have a belly!")
+ return
+
var/obj/item/I = get_active_hand()
if(!I)
to_chat(src, "You are not holding anything.")
return
+
if(is_type_in_list(I,edible_trash))
drop_item()
- var/belly = vore_selected
- var/datum/belly/selected = vore_organs[belly]
- playsound(src.loc, selected.vore_sound, 20, 1)
- I.forceMove(src)
- selected.internal_contents |= I
+ I.forceMove(vore_selected)
updateVRPanel()
+
if(istype(I,/obj/item/device/flashlight/flare) || istype(I,/obj/item/weapon/flame/match) || istype(I,/obj/item/weapon/storage/box/matches))
to_chat(src, "You can taste the flavor of spicy cardboard.")
else if(istype(I,/obj/item/device/flashlight/glowstick))
diff --git a/code/modules/vore/eating/simple_animal_vr.dm b/code/modules/vore/eating/simple_animal_vr.dm
index 8ffc08ad37..e8fd6390ed 100644
--- a/code/modules/vore/eating/simple_animal_vr.dm
+++ b/code/modules/vore/eating/simple_animal_vr.dm
@@ -34,20 +34,19 @@
var/mob/living/carbon/human/user = usr
if(!istype(user) || user.stat) return
- var/datum/belly/B = vore_organs[vore_selected]
if(retaliate || (hostile && faction != user.faction))
user << "This predator isn't friendly, and doesn't give a shit about your opinions of it digesting you."
return
- if(B.digest_mode == "Hold")
+ if(vore_selected.digest_mode == DM_HOLD)
var/confirm = alert(user, "Enabling digestion on [name] will cause it to digest all stomach contents. Using this to break OOC prefs is against the rules. Digestion will reset after 20 minutes.", "Enabling [name]'s Digestion", "Enable", "Cancel")
if(confirm == "Enable")
- B.digest_mode = "Digest"
+ vore_selected.digest_mode = DM_DIGEST
spawn(12000) //12000=20 minutes
- if(src) B.digest_mode = vore_default_mode
+ if(src) vore_selected.digest_mode = vore_default_mode
else
var/confirm = alert(user, "This mob is currently set to process all stomach contents. Do you want to disable this?", "Disabling [name]'s Digestion", "Disable", "Cancel")
if(confirm == "Disable")
- B.digest_mode = "Hold"
+ vore_selected.digest_mode = DM_HOLD
/mob/living/simple_animal/attackby(var/obj/item/O, var/mob/user)
if (istype(O, /obj/item/weapon/newspaper) && !(ckey || (hostile && faction != user.faction)) && isturf(user.loc))
@@ -65,9 +64,7 @@
LoseTarget() // only make one attempt at an attack rather than going into full rage mode
else
user.visible_message("\the [user] swats \the [src] with \the [O]!!")
- for(var/I in vore_organs)
- var/datum/belly/B = vore_organs[I]
- B.release_all_contents(include_absorbed = TRUE) // Until we can get a mob version of unsorbitol or whatever, release absorbed too
+ release_vore_contents()
for(var/mob/living/L in living_mobs(0)) //add everyone on the tile to the do-not-eat list for a while
if(!(L in prey_excludes)) // Unless they're already on it, just to avoid fuckery.
prey_excludes += L
diff --git a/code/modules/vore/eating/transforming_vr.dm b/code/modules/vore/eating/transforming_vr.dm
index b6016b1127..b978bf8963 100644
--- a/code/modules/vore/eating/transforming_vr.dm
+++ b/code/modules/vore/eating/transforming_vr.dm
@@ -1,10 +1,10 @@
-/datum/belly/proc/check_eyes(var/mob/living/carbon/human/M)
+/obj/belly/proc/check_eyes(var/mob/living/carbon/human/M)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return 0
return (M.r_eyes != O.r_eyes || M.g_eyes != O.g_eyes || M.b_eyes != O.b_eyes)
-/datum/belly/proc/change_eyes(var/mob/living/carbon/human/M, message=0)
+/obj/belly/proc/change_eyes(var/mob/living/carbon/human/M, message=0)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return
@@ -18,7 +18,7 @@
to_chat(M, "You feel lightheaded and drowsy...")
to_chat(O, "You feel warm as you make subtle changes to your captive's body.")
-/datum/belly/proc/check_hair(var/mob/living/carbon/human/M)
+/obj/belly/proc/check_hair(var/mob/living/carbon/human/M)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return 0
@@ -31,7 +31,7 @@
return 1
return 0
-/datum/belly/proc/change_hair(var/mob/living/carbon/human/M, message=0)
+/obj/belly/proc/change_hair(var/mob/living/carbon/human/M, message=0)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return
@@ -49,14 +49,14 @@
to_chat(M, "Your body tingles all over...")
to_chat(O, "You tingle as you make noticeable changes to your captive's body.")
-/datum/belly/proc/check_skin(var/mob/living/carbon/human/M)
+/obj/belly/proc/check_skin(var/mob/living/carbon/human/M)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return 0
return (M.r_skin != O.r_skin || M.g_skin != O.g_skin || M.b_skin != O.b_skin)
-/datum/belly/proc/change_skin(var/mob/living/carbon/human/M, message=0)
+/obj/belly/proc/change_skin(var/mob/living/carbon/human/M, message=0)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return
@@ -71,7 +71,7 @@
to_chat(M, "Your body tingles all over...")
to_chat(O, "You tingle as you make noticeable changes to your captive's body.")
-/datum/belly/proc/check_gender(var/mob/living/carbon/human/M, target_gender)
+/obj/belly/proc/check_gender(var/mob/living/carbon/human/M, target_gender)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return 0
@@ -81,7 +81,7 @@
return (M.gender != target_gender || M.identifying_gender != target_gender)
-/datum/belly/proc/change_gender(var/mob/living/carbon/human/M, target_gender, message=0)
+/obj/belly/proc/change_gender(var/mob/living/carbon/human/M, target_gender, message=0)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return
@@ -100,7 +100,7 @@
to_chat(M, "Your body feels very strange...")
to_chat(O, "You feel strange as you alter your captive's gender.")
-/datum/belly/proc/check_tail(var/mob/living/carbon/human/M)
+/obj/belly/proc/check_tail(var/mob/living/carbon/human/M)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return 0
@@ -111,7 +111,7 @@
return 1
return 0
-/datum/belly/proc/change_tail(var/mob/living/carbon/human/M, message=0)
+/obj/belly/proc/change_tail(var/mob/living/carbon/human/M, message=0)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return
@@ -125,14 +125,14 @@
to_chat(M, "Your body tingles all over...")
to_chat(O, "You tingle as you make noticeable changes to your captive's body.")
-/datum/belly/proc/check_tail_nocolor(var/mob/living/carbon/human/M)
+/obj/belly/proc/check_tail_nocolor(var/mob/living/carbon/human/M)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return 0
return (M.tail_style != O.tail_style)
-/datum/belly/proc/change_tail_nocolor(var/mob/living/carbon/human/M, message=0)
+/obj/belly/proc/change_tail_nocolor(var/mob/living/carbon/human/M, message=0)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return
@@ -143,7 +143,7 @@
to_chat(M, "Your body tingles all over...")
to_chat(O, "You tingle as you make noticeable changes to your captive's body.")
-/datum/belly/proc/check_wing(var/mob/living/carbon/human/M)
+/obj/belly/proc/check_wing(var/mob/living/carbon/human/M)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return 0
@@ -154,7 +154,7 @@
return 1
return 0
-/datum/belly/proc/change_wing(var/mob/living/carbon/human/M, message=0)
+/obj/belly/proc/change_wing(var/mob/living/carbon/human/M, message=0)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return
@@ -168,14 +168,14 @@
to_chat(M, "Your body tingles all over...")
to_chat(O, "You tingle as you make noticeable changes to your captive's body.")
-/datum/belly/proc/check_wing_nocolor(var/mob/living/carbon/human/M)
+/obj/belly/proc/check_wing_nocolor(var/mob/living/carbon/human/M)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return 0
return (M.wing_style != O.wing_style)
-/datum/belly/proc/change_wing_nocolor(var/mob/living/carbon/human/M, message=0)
+/obj/belly/proc/change_wing_nocolor(var/mob/living/carbon/human/M, message=0)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return
@@ -186,14 +186,14 @@
to_chat(M, "Your body tingles all over...")
to_chat(O, "You tingle as you make noticeable changes to your captive's body.")
-/datum/belly/proc/check_ears(var/mob/living/carbon/human/M)
+/obj/belly/proc/check_ears(var/mob/living/carbon/human/M)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return 0
return (M.ear_style != O.ear_style)
-/datum/belly/proc/change_ears(var/mob/living/carbon/human/M, message=0)
+/obj/belly/proc/change_ears(var/mob/living/carbon/human/M, message=0)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return
@@ -201,7 +201,7 @@
M.ear_style = O.ear_style
M.update_hair()
-/datum/belly/proc/check_species(var/mob/living/carbon/human/M)
+/obj/belly/proc/check_species(var/mob/living/carbon/human/M)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return 0
@@ -210,7 +210,7 @@
return 1
return 0
-/datum/belly/proc/change_species(var/mob/living/carbon/human/M, message=0)
+/obj/belly/proc/change_species(var/mob/living/carbon/human/M, message=0)
var/mob/living/carbon/human/O = owner
if(!istype(M) || !istype(O))
return
@@ -247,7 +247,7 @@
M.verbs += /mob/living/proc/set_size
M.shapeshifter_select_shape()
-/datum/belly/proc/put_in_egg(var/atom/movable/M, message=0)
+/obj/belly/proc/put_in_egg(var/atom/movable/M, message=0)
var/mob/living/carbon/human/O = owner
var/egg_path = /obj/structure/closet/secure_closet/egg
var/egg_name = "odd egg"
@@ -256,11 +256,9 @@
egg_path = tf_egg_types[O.egg_type]
egg_name = "[O.egg_type] egg"
- var/obj/structure/closet/secure_closet/egg/egg = new egg_path(owner)
+ var/obj/structure/closet/secure_closet/egg/egg = new egg_path(src)
M.forceMove(egg)
egg.name = egg_name
- internal_contents -= M
- internal_contents |= egg
if(message)
to_chat(M, "You lose sensation of your body, feeling only the warmth around you as you're encased in an egg.")
to_chat(O, "Your body shifts as you encase [M] in an egg.")
\ No newline at end of file
diff --git a/code/modules/vore/eating/vore_vr.dm b/code/modules/vore/eating/vore_vr.dm
index 4988faa81e..dcef2a4577 100644
--- a/code/modules/vore/eating/vore_vr.dm
+++ b/code/modules/vore/eating/vore_vr.dm
@@ -45,8 +45,6 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
var/allowmobvore = 1
var/list/belly_prefs = list()
var/vore_taste
- var/conceal_nif
- var/nif_examine
var/can_be_drop_prey
var/can_be_drop_pred
@@ -74,16 +72,10 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
//
// Belly searching for simplifying other procs
+// Mostly redundant now with belly-objects and isbelly(loc)
//
/proc/check_belly(atom/movable/A)
- if(istype(A.loc,/mob/living))
- var/mob/living/M = A.loc
- for(var/I in M.vore_organs)
- var/datum/belly/B = M.vore_organs[I]
- if(A in B.internal_contents)
- return(B)
-
- return 0
+ return isbelly(A.loc)
//
// Save/Load Vore Preferences
@@ -109,8 +101,6 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
S["allowmobvore"] >> allowmobvore
S["belly_prefs"] >> belly_prefs
S["vore_taste"] >> vore_taste
- S["conceal_nif"] >> conceal_nif
- S["nif_examine"] >> nif_examine
S["can_be_drop_prey"] >> can_be_drop_prey
S["can_be_drop_pred"] >> can_be_drop_pred
@@ -134,8 +124,6 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
S["allowmobvore"] << allowmobvore
S["belly_prefs"] << belly_prefs
S["vore_taste"] << vore_taste
- S["conceal_nif"] << conceal_nif
- S["nif_examine"] << nif_examine
S["can_be_drop_prey"] << can_be_drop_prey
S["can_be_drop_pred"] << can_be_drop_pred
diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm
index 7f4d9ae26c..f0f564f87f 100644
--- a/code/modules/vore/eating/vorepanel_vr.dm
+++ b/code/modules/vore/eating/vorepanel_vr.dm
@@ -14,7 +14,7 @@
var/datum/vore_look/picker_holder = new()
picker_holder.loop = picker_holder
- picker_holder.selected = vore_organs[vore_selected]
+ picker_holder.selected = vore_selected
var/dat = picker_holder.gen_ui(src)
@@ -27,7 +27,7 @@
if(src.openpanel == 1)
var/datum/vore_look/picker_holder = new()
picker_holder.loop = picker_holder
- picker_holder.selected = vore_organs[vore_selected]
+ picker_holder.selected = vore_selected
var/dat = picker_holder.gen_ui(src)
@@ -39,7 +39,7 @@
// Callback Handler for the Inside form
//
/datum/vore_look
- var/datum/belly/selected
+ var/obj/belly/selected
var/show_interacts = 0
var/datum/browser/popup
var/loop = null; // Magic self-reference to stop the handler from being GC'd before user takes action.
@@ -56,24 +56,22 @@
/datum/vore_look/proc/gen_ui(var/mob/living/user)
var/dat
-
- if (is_vore_predator(user.loc))
- var/mob/living/eater = user.loc
- var/datum/belly/inside_belly
-
- //This big block here figures out where the prey is
- inside_belly = check_belly(user)
+
+ var/atom/userloc = user.loc
+ if (isbelly(userloc))
+ var/obj/belly/inside_belly = userloc
+ var/mob/living/eater = inside_belly.owner
//Don't display this part if we couldn't find the belly since could be held in hand.
if(inside_belly)
dat += "You are currently [user.absorbed ? "absorbed into " : "inside "] [eater]'s [inside_belly]!
"
- if(inside_belly.inside_flavor)
- dat += "[inside_belly.inside_flavor]
"
+ if(inside_belly.desc)
+ dat += "[inside_belly.desc]
"
- if (inside_belly.internal_contents.len > 1)
+ if (inside_belly.contents.len > 1)
dat += "You can see the following around you:
"
- for (var/atom/movable/O in inside_belly.internal_contents)
+ for (var/atom/movable/O in inside_belly)
if(istype(O,/mob/living))
var/mob/living/M = O
//That's just you
@@ -99,8 +97,8 @@
dat += "
"
dat += ""
- for(var/K in user.vore_organs) //Fuggin can't iterate over values
- var/datum/belly/B = user.vore_organs[K]
+ for(var/belly in user.vore_organs)
+ var/obj/belly/B = belly
if(B == selected)
dat += "- [B.name]"
else
@@ -153,7 +151,7 @@
if(DM_EGG)
spanstyle = "color:purple;"
- dat += " ([B.internal_contents.len])
"
+ dat += " ([B.contents.len])"
if(user.vore_organs.len < BELLIES_MAX)
dat += "- New+
"
@@ -164,9 +162,9 @@
if(!selected)
dat += "No belly selected. Click one to select it."
else
- if(selected.internal_contents.len > 0)
+ if(selected.contents.len)
dat += "Contents: "
- for(var/O in selected.internal_contents)
+ for(var/O in selected)
//Mobs can be absorbed, so treat them separately from everything else
if(istype(O,/mob/living))
@@ -184,7 +182,7 @@
dat += ""
//If there's more than one thing, add an [All] button
- if(selected.internal_contents.len > 1)
+ if(selected.contents.len > 1)
dat += "\[All\]"
dat += "
"
@@ -203,7 +201,7 @@
//Inside flavortext
dat += "
Flavor Text:"
- dat += " '[selected.inside_flavor]'"
+ dat += " '[selected.desc]'"
//Belly sound
dat += "
Set Vore Sound"
@@ -317,8 +315,8 @@
if(href_list["outsidepick"])
var/atom/movable/tgt = locate(href_list["outsidepick"])
- var/datum/belly/OB = locate(href_list["outsidebelly"])
- if(!(tgt in OB.internal_contents)) //Aren't here anymore, need to update menu.
+ var/obj/belly/OB = locate(href_list["outsidebelly"])
+ if(!(tgt in OB)) //Aren't here anymore, need to update menu.
return 1
var/intent = "Examine"
@@ -331,49 +329,47 @@
if("Help Out") //Help the inside-mob out
if(user.stat || user.absorbed || M.absorbed)
- user << "You can't do that in your state!"
+ to_chat(user,"You can't do that in your state!")
return 1
- user << "You begin to push [M] to freedom!"
- M << "[usr] begins to push you to freedom!"
- M.loc << "Someone is trying to escape from inside you!"
+ to_chat(user,"You begin to push [M] to freedom!")
+ to_chat(M,"[usr] begins to push you to freedom!")
+ to_chat(M.loc,"Someone is trying to escape from inside you!")
sleep(50)
if(prob(33))
OB.release_specific_contents(M)
- usr << "You manage to help [M] to safety!"
- M << "[user] pushes you free!"
- M.loc << "[M] forces free of the confines of your body!"
+ to_chat(usr,"You manage to help [M] to safety!")
+ to_chat(M,"[user] pushes you free!")
+ to_chat(OB.owner,"[M] forces free of the confines of your body!")
else
- user << "[M] slips back down inside despite your efforts."
- M << " Even with [user]'s help, you slip back inside again."
- M.loc << "Your body efficiently shoves [M] back where they belong."
+ to_chat(user,"[M] slips back down inside despite your efforts.")
+ to_chat(M," Even with [user]'s help, you slip back inside again.")
+ to_chat(OB.owner,"Your body efficiently shoves [M] back where they belong.")
if("Devour") //Eat the inside mob
if(user.absorbed || user.stat)
- user << "You can't do that in your state!"
+ to_chat(user,"You can't do that in your state!")
return 1
if(!user.vore_selected)
- user << "Pick a belly on yourself first!"
+ to_chat(user,"Pick a belly on yourself first!")
return 1
- var/datum/belly/TB = user.vore_organs[user.vore_selected]
- user << "You begin to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!"
- M << "[user] begins to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!"
- M.loc << "Someone inside you is eating someone else!"
+ var/obj/belly/TB = user.vore_selected
+ to_chat(user,"You begin to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!")
+ to_chat(M,"[user] begins to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!")
+ to_chat(OB.owner,"Someone inside you is eating someone else!")
- sleep(TB.nonhuman_prey_swallow_time)
- if((user in OB.internal_contents) && (M in OB.internal_contents))
- user << "You manage to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!"
- M << "[user] manages to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!"
- M.loc << "Someone inside you has eaten someone else!"
- M.loc = user
+ sleep(TB.nonhuman_prey_swallow_time) //Can't do after, in a stomach, weird things abound.
+ if((user in OB) && (M in OB)) //Make sure they're still here.
+ to_chat(user,"You manage to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!")
+ to_chat(M,"[user] manages to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!")
+ to_chat(OB.owner,"Someone inside you has eaten someone else!")
TB.nom_mob(M)
- OB.internal_contents -= M
else if(istype(tgt,/obj/item))
var/obj/item/T = tgt
- if(!(tgt in OB.internal_contents))
+ if(!(tgt in OB))
//Doesn't exist anymore, update.
return 1
intent = alert("What do you want to do to that?","Query","Examine","Use Hand")
@@ -383,7 +379,7 @@
if("Use Hand")
if(user.stat)
- user << "You can't do that in your state!"
+ to_chat(user,"You can't do that in your state!")
return 1
user.ClickOn(T)
@@ -401,32 +397,26 @@
if("Eject all")
if(user.stat)
- user << "You can't do that in your state!"
+ to_chat(user,"You can't do that in your state!")
return 0
selected.release_all_contents()
- playsound(user, 'sound/effects/splat.ogg', 50, 1)
if("Move all")
if(user.stat)
- user << "You can't do that in your state!"
+ to_chat(user,"You can't do that in your state!")
return 0
- var/choice = input("Move all where?","Select Belly") in user.vore_organs + "Cancel - Don't Move"
-
- if(choice == "Cancel - Don't Move")
+ var/obj/belly/choice = input("Move all where?","Select Belly") as null|anything in user.vore_organs
+ if(!choice)
return 0
- else
- var/datum/belly/B = user.vore_organs[choice]
- for(var/atom/movable/tgt in selected.internal_contents)
- tgt << "You're squished from [user]'s [selected] to their [B]!"
- selected.transfer_contents(tgt, B, 1)
-
- for(var/mob/hearer in range(1,user))
- hearer << sound('sound/vore/squish2.ogg',volume=80)
+
+ for(var/atom/movable/tgt in selected)
+ to_chat(tgt,"You're squished from [user]'s [lowertext(selected)] to their [lowertext(choice.name)]!")
+ selected.transfer_contents(tgt, choice, 1)
var/atom/movable/tgt = locate(href_list["insidepick"])
- if(!(tgt in selected.internal_contents)) //Old menu, needs updating because they aren't really there.
+ if(!(tgt in selected)) //Old menu, needs updating because they aren't really there.
return 1 //Forces update
intent = "Examine"
intent = alert("Examine, Eject, Move? Examine if you want to leave this box.","Query","Examine","Eject","Move")
@@ -436,28 +426,22 @@
if("Eject")
if(user.stat)
- user << "You can't do that in your state!"
+ to_chat(user,"You can't do that in your state!")
return 0
selected.release_specific_contents(tgt)
- playsound(user, 'sound/effects/splat.ogg', 50, 1)
if("Move")
if(user.stat)
- user << "You can't do that in your state!"
+ to_chat(user,"You can't do that in your state!")
return 0
- var/choice = input("Move [tgt] where?","Select Belly") in user.vore_organs + "Cancel - Don't Move"
-
- if(choice == "Cancel - Don't Move")
+ var/obj/belly/choice = input("Move [tgt] where?","Select Belly") as null|anything in user.vore_organs
+ if(!choice || !(tgt in selected))
return 0
- else
- var/datum/belly/B = user.vore_organs[choice]
- if (!(tgt in selected.internal_contents))
- return 0
- tgt << "You're squished from [user]'s [lowertext(selected.name)] to their [lowertext(B.name)]!"
- selected.transfer_contents(tgt, B)
+ to_chat(tgt,"You're squished from [user]'s [lowertext(selected.name)] to their [lowertext(choice.name)]!")
+ selected.transfer_contents(tgt, choice)
if(href_list["newbelly"])
if(user.vore_organs.len >= BELLIES_MAX)
@@ -465,21 +449,28 @@
var/new_name = html_encode(input(usr,"New belly's name:","New Belly") as text|null)
+ var/failure_msg
if(length(new_name) > BELLIES_NAME_MAX || length(new_name) < BELLIES_NAME_MIN)
- alert("Entered belly name length invalid (must be longer than [BELLIES_NAME_MIN], no more than than [BELLIES_NAME_MAX]).","Error")
- return 0
- if(new_name in user.vore_organs)
- alert("No duplicate belly names, please.","Error")
+ failure_msg = "Entered belly name length invalid (must be longer than [BELLIES_NAME_MIN], no more than than [BELLIES_NAME_MAX])."
+ // else if(whatever) //Next test here.
+ else
+ for(var/belly in user.vore_organs)
+ var/obj/belly/B = belly
+ if(lowertext(new_name) == lowertext(B.name))
+ failure_msg = "No duplicate belly names, please."
+ break
+
+ if(failure_msg) //Something went wrong.
+ alert(user,failure_msg,"Error!")
return 0
- var/datum/belly/NB = new(user)
+ var/obj/belly/NB = new(user)
NB.name = new_name
- user.vore_organs[new_name] = NB
selected = NB
if(href_list["bellypick"])
selected = locate(href_list["bellypick"])
- user.vore_selected = selected.name
+ user.vore_selected = selected
////
//Please keep these the same order they are on the panel UI for ease of coding
@@ -487,47 +478,43 @@
if(href_list["b_name"])
var/new_name = html_encode(input(usr,"Belly's new name:","New Name") as text|null)
+ var/failure_msg
if(length(new_name) > BELLIES_NAME_MAX || length(new_name) < BELLIES_NAME_MIN)
- alert("Entered belly name length invalid (must be longer than [BELLIES_NAME_MIN], no more than than [BELLIES_NAME_MAX]).","Error")
- return 0
- if(new_name in user.vore_organs)
- alert("No duplicate belly names, please.","Error")
+ failure_msg = "Entered belly name length invalid (must be longer than [BELLIES_NAME_MIN], no more than than [BELLIES_NAME_MAX])."
+ // else if(whatever) //Next test here.
+ else
+ for(var/belly in user.vore_organs)
+ var/obj/belly/B = belly
+ if(lowertext(new_name) == lowertext(B.name))
+ failure_msg = "No duplicate belly names, please."
+ break
+
+ if(failure_msg) //Something went wrong.
+ alert(user,failure_msg,"Error!")
return 0
- user.vore_organs[new_name] = selected
- user.vore_organs -= selected.name
selected.name = new_name
if(href_list["b_mode"])
var/list/menu_list = selected.digest_modes
if(istype(usr,/mob/living/carbon/human))
- //var/mob/living/carbon/human/H = usr
- //if(H.species.vore_numbing)
- //menu_list += DM_DIGEST_NUMB
menu_list += selected.transform_modes
- if(selected.digest_modes.len == 1) // Don't do anything
+ var/new_mode = input("Choose Mode (currently [selected.digest_mode])") as null|anything in menu_list
+ if(!new_mode)
return 0
- if(selected.digest_modes.len == 2) // Just toggle... there's probably a more elegant way to do this...
- var/index = selected.digest_modes.Find(selected.digest_mode)
- switch(index)
- if(1)
- selected.digest_mode = selected.digest_modes[2]
- if(2)
- selected.digest_mode = selected.digest_modes[1]
- else
- selected.digest_mode = input("Choose Mode (currently [selected.digest_mode])") in menu_list
- selected.items_preserved.Cut() //Re-evaltuate all items in belly on belly-mode change
+ selected.digest_mode = new_mode
+ selected.items_preserved.Cut() //Re-evaltuate all items in belly on belly-mode change
if(href_list["b_desc"])
- var/new_desc = html_encode(input(usr,"Belly Description (1024 char limit):","New Description",selected.inside_flavor) as message|null)
+ var/new_desc = html_encode(input(usr,"Belly Description ([BELLIES_DESC_MAX] char limit):","New Description",selected.desc) as message|null)
if(new_desc)
new_desc = readd_quotes(new_desc)
if(length(new_desc) > BELLIES_DESC_MAX)
alert("Entered belly desc too long. [BELLIES_DESC_MAX] character limit.","Error")
return 0
- selected.inside_flavor = new_desc
+ selected.desc = new_desc
else //Returned null
return 0
@@ -612,31 +599,32 @@
return
if(new_bulge == 0) //Disable.
selected.bulge_size = 0
- user << "Your stomach will not be seen on examine."
+ to_chat(user,"Your stomach will not be seen on examine.")
else if (!IsInRange(new_bulge,25,200))
selected.bulge_size = 0.25 //Set it to the default.
- user << "Invalid size."
+ to_chat(user,"Invalid size.")
else if(new_bulge)
selected.bulge_size = (new_bulge/100)
+
if(href_list["b_grow_shrink"])
- var/new_grow = input(user, "Choose the size that prey will be grown/shrunk to, ranging from 25% to 200%", "Set Growth Shrink Size.") as num|null
+ var/new_grow = input(user, "Choose the size that prey will be grown/shrunk to, ranging from 25% to 200%", "Set Growth Shrink Size.", selected.shrink_grow_size) as num|null
if (new_grow == null)
return
if (!IsInRange(new_grow,25,200))
selected.shrink_grow_size = 1 //Set it to the default
- user << "Invalid size."
+ to_chat(user,"Invalid size.")
else if(new_grow)
- selected.shrink_grow_size = (new_grow/100)
+ selected.shrink_grow_size = (new_grow*0.01)
if(href_list["b_burn_dmg"])
- var/new_damage = input(user, "Choose the amount of burn damage prey will take per tick. Ranges from 0 to 6.", "Set Belly Burn Damage.") as num|null
+ var/new_damage = input(user, "Choose the amount of burn damage prey will take per tick. Ranges from 0 to 6.", "Set Belly Burn Damage.", selected.digest_burn) as num|null
if(new_damage == null)
return
var/new_new_damage = Clamp(new_damage, 0, 6)
selected.digest_burn = new_new_damage
if(href_list["b_brute_dmg"])
- var/new_damage = input(user, "Choose the amount of brute damage prey will take per tick. Ranges from 0 to 6", "Set Belly Brute Damage.") as num|null
+ var/new_damage = input(user, "Choose the amount of brute damage prey will take per tick. Ranges from 0 to 6", "Set Belly Brute Damage.", selected.digest_brute) as num|null
if(new_damage == null)
return
var/new_new_damage = Clamp(new_damage, 0, 6)
@@ -645,10 +633,10 @@
if(href_list["b_escapable"])
if(selected.escapable == 0) //Possibly escapable and special interactions.
selected.escapable = 1
- usr << "Prey now have special interactions with your [selected.name] depending on your settings."
+ to_chat(usr,"Prey now have special interactions with your [lowertext(selected.name)] depending on your settings.")
else if(selected.escapable == 1) //Never escapable.
selected.escapable = 0
- usr << "Prey will not be able to have special interactions with your [selected.name]."
+ to_chat(usr,"Prey will not be able to have special interactions with your [lowertext(selected.name)].")
show_interacts = 0 //Force the hiding of the panel
else
alert("Something went wrong. Your stomach will now not have special interactions. Press the button enable them again and tell a dev.","Error") //If they somehow have a varable that's not 0 or 1
@@ -671,14 +659,14 @@
selected.transferchance = sanitize_integer(transfer_chance_input, 0, 100, initial(selected.transferchance))
if(href_list["b_transferlocation"])
- var/choice = input("Where do you want your [selected.name] to lead if prey resists?","Select Belly") as null|anything in (user.vore_organs + "None - Remove" - selected.name)
+ var/obj/belly/choice = input("Where do you want your [lowertext(selected.name)] to lead if prey resists?","Select Belly") as null|anything in (user.vore_organs + "None - Remove" - selected)
if(!choice) //They cancelled, no changes
return 0
else if(choice == "None - Remove")
selected.transferlocation = null
else
- selected.transferlocation = user.vore_organs[choice]
+ selected.transferlocation = choice.name
if(href_list["b_absorbchance"])
var/absorb_chance_input = input(user, "Set belly absorb mode chance on resist (as %)", "Prey Absorb Chance") as num|null
@@ -691,51 +679,51 @@
selected.digestchance = sanitize_integer(digest_chance_input, 0, 100, initial(selected.digestchance))
if(href_list["b_del"])
- var/dest_for = 0 //Check to see if it's the destination of another vore organ.
- for(var/I in user.vore_organs)
- var/datum/belly/B = user.vore_organs[I]
+ var/alert = alert("Are you sure you want to delete your [lowertext(selected.name)]?","Confirmation","Delete","Cancel")
+ if(!alert == "Delete")
+ return 0
+
+ var/failure_msg = ""
+
+ var/dest_for //Check to see if it's the destination of another vore organ.
+ for(var/belly in user.vore_organs)
+ var/obj/belly/B = belly
if(B.transferlocation == selected)
dest_for = B.name
+ failure_msg += "This is the destiantion for at least '[dest_for]' belly transfers. Remove it as the destination from any bellies before deleting it. "
break
- if(dest_for)
- alert("This is the destiantion for at least '[dest_for]' belly transfers. Remove it as the destination from any bellies before deleting it.","Error")
- return 1
- else if(selected.internal_contents.len)
- alert("Can't delete bellies with contents!","Error")
- return 1
- else if(selected.immutable)
- alert("This belly is marked as undeletable.","Error")
- return 1
- else if(user.vore_organs.len == 1)
- alert("You must have at least one belly.","Error")
- return 1
- else
- var/alert = alert("Are you sure you want to delete [selected]?","Confirmation","Delete","Cancel")
- if(alert == "Delete" && !selected.internal_contents.len)
- user.vore_organs -= selected.name
- user.vore_organs.Remove(selected)
- selected = user.vore_organs[1]
- user.vore_selected = user.vore_organs[1]
- usr << "Note: If you had this organ selected as a transfer location, please remove the transfer location by selecting Cancel - None - Remove on this stomach." //If anyone finds a fix to this bug, please tell me. I, for the life of me, can't find any way to fix it.
+ if(selected.contents.len)
+ failure_msg += "You cannot delete bellies with contents! " //These end with spaces, to be nice looking. Make sure you do the same.
+ if(selected.immutable)
+ failure_msg += "This belly is marked as undeletable. "
+ if(user.vore_organs.len == 1)
+ failure_msg += "You must have at least one belly. "
+
+ if(failure_msg)
+ alert(user,failure_msg,"Error!")
+ return 0
+
+ qdel(selected)
+ selected = user.vore_organs[1]
+ user.vore_selected = user.vore_organs[1]
if(href_list["saveprefs"])
if(!user.save_vore_prefs())
alert("ERROR: Virgo-specific preferences failed to save!","Error")
else
- user << "Virgo-specific preferences saved!"
+ to_chat(user,"Virgo-specific preferences saved!")
if(href_list["setflavor"])
var/new_flavor = html_encode(input(usr,"What your character tastes like (40ch limit). This text will be printed to the pred after 'X tastes of...' so just put something like 'strawberries and cream':","Character Flavor",user.vore_taste) as text|null)
-
- if(new_flavor)
- new_flavor = readd_quotes(new_flavor)
- if(length(new_flavor) > FLAVOR_MAX)
- alert("Entered flavor/taste text too long. [FLAVOR_MAX] character limit.","Error")
- return 0
- user.vore_taste = new_flavor
- else //Returned null
+ if(!new_flavor)
return 0
+
+ new_flavor = readd_quotes(new_flavor)
+ if(length(new_flavor) > FLAVOR_MAX)
+ alert("Entered flavor/taste text too long. [FLAVOR_MAX] character limit.","Error!")
+ return 0
+ user.vore_taste = new_flavor
if(href_list["toggle_dropnom_pred"])
var/choice = alert(user, "You are currently [user.can_be_drop_pred ? " able to eat prey that fall from above or that you fall onto" : "not able to eat prey that fall from above or that you fall onto."]", "", "Be Pred", "Cancel", "Don't be Pred")
@@ -743,9 +731,9 @@
if("Cancel")
return 0
if("Be Pred")
- user.can_be_drop_pred = 1
+ user.can_be_drop_pred = TRUE
if("Don't be Pred")
- user.can_be_drop_pred = 0
+ user.can_be_drop_pred = FALSE
if(href_list["toggle_dropnom_prey"])
var/choice = alert(user, "You are currently [user.can_be_drop_prey ? "able to be eaten." : "not able to be eaten."]", "", "Be Prey", "Cancel", "Don't Be Prey")
@@ -753,19 +741,19 @@
if("Cancel")
return 0
if("Be Prey")
- user.can_be_drop_prey = 1
+ user.can_be_drop_prey = TRUE
if("Don't Be Prey")
- user.can_be_drop_prey = 0
+ user.can_be_drop_prey = FALSE
if(href_list["toggledg"])
- var/choice = alert(user, "This button is for those who don't like being digested. It can make you undigestable. Don't abuse this button by toggling it back and forth to extend a scene or whatever, or you'll make the admins cry. Digesting you is currently: [user.digestable ? "Allowed" : "Prevented"]", "", "Allow Digestion", "Cancel", "Prevent Digestion")
+ var/choice = alert(user, "This button is for those who don't like being digested. It can make you undigestable. Messages admins when changed, so don't try to use it for mechanical benefit. Set it once and save it. Digesting you is currently: [user.digestable ? "Allowed" : "Prevented"]", "", "Allow Digestion", "Cancel", "Prevent Digestion")
switch(choice)
if("Cancel")
return 0
if("Allow Digestion")
- user.digestable = 1
+ user.digestable = TRUE
if("Prevent Digestion")
- user.digestable = 0
+ user.digestable = FALSE
message_admins("[key_name(user)] toggled their digestability to [user.digestable] ([user ? "JMP" : "null"])")
@@ -773,14 +761,14 @@
user.client.prefs_vr.digestable = user.digestable
if(href_list["togglemv"])
- var/choice = alert(user, "This button is for those who don't like being eaten by mobs. Don't abuse this button by toggling it back and forth in combat or whatever, or you'll make the admins cry. Mobs are currently: [user.allowmobvore ? "Allowed to eat" : "Prevented from eating"] you.", "", "Allow Mob Predation", "Cancel", "Prevent Mob Predation")
+ var/choice = alert(user, "This button is for those who don't like being eaten by mobs. Messages admins when changed, so don't try to use it for mechanical benefit. Set it once and save it. Mobs are currently: [user.allowmobvore ? "Allowed to eat" : "Prevented from eating"] you.", "", "Allow Mob Predation", "Cancel", "Prevent Mob Predation")
switch(choice)
if("Cancel")
return 0
if("Allow Mob Predation")
- user.allowmobvore = 1
+ user.allowmobvore = TRUE
if("Prevent Mob Predation")
- user.allowmobvore = 0
+ user.allowmobvore = FALSE
message_admins("[key_name(user)] toggled their mob vore preference to [user.allowmobvore] ([user ? "JMP" : "null"])")
@@ -793,9 +781,9 @@
if("Cancel")
return 0
if("Enable audible hunger")
- user.noisy = 1
+ user.noisy = TRUE
if("Disable audible hunger")
- user.noisy = 0
+ user.noisy = FALSE
//Refresh when interacted with, returning 1 makes vore_look.Topic update
return 1
diff --git a/code/modules/vore/fluffstuff/custom_boxes_vr.dm b/code/modules/vore/fluffstuff/custom_boxes_vr.dm
index 549c6d1239..bf9edaafd5 100644
--- a/code/modules/vore/fluffstuff/custom_boxes_vr.dm
+++ b/code/modules/vore/fluffstuff/custom_boxes_vr.dm
@@ -190,7 +190,7 @@
new /obj/item/ammo_casing/nsfw_batt/net(src)
new /obj/item/clothing/accessory/holster(src)
-/obj/item/weapon/storage/backpack/satchel/gen/fluff/aronai/digest_act(var/datum/belly/belly = null)
+/obj/item/weapon/storage/backpack/satchel/gen/fluff/aronai/digest_act(...)
return FALSE //I get eaten a lot, okay
//Aerowing:Sebastian Aji
diff --git a/code/modules/vore/fluffstuff/custom_clothes_vr.dm b/code/modules/vore/fluffstuff/custom_clothes_vr.dm
index eb111673d4..17f8cbf144 100644
--- a/code/modules/vore/fluffstuff/custom_clothes_vr.dm
+++ b/code/modules/vore/fluffstuff/custom_clothes_vr.dm
@@ -105,7 +105,7 @@
else
RemoveHood_roiz()
-/obj/item/clothing/suit/storage/hooded/wintercoat/roiz/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/clothing/suit/storage/hooded/wintercoat/roiz/digest_act(var/atom/movable/item_storage = null)
return FALSE
//ketrai:Ketrai
@@ -679,7 +679,7 @@
else
return 1
-/obj/item/clothing/under/fluff/screesuit/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/clothing/under/fluff/screesuit/digest_act(var/atom/movable/item_storage = null)
return FALSE
//HOS Hardsuit
@@ -769,7 +769,7 @@
action_button_name = "Toggle pom-pom"
-/obj/item/clothing/head/fluff/pompom/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null)
+/obj/item/clothing/head/fluff/pompom/digest_act(var/atom/movable/item_storage = null)
return FALSE
/obj/item/clothing/head/fluff/pompom/attack_self(mob/user)
diff --git a/code/modules/vore/fluffstuff/custom_items_vr.dm b/code/modules/vore/fluffstuff/custom_items_vr.dm
index 6df119ad0e..8a940c9186 100644
--- a/code/modules/vore/fluffstuff/custom_items_vr.dm
+++ b/code/modules/vore/fluffstuff/custom_items_vr.dm
@@ -1508,34 +1508,25 @@
to_chat(user,"\The [src] malfunctions and sends you to the wrong beacon!")
//Destination beacon vore checking
- var/datum/belly/target_belly
- var/atom/real_dest = get_turf(destination)
-
- //Destination beacon is held/eaten
- if(isliving(destination.loc) && (target != destination.loc)) //We should definitely get televored unless we're teleporting ourselves into ourselves
- var/mob/living/L = destination.loc
-
- //Is the beacon IN a belly?
- target_belly = check_belly(destination)
-
- //No? Well do they have vore organs at all?
- if(!target_belly && L.vore_organs.len)
-
- //If they do, use their picked one.
- if(L.vore_selected)
- target_belly = L.vore_organs[L.vore_selected]
- else
- //Else just use the first one.
- var/I = L.vore_organs[1] //We're just going to use 1
- target_belly = L.vore_organs[I]
+ var/atom/real_dest = dT
+ var/televored = FALSE //UR GONNA GET VORED
+ var/atom/real_loc = destination.loc
+ if(isbelly(real_loc))
+ real_dest = real_loc
+ televored = TRUE
+ if(isliving(real_loc))
+ var/mob/living/L = real_loc
+ if(L.vore_selected)
+ real_dest = L.vore_selected
+ televored = TRUE
+ else if(L.vore_organs.len)
+ real_dest = pick(L.vore_organs)
+ televored = TRUE
+
//Televore fluff stuff
- if(target_belly)
- real_dest = destination.loc
- target_belly.internal_contents |= target
- playsound(target_belly.owner, target_belly.vore_sound, 100, 1)
- to_chat(target,"\The [src] teleports you right into [target_belly.owner]'s [target_belly.name]!")
- to_chat(target_belly.owner,"Your [target_belly.name] suddenly has a new occupant!")
+ if(televored)
+ to_chat(target,"\The [src] teleports you right into \a [lowertext(real_dest.name)]!")
//Phase-out effect
phase_out(target,get_turf(target))
@@ -1555,20 +1546,18 @@
//Move them, and televore if necessary
G.affecting.forceMove(real_dest)
- if(target_belly)
- target_belly.internal_contents |= G.affecting
- to_chat(G.affecting,"\The [src] teleports you right into [target_belly.owner]'s [target_belly.name]!")
+ if(televored)
+ to_chat(target,"\The [src] teleports you right into \a [lowertext(real_dest.name)]!")
//Phase-in effect for grabbed person
phase_in(G.affecting,get_turf(G.affecting))
update_icon()
spawn(30 SECONDS)
- if(src) //If we still exist, anyway.
- ready = 1
- update_icon()
+ ready = 1
+ update_icon()
- logged_events["[world.time]"] = "[user] teleported [target] to [real_dest] [target_belly ? "(Belly: [target_belly.name])" : null]"
+ logged_events["[world.time]"] = "[user] teleported [target] to [real_dest] [televored ? "(Belly: [lowertext(real_loc.name)])" : null]"
/obj/item/device/perfect_tele/proc/phase_out(var/mob/M,var/turf/T)
@@ -1631,16 +1620,13 @@
var/mob/living/L = user
var/confirm = alert(user, "You COULD eat the beacon...", "Eat beacon?", "Eat it!", "No, thanks.")
if(confirm == "Eat it!")
- var/bellychoice = input("Which belly?","Select A Belly") in L.vore_organs|null
+ var/obj/belly/bellychoice = input("Which belly?","Select A Belly") as null|anything in L.vore_organs
if(bellychoice)
- var/datum/belly/B = L.vore_organs[bellychoice]
user.visible_message("[user] is trying to stuff \the [src] into [user.gender == MALE ? "his" : user.gender == FEMALE ? "her" : "their"] [bellychoice]!","You begin putting \the [src] into your [bellychoice]!")
if(do_after(user,5 SECONDS,src))
user.unEquip(src)
- forceMove(user)
- B.internal_contents |= src
+ forceMove(bellychoice)
user.visible_message("[user] eats a telebeacon!","You eat the the beacon!")
- playsound(user, B.vore_sound, 70, 1)
//InterroLouis: Ruda Lizden
/obj/item/clothing/accessory/badge/holo/detective/ruda
diff --git a/code/modules/vore/fluffstuff/guns/sickshot.dm b/code/modules/vore/fluffstuff/guns/sickshot.dm
index 8733e4aadf..f7d5a4b291 100644
--- a/code/modules/vore/fluffstuff/guns/sickshot.dm
+++ b/code/modules/vore/fluffstuff/guns/sickshot.dm
@@ -35,14 +35,16 @@
kill_count = 5 //Scary name, but just deletes the projectile after this range
/obj/item/projectile/sickshot/on_hit(var/atom/movable/target, var/blocked = 0)
- if(ishuman(target))
- var/mob/living/carbon/human/H = target
- H.vomit()
- H.Confuse(2)
+ if(isliving(target))
+ var/mob/living/L = target
if(prob(20))
- for(var/X in H.vore_organs)
- var/datum/belly/B = H.vore_organs[X]
- B.release_all_contents()
+ L.release_vore_contents()
+
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ H.vomit()
+ H.Confuse(2)
+
return 1
//R&D Design
diff --git a/code/stylesheet.dm b/code/stylesheet.dm
index 4f0a5fd0ae..fd861355d0 100644
--- a/code/stylesheet.dm
+++ b/code/stylesheet.dm
@@ -92,6 +92,7 @@ h1.alert, h2.alert {color: #000000;}
.tajaran {color: #803B56;}
.tajaran_signlang {color: #941C1C;}
.skrell {color: #00B0B3;}
+.skrellfar {color: #70FCFF;}
.soghun {color: #228B22;}
.solcom {color: #22228B;}
.changeling {color: #800080;}
@@ -103,7 +104,7 @@ h1.alert, h2.alert {color: #000000;}
.vox {color: #AA00AA;}
.rough {font-family: "Trebuchet MS", cursive, sans-serif;}
.say_quote {font-family: Georgia, Verdana, sans-serif;}
-
+.terminus {font-family: "Times New Roman", Times, serif, sans-serif}
.interface {color: #330033;}
BIG IMG.icon {width: 32px; height: 32px;}
diff --git a/code/unit_tests/vore_tests_vr.dm b/code/unit_tests/vore_tests_vr.dm
index e50c50b2fa..7d060b1ca4 100644
--- a/code/unit_tests/vore_tests_vr.dm
+++ b/code/unit_tests/vore_tests_vr.dm
@@ -21,21 +21,25 @@
// Unfortuantely we need to wait for the pred's belly to initialize. (Currently after a spawn())
if(!pred.vore_organs || !pred.vore_organs.len)
return 0
+
// Now that pred belly exists, we can eat the prey.
- if(prey.loc != pred)
- if(!pred.vore_selected)
- fail("[pred] has no vore_selected.")
- return 1
- var/datum/belly/TB = pred.vore_organs[pred.vore_selected]
- TB.nom_mob(prey)
- if(prey.loc != pred)
- fail("[TB].nom_mob([prey]) did not put prey inside [pred]")
+ if(!pred.vore_selected)
+ fail("[pred] has no vore_selected.")
+ return 1
+
+ // Attempt to eat the prey
+ if(prey.loc != pred.vore_selected)
+ pred.vore_selected.nom_mob(prey)
+
+ if(prey.loc != pred.vore_selected)
+ fail("[pred.vore_selected].nom_mob([prey]) did not put prey inside [pred]")
return 1
+
// Okay, we succeeded in eating them, now lets wait a bit
startLifeTick = pred.life_tick
startOxyloss = prey.getOxyLoss()
return 0
-
+
if(pred.life_tick < (startLifeTick + 10))
return 0 // Wait for them to breathe a few times
@@ -49,3 +53,123 @@
qdel(prey)
qdel(pred)
return 1
+////////////////////////////////////////////////////////////////
+/datum/unit_test/belly_spacesafe
+ name = "MOB: human mob protected from space in a belly"
+ var/startLifeTick
+ var/startOxyloss
+ var/endOxyloss
+ var/mob/living/carbon/human/pred
+ var/mob/living/carbon/human/prey
+ async = 1
+
+/datum/unit_test/belly_spacesafe/start_test()
+ pred = create_test_mob()
+ if(!istype(pred))
+ return 0
+ prey = create_test_mob(pred.loc)
+ if(!istype(prey))
+ return 0
+
+ return 1
+
+/datum/unit_test/belly_spacesafe/check_result()
+ // Unfortuantely we need to wait for the pred's belly to initialize. (Currently after a spawn())
+ if(!pred.vore_organs || !pred.vore_organs.len)
+ return 0
+
+ // Now that pred belly exists, we can eat the prey.
+ if(!pred.vore_selected)
+ fail("[pred] has no vore_selected.")
+ return 1
+
+ // Attempt to eat the prey
+ if(prey.loc != pred.vore_selected)
+ pred.vore_selected.nom_mob(prey)
+
+ if(prey.loc != pred.vore_selected)
+ fail("[pred.vore_selected].nom_mob([prey]) did not put prey inside [pred]")
+ return 1
+ else
+ var/turf/T = locate(/turf/space)
+ if(!T)
+ fail("could not find a space turf for testing")
+ return 1
+ else
+ pred.forceMove(T)
+
+ // Okay, we succeeded in eating them, now lets wait a bit
+ startLifeTick = pred.life_tick
+ startOxyloss = prey.getOxyLoss()
+ return 0
+
+ if(pred.life_tick < (startLifeTick + 10))
+ return 0 // Wait for them to breathe a few times
+
+ // Alright lets check it!
+ endOxyloss = prey.getOxyLoss()
+ if(startOxyloss < endOxyloss)
+ fail("Prey takes oxygen damage in space! (Before: [startOxyloss]; after: [endOxyloss])")
+ else
+ pass("Prey is not taking oxygen damage in space. (Before: [startOxyloss]; after: [endOxyloss])")
+
+ qdel(prey)
+ qdel(pred)
+ return 1
+////////////////////////////////////////////////////////////////
+/datum/unit_test/belly_damage
+ name = "MOB: human mob takes damage from digestion"
+ var/startLifeTick
+ var/startBruteBurn
+ var/endBruteBurn
+ var/mob/living/carbon/human/pred
+ var/mob/living/carbon/human/prey
+ async = 1
+
+/datum/unit_test/belly_damage/start_test()
+ pred = create_test_mob()
+ if(!istype(pred))
+ return 0
+ prey = create_test_mob(pred.loc)
+ if(!istype(prey))
+ return 0
+
+ return 1
+
+/datum/unit_test/belly_damage/check_result()
+ // Unfortuantely we need to wait for the pred's belly to initialize. (Currently after a spawn())
+ if(!pred.vore_organs || !pred.vore_organs.len)
+ return 0
+
+ // Now that pred belly exists, we can eat the prey.
+ if(!pred.vore_selected)
+ fail("[pred] has no vore_selected.")
+ return 1
+
+ // Attempt to eat the prey
+ if(prey.loc != pred.vore_selected)
+ pred.vore_selected.nom_mob(prey)
+
+ if(prey.loc != pred.vore_selected)
+ fail("[pred.vore_selected].nom_mob([prey]) did not put prey inside [pred]")
+ return 1
+
+ // Okay, we succeeded in eating them, now lets wait a bit
+ pred.vore_selected.digest_mode = DM_DIGEST
+ startLifeTick = pred.life_tick
+ startBruteBurn = prey.getBruteLoss() + prey.getFireLoss()
+ return 0
+
+ if(pred.life_tick < (startLifeTick + 10))
+ return 0 // Wait a few ticks for damage to happen
+
+ // Alright lets check it!
+ endBruteBurn = prey.getBruteLoss() + prey.getFireLoss()
+ if(startBruteBurn >= endBruteBurn)
+ fail("Prey doesn't take damage in digesting belly! (Before: [startBruteBurn]; after: [endBruteBurn])")
+ else
+ pass("Prey is taking damage in pred's belly. (Before: [startBruteBurn]; after: [endBruteBurn])")
+
+ qdel(prey)
+ qdel(pred)
+ return 1
diff --git a/code/world.dm b/code/world.dm
index 6ef82622ec..f60b2c85d9 100644
--- a/code/world.dm
+++ b/code/world.dm
@@ -111,6 +111,9 @@ var/global/datum/global_init/init = new ()
// Create frame types.
populate_frame_types()
+ // Create floor types.
+ populate_flooring_types()
+
// Create robolimbs for chargen.
populate_robolimb_list()
@@ -124,7 +127,7 @@ var/global/datum/global_init/init = new ()
processScheduler.setup()
Master.Initialize(10, FALSE)
- spawn(1)
+ spawn(1)
master_controller.setup()
#if UNIT_TEST
initialize_unit_tests()
diff --git a/html/changelog.html b/html/changelog.html
index 7f0da511fd..6212ec3092 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -53,6 +53,30 @@
-->
+
25 February 2018
+
Anewbe updated:
+
+ - Splinted bodyparts act broken 30% of the time.
+ - Splinted legs still slow you down like broken ones.
+
+
Leshana updated:
+
+ - Added a client preference setting for wether Hotkeys Mode should be enabled or disabled by default.
+ - CTRL+NUMPAD8 while playing a robot won't runtime anymore.
+ - Grounding rods act intuitively, only having an expanded lighting catch area when anchored.
+
+
Nerezza updated:
+
+ - Fixes not being able to install the different carpet colors. Finally.
+ - Removes certain unusable duplicate stacks of tiles from the code.
+
+
Schnayy updated:
+
+ - Added Gilthari Luxury Champagne. Drink responsibly.
+ - Added a singular AlliCo Baubles and Confectionaries vending machine in the locker rooms. Dispenses a variety of gifts.
+ - Removed hot drinks vendor from locker room.
+
+
22 February 2018
Anewbe updated:
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index 00e12a4c75..f9f5c59c9f 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -3942,3 +3942,21 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- rscadd: Added blue sifwood floor tiles.
- bugfix: Fixed blue carpet, now known as teal carpet
- rscadd: Added the ability to dig up tree stumps with a shovel.
+2018-02-25:
+ Anewbe:
+ - tweak: Splinted bodyparts act broken 30% of the time.
+ - tweak: Splinted legs still slow you down like broken ones.
+ Leshana:
+ - rscadd: Added a client preference setting for wether Hotkeys Mode should be enabled
+ or disabled by default.
+ - bugfix: CTRL+NUMPAD8 while playing a robot won't runtime anymore.
+ - tweak: Grounding rods act intuitively, only having an expanded lighting catch
+ area when anchored.
+ Nerezza:
+ - bugfix: Fixes not being able to install the different carpet colors. Finally.
+ - bugfix: Removes certain unusable duplicate stacks of tiles from the code.
+ Schnayy:
+ - rscadd: Added Gilthari Luxury Champagne. Drink responsibly.
+ - rscadd: Added a singular AlliCo Baubles and Confectionaries vending machine in
+ the locker rooms. Dispenses a variety of gifts.
+ - rscdel: Removed hot drinks vendor from locker room.
diff --git a/html/changelogs/Leshana - hotkeys-qol.yml b/html/changelogs/Leshana - hotkeys-qol.yml
deleted file mode 100644
index 336970930c..0000000000
--- a/html/changelogs/Leshana - hotkeys-qol.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: Leshana
-delete-after: True
-changes:
- - rscadd: "Added a client preference setting for wether Hotkeys Mode should be enabled or disabled by default."
- - bugfix: "CTRL+NUMPAD8 while playing a robot won't runtime anymore."
diff --git a/html/changelogs/Leshana - tesla-grounding.yml b/html/changelogs/Leshana - tesla-grounding.yml
deleted file mode 100644
index ee246f5f27..0000000000
--- a/html/changelogs/Leshana - tesla-grounding.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: Leshana
-delete-after: True
-changes:
- - tweak: "Grounding rods act intuitively, only having an expanded lighting catch area when anchored."
diff --git a/html/changelogs/Schnayy - AlliCo Hallmark Goods.yml b/html/changelogs/Nerezza - Tilematic.yml
similarity index 82%
rename from html/changelogs/Schnayy - AlliCo Hallmark Goods.yml
rename to html/changelogs/Nerezza - Tilematic.yml
index 911fbef263..058a3dfc1c 100644
--- a/html/changelogs/Schnayy - AlliCo Hallmark Goods.yml
+++ b/html/changelogs/Nerezza - Tilematic.yml
@@ -22,7 +22,7 @@
#################################
# Your name.
-author: Schnayy
+author: Nerezza
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
@@ -33,6 +33,4 @@ delete-after: True
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
changes:
- - rscadd: "Added Gilthari Luxury Champagne. Drink responsibly."
- - rscadd: "Added a singular AlliCo Baubles and Confectionaries vending machine in the locker rooms. Dispenses a variety of gifts."
- - rscdel: "Removed hot drinks vendor from locker room."
+ - rscadd: "Added /tg/-style floor tile swapping. Equip crowbar/screwdriver in offhand and click the floor tiles you want to directly swap with a stack of new floor tiles (like teal carpet)."
diff --git a/icons/goonstation/LICENSE.md b/icons/goonstation/LICENSE.md
new file mode 100644
index 0000000000..bb6102702e
--- /dev/null
+++ b/icons/goonstation/LICENSE.md
@@ -0,0 +1,2 @@
+All files located in this directory and any subdirectories are licensed under the
+Creative Commons 3.0 BY-NC-SA license (https://creativecommons.org/licenses/by-nc-sa/3.0)
\ No newline at end of file
diff --git a/icons/goonstation/objects/syringe.dmi b/icons/goonstation/objects/syringe.dmi
new file mode 100644
index 0000000000..a2681222f2
Binary files /dev/null and b/icons/goonstation/objects/syringe.dmi differ
diff --git a/icons/goonstation/objects/syringe_vr.dmi b/icons/goonstation/objects/syringe_vr.dmi
new file mode 100644
index 0000000000..7136e09eae
Binary files /dev/null and b/icons/goonstation/objects/syringe_vr.dmi differ
diff --git a/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi b/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi
index ce332e9bc4..d88df87ddb 100644
Binary files a/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi and b/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi differ
diff --git a/icons/mob/human_races/cyberlimbs/cybersolutions/cybersolutions_main.dmi b/icons/mob/human_races/cyberlimbs/cybersolutions/cybersolutions_main.dmi
index c30253905f..216938d0b3 100644
Binary files a/icons/mob/human_races/cyberlimbs/cybersolutions/cybersolutions_main.dmi and b/icons/mob/human_races/cyberlimbs/cybersolutions/cybersolutions_main.dmi differ
diff --git a/icons/mob/human_races/cyberlimbs/grayson/grayson_main.dmi b/icons/mob/human_races/cyberlimbs/grayson/grayson_main.dmi
index 4fd25b4bbd..f27b5246b4 100644
Binary files a/icons/mob/human_races/cyberlimbs/grayson/grayson_main.dmi and b/icons/mob/human_races/cyberlimbs/grayson/grayson_main.dmi differ
diff --git a/icons/mob/human_races/cyberlimbs/morpheus/morpheus_main.dmi b/icons/mob/human_races/cyberlimbs/morpheus/morpheus_main.dmi
index 5c466d63ed..dc1cee2262 100644
Binary files a/icons/mob/human_races/cyberlimbs/morpheus/morpheus_main.dmi and b/icons/mob/human_races/cyberlimbs/morpheus/morpheus_main.dmi differ
diff --git a/icons/mob/human_races/cyberlimbs/zenghu/zenghu_main.dmi b/icons/mob/human_races/cyberlimbs/zenghu/zenghu_main.dmi
index ebc3bb066c..1acd71f055 100644
Binary files a/icons/mob/human_races/cyberlimbs/zenghu/zenghu_main.dmi and b/icons/mob/human_races/cyberlimbs/zenghu/zenghu_main.dmi differ
diff --git a/icons/mob/human_races/r_def_tajaran_vr.dmi b/icons/mob/human_races/r_def_tajaran_vr.dmi
index 64b1a2d30d..cba7225cf2 100644
Binary files a/icons/mob/human_races/r_def_tajaran_vr.dmi and b/icons/mob/human_races/r_def_tajaran_vr.dmi differ
diff --git a/icons/mob/human_races/robotic.dmi b/icons/mob/human_races/robotic.dmi
index e98d2e3512..3d14ae415a 100644
Binary files a/icons/mob/human_races/robotic.dmi and b/icons/mob/human_races/robotic.dmi differ
diff --git a/icons/mob/items/lefthand.dmi b/icons/mob/items/lefthand.dmi
index a42fe56547..a06310415f 100644
Binary files a/icons/mob/items/lefthand.dmi and b/icons/mob/items/lefthand.dmi differ
diff --git a/icons/mob/items/lefthand_storage.dmi b/icons/mob/items/lefthand_storage.dmi
index 530823eb77..d7e1c4ec10 100644
Binary files a/icons/mob/items/lefthand_storage.dmi and b/icons/mob/items/lefthand_storage.dmi differ
diff --git a/icons/mob/items/lefthand_uniforms.dmi b/icons/mob/items/lefthand_uniforms.dmi
index 02d12e4f79..0a03f53ccd 100644
Binary files a/icons/mob/items/lefthand_uniforms.dmi and b/icons/mob/items/lefthand_uniforms.dmi differ
diff --git a/icons/mob/items/righthand.dmi b/icons/mob/items/righthand.dmi
index 54720b1f6d..ac1ea14c40 100644
Binary files a/icons/mob/items/righthand.dmi and b/icons/mob/items/righthand.dmi differ
diff --git a/icons/mob/items/righthand_storage.dmi b/icons/mob/items/righthand_storage.dmi
index 2d6ff6d601..66646547c5 100644
Binary files a/icons/mob/items/righthand_storage.dmi and b/icons/mob/items/righthand_storage.dmi differ
diff --git a/icons/mob/items/righthand_uniforms.dmi b/icons/mob/items/righthand_uniforms.dmi
index 88710db2d5..78bc6edd3e 100644
Binary files a/icons/mob/items/righthand_uniforms.dmi and b/icons/mob/items/righthand_uniforms.dmi differ
diff --git a/icons/mob/robots_vr.dmi b/icons/mob/robots_vr.dmi
new file mode 100644
index 0000000000..1640981e46
Binary files /dev/null and b/icons/mob/robots_vr.dmi differ
diff --git a/icons/mob/species/seromi/uniform.dmi b/icons/mob/species/seromi/uniform.dmi
index c11e63db0c..c354d0bd12 100644
Binary files a/icons/mob/species/seromi/uniform.dmi and b/icons/mob/species/seromi/uniform.dmi differ
diff --git a/icons/mob/uniform.dmi b/icons/mob/uniform.dmi
index a41e567a82..5ad776778d 100644
Binary files a/icons/mob/uniform.dmi and b/icons/mob/uniform.dmi differ
diff --git a/icons/obj/clothing/uniforms.dmi b/icons/obj/clothing/uniforms.dmi
index e494bc966c..708023477a 100644
Binary files a/icons/obj/clothing/uniforms.dmi and b/icons/obj/clothing/uniforms.dmi differ
diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi
index add3c315a6..a8e41841c3 100644
Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ
diff --git a/icons/obj/radio_vr.dmi b/icons/obj/radio_vr.dmi
index f26ff6c3f6..77d695cf23 100644
Binary files a/icons/obj/radio_vr.dmi and b/icons/obj/radio_vr.dmi differ
diff --git a/icons/turf/flooring/wood_vr.dmi b/icons/turf/flooring/wood_vr.dmi
index de198c710e..d6024f3de0 100644
Binary files a/icons/turf/flooring/wood_vr.dmi and b/icons/turf/flooring/wood_vr.dmi differ
diff --git a/maps/tether/submaps/beach/_beach.dm b/maps/tether/submaps/beach/_beach.dm
index 54f8e149f7..e96c75641b 100644
--- a/maps/tether/submaps/beach/_beach.dm
+++ b/maps/tether/submaps/beach/_beach.dm
@@ -147,7 +147,7 @@
/turf/simulated/floor/beach/coastwater/New()
..()
- overlays += image("icon"='icons/misc/beach.dmi',"icon_state"="water","layer"=MOB_LAYER+0.1)
+ add_overlay(image("icon"='icons/misc/beach.dmi',"icon_state"="water","layer"=MOB_LAYER+0.1))
// -- Areas -- //
diff --git a/maps/tether/tether-02-surface2.dmm b/maps/tether/tether-02-surface2.dmm
index 51329c8d0c..d84b9b0036 100644
--- a/maps/tether/tether-02-surface2.dmm
+++ b/maps/tether/tether-02-surface2.dmm
@@ -287,7 +287,7 @@
"aR" = (
/obj/machinery/door/blast/shutters{
dir = 2;
- id = "PubPrep";
+ id = "GateShut";
layer = 3.3;
name = "Gateway Shutter"
},
diff --git a/maps/tether/tether-06-station2.dmm b/maps/tether/tether-06-station2.dmm
index b2740b3521..8fee696396 100644
--- a/maps/tether/tether-06-station2.dmm
+++ b/maps/tether/tether-06-station2.dmm
@@ -6988,11 +6988,6 @@
pixel_y = 3
},
/obj/item/weapon/circuitboard/autolathe,
-/obj/structure/cable/green{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
/obj/item/weapon/circuitboard/scan_consolenew{
pixel_x = 6;
pixel_y = -3
@@ -8725,10 +8720,6 @@
},
/obj/item/device/multitool,
/obj/item/clothing/glasses/meson,
-/obj/machinery/ai_status_display{
- pixel_x = 32;
- pixel_y = 0
- },
/obj/machinery/light/small,
/turf/simulated/floor/plating,
/area/storage/tech)
@@ -8745,6 +8736,10 @@
/obj/item/device/t_scanner,
/obj/item/clothing/glasses/meson,
/obj/item/device/multitool,
+/obj/machinery/ai_status_display{
+ pixel_x = 0;
+ pixel_y = -32
+ },
/turf/simulated/floor/plating,
/area/storage/tech)
"oI" = (
diff --git a/vorestation.dme b/vorestation.dme
index 92190c050a..fd8a3b402a 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -12,6 +12,7 @@
// BEGIN_INCLUDE
#include "code\_away_mission_tests.dm"
#include "code\_macros.dm"
+#include "code\_macros_vr.dm"
#include "code\_map_tests.dm"
#include "code\_unit_tests.dm"
#include "code\global.dm"
@@ -56,6 +57,7 @@
#include "code\__defines\qdel.dm"
#include "code\__defines\research.dm"
#include "code\__defines\roguemining_vr.dm"
+#include "code\__defines\sound.dm"
#include "code\__defines\server_tools.config.dm"
#include "code\__defines\server_tools.dm"
#include "code\__defines\species_languages.dm"
@@ -133,9 +135,7 @@
#include "code\ATMOSPHERICS\atmospherics.dm"
#include "code\ATMOSPHERICS\datum_pipe_network.dm"
#include "code\ATMOSPHERICS\datum_pipeline.dm"
-#include "code\ATMOSPHERICS\he_pipes.dm"
#include "code\ATMOSPHERICS\mainspipe.dm"
-#include "code\ATMOSPHERICS\pipes.dm"
#include "code\ATMOSPHERICS\components\portables_connector.dm"
#include "code\ATMOSPHERICS\components\tvalve.dm"
#include "code\ATMOSPHERICS\components\valve.dm"
@@ -164,6 +164,15 @@
#include "code\ATMOSPHERICS\components\unary\unary_base.dm"
#include "code\ATMOSPHERICS\components\unary\vent_pump.dm"
#include "code\ATMOSPHERICS\components\unary\vent_scrubber.dm"
+#include "code\ATMOSPHERICS\pipes\cap.dm"
+#include "code\ATMOSPHERICS\pipes\he_pipes.dm"
+#include "code\ATMOSPHERICS\pipes\manifold.dm"
+#include "code\ATMOSPHERICS\pipes\manifold4w.dm"
+#include "code\ATMOSPHERICS\pipes\pipe_base.dm"
+#include "code\ATMOSPHERICS\pipes\simple.dm"
+#include "code\ATMOSPHERICS\pipes\tank.dm"
+#include "code\ATMOSPHERICS\pipes\universal.dm"
+#include "code\ATMOSPHERICS\pipes\vent.dm"
#include "code\controllers\autotransfer.dm"
#include "code\controllers\communications.dm"
#include "code\controllers\configuration.dm"
@@ -202,7 +211,7 @@
#include "code\controllers\subsystems\air.dm"
#include "code\controllers\subsystems\airflow.dm"
#include "code\controllers\subsystems\atoms.dm"
-#include "code\controllers\subsystems\floor_decals.dm"
+#include "code\controllers\subsystems\bellies_vr.dm"
#include "code\controllers\subsystems\garbage.dm"
#include "code\controllers\subsystems\lighting.dm"
#include "code\controllers\subsystems\machines.dm"
@@ -1226,7 +1235,6 @@
#include "code\game\turfs\flooring\flooring_premade.dm"
#include "code\game\turfs\flooring\flooring_vr.dm"
#include "code\game\turfs\flooring\shuttle_vr.dm"
-#include "code\game\turfs\flooring\turf_overlay_holder.dm"
#include "code\game\turfs\initialization\init.dm"
#include "code\game\turfs\initialization\maintenance.dm"
#include "code\game\turfs\simulated\floor.dm"
@@ -2516,6 +2524,7 @@
#include "code\modules\reagents\reagent_containers\spray.dm"
#include "code\modules\reagents\reagent_containers\spray_vr.dm"
#include "code\modules\reagents\reagent_containers\syringes.dm"
+#include "code\modules\reagents\reagent_containers\syringes_vr.dm"
#include "code\modules\reagents\reagent_containers\drinkingglass\drinkingglass.dm"
#include "code\modules\reagents\reagent_containers\drinkingglass\extras.dm"
#include "code\modules\reagents\reagent_containers\drinkingglass\glass_boxes.dm"
@@ -2717,7 +2726,8 @@
#include "code\modules\vore\appearance\sprite_accessories_vr.dm"
#include "code\modules\vore\appearance\sprite_accessories_yw.dm"
#include "code\modules\vore\appearance\update_icons_vr.dm"
-#include "code\modules\vore\eating\belly_vr.dm"
+#include "code\modules\vore\eating\belly_dat_vr.dm"
+#include "code\modules\vore\eating\belly_obj_vr.dm"
#include "code\modules\vore\eating\bellymodes_vr.dm"
#include "code\modules\vore\eating\contaminate_vr.dm"
#include "code\modules\vore\eating\digest_act_vr.dm"
@@ -2856,6 +2866,9 @@
#include "maps\southern_cross\items\clothing\sc_suit.dm"
#include "maps\southern_cross\items\clothing\sc_under.dm"
#include "maps\southern_cross\job\outfits.dm"
+#include "maps\southern_cross\loadout\loadout_head.dm"
+#include "maps\southern_cross\loadout\loadout_suit.dm"
+#include "maps\southern_cross\loadout\loadout_uniform.dm"
#include "maps\southern_cross\structures\closets\misc.dm"
#include "maps\submaps\_readme.dm"
#include "maps\submaps\engine_submaps\engine.dm"