diff --git a/.gitignore b/.gitignore index 03ec2b8483..abf84becce 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ Thumbs.db *.dmb *.lk *.backup +*.pyc data/ cfg/ diff --git a/.travis.yml b/.travis.yml index 428ab53b86..fc1c93b83c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,14 @@ language: c sudo: false env: - BYOND_MAJOR="512" - BYOND_MINOR="1403" - MACRO_COUNT=4 + global: + - BYOND_MAJOR="512" + - BYOND_MINOR="1403" + - MACRO_COUNT=4 + matrix: + - TEST_DEFINE="MAP_TEST" TEST_FILE="code/_map_tests.dm" RUN="0" + - TEST_DEFINE="AWAY_MISSION_TEST" TEST_FILE="code/_away_mission_tests.dm" RUN="0" + - TEST_DEFINE="UNIT_TEST" TEST_FILE="code/_unit_tests.dm" RUN="1" cache: directories: @@ -37,14 +42,9 @@ script: - (num=`grep -E '\\\\(red|blue|green|black|b|i[^mc])' **/*.dm | wc -l`; echo "$num escapes (expecting ${MACRO_COUNT} or less)"; [ $num -le ${MACRO_COUNT} ]) - source $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}/byond/bin/byondsetup - python tools/TagMatcher/tag-matcher.py ../.. - #First compile is to ensure maps are valid. - - echo "#define MAP_TEST 1" > code/_map_tests.dm + # Run our test - cp config/example/* config/ + - echo "#define ${TEST_DEFINE} 1" > ${TEST_FILE} - DreamMaker vorestation.dme - - echo "#define MAP_TEST 0" > code/_map_tests.dm - #Second compile is for the unit tests. Compiling a second time to exclude the validated maps is actually faster than waiting for startup with them compiled. - - echo "#define UNIT_TEST 1" > code/_unit_tests.dm - - DreamMaker vorestation.dme - - DreamDaemon vorestation.dmb -invisible -trusted -core 2>&1 | tee log.txt - - grep "All Unit Tests Passed" log.txt - + - if [ $RUN -eq 1 ]; then DreamDaemon vorestation.dmb -invisible -trusted -core 2>&1 | tee log.txt; fi + - if [ $RUN -eq 1 ]; then grep "All Unit Tests Passed" log.txt; fi \ No newline at end of file diff --git a/SQL/feedback_schema.sql b/SQL/feedback_schema.sql index 3fa0f7080d..ee8975263b 100644 --- a/SQL/feedback_schema.sql +++ b/SQL/feedback_schema.sql @@ -117,4 +117,11 @@ CREATE TABLE `erro_privacy` ( `ckey` varchar(32) NOT NULL, `option` varchar(128) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; \ No newline at end of file +) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; + +CREATE TABLE `vr_player_hours` ( + `ckey` varchar(32) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL, + `department` varchar(64) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL, + `hours` double NOT NULL, + PRIMARY KEY (`ckey`,`department`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/omni_devices/mixer.dm b/code/ATMOSPHERICS/components/omni_devices/mixer.dm index f52269ee60..6340397870 100644 --- a/code/ATMOSPHERICS/components/omni_devices/mixer.dm +++ b/code/ATMOSPHERICS/components/omni_devices/mixer.dm @@ -52,7 +52,7 @@ /obj/machinery/atmospherics/omni/mixer/Destroy() inputs.Cut() output = null - ..() + . = ..() /obj/machinery/atmospherics/omni/mixer/sort_ports() for(var/datum/omni_port/P in ports) diff --git a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm index b1131c9d4a..a469b4e9ee 100644 --- a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm +++ b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm @@ -244,7 +244,7 @@ P.node.disconnect(src) qdel(P.network) P.node = null - + ports = null . = ..() /obj/machinery/atmospherics/omni/atmos_init() diff --git a/code/ZAS/Airflow.dm b/code/ZAS/Airflow.dm index fde7b78aca..e5d2b7eb11 100644 --- a/code/ZAS/Airflow.dm +++ b/code/ZAS/Airflow.dm @@ -26,15 +26,17 @@ mob/living/simple_animal/slime/airflow_stun() return mob/living/carbon/human/airflow_stun() - if(shoes) - if(shoes.item_flags & NOSLIP) return 0 + if(shoes && (shoes.item_flags & NOSLIP)) + to_chat(src, "Air suddenly rushes past you!") + return 0 ..() atom/movable/proc/check_airflow_movable(n) + if(!simulated) return 0 if(anchored && !ismob(src)) return 0 - if(!istype(src,/obj/item) && n < vsc.airflow_dense_pressure) return 0 + if(!isobj(src) && n < vsc.airflow_dense_pressure) return 0 return 1 @@ -50,15 +52,20 @@ mob/living/silicon/check_airflow_movable() return 0 -obj/item/check_airflow_movable(n) - . = ..() +obj/check_airflow_movable(n) + if (!(. = ..())) + return 0 + if(isnull(w_class)) + if(n < vsc.airflow_dense_pressure) return 0 //most non-item objs don't have a w_class yet switch(w_class) - if(2) + if(ITEMSIZE_TINY,ITEMSIZE_SMALL) if(n < vsc.airflow_lightest_pressure) return 0 - if(3) + if(ITEMSIZE_NORMAL) if(n < vsc.airflow_light_pressure) return 0 - if(4,5) + if(ITEMSIZE_LARGE,ITEMSIZE_HUGE) if(n < vsc.airflow_medium_pressure) return 0 + else + if(n < vsc.airflow_dense_pressure) return 0 /atom/movable/var/tmp/turf/airflow_dest /atom/movable/var/tmp/airflow_speed = 0 @@ -78,116 +85,6 @@ obj/item/check_airflow_movable(n) return 0 return 1 -/atom/movable/proc/GotoAirflowDest(n) - if(!airflow_dest) return - if(airflow_speed < 0) return - if(last_airflow > world.time - vsc.airflow_delay) return - if(airflow_speed) - airflow_speed = n/max(get_dist(src,airflow_dest),1) - return - if(airflow_dest == loc) - step_away(src,loc) - if(!src.AirflowCanMove(n)) - return - if(ismob(src)) - src << "You are sucked away by airflow!" - last_airflow = world.time - var/airflow_falloff = 9 - sqrt((x - airflow_dest.x) ** 2 + (y - airflow_dest.y) ** 2) - if(airflow_falloff < 1) - airflow_dest = null - return - airflow_speed = min(max(n * (9/airflow_falloff),1),9) - var - xo = airflow_dest.x - src.x - yo = airflow_dest.y - src.y - od = 0 - airflow_dest = null - if(!density) - density = 1 - od = 1 - while(airflow_speed > 0) - if(airflow_speed <= 0) break - airflow_speed = min(airflow_speed,15) - airflow_speed -= vsc.airflow_speed_decay - if(airflow_speed > 7) - if(airflow_time++ >= airflow_speed - 7) - if(od) - density = 0 - sleep(1 * tick_multiplier) - else - if(od) - density = 0 - sleep(max(1,10-(airflow_speed+3)) * tick_multiplier) - if(od) - density = 1 - if ((!( src.airflow_dest ) || src.loc == src.airflow_dest)) - src.airflow_dest = locate(min(max(src.x + xo, 1), world.maxx), min(max(src.y + yo, 1), world.maxy), src.z) - if ((src.x == 1 || src.x == world.maxx || src.y == 1 || src.y == world.maxy)) - break - if(!istype(loc, /turf)) - break - step_towards(src, src.airflow_dest) - var/mob/M = src - if(istype(M) && M.client) - M.setMoveCooldown(vsc.airflow_mob_slowdown) - airflow_dest = null - airflow_speed = 0 - airflow_time = 0 - if(od) - density = 0 - - -/atom/movable/proc/RepelAirflowDest(n) - if(!airflow_dest) return - if(airflow_speed < 0) return - if(last_airflow > world.time - vsc.airflow_delay) return - if(airflow_speed) - airflow_speed = n/max(get_dist(src,airflow_dest),1) - return - if(airflow_dest == loc) - step_away(src,loc) - if(!src.AirflowCanMove(n)) - return - if(ismob(src)) - src << "You are pushed away by airflow!" - last_airflow = world.time - var/airflow_falloff = 9 - sqrt((x - airflow_dest.x) ** 2 + (y - airflow_dest.y) ** 2) - if(airflow_falloff < 1) - airflow_dest = null - return - airflow_speed = min(max(n * (9/airflow_falloff),1),9) - var - xo = -(airflow_dest.x - src.x) - yo = -(airflow_dest.y - src.y) - od = 0 - airflow_dest = null - if(!density) - density = 1 - od = 1 - while(airflow_speed > 0) - if(airflow_speed <= 0) return - airflow_speed = min(airflow_speed,15) - airflow_speed -= vsc.airflow_speed_decay - if(airflow_speed > 7) - if(airflow_time++ >= airflow_speed - 7) - sleep(1 * tick_multiplier) - else - sleep(max(1,10-(airflow_speed+3)) * tick_multiplier) - if ((!( src.airflow_dest ) || src.loc == src.airflow_dest)) - src.airflow_dest = locate(min(max(src.x + xo, 1), world.maxx), min(max(src.y + yo, 1), world.maxy), src.z) - if ((src.x == 1 || src.x == world.maxx || src.y == 1 || src.y == world.maxy)) - return - if(!istype(loc, /turf)) - return - step_towards(src, src.airflow_dest) - if(ismob(src) && src:client) - src:client:move_delay = world.time + vsc.airflow_mob_slowdown - airflow_dest = null - airflow_speed = 0 - airflow_time = 0 - if(od) - density = 0 - /atom/movable/Bump(atom/A) if(airflow_speed > 0 && airflow_dest) airflow_hit(A) diff --git a/code/ZAS/Atom.dm b/code/ZAS/Atom.dm index 4961355940..63ed9cf090 100644 --- a/code/ZAS/Atom.dm +++ b/code/ZAS/Atom.dm @@ -76,7 +76,8 @@ turf/c_airblock(turf/other) return AIR_BLOCKED var/result = 0 - for(var/atom/movable/M in contents) + for(var/mm in contents) + var/atom/movable/M = mm result |= M.c_airblock(other) if(result == BLOCKED) return BLOCKED return result diff --git a/code/ZAS/Controller.dm b/code/ZAS/Controller.dm index 9688fabf72..7adba1474f 100644 --- a/code/ZAS/Controller.dm +++ b/code/ZAS/Controller.dm @@ -1,4 +1,4 @@ -var/datum/controller/air_system/air_master +var/datum/controller/subsystem/air/air_master var/tick_multiplier = 2 @@ -65,201 +65,35 @@ Class Procs: */ +// +// The rest of the air subsystem is defined in air.dm +// -//Geometry lists -/datum/controller/air_system/var/list/zones = list() -/datum/controller/air_system/var/list/edges = list() +/datum/controller/subsystem/air + //Geometry lists + var/list/zones = list() + var/list/edges = list() + //Geometry updates lists + var/list/tiles_to_update = list() + var/list/zones_to_update = list() + var/list/active_fire_zones = list() + var/list/active_hotspots = list() + var/list/active_edges = list() -//Geometry updates lists -/datum/controller/air_system/var/list/tiles_to_update = list() -/datum/controller/air_system/var/list/zones_to_update = list() -/datum/controller/air_system/var/list/active_fire_zones = list() -/datum/controller/air_system/var/list/active_hotspots = list() -/datum/controller/air_system/var/list/active_edges = list() + var/active_zones = 0 + var/current_cycle = 0 + var/next_id = 1 //Used to keep track of zone UIDs. -/datum/controller/air_system/var/active_zones = 0 - -/datum/controller/air_system/var/current_cycle = 0 -/datum/controller/air_system/var/update_delay = 5 //How long between check should it try to process atmos again. -/datum/controller/air_system/var/failed_ticks = 0 //How many ticks have runtimed? - -/datum/controller/air_system/var/tick_progress = 0 - -/datum/controller/air_system/var/next_id = 1 //Used to keep track of zone UIDs. - - -#if UNIT_TEST -#define CHECK_SLEEP_ZAS_SETUP // For unit tests we don't care about a smooth lobby screen experience. We care about speed. -#else -#define CHECK_SLEEP_ZAS_SETUP if(++done_turfs > 10000) { done_turfs=0;sleep(world.tick_lag); } -#endif -/datum/controller/air_system/proc/Setup() - //Purpose: Call this at the start to setup air groups geometry - // (Warning: Very processor intensive but only must be done once per round) - //Called by: Gameticker/Master controller - //Inputs: None. - //Outputs: None. - - #if !UNIT_TEST - var/done_turfs = 0 - #endif - #ifndef ZASDBG - set background = 1 - #endif - - admin_notice("Processing Geometry...", R_DEBUG) - sleep(-1) - - var/start_time = world.timeofday - - var/simulated_turf_count = 0 - - for(var/turf/simulated/S in world) - simulated_turf_count++ - S.update_air_properties() - CHECK_SLEEP_ZAS_SETUP - - admin_notice({"Geometry initialized in [round(0.1*(world.timeofday-start_time),0.1)] seconds. - -Total Simulated Turfs: [simulated_turf_count] -Total Zones: [zones.len] -Total Edges: [edges.len] -Total Active Edges: [active_edges.len ? "[active_edges.len]" : "None"] -Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_count] -"}, R_DEBUG) - - // Uncomment this if you're having problems finding where active edges are. - /* - for(var/connection_edge/E in active_edges) - world << "Edge became active: [E]." - var/i = 1 - for(var/turf/T in E.connecting_turfs) - world << "[i] [T]:[T.x],[T.y],[T.z]" - i++ - */ - - -// spawn Start() - - -/datum/controller/air_system/proc/Start() - //Purpose: This is kicked off by the master controller, and controls the processing of all atmosphere. - //Called by: Master controller - //Inputs: None. - //Outputs: None. - - #ifndef ZASDBG - set background = 1 - #endif - - while(1) - Tick() - sleep(max(5,update_delay*tick_multiplier)) - - -/datum/controller/air_system/proc/Tick() - . = 1 //Set the default return value, for runtime detection. - - current_cycle++ - - //If there are tiles to update, do so. - tick_progress = "updating turf properties" - - var/list/updating - - if(tiles_to_update.len) - updating = tiles_to_update - tiles_to_update = list() - - #ifdef ZASDBG - var/updated = 0 - #endif - - //defer updating of self-zone-blocked turfs until after all other turfs have been updated. - //this hopefully ensures that non-self-zone-blocked turfs adjacent to self-zone-blocked ones - //have valid zones when the self-zone-blocked turfs update. - - //This ensures that doorways don't form their own single-turf zones, since doorways are self-zone-blocked and - //can merge with an adjacent zone, whereas zones that are formed on adjacent turfs cannot merge with the doorway. - var/list/deferred = list() - - for(var/turf/T in updating) - //check if the turf is self-zone-blocked - if(T.c_airblock(T) & ZONE_BLOCKED) - deferred += T - continue - - T.update_air_properties() - T.post_update_air_properties() - T.needs_air_update = 0 - #ifdef ZASDBG - T.overlays -= mark - updated++ - #endif - //sleep(1) - - for(var/turf/T in deferred) - T.update_air_properties() - T.post_update_air_properties() - T.needs_air_update = 0 - #ifdef ZASDBG - T.overlays -= mark - updated++ - #endif - - #ifdef ZASDBG - if(updated != updating.len) - tick_progress = "[updating.len - updated] tiles left unupdated." - world << "[tick_progress]" - . = 0 - #endif - - //Where gas exchange happens. - if(.) - tick_progress = "processing edges" - - for(var/connection_edge/edge in active_edges) - edge.tick() - - //Process fire zones. - if(.) - tick_progress = "processing fire zones" - - for(var/zone/Z in active_fire_zones) - Z.process_fire() - - //Process hotspots. - if(.) - tick_progress = "processing hotspots" - - for(var/obj/fire/fire in active_hotspots) - fire.process() - - //Process zones. - if(.) - tick_progress = "updating zones" - - active_zones = zones_to_update.len - if(zones_to_update.len) - updating = zones_to_update - zones_to_update = list() - for(var/zone/zone in updating) - zone.tick() - zone.needs_update = 0 - - if(.) - tick_progress = "success" - -/datum/controller/air_system/proc/add_zone(zone/z) +/datum/controller/subsystem/air/proc/add_zone(zone/z) zones.Add(z) z.name = "Zone [next_id++]" mark_zone_update(z) -/datum/controller/air_system/proc/remove_zone(zone/z) +/datum/controller/subsystem/air/proc/remove_zone(zone/z) zones.Remove(z) zones_to_update.Remove(z) -/datum/controller/air_system/proc/air_blocked(turf/A, turf/B) +/datum/controller/subsystem/air/proc/air_blocked(turf/A, turf/B) #ifdef ZASDBG ASSERT(isturf(A)) ASSERT(isturf(B)) @@ -268,13 +102,13 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun if(ablock == BLOCKED) return BLOCKED return ablock | B.c_airblock(A) -/datum/controller/air_system/proc/has_valid_zone(turf/simulated/T) +/datum/controller/subsystem/air/proc/has_valid_zone(turf/simulated/T) #ifdef ZASDBG ASSERT(istype(T)) #endif return istype(T) && T.zone && !T.zone.invalid -/datum/controller/air_system/proc/merge(zone/A, zone/B) +/datum/controller/subsystem/air/proc/merge(zone/A, zone/B) #ifdef ZASDBG ASSERT(istype(A)) ASSERT(istype(B)) @@ -289,7 +123,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun B.c_merge(A) mark_zone_update(A) -/datum/controller/air_system/proc/connect(turf/simulated/A, turf/simulated/B) +/datum/controller/subsystem/air/proc/connect(turf/simulated/A, turf/simulated/B) #ifdef ZASDBG ASSERT(istype(A)) ASSERT(isturf(B)) @@ -330,7 +164,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun if(direct) c.mark_direct() -/datum/controller/air_system/proc/mark_for_update(turf/T) +/datum/controller/subsystem/air/proc/mark_for_update(turf/T) #ifdef ZASDBG ASSERT(isturf(T)) #endif @@ -341,7 +175,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun #endif T.needs_air_update = 1 -/datum/controller/air_system/proc/mark_zone_update(zone/Z) +/datum/controller/subsystem/air/proc/mark_zone_update(zone/Z) #ifdef ZASDBG ASSERT(istype(Z)) #endif @@ -349,7 +183,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun zones_to_update.Add(Z) Z.needs_update = 1 -/datum/controller/air_system/proc/mark_edge_sleeping(connection_edge/E) +/datum/controller/subsystem/air/proc/mark_edge_sleeping(connection_edge/E) #ifdef ZASDBG ASSERT(istype(E)) #endif @@ -357,7 +191,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun active_edges.Remove(E) E.sleeping = 1 -/datum/controller/air_system/proc/mark_edge_active(connection_edge/E) +/datum/controller/subsystem/air/proc/mark_edge_active(connection_edge/E) #ifdef ZASDBG ASSERT(istype(E)) #endif @@ -365,10 +199,10 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun active_edges.Add(E) E.sleeping = 0 -/datum/controller/air_system/proc/equivalent_pressure(zone/A, zone/B) +/datum/controller/subsystem/air/proc/equivalent_pressure(zone/A, zone/B) return A.air.compare(B.air) -/datum/controller/air_system/proc/get_edge(zone/A, zone/B) +/datum/controller/subsystem/air/proc/get_edge(zone/A, zone/B) if(istype(B)) for(var/connection_edge/zone/edge in A.edges) @@ -385,7 +219,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun edge.recheck() return edge -/datum/controller/air_system/proc/has_same_air(turf/A, turf/B) +/datum/controller/subsystem/air/proc/has_same_air(turf/A, turf/B) if(A.oxygen != B.oxygen) return 0 if(A.nitrogen != B.nitrogen) return 0 if(A.phoron != B.phoron) return 0 @@ -393,6 +227,6 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun if(A.temperature != B.temperature) return 0 return 1 -/datum/controller/air_system/proc/remove_edge(connection_edge/E) +/datum/controller/subsystem/air/proc/remove_edge(connection_edge/E) edges.Remove(E) if(!E.sleeping) active_edges.Remove(E) diff --git a/code/ZAS/Diagnostic.dm b/code/ZAS/Diagnostic.dm index cbf35d93bd..29ab678ef1 100644 --- a/code/ZAS/Diagnostic.dm +++ b/code/ZAS/Diagnostic.dm @@ -1,6 +1,12 @@ client/proc/ZoneTick() set category = "Debug" set name = "Process Atmos" + set desc = "Manually run a single tick of the air subsystem" + + // TODO - This might be a useful diagnostic tool. However its complicated to do with StonedMC + // Therefore it is left unimplemented for now until its use actually becomes required. ~Leshana + /* + if(!check_rights(R_DEBUG)) return var/result = air_master.Tick() if(result) @@ -8,7 +14,7 @@ client/proc/ZoneTick() else src << "Failed to process! ([air_master.tick_progress])" - + */ client/proc/Zone_Info(turf/T as null|turf) set category = "Debug" diff --git a/code/ZAS/_docs.dm b/code/ZAS/_docs.dm index 7b28d52688..382f1f0abb 100644 --- a/code/ZAS/_docs.dm +++ b/code/ZAS/_docs.dm @@ -26,11 +26,3 @@ Notes for people who used ZAS before: var/zone/connected_zone = edge.get_connected_zone(zone) */ - -//#define ZASDBG -#define MULTIZAS -#define AIR_BLOCKED 1 -#define ZONE_BLOCKED 2 -#define BLOCKED 3 - -#define ZONE_MIN_SIZE 14 //zones with less than this many turfs will always merge, even if the connection is not direct diff --git a/code/__defines/ZAS.dm b/code/__defines/ZAS.dm new file mode 100644 index 0000000000..8712dd2bf7 --- /dev/null +++ b/code/__defines/ZAS.dm @@ -0,0 +1,6 @@ +// Bitflag values for c_airblock() +#define AIR_BLOCKED 1 // Blocked +#define ZONE_BLOCKED 2 // Not blocked, but zone boundaries will not cross. +#define BLOCKED 3 // Blocked, zone boundaries will not cross even if opened. + +#define ZONE_MIN_SIZE 14 // Zones with less than this many turfs will always merge, even if the connection is not direct diff --git a/code/__defines/_compile_options.dm b/code/__defines/_compile_options.dm index 3190e391a4..229d0b94ad 100644 --- a/code/__defines/_compile_options.dm +++ b/code/__defines/_compile_options.dm @@ -7,6 +7,10 @@ 2 for preloading absolutely everything; */ +// ZAS Compile Options +//#define ZASDBG // Uncomment to turn on super detailed ZAS debugging that probably won't even compile. +#define MULTIZAS // Uncomment to turn on Multi-Z ZAS Support! + // If we are doing the map test build, do not include the main maps, only the submaps. #if MAP_TEST #define USING_MAP_DATUM /datum/map diff --git a/code/__defines/_planes+layers.dm b/code/__defines/_planes+layers.dm index baff5ad577..ad4fe2181d 100644 --- a/code/__defines/_planes+layers.dm +++ b/code/__defines/_planes+layers.dm @@ -58,6 +58,8 @@ What is the naming convention for planes or layers? //////////////////////////////////////////////////////////////////////////////////////// //#define TURF_LAYER 2 //For easy recordkeeping; this is a byond define + #define DECALS_LAYER 2.01 + #define OVERTURF_LAYER 2.1 #define DOOR_OPEN_LAYER 2.7 //Under all objects if opened. 2.7 due to tables being at 2.6 //#define OBJ_LAYER 3 //For easy recordkeeping; this is a byond define #define DOOR_CLOSED_LAYER 3.1 //Above most items if closed @@ -70,7 +72,6 @@ What is the naming convention for planes or layers? //#define FLY_LAYER 5 //For easy recordkeeping; this is a byond define #define LIGHTING_LAYER 11 //Layer that lighting used to be on (now it's on a plane) #define HUD_LAYER 20 //Above lighting, but below obfuscation. For in-game HUD effects (whereas SCREEN_LAYER is for abstract/OOC things like inventory slots) - #define OBFUSCATION_LAYER 21 //Where images covering the view for eyes are put #define SCREEN_LAYER 22 //Mob HUD/effects layer #define PLANE_LIGHTING 5 //Where the lighting (and darkness) lives @@ -91,9 +92,11 @@ What is the naming convention for planes or layers? #define PLANE_CH_SPECIAL 23 //Special role icon (revhead or w/e) #define PLANE_CH_STATUS_OOC 24 //OOC status hud for spooks +#define PLANE_MESONS 30 //Stuff seen with mesons, like open ceilings. This is 30 for downstreams. //Fullscreen overlays under inventory -#define PLANE_FULLSCREEN 90 //Blindness, mesons, druggy, etc +#define PLANE_FULLSCREEN 90 //Blindness, mesons, druggy, etc + #define OBFUSCATION_LAYER 5 //Where images covering the view for eyes are put #define FULLSCREEN_LAYER 18 #define DAMAGE_LAYER 18.1 #define BLIND_LAYER 18.2 diff --git a/code/__defines/machinery.dm b/code/__defines/machinery.dm index b577225e01..877982691e 100644 --- a/code/__defines/machinery.dm +++ b/code/__defines/machinery.dm @@ -53,7 +53,7 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called #define NETWORK_PRISON "Prison" #define NETWORK_SECURITY "Security" #define NETWORK_INTERROGATION "Interrogation" -#define NETWORK_TELECOM "Tcomsat" +#define NETWORK_TELECOM "Tcomms" #define NETWORK_THUNDER "Thunderdome" #define NETWORK_COMMUNICATORS "Communicators" diff --git a/code/__defines/misc_vr.dm b/code/__defines/misc_vr.dm index ed6d8e8031..f8da0d70ce 100644 --- a/code/__defines/misc_vr.dm +++ b/code/__defines/misc_vr.dm @@ -29,3 +29,6 @@ #define SHUTTLE_CRASHED 3 // Yup that can happen now #define BLUE_SHIELDED 2 // Shield from bluespace teleportation (telescience) + +//Assistant/Visitor/Whatever +#define USELESS_JOB "Visitor" \ No newline at end of file diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index cb0ecc37f5..dd504dfb9b 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -231,25 +231,28 @@ //Vision flags, for dealing with plane visibility #define VIS_FULLBRIGHT 1 -#define VIS_GHOSTS 2 -#define VIS_AI_EYE 3 +#define VIS_LIGHTING 2 +#define VIS_GHOSTS 3 +#define VIS_AI_EYE 4 -#define VIS_CH_STATUS 4 -#define VIS_CH_HEALTH 5 -#define VIS_CH_LIFE 6 -#define VIS_CH_ID 7 -#define VIS_CH_WANTED 8 -#define VIS_CH_IMPLOYAL 9 -#define VIS_CH_IMPTRACK 10 -#define VIS_CH_IMPCHEM 11 -#define VIS_CH_SPECIAL 12 -#define VIS_CH_STATUS_OOC 13 +#define VIS_CH_STATUS 5 +#define VIS_CH_HEALTH 6 +#define VIS_CH_LIFE 7 +#define VIS_CH_ID 8 +#define VIS_CH_WANTED 9 +#define VIS_CH_IMPLOYAL 10 +#define VIS_CH_IMPTRACK 11 +#define VIS_CH_IMPCHEM 12 +#define VIS_CH_SPECIAL 13 +#define VIS_CH_STATUS_OOC 14 -#define VIS_D_COLORBLIND 14 -#define VIS_D_COLORBLINDI 15 +#define VIS_D_COLORBLIND 15 +#define VIS_D_COLORBLINDI 16 -#define VIS_ADMIN1 16 -#define VIS_ADMIN2 17 -#define VIS_ADMIN3 18 +#define VIS_ADMIN1 17 +#define VIS_ADMIN2 18 +#define VIS_ADMIN3 19 -#define VIS_COUNT 18 //Must be highest number from above. \ No newline at end of file +#define VIS_MESONS 20 + +#define VIS_COUNT 20 //Must be highest number from above. diff --git a/code/__defines/mobs_vr.dm b/code/__defines/mobs_vr.dm index 9209b86159..b8a1f86a24 100644 --- a/code/__defines/mobs_vr.dm +++ b/code/__defines/mobs_vr.dm @@ -1,10 +1,10 @@ #undef VIS_COUNT -#define VIS_CH_STATUS_R 18 -#define VIS_CH_HEALTH_VR 19 -#define VIS_CH_BACKUP 20 -#define VIS_CH_VANTAG 21 +#define VIS_CH_STATUS_R 21 +#define VIS_CH_HEALTH_VR 22 +#define VIS_CH_BACKUP 23 +#define VIS_CH_VANTAG 24 -#define VIS_AUGMENTED 22 +#define VIS_AUGMENTED 25 -#define VIS_COUNT 22 \ No newline at end of file +#define VIS_COUNT 25 diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index eb350656b9..bec4a7953a 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -18,3 +18,4 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define INIT_ORDER_MAPPING 20 // VOREStation Edit #define INIT_ORDER_MACHINES 10 #define INIT_ORDER_LIGHTING 0 +#define INIT_ORDER_AIR -1 diff --git a/code/_away_mission_tests.dm b/code/_away_mission_tests.dm new file mode 100644 index 0000000000..75286fb34e --- /dev/null +++ b/code/_away_mission_tests.dm @@ -0,0 +1,10 @@ +/* + * + * This file is used by Travis to indicate that additional maps need to be compiled to look for errors such as missing paths. + * Do not add anything but the AWAY_MISSION_TEST definition here as it will be overwritten by Travis when running tests. + * + * + * Should you wish to edit set AWAY_MISSION_TEST to 1 like so: + * #define AWAY_MISSION_TEST 1 + */ +#define AWAY_MISSION_TEST 0 diff --git a/code/_helpers/icons.dm b/code/_helpers/icons.dm index 8819511973..e5523557a6 100644 --- a/code/_helpers/icons.dm +++ b/code/_helpers/icons.dm @@ -817,6 +817,11 @@ proc // Creates a single icon from a given /atom or /image. Only the first argu qdel(west) return full +/proc/downloadImage(atom/A, dir) + var/icon/this_icon = getFlatIcon(A,defdir=dir||A.dir,always_use_defdir=1) + + usr << ftp(this_icon,"[A.name].png") + /mob/proc/AddCamoOverlay(atom/A)//A is the atom which we are using as the overlay. var/icon/opacity_icon = new(A.icon, A.icon_state)//Don't really care for overlays/underlays. //Now we need to culculate overlays+underlays and add them together to form an image for a mask. diff --git a/code/_helpers/logging.dm b/code/_helpers/logging.dm index c58b2d1381..07e2985bbb 100644 --- a/code/_helpers/logging.dm +++ b/code/_helpers/logging.dm @@ -88,6 +88,10 @@ /proc/log_unit_test(text) world.log << "## UNIT_TEST: [text]" +/proc/report_progress(var/progress_message) + admin_notice("[progress_message]", R_DEBUG) + to_world_log(progress_message) + //pretty print a direction bitflag, can be useful for debugging. /proc/print_dir(var/dir) var/list/comps = list() diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm index 4bd85ac182..e1215bb901 100644 --- a/code/_helpers/mobs.dm +++ b/code/_helpers/mobs.dm @@ -248,3 +248,19 @@ Proc for attack log creation, because really why not if (progbar) qdel(progbar) + +/atom/proc/living_mobs(var/range = world.view) + var/list/viewers = oviewers(src,range) + var/list/living = list() + for(var/mob/living/L in viewers) + living += L + + return living + +/atom/proc/human_mobs(var/range = world.view) + var/list/viewers = oviewers(src,range) + var/list/humans = list() + for(var/mob/living/carbon/human/H in viewers) + humans += H + + return humans diff --git a/code/_helpers/mobs_vr.dm b/code/_helpers/mobs_vr.dm deleted file mode 100644 index 602a2ed6ce..0000000000 --- a/code/_helpers/mobs_vr.dm +++ /dev/null @@ -1,7 +0,0 @@ -/atom/proc/living_mobs(var/range = world.view) - var/list/viewers = oviewers(src,range) - var/list/living = list() - for(var/mob/living/L in viewers) - living += L - - return living diff --git a/code/_helpers/sorts/comparators.dm b/code/_helpers/sorts/comparators.dm index 58f9251392..1b4b834692 100644 --- a/code/_helpers/sorts/comparators.dm +++ b/code/_helpers/sorts/comparators.dm @@ -28,3 +28,11 @@ . = B.failures - A.failures if (!.) . = B.qdels - A.qdels + +// Sorts jobs by department, and then by flag within department +/proc/cmp_job_datums(var/datum/job/a, var/datum/job/b) + . = sorttext(b.department, a.department) + if (. == 0) //Same department, push up if they're a head + . = b.head_position - a.head_position + if (. == 0) //Already in head/nothead spot, sort by name + . = sorttext(b.title, a.title) diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index 2fe3e1f6e4..5f963fe8ba 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -792,6 +792,7 @@ proc/GaussRandRound(var/sigma,var/roundto) 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 X = B.ChangeTurf(T.type) X.set_dir(old_dir1) @@ -799,6 +800,9 @@ proc/GaussRandRound(var/sigma,var/roundto) X.icon = old_icon1 X.overlays = old_overlays 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 @@ -824,9 +828,11 @@ proc/GaussRandRound(var/sigma,var/roundto) 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/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 3c6a6a6c56..6ab4b7627f 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -28,6 +28,7 @@ var/list/global_huds = list( var/obj/screen/whitense var/list/vimpaired var/list/darkMask + var/obj/screen/darksight var/obj/screen/nvg var/obj/screen/thermal var/obj/screen/meson @@ -66,6 +67,13 @@ var/list/global_huds = list( whitense.icon = 'icons/effects/static.dmi' whitense.icon_state = "1 light" + //darksight 'hanger' for attached icons + darksight = new /obj/screen() + darksight.icon = null + darksight.screen_loc = "1,1" + darksight.plane = PLANE_LIGHTING + darksight.plane = LIGHTING_LAYER + 0.1 + nvg = setup_overlay("nvg_hud") thermal = setup_overlay("thermal_hud") meson = setup_overlay("meson_hud") diff --git a/code/controllers/configuration_vr.dm b/code/controllers/configuration_vr.dm index f1298d4d61..804fbc4ec8 100644 --- a/code/controllers/configuration_vr.dm +++ b/code/controllers/configuration_vr.dm @@ -4,8 +4,10 @@ /datum/configuration var/list/engine_map // Comma separated list of engines to choose from. Blank means fully random. - var/assistants_ratio - var/assistants_assured = 15 // Default 15, only used if the ratio is set though. + var/time_off = FALSE + var/limit_interns = -1 //Unlimited by default + var/limit_visitors = -1 //Unlimited by default + var/pto_cap = 100 //Hours /hook/startup/proc/read_vs_config() var/list/Lines = file2list("config/config.txt") @@ -32,10 +34,6 @@ continue switch (name) - if ("assistants_ratio") - config.assistants_ratio = text2num(value) - if ("assistants_assured") - config.assistants_assured = text2num(value) if ("chat_webhook_url") config.chat_webhook_url = value if ("chat_webhook_key") @@ -46,5 +44,13 @@ config.fax_export_dir = value if ("items_survive_digestion") config.items_survive_digestion = 1 + if ("limit_interns") + config.limit_interns = text2num(value) + if ("limit_visitors") + config.limit_visitors = text2num(value) + if ("pto_cap") + config.pto_cap = text2num(value) + if ("time_off") + config.time_off = TRUE return 1 diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 3ecb3b7fcb..961f657b2d 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -573,14 +573,11 @@ var/datum/controller/master/Master = new() var/datum/controller/subsystem/SS = S SS.StartLoadingMap() - // ZAS might displace objects as the map loads if an air tick is processed mid-load. - air_processing_killed = TRUE map_loading = TRUE /datum/controller/master/StopLoadingMap(var/quiet = TRUE) if(!quiet) admin_notice("Map is finished. Unlocking.", R_DEBUG) - air_processing_killed = FALSE map_loading = FALSE for(var/S in subsystems) var/datum/controller/subsystem/SS = S diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index ab72c18292..e92ec6a3df 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -11,7 +11,6 @@ var/global/datum/controller/game_controller/master_controller //Set in world.New var/global/controller_iteration = 0 var/global/last_tick_duration = 0 -var/global/air_processing_killed = 0 var/global/pipe_processing_killed = 0 datum/controller/game_controller diff --git a/code/controllers/subsystems/air.dm b/code/controllers/subsystems/air.dm new file mode 100644 index 0000000000..ed4602f048 --- /dev/null +++ b/code/controllers/subsystems/air.dm @@ -0,0 +1,271 @@ +// Air update stages +#define SSAIR_TURFS 1 +#define SSAIR_EDGES 2 +#define SSAIR_FIREZONES 3 +#define SSAIR_HOTSPOTS 4 +#define SSAIR_ZONES 5 +#define SSAIR_DONE 6 + +SUBSYSTEM_DEF(air) + name = "Air" + init_order = INIT_ORDER_AIR + priority = 20 + wait = 2 SECONDS // seconds (We probably can speed this up actually) + flags = SS_BACKGROUND // TODO - Should this really be background? It might be important. + runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + var/static/list/part_names = list("turfs", "edges", "fire zones", "hotspots", "zones") + + var/cost_turfs = 0 + var/cost_edges = 0 + var/cost_firezones = 0 + var/cost_hotspots = 0 + var/cost_zones = 0 + + var/list/currentrun = null + var/current_step = null + + // Updating zone tiles requires temporary storage location of self-zone-blocked turfs across resumes. Used only by process_tiles_to_update. + var/list/selfblock_deferred = null + +/datum/controller/subsystem/air/PreInit() + air_master = src + +/datum/controller/subsystem/air/Initialize(timeofday) + report_progress("Processing Geometry...") + + current_cycle = 0 + var/simulated_turf_count = 0 + for(var/turf/simulated/S in world) + simulated_turf_count++ + S.update_air_properties() + CHECK_TICK + + admin_notice({"Geometry initialized in [round(0.1*(REALTIMEOFDAY-timeofday),0.1)] seconds. + +Total Simulated Turfs: [simulated_turf_count] +Total Zones: [zones.len] +Total Edges: [edges.len] +Total Active Edges: [active_edges.len ? "[active_edges.len]" : "None"] +Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_count] +"}, R_DEBUG) + + // Note - Baystation settles the air by running for one tick. We prefer to not have active edges. + // Maps should not have active edges on boot. If we've got some, log it so it can get fixed. + if(active_edges.len) + var/list/edge_log = list() + for(var/connection_edge/E in active_edges) + edge_log += "Active Edge [E] ([E.type])" + for(var/turf/T in E.connecting_turfs) + edge_log += "+--- Connecting Turf [T] @ [T.x], [T.y], [T.z]" + log_debug("Active Edges on ZAS Startup\n" + edge_log.Join("\n")) + + ..() + +/datum/controller/subsystem/air/fire(resumed = 0) + var/timer + if(!resumed) + ASSERT(LAZYLEN(currentrun) == 0) // Santity checks to make sure we don't somehow have items left over from last cycle + ASSERT(current_step == null) // Or somehow didn't finish all the steps from last cycle + current_cycle++ // Begin a new air_master cycle! + current_step = SSAIR_TURFS // Start with Step 1 of course + + INTERNAL_PROCESS_STEP(SSAIR_TURFS, TRUE, process_tiles_to_update, cost_turfs, SSAIR_EDGES) + INTERNAL_PROCESS_STEP(SSAIR_EDGES, FALSE, process_active_edges, cost_edges, SSAIR_FIREZONES) + INTERNAL_PROCESS_STEP(SSAIR_FIREZONES, FALSE, process_active_fire_zones, cost_firezones, SSAIR_HOTSPOTS) + INTERNAL_PROCESS_STEP(SSAIR_HOTSPOTS, FALSE, process_active_hotspots, cost_hotspots, SSAIR_ZONES) + INTERNAL_PROCESS_STEP(SSAIR_ZONES, FALSE, process_zones_to_update, cost_zones, SSAIR_DONE) + + // Okay, we're done! Woo! Got thru a whole air_master cycle! + ASSERT(LAZYLEN(currentrun) == 0) // Sanity checks to make sure there are really none left + ASSERT(current_step == SSAIR_DONE) // And that we didn't somehow skip past the last step + currentrun = null + current_step = null + +/datum/controller/subsystem/air/proc/process_tiles_to_update(resumed = 0) + if (!resumed) + // NOT a copy, because we are supposed to drain active turfs each cycle anyway, so just replace with empty list. + // We still use a separate list tho, to ensure we don't process a turf twice during a single cycle! + src.currentrun = tiles_to_update + tiles_to_update = list() + + //defer updating of self-zone-blocked turfs until after all other turfs have been updated. + //this hopefully ensures that non-self-zone-blocked turfs adjacent to self-zone-blocked ones + //have valid zones when the self-zone-blocked turfs update. + //This ensures that doorways don't form their own single-turf zones, since doorways are self-zone-blocked and + //can merge with an adjacent zone, whereas zones that are formed on adjacent turfs cannot merge with the doorway. + ASSERT(src.selfblock_deferred == null) // Sanity check to make sure it was not remaining from last cycle somehow. + src.selfblock_deferred = list() + + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + var/list/selfblock_deferred = src.selfblock_deferred + + // Run thru the list, processing non-self-zone-blocked and deferring self-zone-blocked + while(currentrun.len) + var/turf/T = currentrun[currentrun.len] + currentrun.len-- + //check if the turf is self-zone-blocked + if(T.c_airblock(T) & ZONE_BLOCKED) + selfblock_deferred += T + if(MC_TICK_CHECK) + return + else + continue + T.update_air_properties() + T.post_update_air_properties() + T.needs_air_update = 0 + #ifdef ZASDBG + T.overlays -= mark + #endif + if(MC_TICK_CHECK) + return + + ASSERT(LAZYLEN(currentrun) == 0) + + // Run thru the deferred list and processing them + while(selfblock_deferred.len) + var/turf/T = selfblock_deferred[selfblock_deferred.len] + selfblock_deferred.len-- + T.update_air_properties() + T.post_update_air_properties() + T.needs_air_update = 0 + #ifdef ZASDBG + T.overlays -= mark + #endif + if(MC_TICK_CHECK) + return + + ASSERT(LAZYLEN(selfblock_deferred) == 0) + src.selfblock_deferred = null + +/datum/controller/subsystem/air/proc/process_active_edges(resumed = 0) + if (!resumed) + src.currentrun = active_edges.Copy() + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + while(currentrun.len) + var/connection_edge/edge = currentrun[currentrun.len] + currentrun.len-- + if(edge) // TODO - Do we need to check this? Old one didn't, but old one was single-threaded. + edge.tick() + if(MC_TICK_CHECK) + return + +/datum/controller/subsystem/air/proc/process_active_fire_zones(resumed = 0) + if (!resumed) + src.currentrun = active_fire_zones.Copy() + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + while(currentrun.len) + var/zone/Z = currentrun[currentrun.len] + currentrun.len-- + if(Z) // TODO - Do we need to check this? Old one didn't, but old one was single-threaded. + Z.process_fire() + if(MC_TICK_CHECK) + return + +/datum/controller/subsystem/air/proc/process_active_hotspots(resumed = 0) + if (!resumed) + src.currentrun = active_hotspots.Copy() + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + while(currentrun.len) + var/obj/fire/fire = currentrun[currentrun.len] + currentrun.len-- + if(fire) // TODO - Do we need to check this? Old one didn't, but old one was single-threaded. + fire.process() + if(MC_TICK_CHECK) + return + +/datum/controller/subsystem/air/proc/process_zones_to_update(resumed = 0) + if (!resumed) + active_zones = zones_to_update.len // Save how many zones there were to update this cycle (used by some debugging stuff) + if(!zones_to_update.len) + return // Nothing to do here this cycle! + // NOT a copy, because we are supposed to drain active turfs each cycle anyway, so just replace with empty list. + // Blanking the public list means we actually are removing processed ones from the list! Maybe we could we use zones_for_update directly? + // But if we dom any zones added to zones_to_update DURING this step will get processed again during this step. + // I don't know if that actually happens? But if it does, it could lead to an infinate loop. Better preserve original semantics. + src.currentrun = zones_to_update + zones_to_update = list() + + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + while(currentrun.len) + var/zone/zone = currentrun[currentrun.len] + currentrun.len-- + if(zone) // TODO - Do we need to check this? Old one didn't, but old one was single-threaded. + zone.tick() + zone.needs_update = 0 + if(MC_TICK_CHECK) + return + +/datum/controller/subsystem/air/stat_entry(msg_prefix) + var/list/msg = list(msg_prefix) + msg += "S:[current_step ? part_names[current_step] : ""] " + msg += "C:{" + msg += "T [round(cost_turfs, 1)] | " + msg += "E [round(cost_edges, 1)] | " + msg += "F [round(cost_firezones, 1)] | " + msg += "H [round(cost_hotspots, 1)] | " + msg += "Z [round(cost_zones, 1)] " + msg += "}" + msg += "Z: [zones.len] " + msg += "E: [edges.len] " + msg += "Cycle: [current_cycle] {" + msg += "T [tiles_to_update.len] | " + msg += "E [active_edges.len] | " + msg += "F [active_fire_zones.len] | " + msg += "H [active_hotspots.len] | " + msg += "Z [zones_to_update.len] " + msg += "}" + ..(msg.Join()) + +// ZAS might displace objects as the map loads if an air tick is processed mid-load. +/datum/controller/subsystem/air/StartLoadingMap(var/quiet = TRUE) + can_fire = FALSE + . = ..() + +/datum/controller/subsystem/air/StopLoadingMap(var/quiet = TRUE) + can_fire = TRUE + . = ..() + +// Reboot the air master. A bit hacky right now, but sometimes necessary still. +/datum/controller/subsystem/air/proc/RebootZAS() + can_fire = FALSE // Pause processing while we reboot + // If we should happen to be in the middle of processing... wait until that finishes. + if (state != SS_IDLE) + report_progress("ZAS Rebuild initiated. Waiting for current air tick to complete before continuing.") + while (state != SS_IDLE) + stoplag() + + // Invalidate all zones + for(var/zone/zone in zones) + zone.c_invalidate() + + // Reset all the lists + zones.Cut() + edges.Cut() + tiles_to_update.Cut() + zones_to_update.Cut() + active_fire_zones.Cut() + active_hotspots.Cut() + active_edges.Cut() + + // Start it up again + Initialize(REALTIMEOFDAY) + + // Update next_fire so the MC doesn't try to make up for missed ticks. + next_fire = world.time + wait + can_fire = TRUE // Unpause + +// +// The procs from the ZAS Air Controller are in ZAS/Controller.dm +// + +#undef SSAIR_TURFS +#undef SSAIR_EDGES +#undef SSAIR_FIREZONES +#undef SSAIR_HOTSPOTS +#undef SSAIR_ZONES +#undef SSAIR_DONE diff --git a/code/controllers/subsystems/airflow.dm b/code/controllers/subsystems/airflow.dm new file mode 100644 index 0000000000..9db8138826 --- /dev/null +++ b/code/controllers/subsystems/airflow.dm @@ -0,0 +1,163 @@ +#define CLEAR_OBJECT(TARGET) \ + processing -= TARGET; \ + TARGET.airflow_dest = null; \ + TARGET.airflow_speed = 0; \ + TARGET.airflow_time = 0; \ + TARGET.airflow_skip_speedcheck = FALSE; \ + if (TARGET.airflow_od) { \ + TARGET.density = 0; \ + } + +// No point in making this a processing substem, it overrides fire() and handles its own processing list! +SUBSYSTEM_DEF(airflow) + name = "Airflow" + wait = 2 + flags = SS_NO_INIT + runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME + priority = 15 + + var/list/processing = list() + var/list/currentrun = list() + +/datum/controller/subsystem/airflow/fire(resumed = FALSE) + if (!resumed) + currentrun = processing.Copy() + + var/mywait = wait + var/list/curr = currentrun // Cache for sanic speed + while (curr.len) + var/atom/movable/target = curr[curr.len] + curr.len-- + if(QDELETED(target)) + processing -= target + if (MC_TICK_CHECK) + return + continue + + if (target.airflow_speed <= 0) + CLEAR_OBJECT(target) + if (MC_TICK_CHECK) + return + continue + + if (target.airflow_process_delay > 0) + target.airflow_process_delay -= mywait + if (MC_TICK_CHECK) + return + continue + else if (target.airflow_process_delay) + target.airflow_process_delay = 0 + + target.airflow_speed = min(target.airflow_speed, 15) + target.airflow_speed -= vsc.airflow_speed_decay + if (!target.airflow_skip_speedcheck) + if (target.airflow_speed > 7) + if (target.airflow_time++ >= target.airflow_speed - 7) + if (target.airflow_od) + target.density = 0 + target.airflow_skip_speedcheck = TRUE + + if (MC_TICK_CHECK) + return + continue + else + if (target.airflow_od) + target.density = 0 + target.airflow_process_delay = max(1, 10 - (target.airflow_speed + 3)) + target.airflow_skip_speedcheck = TRUE + + if (MC_TICK_CHECK) + return + continue + + target.airflow_skip_speedcheck = FALSE + + if (target.airflow_od) + target.density = 1 + + if (!target.airflow_dest || target.loc == target.airflow_dest) + target.airflow_dest = locate(min(max(target.x + target.airflow_xo, 1), world.maxx), min(max(target.y + target.airflow_yo, 1), world.maxy), target.z) + + if ((target.x == 1) || (target.x == world.maxx) || (target.y == 1) || (target.y == world.maxy)) + CLEAR_OBJECT(target) + if (MC_TICK_CHECK) + return + continue + + if (!isturf(target.loc)) + CLEAR_OBJECT(target) + if (MC_TICK_CHECK) + return + continue + + step_towards(target, target.airflow_dest) + var/mob/M = target + if (ismob(target) && M.client) + M.setMoveCooldown(vsc.airflow_mob_slowdown) + + if (MC_TICK_CHECK) + return + +#undef CLEAR_OBJECT + +/atom/movable + var/tmp/airflow_xo + var/tmp/airflow_yo + var/tmp/airflow_od + var/tmp/airflow_process_delay + var/tmp/airflow_skip_speedcheck + +/atom/movable/proc/prepare_airflow(n) + if (!airflow_dest || airflow_speed < 0 || last_airflow > world.time - vsc.airflow_delay) + return FALSE + if (airflow_speed) + airflow_speed = n / max(get_dist(src, airflow_dest), 1) + return FALSE + + if (airflow_dest == loc) + step_away(src, loc) + + if (!src.AirflowCanMove(n)) + return FALSE + + if (ismob(src)) + to_chat(src,"You are pushed away by airflow!") + + last_airflow = world.time + var/airflow_falloff = 9 - sqrt((x - airflow_dest.x) ** 2 + (y - airflow_dest.y) ** 2) + + if (airflow_falloff < 1) + airflow_dest = null + return FALSE + + airflow_speed = min(max(n * (9 / airflow_falloff), 1), 9) + + airflow_od = 0 + + if (!density) + density = 1 + airflow_od = 1 + + return TRUE + +/atom/movable/proc/GotoAirflowDest(n) + if (!prepare_airflow(n)) + return + + airflow_xo = airflow_dest.x - src.x + airflow_yo = airflow_dest.y - src.y + + airflow_dest = null + + SSairflow.processing += src + +/atom/movable/proc/RepelAirflowDest(n) + if (!prepare_airflow(n)) + return + + airflow_xo = -(airflow_dest.x - src.x) + airflow_yo = -(airflow_dest.y - src.y) + + airflow_dest = null + + SSairflow.processing += src diff --git a/code/controllers/subsystems/garbage.dm b/code/controllers/subsystems/garbage.dm index 9deed740b6..1ff49edba2 100644 --- a/code/controllers/subsystems/garbage.dm +++ b/code/controllers/subsystems/garbage.dm @@ -169,7 +169,7 @@ SUBSYSTEM_DEF(garbage) #endif var/type = D.type var/datum/qdel_item/I = items[type] - testing("GC: -- \ref[src] | [type] was unable to be GC'd --") + testing("GC: -- \ref[D] | [type] was unable to be GC'd --") I.failures++ if (GC_QUEUE_HARDDELETE) HardDelete(D) diff --git a/code/controllers/subsystems/mapping_vr.dm b/code/controllers/subsystems/mapping_vr.dm index 498548d931..ef55dfaed9 100644 --- a/code/controllers/subsystems/mapping_vr.dm +++ b/code/controllers/subsystems/mapping_vr.dm @@ -19,6 +19,8 @@ SUBSYSTEM_DEF(mapping) // createRandomZlevel() // Mining generation probably should be here too // TODO - Other stuff related to maps and areas could be moved here too. Look at /tg + if(using_map) + loadLateMaps() ..() /datum/controller/subsystem/mapping/proc/loadEngine() @@ -49,10 +51,38 @@ SUBSYSTEM_DEF(mapping) // Annihilate movable atoms engine_loader.annihilate_bounds() - CHECK_TICK + //CHECK_TICK //Don't let anything else happen for now // Actually load it chosen_type.load(T) +/datum/controller/subsystem/mapping/proc/loadLateMaps() + var/list/deffo_load = using_map.lateload_z_levels + var/list/maybe_load = using_map.lateload_single_pick + + for(var/mapname in deffo_load) + var/datum/map_template/MT = map_templates[mapname] + if(!istype(MT)) + error("Lateload Z level \"[mapname]\" is not a valid map!") + continue + MT.load_new_z(centered = FALSE, dont_init = TRUE) + //CHECK_TICK //Can't deal with this until SSAtoms + + if(LAZYLEN(maybe_load)) + var/picked = pick(maybe_load) + var/list/picklist + + if(islist(picked)) //So you can have a 'chain' of z-levels that make up one away mission + picklist = picked + else + picklist = list(picked) + + for(var/map in picklist) + var/datum/map_template/MT = map_templates[map] + if(!istype(MT)) + error("Randompick Z level \"[map]\" is not a valid map!") + else + MT.load_new_z(centered = FALSE, dont_init = TRUE) + /datum/controller/subsystem/mapping/stat_entry(msg) if (!Debug2) return // Only show up in stat panel if debugging is enabled. diff --git a/code/controllers/subsystems/persist_vr.dm b/code/controllers/subsystems/persist_vr.dm new file mode 100644 index 0000000000..b2bcc4b2c0 --- /dev/null +++ b/code/controllers/subsystems/persist_vr.dm @@ -0,0 +1,81 @@ +//////////////////////////////// +//// Paid Leave Subsystem +//// For tracking how much department PTO time players have accured +//////////////////////////////// + +SUBSYSTEM_DEF(persist) + name = "Persist" + priority = 20 + wait = 15 MINUTES + flags = SS_BACKGROUND|SS_NO_INIT|SS_KEEP_TIMING + runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME + var/list/currentrun = list() + +/datum/controller/subsystem/persist/fire(var/resumed = FALSE) + update_department_hours(resumed) + +// Do PTO Accruals +/datum/controller/subsystem/persist/proc/update_department_hours(var/resumed = FALSE) + if(!config.time_off) + return + + establish_db_connection() + if(!dbcon.IsConnected()) + src.currentrun.Cut() + return + if(!resumed) + src.currentrun = human_mob_list.Copy() + + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + while (currentrun.len) + var/mob/M = currentrun[currentrun.len] + currentrun.len-- + if (QDELETED(M) || !istype(M) || !M.mind || !M.client || TICKS2DS(M.client.inactivity) > wait) + continue + + // Try and detect job and department of mob + var/datum/job/J = detect_job(M) + if(!istype(J) || !J.department || !J.timeoff_factor) + if (MC_TICK_CHECK) + return + continue + + // Update client whatever + var/client/C = M.client + var/wait_in_hours = (wait / (1 HOUR)) * J.timeoff_factor + LAZYINITLIST(C.department_hours) + var/dept_hours = C.department_hours + if(isnum(C.department_hours[J.department])) + dept_hours[J.department] += wait_in_hours + else + dept_hours[J.department] = wait_in_hours + + //Cap it + dept_hours[J.department] = min(config.pto_cap, dept_hours[J.department]) + + + // Okay we figured it out, lets update database! + var/sql_ckey = sql_sanitize_text(C.ckey) + var/sql_dpt = sql_sanitize_text(J.department) + var/sql_bal = text2num("[C.department_hours[J.department]]") + var/DBQuery/query = dbcon.NewQuery("INSERT INTO vr_player_hours (ckey, department, hours) VALUES ('[sql_ckey]', '[sql_dpt]', [sql_bal]) ON DUPLICATE KEY UPDATE hours = VALUES(hours)") + query.Execute() + + if (MC_TICK_CHECK) + return + +// This proc tries to find the job datum of an arbitrary mob. +/datum/controller/subsystem/persist/proc/detect_job(var/mob/M) + // Records are usually the most reliable way to get what job someone is. + var/datum/data/record/R = find_general_record("name", M.real_name) + if(R) // We found someone with a record. + var/recorded_rank = R.fields["real_rank"] + if(recorded_rank) + . = job_master.GetJob(recorded_rank) + if(.) return + + // They have a custom title, aren't crew, or someone deleted their record, so we need a fallback method. + // Let's check the mind. + if(M.mind && M.mind.assigned_role) + . = job_master.GetJob(M.mind.assigned_role) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index feef09b45e..3f4397df6b 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -499,7 +499,7 @@ //HUMAN /mob/living/carbon/human/mind_initialize() ..() - if(!mind.assigned_role) mind.assigned_role = "Assistant" //defualt + if(!mind.assigned_role) mind.assigned_role = USELESS_JOB //defualt //VOREStation Edit - Visitor not Assistant //slime /mob/living/simple_animal/slime/mind_initialize() diff --git a/code/datums/outfits/jobs/civilian.dm b/code/datums/outfits/jobs/civilian.dm index afbd7278e0..f3237249b1 100644 --- a/code/datums/outfits/jobs/civilian.dm +++ b/code/datums/outfits/jobs/civilian.dm @@ -1,5 +1,5 @@ /decl/hierarchy/outfit/job/assistant - name = OUTFIT_JOB_NAME("Assistant") + name = OUTFIT_JOB_NAME(USELESS_JOB) //VOREStation Edit - Visitor not Assistant id_type = /obj/item/weapon/card/id/assistant /decl/hierarchy/outfit/job/assistant/visitor @@ -11,7 +11,11 @@ name = OUTFIT_JOB_NAME("Resident") id_pda_assignment = "Resident" uniform = /obj/item/clothing/under/color/white - +//VOREStation Add - Interns +/decl/hierarchy/outfit/job/assistant/intern + name = OUTFIT_JOB_NAME("Intern") + id_type = /obj/item/weapon/card/id/civilian +//VOREStation Add End - Interns /decl/hierarchy/outfit/job/service l_ear = /obj/item/device/radio/headset/headset_service hierarchy_type = /decl/hierarchy/outfit/job/service diff --git a/code/datums/supplypacks/misc_vr.dm b/code/datums/supplypacks/misc_vr.dm index 144df5163b..6ff285ef99 100644 --- a/code/datums/supplypacks/misc_vr.dm +++ b/code/datums/supplypacks/misc_vr.dm @@ -11,4 +11,24 @@ cost = 50 containertype = /obj/structure/closet/crate/secure/gear containername = "Belt-miner gear crate" + access = access_mining + +/datum/supply_packs/misc/eva_rig + name = "eva hardsuit (empty)" + contains = list( + /obj/item/weapon/rig/eva = 1 + ) + cost = 150 + containertype = /obj/structure/closet/crate/secure/gear + containername = "eva hardsuit crate" + access = access_mining + +/datum/supply_packs/misc/mining_rig + name = "industrial hardsuit (empty)" + contains = list( + /obj/item/weapon/rig/industrial = 1 + ) + cost = 150 + containertype = /obj/structure/closet/crate/secure/gear + containername = "industrial hardsuit crate" access = access_mining \ No newline at end of file diff --git a/code/datums/supplypacks/recreation_vr.dm b/code/datums/supplypacks/recreation_vr.dm index 19b0df7e8c..bba16b04d8 100644 --- a/code/datums/supplypacks/recreation_vr.dm +++ b/code/datums/supplypacks/recreation_vr.dm @@ -20,7 +20,8 @@ /obj/item/clothing/suit/straight_jacket, /obj/item/weapon/handcuffs/legcuffs, /obj/item/weapon/melee/fluff/holochain/mass, - /obj/item/weapon/material/twohanded/fluff/riding_crop + /obj/item/weapon/material/twohanded/fluff/riding_crop, + /obj/item/clothing/under/fluff/latexmaid ) containertype = /obj/structure/closet/crate containername = "Restraints crate" diff --git a/code/datums/supplypacks/science_vr.dm b/code/datums/supplypacks/science_vr.dm index c3ec833438..327bc71798 100644 --- a/code/datums/supplypacks/science_vr.dm +++ b/code/datums/supplypacks/science_vr.dm @@ -66,3 +66,10 @@ containertype = /obj/structure/largecrate/animal/otie containername = "VARMAcorp adoptable reject (Dangerous!)" access = access_xenobiology + +/datum/supply_packs/sci/phoronotie + name = "VARMAcorp adaptive beta subject (Experimental)" + cost = 200 + containertype = /obj/structure/largecrate/animal/otie/phoron + containername = "VARMAcorp adaptive beta subject (Experimental)" + access = access_xenobiology \ No newline at end of file diff --git a/code/datums/supplypacks/security_vr.dm b/code/datums/supplypacks/security_vr.dm index 3c656741ee..20629de0b4 100644 --- a/code/datums/supplypacks/security_vr.dm +++ b/code/datums/supplypacks/security_vr.dm @@ -7,6 +7,15 @@ access_security, access_xenobiology) +/datum/supply_packs/security/guardmutant + name = "VARMAcorp autoNOMous security solution for hostile environments" + cost = 250 + containertype = /obj/structure/largecrate/animal/guardmutant + containername = "VARMAcorp autoNOMous security phoron-proof solution crate" + access = list( + access_security, + access_xenobiology) + /datum/supply_packs/security/biosuit contains = list( /obj/item/clothing/head/bio_hood/security = 3, diff --git a/code/defines/obj.dm b/code/defines/obj.dm index fbd0a156a7..47a24f192f 100644 --- a/code/defines/obj.dm +++ b/code/defines/obj.dm @@ -137,6 +137,18 @@ var/global/list/PDA_Manifest = list() if(!department && !(name in heads)) misc[++misc.len] = list("name" = name, "rank" = rank, "active" = isactive) + // Synthetics don't have actual records, so we will pull them from here. + // Synths don't have records, which is the means by which isactive is retrieved, so I'm hardcoding it to active, don't really have any better means + for(var/mob/living/silicon/ai/ai in mob_list) + bot[++bot.len] = list("name" = ai.real_name, "rank" = "Artificial Intelligence", "active" = "Active") + + for(var/mob/living/silicon/robot/robot in mob_list) + // No combat/syndicate cyborgs, no drones. + if(robot.module && robot.module.hide_on_manifest) + continue + + bot[++bot.len] = list("name" = robot.real_name, "rank" = "[robot.modtype] [robot.braintype]", "active" = "Active") + PDA_Manifest = list( list("cat" = "Command", "elems" = heads), diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 1898322b95..08d1fc4e99 100755 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -1646,7 +1646,6 @@ area/space/atmosalert() requires_power = 1 always_unpowered = 1 dynamic_lighting = 0 - base_turf = /turf/space auxport name = "\improper Fore Port Solar Array" diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 3403ffdbb8..fe0c7a08b3 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -322,3 +322,9 @@ var/list/mob/living/forced_ambiance_list = new if(A && A.has_gravity()) return 1 return 0 + +/area/proc/shuttle_arrived() + return TRUE + +/area/proc/shuttle_departed() + return TRUE diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm index 0dc9b72be7..dfb9d37147 100644 --- a/code/game/dna/dna_modifier.dm +++ b/code/game/dna/dna_modifier.dm @@ -126,7 +126,7 @@ /obj/machinery/dna_scannernew/attackby(var/obj/item/weapon/item as obj, var/mob/user as mob) if(istype(item, /obj/item/weapon/reagent_containers/glass)) if(beaker) - user << "A beaker is already loaded into the machine." + to_chat(user, "A beaker is already loaded into the machine.") return beaker = item @@ -134,16 +134,32 @@ item.loc = src user.visible_message("\The [user] adds \a [item] to \the [src]!", "You add \a [item] to \the [src]!") return + + else if(istype(item, /obj/item/organ/internal/brain)) + if (src.occupant) + to_chat(user, "The scanner is already occupied!") + return + var/obj/item/organ/internal/brain/brain = item + if(brain.clone_source) + user.drop_item() + brain.loc = src + put_in(brain.brainmob) + src.add_fingerprint(user) + user.visible_message("\The [user] adds \a [item] to \the [src]!", "You add \a [item] to \the [src]!") + return + else + to_chat(user,"\The [brain] is not acceptable for genetic sampling!") + else if (!istype(item, /obj/item/weapon/grab)) return var/obj/item/weapon/grab/G = item if (!ismob(G.affecting)) return if (src.occupant) - user << "The scanner is already occupied!" + to_chat(user, "The scanner is already occupied!") return if (G.affecting.abiotic()) - user << "The subject cannot have abiotic items on." + to_chat(user, "The subject cannot have abiotic items on.") return put_in(G.affecting) src.add_fingerprint(user) @@ -167,7 +183,7 @@ if(!M.client && M.mind) for(var/mob/observer/dead/ghost in player_list) if(ghost.mind == M.mind) - ghost << "Your corpse has been placed into a cloning scanner. Return to your body if you want to be resurrected/cloned! (Verbs -> Ghost -> Re-enter corpse)" + to_chat(ghost, "Your corpse has been placed into a cloning scanner. Return to your body if you want to be resurrected/cloned! (Verbs -> Ghost -> Re-enter corpse)") break return @@ -177,7 +193,14 @@ if (src.occupant.client) src.occupant.client.eye = src.occupant.client.mob src.occupant.client.perspective = MOB_PERSPECTIVE - src.occupant.loc = src.loc + if(istype(occupant,/mob/living/carbon/brain)) + for(var/obj/O in src) + if(istype(O,/obj/item/organ/internal/brain)) + O.loc = get_turf(src) + src.occupant.loc = O + break + else + src.occupant.loc = src.loc src.occupant = null src.icon_state = "scanner_0" return diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 850f061250..7237669a77 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -149,7 +149,7 @@ datum/objective/anti_revolution/demote if(!istype(I)) return 1 - if(I.assignment == "Assistant") + if(I.assignment == USELESS_JOB) //VOREStation Edit - Visitor not Assistant return 1 else return 0 diff --git a/code/game/jobs/job/assistant.dm b/code/game/jobs/job/assistant.dm index 50f22c6fef..d558d7b14e 100644 --- a/code/game/jobs/job/assistant.dm +++ b/code/game/jobs/job/assistant.dm @@ -1,23 +1,50 @@ +//VOREStation Edit - Basically this whole file +/datum/job/intern + title = "Intern" + flag = INTERN + department = "Civilian" + department_flag = ENGSEC // VOREStation Edit - Ran out of bits + faction = "Station" + total_positions = -1 + spawn_positions = -1 + supervisors = "the staff from the departmen you're interning in" + selection_color = "#555555" + economic_modifier = 2 + access = list() //See /datum/job/assistant/get_access() + minimal_access = list() //See /datum/job/assistant/get_access() + outfit_type = /decl/hierarchy/outfit/job/assistant/intern + alt_titles = list("Apprentice Engineer","Medical Intern","Lab Assistant","Security Cadet","Jr. Cargo Tech") //VOREStation Edit +//VOREStation Add +/datum/job/intern/New() + ..() + if(config) + total_positions = config.limit_interns + spawn_positions = config.limit_interns +//VOREStation Add End + +// VOREStation Add /datum/job/assistant - title = "Assistant" + title = USELESS_JOB flag = ASSISTANT department = "Civilian" department_flag = CIVILIAN faction = "Station" total_positions = -1 spawn_positions = -1 - supervisors = "absolutely everyone" + supervisors = "nobody! You don't work here" selection_color = "#515151" economic_modifier = 1 - access = list() //See /datum/job/assistant/get_access() - minimal_access = list() //See /datum/job/assistant/get_access() + access = list() + minimal_access = list() outfit_type = /decl/hierarchy/outfit/job/assistant - alt_titles = list("Technical Assistant","Test Subject","Medical Intern","Research Assistant", - "Visitor" = /decl/hierarchy/outfit/job/assistant/visitor, - "Resident" = /decl/hierarchy/outfit/job/assistant/resident) //Test Subject is a VOREStation edit - +/datum/job/assistant/New() + ..() + if(config) + total_positions = config.limit_visitors + spawn_positions = config.limit_visitors /datum/job/assistant/get_access() if(config.assistant_maint) return list(access_maint_tunnels) else return list() +//VOREStation Add End diff --git a/code/game/jobs/job/captain.dm b/code/game/jobs/job/captain.dm index 89aaae88f5..269484239b 100644 --- a/code/game/jobs/job/captain.dm +++ b/code/game/jobs/job/captain.dm @@ -36,7 +36,7 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) /datum/job/hop title = "Head of Personnel" flag = HOP - department = "Civilian" + department = "Command" head_position = 1 department_flag = CIVILIAN faction = "Station" @@ -71,7 +71,7 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) /datum/job/secretary title = "Command Secretary" flag = BRIDGE - department = "Civilian" + department = "Command" head_position = 1 department_flag = CIVILIAN faction = "Station" @@ -83,8 +83,8 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) minimal_player_age = 5 economic_modifier = 7 - access = list(access_heads) - minimal_access = list(access_heads) + access = list(access_heads, access_keycard_auth) + minimal_access = list(access_heads, access_keycard_auth) outfit_type = /decl/hierarchy/outfit/job/secretary - alt_titles = list("Command Liaison", "Bridge Secretary") \ No newline at end of file + alt_titles = list("Command Liaison", "Bridge Secretary") diff --git a/code/game/jobs/job/civilian.dm b/code/game/jobs/job/civilian.dm index 9786c72ea0..c9a9e4d23e 100644 --- a/code/game/jobs/job/civilian.dm +++ b/code/game/jobs/job/civilian.dm @@ -56,12 +56,13 @@ title = "Quartermaster" flag = QUARTERMASTER department = "Cargo" + head_position = 1 department_flag = CIVILIAN faction = "Station" total_positions = 1 spawn_positions = 1 supervisors = "the head of personnel" - selection_color = "#515151" + selection_color = "#7a4f33" idtype = /obj/item/weapon/card/id/cargo/head economic_modifier = 5 access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station) @@ -81,7 +82,7 @@ total_positions = 2 spawn_positions = 2 supervisors = "the quartermaster and the head of personnel" - selection_color = "#515151" + selection_color = "#9b633e" idtype = /obj/item/weapon/card/id/cargo/cargo_tech access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_mining, access_mining_station) minimal_access = list(access_maint_tunnels, access_cargo, access_cargo_bot, access_mailsorting) @@ -97,7 +98,7 @@ total_positions = 3 spawn_positions = 3 supervisors = "the quartermaster and the head of personnel" - selection_color = "#515151" + selection_color = "#9b633e" idtype = /obj/item/weapon/card/id/cargo/mining economic_modifier = 5 access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_mining, access_mining_station) diff --git a/code/game/jobs/job/job_vr.dm b/code/game/jobs/job/job_vr.dm index d1bb79e7cc..71cb74a950 100644 --- a/code/game/jobs/job/job_vr.dm +++ b/code/game/jobs/job/job_vr.dm @@ -3,4 +3,11 @@ var/whitelist_only = 0 //Does not display this job on the occupation setup screen - var/latejoin_only = 0 \ No newline at end of file + var/latejoin_only = 0 + + //Every hour playing this role gains this much time off. (Can be negative for off duty jobs!) + var/timeoff_factor = 3 + +// Check client-specific availability rules. +/datum/job/proc/player_has_enough_pto(client/C) + return timeoff_factor >= 0 || (C && LAZYACCESS(C.department_hours, department) > 0) diff --git a/code/game/jobs/job/offduty_vr.dm b/code/game/jobs/job/offduty_vr.dm new file mode 100644 index 0000000000..420943c562 --- /dev/null +++ b/code/game/jobs/job/offduty_vr.dm @@ -0,0 +1,81 @@ +// +// "Off-duty" jobs are for people who want to do nothing and have earned it. +// + +/datum/job/offduty_civilian + title = "Off-Duty Worker" + latejoin_only = TRUE + timeoff_factor = -1 + total_positions = -1 + faction = "Station" + department = "Civilian" + supervisors = "nobody! Enjoy your time off" + selection_color = "#9b633e" + access = list(access_maint_tunnels) + minimal_access = list(access_maint_tunnels) + outfit_type = /decl/hierarchy/outfit/job/assistant + +/datum/job/offduty_cargo + title = "Off-duty Cargo" + latejoin_only = TRUE + timeoff_factor = -1 + total_positions = -1 + faction = "Station" + department = "Cargo" + supervisors = "nobody! Enjoy your time off" + selection_color = "#9b633e" + access = list(access_maint_tunnels) + minimal_access = list(access_maint_tunnels) + outfit_type = /decl/hierarchy/outfit/job/assistant + +/datum/job/offduty_engineering + title = "Off-duty Engineer" + latejoin_only = TRUE + timeoff_factor = -1 + total_positions = -1 + faction = "Station" + department = "Engineering" + supervisors = "nobody! Enjoy your time off" + selection_color = "#5B4D20" + access = list(access_maint_tunnels, access_external_airlocks, access_construction) + minimal_access = list(access_maint_tunnels, access_external_airlocks) + outfit_type = /decl/hierarchy/outfit/job/assistant + +/datum/job/offduty_medical + title = "Off-duty Medic" + latejoin_only = TRUE + timeoff_factor = -1 + total_positions = -1 + faction = "Station" + department = "Medical" + supervisors = "nobody! Enjoy your time off" + selection_color = "#013D3B" + access = list(access_maint_tunnels, access_external_airlocks) + minimal_access = list(access_maint_tunnels, access_external_airlocks) + outfit_type = /decl/hierarchy/outfit/job/assistant + +/datum/job/offduty_science + title = "Off-duty Scientist" + latejoin_only = TRUE + timeoff_factor = -1 + total_positions = -1 + faction = "Station" + department = "Science" + supervisors = "nobody! Enjoy your time off" + selection_color = "#633D63" + access = list(access_maint_tunnels) + minimal_access = list(access_maint_tunnels) + outfit_type = /decl/hierarchy/outfit/job/assistant + +/datum/job/offduty_security + title = "Off-duty Officer" + latejoin_only = TRUE + timeoff_factor = -1 + total_positions = -1 + faction = "Station" + department = "Security" + supervisors = "nobody! Enjoy your time off" + selection_color = "#601C1C" + access = list(access_maint_tunnels) + minimal_access = list(access_maint_tunnels) + outfit_type = /decl/hierarchy/outfit/job/assistant diff --git a/code/game/jobs/job/special_sc_vr.dm b/code/game/jobs/job/special_sc_vr.dm deleted file mode 100644 index 8750fc6578..0000000000 --- a/code/game/jobs/job/special_sc_vr.dm +++ /dev/null @@ -1,194 +0,0 @@ -//These are a copy of Polaris' Southern Cross jobs - -var/const/access_pilot = 67 -var/const/access_explorer = 43 - -//////////////////////////////////////////////////////////// - -/datum/access/pilot - id = access_pilot - desc = "Pilot" - region = ACCESS_REGION_SUPPLY - -/datum/access/explorer - id = access_explorer - desc = "Explorer" - region = ACCESS_REGION_GENERAL - -//////////////////////////////////////////////////////////// - -/obj/item/weapon/card/id/medical/sar - assignment = "Search and Rescue" - rank = "Search and Rescue" - job_access_type = /datum/job/sar - -/obj/item/weapon/card/id/civilian/pilot - assignment = "Pilot" - rank = "Pilot" - job_access_type = /datum/job/pilot - -/obj/item/weapon/card/id/civilian/explorer - assignment = "Explorer" - rank = "Explorer" - job_access_type = /datum/job/explorer - -//////////////////////////////////////////////////////////// - -/datum/job/pilot - title = "Pilot" - flag = PILOT - department = "Civilian" - department_flag = MEDSCI - faction = "Station" - total_positions = 2 - spawn_positions = 2 - supervisors = "the head of personnel" - selection_color = "#515151" - idtype = /obj/item/weapon/card/id/civilian/pilot - economic_modifier = 4 - whitelist_only = 1 - latejoin_only = 1 - access = list(access_pilot, access_cargo, access_mining, access_mining_station) - minimal_access = list(access_pilot, access_cargo, access_mining, access_mining_station) - outfit_type = /decl/hierarchy/outfit/job/pilot - -/datum/job/explorer - title = "Explorer" - flag = EXPLORER - department = "Science" - department_flag = MEDSCI - faction = "Station" - total_positions = 4 - spawn_positions = 4 - supervisors = "the explorer leader and the head of personnel" - selection_color = "#515151" - idtype = /obj/item/weapon/card/id/civilian/explorer - economic_modifier = 4 - whitelist_only = 1 - latejoin_only = 1 - access = list(access_pilot, access_explorer) - minimal_access = list(access_pilot, access_explorer) - outfit_type = /decl/hierarchy/outfit/job/explorer2 -/* I split this into multiple jobs because it's set to latejoin_only, which means you can't see it to select alt titles. - alt_titles = list( - "Explorer Technician" = /decl/hierarchy/outfit/job/explorer2/technician, - "Explorer Medic" = /decl/hierarchy/outfit/job/explorer2/medic) -*/ - -/datum/job/explorer/technician - title = "Explorer Technician" - flag = EXPLORER_T - outfit_type = /decl/hierarchy/outfit/job/explorer2/technician - -/datum/job/explorer/medic - title = "Explorer Medic" - flag = EXPLORER_M - outfit_type = /decl/hierarchy/outfit/job/explorer2/medic - -/datum/job/sar - title = "Search and Rescue" - flag = SAR - department = "Medical" - department_flag = MEDSCI - faction = "Station" - total_positions = 2 - spawn_positions = 2 - supervisors = "the chief medical officer" - selection_color = "#515151" - idtype = /obj/item/weapon/card/id/medical - economic_modifier = 4 - whitelist_only = 1 - latejoin_only = 1 - access = list(access_medical, access_medical_equip, access_morgue, access_surgery, access_chemistry, access_virology, access_eva, access_maint_tunnels, access_external_airlocks, access_psychiatrist, access_explorer) - minimal_access = list(access_medical, access_medical_equip, access_morgue, access_explorer) - outfit_type = /decl/hierarchy/outfit/job/medical/sar - -//////////////////////////////////////////////////////////// - -/decl/hierarchy/outfit/job/explorer2 - name = OUTFIT_JOB_NAME("Explorer") - shoes = /obj/item/clothing/shoes/boots/winter/explorer - uniform = /obj/item/clothing/under/explorer - l_ear = /obj/item/device/radio/headset/explorer - id_slot = slot_wear_id - pda_slot = slot_l_store - pda_type = /obj/item/device/pda/cargo // Brown looks more rugged - id_type = /obj/item/weapon/card/id/civilian/explorer - id_pda_assignment = "Explorer" - -/decl/hierarchy/outfit/job/explorer2/technician - name = OUTFIT_JOB_NAME("Explorer Technician") - belt = /obj/item/weapon/storage/belt/utility/full - pda_slot = slot_l_store - id_pda_assignment = "Explorer Technician" - -/decl/hierarchy/outfit/job/explorer2/medic - name = OUTFIT_JOB_NAME("Explorer Medic") - l_hand = /obj/item/weapon/storage/firstaid/regular - pda_slot = slot_l_store - id_pda_assignment = "Explorer Medic" - -/decl/hierarchy/outfit/job/pilot - name = OUTFIT_JOB_NAME("Pilot") - shoes = /obj/item/clothing/shoes/black - uniform = /obj/item/clothing/under/color/black - suit = /obj/item/clothing/suit/storage/toggle/bomber - gloves = /obj/item/clothing/gloves/fingerless - glasses = /obj/item/clothing/glasses/fakesunglasses/aviator - l_ear = /obj/item/device/radio/headset/pilot - id_slot = slot_wear_id - pda_slot = slot_belt - pda_type = /obj/item/device/pda/cargo // Brown looks more rugged - id_type = /obj/item/weapon/card/id/civilian/pilot - id_pda_assignment = "Pilot" - -/decl/hierarchy/outfit/job/medical/sar - name = OUTFIT_JOB_NAME("Search and Rescue") - uniform = /obj/item/clothing/under/utility/blue - suit = /obj/item/clothing/suit/storage/hooded/wintercoat/medical/sar - shoes = /obj/item/clothing/shoes/boots/winter/explorer - l_hand = /obj/item/weapon/storage/firstaid/adv - belt = /obj/item/weapon/storage/belt/medical/emt - pda_slot = slot_l_store - id_type = /obj/item/weapon/card/id/medical/sar - id_pda_assignment = "Search and Rescue" - flags = OUTFIT_HAS_BACKPACK|OUTFIT_EXTENDED_SURVIVAL - -//////////////////////////////////////////////////////////// - -/obj/item/device/encryptionkey/pilot - name = "pilot's encryption key" - icon_state = "com_cypherkey" - channels = list("Supply" = 1, "Explorer" = 1) - -/obj/item/device/encryptionkey/explorer - name = "explorer radio encryption key" - icon_state = "com_cypherkey" - channels = list("Explorer" = 1) - -//////////////////////////////////////////////////////////// - -/obj/item/device/radio/headset/pilot - name = "pilot's headset" - desc = "A bowman headset used by pilots, has access to supply and explorer channels." - icon_state = "cargo_headset_alt" - item_state = "headset" - ks2type = /obj/item/device/encryptionkey/pilot - -/obj/item/device/radio/headset/explorer - name = "explorer's headset" - desc = "Headset used by explorers for exploring. Access to the explorer channel." - icon_state = "mine_headset" - item_state = "headset" - ks2type = /obj/item/device/encryptionkey/explorer - -//////////////////////////////////////////////////////////// - -/obj/item/clothing/suit/storage/hooded/wintercoat/medical/sar - name = "search and rescue winter coat" - desc = "A heavy winter jacket. A white star of life is emblazoned on the back, with the words search and rescue written underneath." - icon_state = "coatsar" - item_icons = list(slot_wear_suit_str = 'maps/southern_cross/icons/mob/sc_suit.dmi') - icon = 'maps/southern_cross/icons/obj/sc_suit.dmi' - armor = list(melee = 15, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 50, rad = 5) - valid_accessory_slots = list(ACCESSORY_SLOT_INSIGNIA) diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index f88dd1f555..d6b9b7aeb4 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -25,6 +25,7 @@ var/global/datum/controller/occupations/job_master if(!job) continue if(job.faction != faction) continue occupations += job + sortTim(occupations, /proc/cmp_job_datums) return 1 @@ -116,7 +117,7 @@ var/global/datum/controller/occupations/job_master if(job.minimum_character_age && (player.client.prefs.age < job.minimum_character_age)) continue - if(istype(job, GetJob("Assistant"))) // We don't want to give him assistant, that's boring! + if(istype(job, GetJob(USELESS_JOB))) // We don't want to give him assistant, that's boring! //VOREStation Edit - Visitor not Assistant continue if(job.title in command_positions) //If you want a command position, select it! @@ -241,7 +242,7 @@ var/global/datum/controller/occupations/job_master Debug("AC1, Candidates: [assistant_candidates.len]") for(var/mob/new_player/player in assistant_candidates) Debug("AC1 pass, Player: [player]") - AssignRole(player, "Assistant") + AssignRole(player, USELESS_JOB) //VOREStation Edit - Visitor not Assistant assistant_candidates -= player Debug("DO, AC1 end") @@ -322,7 +323,7 @@ var/global/datum/controller/occupations/job_master for(var/mob/new_player/player in unassigned) if(player.client.prefs.alternate_option == BE_ASSISTANT) Debug("AC2 Assistant located, Player: [player]") - AssignRole(player, "Assistant") + AssignRole(player, USELESS_JOB) //VOREStation Edit - Visitor not Assistant //For ones returning to lobby for(var/mob/new_player/player in unassigned) @@ -480,10 +481,9 @@ var/global/datum/controller/occupations/job_master R = locate() in S.contents if(!l_foot || !r_foot || R) var/obj/structure/bed/chair/wheelchair/W = new /obj/structure/bed/chair/wheelchair(H.loc) - H.buckled = W + W.buckle_mob(H) H.update_canmove() W.set_dir(H.dir) - W.buckled_mobs |= H W.add_fingerprint(H) if(R) W.color = R.color diff --git a/code/game/jobs/jobs.dm b/code/game/jobs/jobs.dm index 083c3699b8..667d351a9d 100644 --- a/code/game/jobs/jobs.dm +++ b/code/game/jobs/jobs.dm @@ -11,7 +11,7 @@ var/const/ENGINEER =(1<<6) var/const/ATMOSTECH =(1<<7) var/const/AI =(1<<8) var/const/CYBORG =(1<<9) - +var/const/INTERN =(1<<15) //VOREStation Add var/const/MEDSCI =(1<<1) @@ -26,11 +26,6 @@ var/const/PSYCHIATRIST =(1<<7) var/const/ROBOTICIST =(1<<8) var/const/XENOBIOLOGIST =(1<<9) var/const/PARAMEDIC =(1<<10) -var/const/SAR =(1<<11) //VOREStation THEFT -var/const/PILOT =(1<<12) //VOREStation THEFT -var/const/EXPLORER =(1<<13) //VOREStation THEFT -var/const/EXPLORER_T =(1<<14) //VOREStation THEFT -var/const/EXPLORER_M =(1<<15) //VOREStation THEFT var/const/CIVILIAN =(1<<2) @@ -109,7 +104,8 @@ var/list/civilian_positions = list( "Lawyer", "Chaplain", "Pilot", // VOREStation Edit - Moved Pilot from planetary -> civ - "Assistant" + USELESS_JOB, //VOREStation Edit - Visitor not Assistant + "Intern" //VOREStation Edit - Intern ) diff --git a/code/game/jobs/whitelist_vr.dm b/code/game/jobs/whitelist_vr.dm index 0fce896808..058a9c0dc1 100644 --- a/code/game/jobs/whitelist_vr.dm +++ b/code/game/jobs/whitelist_vr.dm @@ -15,7 +15,7 @@ var/list/job_whitelist = list() var/datum/job/job = job_master.GetJob(rank) if(!job.whitelist_only) return 1 - if(rank == "assistant" || rank == "Assistant") + if(rank == USELESS_JOB) //VOREStation Edit - Visitor not Assistant return 1 if(check_rights(R_ADMIN, 0)) return 1 diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index 8c9737cd9d..da7475780a 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -103,6 +103,9 @@ unregister_radio(src, frequency) qdel(wires) wires = null + if(alarm_area && alarm_area.master_air_alarm == src) + alarm_area.master_air_alarm = null + elect_master(exclude_self = TRUE) return ..() /obj/machinery/alarm/New() @@ -272,8 +275,10 @@ /obj/machinery/alarm/proc/master_is_operating() return alarm_area && alarm_area.master_air_alarm && !(alarm_area.master_air_alarm.stat & (NOPOWER | BROKEN)) -/obj/machinery/alarm/proc/elect_master() +/obj/machinery/alarm/proc/elect_master(exclude_self = FALSE) for(var/obj/machinery/alarm/AA in alarm_area) + if(exclude_self && AA == src) + continue if(!(AA.stat & (NOPOWER|BROKEN))) alarm_area.master_air_alarm = AA return 1 diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 9bed646bc5..4e1d015033 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -153,7 +153,7 @@ modifier_lower_bound = round(modifier_lower_bound * clone_sickness_length, 1) modifier_upper_bound = round(modifier_upper_bound * clone_sickness_length, 1) - H.add_modifier(/datum/modifier/cloning_sickness, rand(modifier_lower_bound, modifier_upper_bound)) + H.add_modifier(H.species.cloning_modifier, rand(modifier_lower_bound, modifier_upper_bound)) // Modifier that doesn't do anything. H.add_modifier(/datum/modifier/cloned) @@ -342,7 +342,10 @@ occupant.client.perspective = MOB_PERSPECTIVE occupant.loc = src.loc eject_wait = 0 //If it's still set somehow. - domutcheck(occupant) //Waiting until they're out before possible transforming. + if(ishuman(occupant)) //Need to be safe. + var/mob/living/carbon/human/patient = occupant + if(!(patient.species.flags & NO_SCAN)) //If, for some reason, someone makes a genetically-unalterable clone, let's not make them permanently disabled. + domutcheck(occupant) //Waiting until they're out before possible transforming. occupant = null biomass -= CLONE_BIOMASS diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index dc67821301..8bf00b4ace 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -40,19 +40,19 @@ if(!usr || usr.stat || usr.lying) return if(scan) - usr << "You remove \the [scan] from \the [src]." + to_chat(usr, "You remove \the [scan] from \the [src].") scan.forceMove(get_turf(src)) if(!usr.get_active_hand() && istype(usr,/mob/living/carbon/human)) usr.put_in_hands(scan) scan = null else if(modify) - usr << "You remove \the [modify] from \the [src]." + to_chat(usr, "You remove \the [modify] from \the [src].") modify.forceMove(get_turf(src)) if(!usr.get_active_hand() && istype(usr,/mob/living/carbon/human)) usr.put_in_hands(modify) modify = null else - usr << "There is nothing to remove from the console." + to_chat(usr, "There is nothing to remove from the console.") return /obj/machinery/computer/card/attackby(obj/item/weapon/card/id/id_card, mob/user) @@ -82,12 +82,15 @@ /obj/machinery/computer/card/ui_interact(mob/user, ui_key="main", var/datum/nanoui/ui = null, var/force_open = 1) user.set_machine(src) + if(data_core) + data_core.get_manifest_list() + var/data[0] data["src"] = "\ref[src]" data["station_name"] = station_name() data["mode"] = mode data["printing"] = printing - data["manifest"] = data_core ? data_core.get_manifest(0) : null + data["manifest"] = PDA_Manifest data["target_name"] = modify ? modify.name : "-----" data["target_owner"] = modify && modify.registered_name ? modify.registered_name : "-----" data["target_rank"] = get_target_rank() @@ -99,13 +102,16 @@ data["all_centcom_access"] = null data["regions"] = null - data["engineering_jobs"] = format_jobs(engineering_positions) - data["medical_jobs"] = format_jobs(medical_positions) - data["science_jobs"] = format_jobs(science_positions) - data["security_jobs"] = format_jobs(security_positions) - data["cargo_jobs"] = format_jobs(cargo_positions) - data["civilian_jobs"] = format_jobs(civilian_positions) - data["centcom_jobs"] = format_jobs(get_all_centcom_jobs()) + data["jobs"] = list( + list("cat" = "Engineering", "jobs" = format_jobs(engineering_positions)), + list("cat" = "Medical", "jobs" = format_jobs(medical_positions)), + list("cat" = "Science", "jobs" = format_jobs(science_positions)), + list("cat" = "Security", "jobs" = format_jobs(security_positions)), + list("cat" = "Cargo", "jobs" = format_jobs(cargo_positions)), + list("cat" = "Planetside", "jobs" = format_jobs(planet_positions)), + list("cat" = "Civilian", "jobs" = format_jobs(civilian_positions)), + list("cat" = "CentCom", "jobs" = format_jobs(get_all_centcom_jobs())) + ) if (modify && is_centcom()) var/list/all_centcom_access = list() @@ -209,7 +215,7 @@ jobdatum = J break if(!jobdatum) - usr << "No log exists for this job: [t1]" + to_chat(usr, "No log exists for this job: [t1]") return access = jobdatum.get_access() diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index 0bd354b541..1e08ea6df2 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -289,10 +289,13 @@ add_fingerprint(usr) /obj/machinery/computer/cloning/proc/scan_mob(mob/living/carbon/human/subject as mob) - if ((isnull(subject)) || (!(ishuman(subject))) || (!subject.dna)) + var/brain_skip = 0 + if (istype(subject, /mob/living/carbon/brain)) //Brain scans. + brain_skip = 1 + if ((isnull(subject)) || (!(ishuman(subject)) && !brain_skip) || (!subject.dna)) scantemp = "Error: Unable to locate valid genetic data." return - if (!subject.has_brain()) + if (!subject.has_brain() && !brain_skip) if(istype(subject, /mob/living/carbon/human)) var/mob/living/carbon/human/H = subject if(H.should_have_organ("brain")) @@ -313,7 +316,7 @@ if (NOCLONE in subject.mutations) scantemp = "Error: Mental interface failure." return - if (subject.species && subject.species.flags & NO_SCAN) + if (subject.species && subject.species.flags & NO_SCAN && !brain_skip) scantemp = "Error: Mental interface failure." return for(var/modifier_type in subject.modifiers) //Can't be cloned, even if they had a previous scan @@ -333,7 +336,10 @@ R.name = R.dna.real_name R.types = DNA2_BUF_UI|DNA2_BUF_UE|DNA2_BUF_SE R.languages = subject.languages - R.flavor = subject.flavor_texts.Copy() + if(!brain_skip) //Brains don't have flavor text. + R.flavor = subject.flavor_texts.Copy() + else + R.flavor = list() for(var/datum/modifier/mod in subject.modifiers) if(mod.flags & MODIFIER_GENETIC) R.genetic_modifiers.Add(mod.type) diff --git a/code/game/machinery/holosign.dm b/code/game/machinery/holosign.dm index f438f7d003..215238a80b 100644 --- a/code/game/machinery/holosign.dm +++ b/code/game/machinery/holosign.dm @@ -12,6 +12,7 @@ var/lit = 0 var/id = null var/on_icon = "sign_on" + var/off_icon = "sign_off" /obj/machinery/holosign/proc/toggle() if(stat & (BROKEN|NOPOWER)) @@ -22,7 +23,7 @@ /obj/machinery/holosign/update_icon() if(!lit) - icon_state = "sign_off" + icon_state = off_icon else icon_state = on_icon @@ -40,7 +41,16 @@ /obj/machinery/holosign/exit name = "exit holosign" desc = "Small wall-mounted holographic projector. This one reads EXIT." - on_icon = "exit" + on_icon = "emergencyexit" + +/obj/machinery/holosign/bar + name = "bar holosign" + desc = "Small wall-mounted holographic projector. This one reads OPEN." + icon_state = "barclosed" + on_icon = "baropen" + off_icon = "barclosed" + + ////////////////////SWITCH/////////////////////////////////////// /obj/machinery/button/holosign diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 840cd5d24c..f6650301c7 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -62,6 +62,7 @@ var/wrenching = 0 var/last_target //last target fired at, prevents turrets from erratically firing at all valid targets in range var/timeout = 10 // When a turret pops up, then finds nothing to shoot at, this number decrements until 0, when it pops down. + var/can_salvage = TRUE // If false, salvaging doesn't give you anything. /obj/machinery/porta_turret/crescent enabled = 0 @@ -102,6 +103,7 @@ desc = "A very tough looking turret made by alien hands. This one looks destroyed, thankfully." icon_state = "destroyed_target_prism" stat = BROKEN + can_salvage = FALSE // So you need to actually kill a turret to get the alien gun. /obj/machinery/porta_turret/New() ..() @@ -325,7 +327,7 @@ var/list/turret_icons //try and salvage its components user << "You begin prying the metal coverings off." if(do_after(user, 20)) - if(prob(70)) + if(can_salvage && prob(70)) user << "You remove the turret and salvage some components." if(installation) var/obj/item/weapon/gun/energy/Gun = new installation(loc) diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index 1951ba7c47..94aef886d0 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -352,6 +352,18 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() var/broadcasting = 1 var/receiving = 1 +// VOREStation Edit - Make sure constructed relays keep relaying for their current Z when moved by shuttles. +/obj/machinery/telecomms/relay/proc/update_z() + if (initial(listening_level) == 0) + var/turf/T = get_turf(src) + listening_level = T.z + +/area/shuttle_arrived() + . = ..() + for(var/obj/machinery/telecomms/relay/R in contents) + R.update_z() +// VOREStation Edit End + /obj/machinery/telecomms/relay/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) // Add our level and send it back diff --git a/code/game/mecha/micro/micro.dm b/code/game/mecha/micro/micro.dm index 080167e2ea..6da9b830c6 100644 --- a/code/game/mecha/micro/micro.dm +++ b/code/game/mecha/micro/micro.dm @@ -35,7 +35,6 @@ var/update = 0 switch(damtype) if("brute") - H.Paralyse(1) update |= temp.take_damage(rand(force/2, force), 0) if("fire") update |= temp.take_damage(0, rand(force/2, force)) @@ -86,10 +85,7 @@ src.visible_message("[src.name] hits [target]") if(!istype(target, /turf/simulated/wall)) target:attackby(src,src.occupant) - else if(prob(5)) - target:dismantle_wall(1) - src.occupant_message("You smash through the wall.") - src.visible_message("[src.name] smashes through the wall") + else playsound(src, 'sound/weapons/smash.ogg', 50, 1) melee_can_hit = 0 if(do_after(melee_cooldown)) diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm index c51a34adef..74014f2b0f 100644 --- a/code/game/mecha/working/ripley.dm +++ b/code/game/mecha/working/ripley.dm @@ -3,11 +3,13 @@ name = "APLU \"Ripley\"" icon_state = "ripley" initial_icon = "ripley" - step_in = 6 + step_in = 5 // vorestation edit, was 6 but that's PAINFULLY slow + step_energy_drain = 5 // vorestation edit because 10 drained a significant chunk of its cell before you even got out the airlock max_temperature = 20000 health = 200 wreckage = /obj/effect/decal/mecha_wreckage/ripley cargo_capacity = 10 + var/obj/item/weapon/mining_scanner/orescanner // vorestation addition /obj/mecha/working/ripley/Destroy() for(var/atom/movable/A in src.cargo) @@ -67,3 +69,19 @@ qdel (B) +// VORESTATION EDIT BEGIN + +/obj/mecha/working/ripley/New() + ..() + orescanner = new /obj/item/weapon/mining_scanner + +/obj/mecha/working/ripley/verb/detect_ore() + set category = "Exosuit Interface" + set name = "Detect Ores" + set src = usr.loc + set popup_menu = 0 + + orescanner.attack_self(usr) + +// VORESTATION EDIT END + diff --git a/code/game/objects/effects/step_triggers.dm b/code/game/objects/effects/step_triggers.dm index 18f66e70f5..eb1ebcd268 100644 --- a/code/game/objects/effects/step_triggers.dm +++ b/code/game/objects/effects/step_triggers.dm @@ -96,7 +96,18 @@ Trigger(var/atom/movable/A) if(teleport_x && teleport_y && teleport_z) var/turf/T = locate(teleport_x, teleport_y, teleport_z) - A.forceMove(T) + if(isliving(A)) + var/mob/living/L = A + if(L.pulling) + var/atom/movable/P = L.pulling + L.stop_pulling() + P.forceMove(T) + L.forceMove(T) + L.start_pulling(P) + else + A.forceMove(T) + else + A.forceMove(T) /* Random teleporter, teleports atoms to locations ranging from teleport_x - teleport_x_offset, etc */ @@ -145,10 +156,7 @@ var/global/list/tele_landmarks = list() // Terrible, but the alternative is loop /obj/effect/step_trigger/teleporter/planetary_fall var/datum/planet/planet = null -/* //VOREStation Removal -/obj/effect/step_trigger/teleporter/planetary_fall/sif/initialize() - planet = planet_sif -*/ //VOREStation Removal end + /obj/effect/step_trigger/teleporter/planetary_fall/Trigger(var/atom/movable/A) if(planet) if(!planet.planet_floors.len) @@ -158,7 +166,10 @@ var/global/list/tele_landmarks = list() // Terrible, but the alternative is loop var/safety = 100 // Infinite loop protection. while(!T && safety) var/turf/simulated/candidate = pick(planet.planet_floors) - if(!istype(candidate) || istype(candidate, /turf/simulated/sky) || !T.outdoors) + if(!istype(candidate) || istype(candidate, /turf/simulated/sky)) + safety-- + continue + else if(candidate && !candidate.outdoors) safety-- continue else diff --git a/code/game/objects/items/devices/communicator/communicator.dm b/code/game/objects/items/devices/communicator/communicator.dm index ad3ad9522f..4ab3644374 100644 --- a/code/game/objects/items/devices/communicator/communicator.dm +++ b/code/game/objects/items/devices/communicator/communicator.dm @@ -174,6 +174,11 @@ var/global/list/obj/item/device/communicator/all_communicators = list() // Description: Simple check to see if the exonet node is active. /obj/item/device/communicator/proc/get_connection_to_tcomms() if(node && node.on && node.allow_external_communicators && !is_jammed(src)) + // VOREStation Edit Start - Lose connection if too far from our exonet node. + var/turf/T = get_turf(src) + if(!T || !is_on_same_plane_or_station(T.z, node.z)) + return 0 + // VOREStation Edit End return 1 return 0 diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index ba5d338a0d..2b40faac66 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -180,6 +180,13 @@ item_state = "headset" ks2type = /obj/item/device/encryptionkey/heads/captain +/obj/item/device/radio/headset/heads/captain/sfr + name = "SFR headset" + desc = "A headset belonging to a Sif Free Radio DJ. SFR, best tunes in the wilderness." + icon_state = "com_headset_alt" + item_state = "headset" + ks2type = /obj/item/device/encryptionkey/heads/captain + /obj/item/device/radio/headset/heads/ai_integrated //No need to care about icons, it should be hidden inside the AI anyway. name = "\improper AI subspace transceiver" desc = "Integrated AI radio transceiver." diff --git a/code/game/objects/items/poi_items.dm b/code/game/objects/items/poi_items.dm new file mode 100644 index 0000000000..8d11e747f6 --- /dev/null +++ b/code/game/objects/items/poi_items.dm @@ -0,0 +1,54 @@ + +/obj/item/poi + icon = 'icons/obj/objects.dmi' + desc = "This is definitely something cool." + +/obj/item/poi/pascalb + icon_state = "pascalb" + name = "misshapen manhole cover" + desc = "The top of this twisted chunk of metal is faintly stamped with a five pointed star. 'Property of US Army, Pascal B - 1957'." + +/obj/item/poi/pascalb/New() + processing_objects += src + return ..() + +/obj/item/poi/pascalb/process() + radiation_repository.radiate(src, 5) + +/obj/item/poi/pascalb/Destroy() + processing_objects -= src + return ..() + +/obj/structure/closet/crate/oldreactor + name = "fission reactor rack" + desc = "Used in older models of nuclear reactors, essentially a cooling rack for high volumes of radioactive material." + icon = 'icons/obj/objects.dmi' + icon_state = "poireactor" + icon_opened = "poireactor_open" + icon_closed = "poireactor" + climbable = 0 + +/obj/structure/closet/crate/oldreactor/New() + ..() + new /obj/item/weapon/fuel_assembly/deuterium(src) + new /obj/item/weapon/fuel_assembly/deuterium(src) + new /obj/item/weapon/fuel_assembly/deuterium(src) + new /obj/item/weapon/fuel_assembly/deuterium(src) + new /obj/item/weapon/fuel_assembly/deuterium(src) + new /obj/item/weapon/fuel_assembly/deuterium(src) + +/obj/item/poi/brokenoldreactor + icon_state = "poireactor_broken" + name = "ruptured fission reactor rack" + desc = "This broken hunk of machinery looks extremely dangerous." + +/obj/item/poi/brokenoldreactor/New() + processing_objects += src + return ..() + +/obj/item/poi/brokenoldreactor/process() + radiation_repository.radiate(src, 25) + +/obj/item/poi/brokenoldreactor/Destroy() + processing_objects -= src + return ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm index df744d1df3..8f5719b8e8 100644 --- a/code/game/objects/items/weapons/RCD.dm +++ b/code/game/objects/items/weapons/RCD.dm @@ -122,10 +122,7 @@ build_delay = deconstruct ? 50 : 20 build_cost = deconstruct ? 10 : 3 build_type = deconstruct ? "floor" : "wall" - if(F.check_destroy_override(F)) - build_turf = deconstruct ? destroy_floor_override_path : /turf/simulated/wall - else - build_turf = deconstruct ? /turf/space : /turf/simulated/wall + build_turf = deconstruct ? get_base_turf_by_area(F) : /turf/simulated/wall if(!build_type) working = 0 diff --git a/code/game/objects/items/weapons/circuitboards/machinery/power.dm b/code/game/objects/items/weapons/circuitboards/machinery/power.dm index 57d8822df6..6242335bed 100644 --- a/code/game/objects/items/weapons/circuitboards/machinery/power.dm +++ b/code/game/objects/items/weapons/circuitboards/machinery/power.dm @@ -29,3 +29,13 @@ board_type = new /datum/frame/frame_types/machine origin_tech = list(TECH_POWER = 4, TECH_ENGINEERING = 3) req_components = list(/obj/item/weapon/stock_parts/capacitor = 3, /obj/item/stack/cable_coil = 10) + +/obj/item/weapon/circuitboard/breakerbox + name = T_BOARD("breaker box") + build_path = /obj/machinery/power/breakerbox + board_type = new /datum/frame/frame_types/machine + origin_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 3) + req_components = list( + /obj/item/weapon/stock_parts/spring = 1, + /obj/item/weapon/stock_parts/manipulator = 1, + /obj/item/stack/cable_coil = 10) diff --git a/code/game/objects/items/weapons/id cards/station_ids.dm b/code/game/objects/items/weapons/id cards/station_ids.dm index e0975361eb..4c1e4b9aaf 100644 --- a/code/game/objects/items/weapons/id cards/station_ids.dm +++ b/code/game/objects/items/weapons/id cards/station_ids.dm @@ -353,8 +353,8 @@ job_access_type = /datum/job/qm /obj/item/weapon/card/id/assistant - assignment = "Assistant" - rank = "Assistant" + assignment = USELESS_JOB //VOREStation Edit - Visitor not Assistant + rank = USELESS_JOB //VOREStation Edit - Visitor not Assistant job_access_type = /datum/job/assistant /obj/item/weapon/card/id/civilian diff --git a/code/game/objects/items/weapons/storage/backpack.dm b/code/game/objects/items/weapons/storage/backpack.dm index d34bb3565d..c564ebe466 100644 --- a/code/game/objects/items/weapons/storage/backpack.dm +++ b/code/game/objects/items/weapons/storage/backpack.dm @@ -399,28 +399,28 @@ return if(!parachute) //This packs the parachute - visible_message("\The [H] starts to pack \the [src]!", \ + H.visible_message("\The [H] starts to pack \the [src]!", \ "You start to pack \the [src]!", \ "You hear the shuffling of cloth.") if(do_after(H, 50)) - visible_message("\The [H] finishes packing \the [src]!", \ + H.visible_message("\The [H] finishes packing \the [src]!", \ "You finish packing \the [src]!", \ "You hear the shuffling of cloth.") parachute = TRUE else - visible_message("\The [src] gives up on packing \the [src]!", \ + H.visible_message("\The [src] gives up on packing \the [src]!", \ "You give up on packing \the [src]!") return else //This unpacks the parachute - visible_message("\The [src] starts to unpack \the [src]!", \ + H.visible_message("\The [src] starts to unpack \the [src]!", \ "You start to unpack \the [src]!", \ "You hear the shuffling of cloth.") if(do_after(H, 25)) - visible_message("\The [src] finishes unpacking \the [src]!", \ + H.visible_message("\The [src] finishes unpacking \the [src]!", \ "You finish unpacking \the [src]!", \ "You hear the shuffling of cloth.") parachute = FALSE else - visible_message("\The [src] decides not to unpack \the [src]!", \ + H.visible_message("\The [src] decides not to unpack \the [src]!", \ "You decide not to unpack \the [src]!") return \ No newline at end of file diff --git a/code/game/objects/items/weapons/storage/backpack_vr.dm b/code/game/objects/items/weapons/storage/backpack_vr.dm index a3b7644152..9615cc8183 100644 --- a/code/game/objects/items/weapons/storage/backpack_vr.dm +++ b/code/game/objects/items/weapons/storage/backpack_vr.dm @@ -116,4 +116,9 @@ icon_state = "taurvest" icon_base = "taurvest" max_storage_space = INVENTORY_STANDARD_SPACE - slowdown = 0 \ No newline at end of file + slowdown = 0 + +/obj/item/weapon/storage/backpack/dufflebag/fluff //Black dufflebag without syndie buffs. + name = "plain black dufflebag" + desc = "A large dufflebag for holding extra tactical supplies." + icon_state = "duffle_syndie" \ No newline at end of file diff --git a/code/game/objects/random/random.dm b/code/game/objects/random/random.dm index 73cca5bdfd..1787a47bc8 100644 --- a/code/game/objects/random/random.dm +++ b/code/game/objects/random/random.dm @@ -902,6 +902,32 @@ something, make sure it's not in one of the other lists.*/ prob(1);/obj/item/weapon/beartrap, prob(2);/obj/item/weapon/handcuffs,) +/obj/random/sfr + name = "random SFR headset" + desc = "This is a headset spawn." + icon = 'icons/misc/mark.dmi' + icon_state = "rup" + +/obj/random/sfr/item_to_spawn() + return pick(prob(25);/obj/item/device/radio/headset/heads/captain/sfr, + prob(25);/obj/item/device/radio/headset/headset_cargo/alt, + prob(25);/obj/item/device/radio/headset/headset_com/alt, + prob(25);/obj/item/device/radio/headset) + +/obj/random/rigsuit + name = "Random rigsuit" + desc = "This is a random rigsuit." + icon = 'icons/obj/rig_modules.dmi' + icon_state = "generic" + +/obj/random/rigsuit/item_to_spawn() + return pick(prob(4);/obj/item/weapon/rig/light/hacker, + prob(5);/obj/item/weapon/rig/industrial, + prob(5);/obj/item/weapon/rig/eva, + prob(4);/obj/item/weapon/rig/light/stealth, + prob(3);/obj/item/weapon/rig/hazard, + prob(1);/obj/item/weapon/rig/merc/empty) + var/list/random_junk_ var/list/random_useful_ /proc/get_random_useful_type() @@ -999,6 +1025,11 @@ var/list/multi_point_spawns id = "Captain's spare id" item_path = /obj/item/weapon/card/id/gold/captain/spare +/obj/random_multi/single_item/sfr_headset + name = "Multi Point - headset" + id = "SFR headset" + item_path = /obj/random/sfr + //Multiple Object Spawn /obj/random/multiple diff --git a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm index f9f77fa684..f4f24e8d50 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm @@ -1,6 +1,6 @@ /obj/structure/closet/secure_closet/guncabinet name = "gun cabinet" - req_access = list(access_armory) + req_one_access = list(access_armory) icon = 'icons/obj/guncabinet.dmi' icon_state = "base" icon_off ="base" diff --git a/code/game/objects/structures/crates_lockers/largecrate_vr.dm b/code/game/objects/structures/crates_lockers/largecrate_vr.dm index b64fdab337..63430b54d3 100644 --- a/code/game/objects/structures/crates_lockers/largecrate_vr.dm +++ b/code/game/objects/structures/crates_lockers/largecrate_vr.dm @@ -53,7 +53,8 @@ /mob/living/simple_animal/hostile/bear;0.5, /mob/living/simple_animal/hostile/bear/brown;0.5, /mob/living/simple_animal/hostile/carp, - /mob/living/simple_animal/hostile/mimic) + /mob/living/simple_animal/hostile/mimic, + /mob/living/simple_animal/otie;0.5) ..() @@ -78,16 +79,28 @@ desc = "The VARMAcorp bioengineering division flagship product on trained optimal snowflake guard dogs." icon = 'icons/obj/storage_vr.dmi' icon_state = "sotiecrate" - held_type = /mob/living/simple_animal/otie/friendly/security + held_type = /mob/living/simple_animal/otie/security + +/obj/structure/largecrate/animal/guardmutant + name = "VARMAcorp autoNOMous security solution for hostile environments." + desc = "The VARMAcorp bioengineering division flagship product on trained optimal snowflake guard dogs. This one can survive hostile atmosphere." + icon = 'icons/obj/storage_vr.dmi' + icon_state = "sotiecrate" + held_type = /mob/living/simple_animal/otie/security/phoron /obj/structure/largecrate/animal/otie name = "VARMAcorp adoptable reject (Dangerous!)" desc = "A warning on the side says the creature inside was returned to the supplier after injuring or devouring several unlucky members of the previous adoption family. It was given a second chance with the next customer. Godspeed and good luck with your new pet!" icon = 'icons/obj/storage_vr.dmi' icon_state = "otiecrate2" - held_type = /mob/living/simple_animal/otie/friendly/cotie + held_type = /mob/living/simple_animal/otie/cotie var/taped = 1 +/obj/structure/largecrate/animal/otie/phoron + name = "VARMAcorp adaptive beta subject (Experimental)" + desc = "VARMAcorp experimental hostile environment adaptive breeding development kit. WARNING, DO NOT RELEASE IN WILD!" + held_type = /mob/living/simple_animal/otie/cotie/phoron + /obj/structure/largecrate/animal/otie/attack_hand(mob/living/carbon/human/M as mob)//I just couldn't decide between the icons lmao if(taped == 1) playsound(src, 'sound/items/poster_ripped.ogg', 50, 1) diff --git a/code/game/objects/structures/dogbed.dm b/code/game/objects/structures/dogbed.dm new file mode 100644 index 0000000000..bf9a65f8eb --- /dev/null +++ b/code/game/objects/structures/dogbed.dm @@ -0,0 +1,8 @@ +/obj/structure/dogbed + name = "dog bed" + desc = "A bed made especially for dogs, or other similarly sized pets." + icon = 'icons/obj/furniture.dmi' + icon_state = "dogbed" + can_buckle = 1 + buckle_dir = SOUTH + buckle_lying = 1 \ No newline at end of file diff --git a/code/game/objects/structures/flora/trees.dm b/code/game/objects/structures/flora/trees.dm index b01c3ace96..872eea47d5 100644 --- a/code/game/objects/structures/flora/trees.dm +++ b/code/game/objects/structures/flora/trees.dm @@ -73,6 +73,7 @@ return is_stump = TRUE + density = FALSE icon_state = "[base_state]_stump" overlays.Cut() // For the Sif tree and other future glowy trees. set_light(0) diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 29b7d89ab7..a3ff9ac9af 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -6,9 +6,65 @@ w_class = ITEMSIZE_HUGE var/state = 0 var/health = 200 + var/max_health = 200 + var/displaced_health = 50 + var/current_damage = 0 var/cover = 50 //how much cover the girder provides against projectiles. + var/default_material = DEFAULT_WALL_MATERIAL + var/material/girder_material var/material/reinf_material var/reinforcing = 0 + var/applies_material_colour = 1 + +/obj/structure/girder/New(var/newloc, var/material_key) + ..(newloc) + if(!material_key) + material_key = default_material + set_material(material_key) + update_icon() + +/obj/structure/girder/Destroy() + if(girder_material.products_need_process()) + processing_objects -= src + . = ..() + +/obj/structure/girder/process() + if(!radiate()) + processing_objects -= src + return + +/obj/structure/girder/proc/radiate() + var/total_radiation = girder_material.radioactivity + (reinf_material ? reinf_material.radioactivity / 2 : 0) + if(!total_radiation) + return + + radiation_repository.radiate(src, total_radiation) + return total_radiation + + +/obj/structure/girder/proc/set_material(var/new_material) + girder_material = get_material_by_name(new_material) + if(!girder_material) + qdel(src) + name = "[girder_material.display_name] [initial(name)]" + max_health = round(girder_material.integrity) //Should be 150 with default integrity (steel). Weaker than ye-olden Girders now. + health = max_health + displaced_health = round(max_health/4) + if(applies_material_colour) + color = girder_material.icon_colour + if(girder_material.products_need_process()) //Am I radioactive or some other? Process me! + processing_objects |= src + else if(src in processing_objects) //If I happened to be radioactive or s.o. previously, and am not now, stop processing. + processing_objects -= src + +/obj/structure/girder/get_material() + return girder_material + +/obj/structure/girder/update_icon() + if(anchored) + icon_state = "girder" + else + icon_state = "displaced" /obj/structure/girder/displaced icon_state = "displaced" @@ -16,6 +72,17 @@ health = 50 cover = 25 +/obj/structure/girder/displaced/New(var/newloc, var/material_key) + ..(newloc, material_key) + displace() + +/obj/structure/girder/proc/displace() + name = "displaced [girder_material.display_name] [initial(name)]" + icon_state = "displaced" + anchored = 0 + health = (displaced_health - round(current_damage / 4)) + cover = 25 + /obj/structure/girder/attack_generic(var/mob/user, var/damage, var/attack_message = "smashes apart", var/wallbreaker) if(!damage || !wallbreaker) return 0 @@ -36,6 +103,25 @@ if(!istype(Proj, /obj/item/projectile/beam)) damage *= 0.4 //non beams do reduced damage + else if(girder_material && girder_material.reflectivity >= 0.5) // Reflect lasers. + var/new_damage = damage * girder_material.reflectivity + var/outgoing_damage = damage - new_damage + damage = round(new_damage) + Proj.damage = outgoing_damage + + visible_message("\The [src] reflects \the [Proj]!") + + // Find a turf near or on the original location to bounce to + var/new_x = Proj.starting.x + pick(0, 0, 0, -1, 1, -2, 2) + var/new_y = Proj.starting.y + pick(0, 0, 0, -1, 1, -2, 2) + //var/turf/curloc = get_turf(src) + var/turf/curloc = get_step(src, get_dir(src, Proj.starting)) + + Proj.penetrating += 1 // Needed for the beam to get out of the girder. + + // redirect the projectile + Proj.redirect(new_x, new_y, curloc, null) + health -= damage ..() if(health <= 0) @@ -47,9 +133,10 @@ dismantle() /obj/structure/girder/proc/reset_girder() + name = "[girder_material.display_name] [initial(name)]" anchored = 1 cover = initial(cover) - health = min(health,initial(health)) + health = min(max_health - current_damage,max_health) state = 0 icon_state = initial(icon_state) reinforcing = 0 @@ -60,62 +147,59 @@ if(istype(W, /obj/item/weapon/wrench) && state == 0) if(anchored && !reinf_material) playsound(src, W.usesound, 100, 1) - user << "Now disassembling the girder..." - if(do_after(user,40 * W.toolspeed)) + to_chat(user, "Now disassembling the girder...") + if(do_after(user,(35 + round(max_health/50)) * W.toolspeed)) if(!src) return - user << "You dissasembled the girder!" + to_chat(user, "You dissasembled the girder!") dismantle() else if(!anchored) playsound(src, W.usesound, 100, 1) - user << "Now securing the girder..." + to_chat(user, "Now securing the girder...") if(do_after(user, 40 * W.toolspeed, src)) - user << "You secured the girder!" + to_chat(user, "You secured the girder!") reset_girder() else if(istype(W, /obj/item/weapon/pickaxe/plasmacutter)) - user << "Now slicing apart the girder..." + to_chat(user, "Now slicing apart the girder...") if(do_after(user,30 * W.toolspeed)) if(!src) return - user << "You slice apart the girder!" + to_chat(user, "You slice apart the girder!") dismantle() else if(istype(W, /obj/item/weapon/pickaxe/diamonddrill)) - user << "You drill through the girder!" + to_chat(user, "You drill through the girder!") dismantle() else if(istype(W, /obj/item/weapon/screwdriver)) if(state == 2) playsound(src, W.usesound, 100, 1) - user << "Now unsecuring support struts..." + to_chat(user, "Now unsecuring support struts...") if(do_after(user,40 * W.toolspeed)) if(!src) return - user << "You unsecured the support struts!" + to_chat(user, "You unsecured the support struts!") state = 1 else if(anchored && !reinf_material) playsound(src, W.usesound, 100, 1) reinforcing = !reinforcing - user << "\The [src] can now be [reinforcing? "reinforced" : "constructed"]!" + to_chat(user, "\The [src] can now be [reinforcing? "reinforced" : "constructed"]!") else if(istype(W, /obj/item/weapon/wirecutters) && state == 1) playsound(src, W.usesound, 100, 1) - user << "Now removing support struts..." + to_chat(user, "Now removing support struts...") if(do_after(user,40 * W.toolspeed)) if(!src) return - user << "You removed the support struts!" + to_chat(user, "You removed the support struts!") reinf_material.place_dismantled_product(get_turf(src)) reinf_material = null reset_girder() else if(istype(W, /obj/item/weapon/crowbar) && state == 0 && anchored) playsound(src, W.usesound, 100, 1) - user << "Now dislodging the girder..." + to_chat(user, "Now dislodging the girder...") if(do_after(user, 40 * W.toolspeed)) if(!src) return - user << "You dislodged the girder!" - icon_state = "displaced" - anchored = 0 - health = 50 - cover = 25 + to_chat(user, "You dislodged the girder!") + displace() else if(istype(W, /obj/item/stack/material)) if(reinforcing && !reinf_material) @@ -130,14 +214,16 @@ /obj/structure/girder/proc/take_damage(var/damage) health -= damage - if(health <= 0) dismantle() + else + current_damage = current_damage + damage //Rather than calculate this every time we need to use it, just calculate it here and save it. + /obj/structure/girder/proc/construct_wall(obj/item/stack/material/S, mob/user) var/amount_to_use = reinf_material ? 1 : 2 if(S.get_amount() < amount_to_use) - user << "There isn't enough material here to construct a wall." + to_chat(user, "There isn't enough material here to construct a wall.") return 0 var/material/M = name_to_material[S.default_type] @@ -148,24 +234,24 @@ add_hiddenprint(usr) if(M.integrity < 50) - user << "This material is too soft for use in wall construction." + to_chat(user, "This material is too soft for use in wall construction.") return 0 - user << "You begin adding the plating..." + to_chat(user, "You begin adding the plating...") if(!do_after(user,40) || !S.use(amount_to_use)) return 1 //once we've gotten this far don't call parent attackby() if(anchored) - user << "You added the plating!" + to_chat(user, "You added the plating!") else - user << "You create a false wall! Push on it to open or close the passage." + to_chat(user, "You create a false wall! Push on it to open or close the passage.") wall_fake = 1 var/turf/Tsrc = get_turf(src) Tsrc.ChangeTurf(/turf/simulated/wall) var/turf/simulated/wall/T = get_turf(src) - T.set_material(M, reinf_material) + T.set_material(M, reinf_material, girder_material) if(wall_fake) T.can_open = 1 T.add_hiddenprint(usr) @@ -174,22 +260,22 @@ /obj/structure/girder/proc/reinforce_with_material(obj/item/stack/material/S, mob/user) //if the verb is removed this can be renamed. if(reinf_material) - user << "\The [src] is already reinforced." + to_chat(user, "\The [src] is already reinforced.") return 0 if(S.get_amount() < 1) - user << "There isn't enough material here to reinforce the girder." + to_chat(user, "There isn't enough material here to reinforce the girder.") return 0 var/material/M = name_to_material[S.default_type] if(!istype(M) || M.integrity < 50) - user << "You cannot reinforce \the [src] with that; it is too soft." + to_chat(user, "You cannot reinforce \the [src] with that; it is too soft.") return 0 - user << "Now reinforcing..." + to_chat(user, "Now reinforcing...") if (!do_after(user,40) || !S.use(1)) return 1 //don't call parent attackby() past this point - user << "You added reinforcement!" + to_chat(user, "You added reinforcement!") reinf_material = M reinforce_girder() @@ -197,13 +283,13 @@ /obj/structure/girder/proc/reinforce_girder() cover = reinf_material.hardness - health = 500 + health = health + round(reinf_material.integrity/2) state = 2 icon_state = "reinforced" reinforcing = 0 /obj/structure/girder/proc/dismantle() - new /obj/item/stack/material/steel(get_turf(src)) + girder_material.place_dismantled_product(get_turf(src)) qdel(src) /obj/structure/girder/attack_hand(mob/user as mob) @@ -235,6 +321,8 @@ icon_state= "cultgirder" health = 250 cover = 70 + girder_material = DEFAULT_WALL_MATERIAL + applies_material_colour = 0 /obj/structure/girder/cult/dismantle() new /obj/effect/decal/remains/human(get_turf(src)) @@ -243,18 +331,18 @@ /obj/structure/girder/cult/attackby(obj/item/W as obj, mob/user as mob) if(istype(W, /obj/item/weapon/wrench)) playsound(src, W.usesound, 100, 1) - user << "Now disassembling the girder..." + to_chat(user, "Now disassembling the girder...") if(do_after(user,40 * W.toolspeed)) - user << "You dissasembled the girder!" + to_chat(user, "You dissasembled the girder!") dismantle() else if(istype(W, /obj/item/weapon/pickaxe/plasmacutter)) - user << "Now slicing apart the girder..." + to_chat(user, "Now slicing apart the girder...") if(do_after(user,30 * W.toolspeed)) - user << "You slice apart the girder!" + to_chat(user, "You slice apart the girder!") dismantle() else if(istype(W, /obj/item/weapon/pickaxe/diamonddrill)) - user << "You drill through the girder!" + to_chat(user, "You drill through the girder!") new /obj/effect/decal/remains/human(get_turf(src)) dismantle() diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm index 14e8b894ba..2d26821bbe 100644 --- a/code/game/objects/structures/signs.dm +++ b/code/game/objects/structures/signs.dm @@ -156,6 +156,9 @@ /obj/structure/sign/warning/docking_area name = "\improper KEEP CLEAR: DOCKING AREA" + +/obj/structure/sign/warning/evac + name = "\improper KEEP CLEAR: EVAC DOCKING AREA" icon_state = "evac" /obj/structure/sign/warning/engineering_access @@ -777,3 +780,13 @@ /obj/structure/sign/atmos/air name = "\improper AIR" icon_state = "atmos_air" + +/obj/structure/sign/poi/engineleft + name = "I.C.V." + desc = "The charred name of a cargo ship of some description." + icon_state = "poi_engine1" + +/obj/structure/sign/poi/engineright + name = "I.C.V." + desc = "The charred name of a cargo ship of some description." + icon_state = "poi_engine2" \ No newline at end of file diff --git a/code/game/objects/structures/trash_pile.dm b/code/game/objects/structures/trash_pile.dm index 0f4df54472..c8b771ab88 100644 --- a/code/game/objects/structures/trash_pile.dm +++ b/code/game/objects/structures/trash_pile.dm @@ -190,6 +190,7 @@ prob(2);/obj/item/weapon/reagent_containers/glass/rag, prob(2);/obj/item/weapon/storage/box/sinpockets, prob(2);/obj/item/weapon/storage/secure/briefcase, + prob(2);/obj/item/clothing/under/fluff/latexmaid, prob(1);/obj/item/clothing/glasses/sunglasses, prob(1);/obj/item/clothing/glasses/welding, prob(1);/obj/item/clothing/gloves/yellow, diff --git a/code/game/turfs/flooring/flooring_decals.dm b/code/game/turfs/flooring/flooring_decals.dm index 6e2d4e48ac..1d981771ae 100644 --- a/code/game/turfs/flooring/flooring_decals.dm +++ b/code/game/turfs/flooring/flooring_decals.dm @@ -5,8 +5,8 @@ var/list/floor_decals = list() /obj/effect/floor_decal name = "floor decal" - icon = 'icons/turf/flooring/decals_vr.dmi' - layer = TURF_LAYER + 0.01 + icon = 'icons/turf/flooring/decals_vr.dmi' // VOREStation Edit + layer = DECALS_LAYER var/supplied_dir /obj/effect/floor_decal/New(var/newloc, var/newdir, var/newcolour) diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index a47590d55d..aac979ff5c 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -62,16 +62,6 @@ /turf/simulated/proc/initialize() return -/turf/simulated/proc/check_destroy_override() - if(destroy_floor_override) //Don't bother doing the additional checks if we don't have to. - var/area/my_area = get_area(src) -// my_area = my_area.master - if(is_type_in_list(my_area, destroy_floor_override_ignore_areas)) - return 0 - if(z in destroy_floor_override_z_levels) - return 1 - return 0 - /turf/simulated/proc/AddTracks(var/typepath,var/bloodDNA,var/comingdir,var/goingdir,var/bloodcolor="#A10808") var/obj/effect/decal/cleanable/blood/tracks/tracks = locate(typepath) in src if(!tracks) diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index f2c640d53a..f906335819 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -48,10 +48,10 @@ make_plating(defer_icon_update = 1) flooring = newflooring footstep_sounds = newflooring.footstep_sounds - // VOREStation Edit - Remember decals from before we were pried up - if(islist(old_decals)) - decals = old_decals - old_decals = null + // VOREStation Edit - We are plating switching to flooring, swap out old_decals for decals + var/tmp/list/overfloor_decals = old_decals + old_decals = decals + decals = overfloor_decals // VOREStation Edit End update_icon(1) levelupdate() @@ -61,12 +61,12 @@ /turf/simulated/floor/proc/make_plating(var/place_product, var/defer_icon_update) overlays.Cut() - if(islist(decals)) - // VOREStation Edit - Don't forget decals when pried up - if(flooring) - old_decals = decals - // VOREStation Edit End - decals = null + // VOREStation Edit - We are flooring switching to plating, swap out old_decals for decals. + if(flooring) + var/tmp/list/underfloor_decals = old_decals + old_decals = decals + decals = underfloor_decals + // VOREStation Edit End name = base_name desc = base_desc diff --git a/code/game/turfs/simulated/floor_icon.dm b/code/game/turfs/simulated/floor_icon.dm index f9feed86ba..940a170cdb 100644 --- a/code/game/turfs/simulated/floor_icon.dm +++ b/code/game/turfs/simulated/floor_icon.dm @@ -1,5 +1,15 @@ var/list/flooring_cache = list() +var/image/no_ceiling_image = null + +/hook/startup/proc/setup_no_ceiling_image() + cache_no_ceiling_image() + return TRUE + +/proc/cache_no_ceiling_image() + no_ceiling_image = image(icon = 'icons/turf/open_space.dmi', icon_state = "no_ceiling", layer = OVERTURF_LAYER) + no_ceiling_image.plane = PLANE_MESONS + /turf/simulated/floor/update_icon(var/update_neighbors) if(lava) @@ -84,6 +94,11 @@ var/list/flooring_cache = list() continue F.update_icon() + // 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 + /turf/simulated/floor/proc/get_flooring_overlay(var/cache_key, var/icon_base, var/icon_dir = 0) if(!flooring_cache[cache_key]) var/image/I = image(icon = flooring.icon, icon_state = icon_base, dir = icon_dir) diff --git a/code/game/turfs/simulated/floor_types.dm b/code/game/turfs/simulated/floor_types.dm index f5beaf312d..8789ddef80 100644 --- a/code/game/turfs/simulated/floor_types.dm +++ b/code/game/turfs/simulated/floor_types.dm @@ -12,6 +12,7 @@ var/turf/turf_type var/turf/simulated/shuttle/my_turf var/image/turf_image + var/list/decals New(var/location = null, var/turf/simulated/shuttle/turf) my_turf = turf @@ -24,6 +25,7 @@ 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 //Set the destination to be like us T.Destroy() @@ -33,13 +35,17 @@ new_dest.icon = my_turf.icon new_dest.overlays = my_turf.overlays new_dest.underlays = my_turf.underlays - //Shuttle specific stuff + new_dest.decals = my_turf.decals + //Shuttle specific stuff new_dest.interior_corner = my_turf.interior_corner new_dest.takes_underlays = my_turf.takes_underlays new_dest.under_turf = my_turf.under_turf 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 @@ -48,6 +54,7 @@ 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 //Update underlays if necessary (interior corners won't have changed). if(new_dest.takes_underlays && !new_dest.interior_corner) @@ -65,6 +72,9 @@ new_source.icon = icon new_source.overlays = overlays 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) @@ -93,6 +103,8 @@ return 0 var/turf/under //May be a path or a turf + var/mutable_appearance/us = new(src) //We'll use this for changes later + us.underlays.Cut() //Mapper wanted something specific if(under_turf) @@ -100,8 +112,10 @@ //Well if this isn't our first rodeo, we know EXACTLY what we landed on, and it looks like this. if(landed_holder && !interior_corner) - underlays.Cut() - underlays += image(landed_holder,layer=FLOAT_LAYER) + var/mutable_appearance/landed_on = new(landed_holder) + landed_on.layer = FLOAT_LAYER //Not turf + us.underlays = list(landed_on) + appearance = us return if(!under) @@ -122,20 +136,26 @@ else under = get_base_turf_by_area(src) - var/use_icon = ispath(under) ? initial(under.icon) : under.icon - var/use_icon_state - if(istype(under,/turf/simulated/shuttle)) interior_corner = 1 //Prevents us from 'landing on grass' and having interior corners update. - if(ispath(under,/turf/space)) - use_icon_state = "[rand(1,25)]" //Space turfs should be random. - else - use_icon_state = ispath(under) ? initial(under.icon_state) : under.icon_state + var/mutable_appearance/under_ma - var/image/under_image = new(use_icon,icon_state = use_icon_state) - underlays.Cut() - underlays |= under_image + if(ispath(under)) //It's just a mapper-specified path + under_ma = new() + under_ma.icon = initial(under.icon) + under_ma.icon_state = initial(under.icon_state) + under_ma.color = initial(under.color) + + else //It's a real turf + under_ma = new(under) + + if(under_ma) + if(ispath(under,/turf/space)) //Scramble space turfs + under_ma.icon_state = "[rand(1,25)]" + us.underlays = list(under_ma) + + appearance = us return under diff --git a/code/game/turfs/simulated/outdoors/atmoscaves_vr.dm b/code/game/turfs/simulated/outdoors/atmoscaves_vr.dm new file mode 100644 index 0000000000..8ac5dc08e5 --- /dev/null +++ b/code/game/turfs/simulated/outdoors/atmoscaves_vr.dm @@ -0,0 +1,19 @@ +/turf/simulated/mineral/cave + oxygen = MOLES_O2STANDARD + nitrogen = MOLES_N2STANDARD + temperature = T20C + +/turf/simulated/mineral/ignore_mapgen/cave + oxygen = MOLES_O2STANDARD + nitrogen = MOLES_N2STANDARD + temperature = T20C + +/turf/simulated/mineral/floor/cave + oxygen = MOLES_O2STANDARD + nitrogen = MOLES_N2STANDARD + temperature = T20C + +/turf/simulated/mineral/floor/ignore_mapgen/cave + oxygen = MOLES_O2STANDARD + nitrogen = MOLES_N2STANDARD + temperature = T20C diff --git a/code/game/turfs/simulated/wall_icon.dm b/code/game/turfs/simulated/wall_icon.dm index eab99bfba7..2dac063723 100644 --- a/code/game/turfs/simulated/wall_icon.dm +++ b/code/game/turfs/simulated/wall_icon.dm @@ -31,9 +31,13 @@ update_icon() -/turf/simulated/wall/proc/set_material(var/material/newmaterial, var/material/newrmaterial) +/turf/simulated/wall/proc/set_material(var/material/newmaterial, var/material/newrmaterial, var/material/newgmaterial) material = newmaterial reinf_material = newrmaterial + if(!newgmaterial) + girder_material = DEFAULT_WALL_MATERIAL + else + girder_material = newgmaterial update_material() /turf/simulated/wall/update_icon() diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index e29541fb04..21fd9492f0 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -14,6 +14,7 @@ var/global/damage_overlays[16] var/active var/can_open = 0 + var/material/girder_material var/material/material var/material/reinf_material var/last_state @@ -26,12 +27,15 @@ for(var/obj/O in src) O.hide(1) -/turf/simulated/wall/New(var/newloc, var/materialtype, var/rmaterialtype) +/turf/simulated/wall/New(var/newloc, var/materialtype, var/rmaterialtype, var/girdertype) ..(newloc) icon_state = "blank" if(!materialtype) materialtype = DEFAULT_WALL_MATERIAL material = get_material_by_name(materialtype) + if(!girdertype) + girdertype = DEFAULT_WALL_MATERIAL + girder_material = get_material_by_name(girdertype) if(!isnull(rmaterialtype)) reinf_material = get_material_by_name(rmaterialtype) update_material() @@ -120,18 +124,18 @@ . = ..(user) if(!damage) - user << "It looks fully intact." + to_chat(user, "It looks fully intact.") else var/dam = damage / material.integrity if(dam <= 0.3) - user << "It looks slightly damaged." + to_chat(user, "It looks slightly damaged.") else if(dam <= 0.6) - user << "It looks moderately damaged." + to_chat(user, "It looks moderately damaged.") else - user << "It looks heavily damaged." + to_chat(user, "It looks heavily damaged.") if(locate(/obj/effect/overlay/wallrot) in src) - user << "There is fungus growing on [src]." + to_chat(user, "There is fungus growing on [src].") //Damage @@ -186,9 +190,9 @@ playsound(src, 'sound/items/Welder.ogg', 100, 1) if(!no_product) if(reinf_material) - reinf_material.place_dismantled_girder(src, reinf_material) + reinf_material.place_dismantled_girder(src, reinf_material, girder_material) else - material.place_dismantled_girder(src) + material.place_dismantled_girder(src, null, girder_material) if(!devastated) material.place_dismantled_product(src) if (!reinf_material) @@ -204,6 +208,7 @@ clear_plants() material = get_material_by_name("placeholder") reinf_material = null + girder_material = null update_connections(1) ChangeTurf(/turf/simulated/floor/plating) @@ -211,10 +216,9 @@ /turf/simulated/wall/ex_act(severity) switch(severity) if(1.0) - if(check_destroy_override()) - src.ChangeTurf(destroy_floor_override_path) - else - src.ChangeTurf(get_base_turf_by_area(src)) //VOREStation Edit - Use area base turf + if(girder_material.explosion_resistance >= 25 && prob(girder_material.explosion_resistance)) + new /obj/structure/girder/displaced(src, girder_material.name) + src.ChangeTurf(get_base_turf_by_area(src)) if(2.0) if(prob(75)) take_damage(rand(150, 250)) @@ -250,12 +254,15 @@ O.density = 1 O.layer = 5 - src.ChangeTurf(/turf/simulated/floor/plating) + if(girder_material.integrity >= 150 && !girder_material.is_brittle()) //Strong girders will remain in place when a wall is melted. + dismantle_wall(1,1) + else + src.ChangeTurf(/turf/simulated/floor/plating) var/turf/simulated/floor/F = src F.burn_tile() - F.icon_state = "wall_thermite" - user << "The thermite starts melting through the wall." + F.icon_state = "dmg[rand(1,4)]" + to_chat(user, "The thermite starts melting through the wall.") spawn(100) if(O) @@ -264,7 +271,7 @@ return /turf/simulated/wall/proc/radiate() - var/total_radiation = material.radioactivity + (reinf_material ? reinf_material.radioactivity / 2 : 0) + var/total_radiation = material.radioactivity + (reinf_material ? reinf_material.radioactivity / 2 : 0) + (girder_material ? girder_material.radioactivity / 2 : 0) if(!total_radiation) return @@ -274,7 +281,7 @@ /turf/simulated/wall/proc/burn(temperature) if(material.combustion_effect(src, temperature, 0.7)) spawn(2) - new /obj/structure/girder(src) + new /obj/structure/girder(src, girder_material.name) src.ChangeTurf(/turf/simulated/floor) for(var/turf/simulated/wall/W in range(3,src)) W.burn((temperature/4)) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 6834859502..6168cd86bf 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -91,7 +91,7 @@ turf/attackby(obj/item/weapon/W as obj, mob/user as mob) return if(istype(O, /obj/screen)) return - if(user.restrained() || user.stat || user.stunned || user.paralysis) + if(user.restrained() || user.stat || user.stunned || user.paralysis || (!user.lying && !istype(user, /mob/living/silicon/robot))) return if((!(istype(O, /atom/movable)) || O.anchored || !Adjacent(user) || !Adjacent(O) || !user.Adjacent(O))) return diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm index 8e99f7333c..89940e5532 100644 --- a/code/game/turfs/turf_changing.dm +++ b/code/game/turfs/turf_changing.dm @@ -12,9 +12,14 @@ // Called after turf replaces old one /turf/proc/post_change() levelupdate() - var/turf/simulated/open/T = GetAbove(src) - if(istype(T)) - T.update_icon() + + var/turf/simulated/open/above = GetAbove(src) + if(istype(above)) + above.update_icon() + + var/turf/simulated/below = GetBelow(src) + if(istype(below)) + below.update_icon() // To add or remove the 'ceiling-less' overlay. //Creates a new turf /turf/proc/ChangeTurf(var/turf/N, var/tell_universe=1, var/force_lighting_update = 0) diff --git a/code/game/turfs/unsimulated/beach.dm b/code/game/turfs/unsimulated/beach.dm index bcbb4b133f..c061d1bbf7 100644 --- a/code/game/turfs/unsimulated/beach.dm +++ b/code/game/turfs/unsimulated/beach.dm @@ -22,14 +22,26 @@ /turf/simulated/floor/beach name = "Beach" icon = 'icons/misc/beach.dmi' + footstep_sounds = list("human" = list( + 'sound/effects/footstep/carpet1.ogg', + 'sound/effects/footstep/carpet2.ogg', + 'sound/effects/footstep/carpet3.ogg', + 'sound/effects/footstep/carpet4.ogg', + 'sound/effects/footstep/carpet5.ogg')) /turf/simulated/floor/beach/sand name = "Sand" icon_state = "sand" /turf/simulated/floor/beach/sand/desert + icon = 'icons/turf/desert.dmi' icon_state = "desert" +/turf/simulated/floor/beach/sand/desert/initialize() + ..() + if(prob(5)) + icon_state = "desert[rand(0,4)]" + /turf/simulated/floor/beach/coastline name = "Coastline" icon = 'icons/misc/beach2.dmi' diff --git a/code/game/turfs/unsimulated/planetary.dm b/code/game/turfs/unsimulated/planetary.dm index 7d9159d04a..613638ec80 100644 --- a/code/game/turfs/unsimulated/planetary.dm +++ b/code/game/turfs/unsimulated/planetary.dm @@ -55,6 +55,10 @@ var/list/planetary_walls = list() nitrogen = 114.50978 * 0.819 temperature = 243.15 // Roughly -30C / -22F +//High Alt Sif +/turf/unsimulated/wall/planetary/sif/alt + temperature = 225.15 + // Fairly close to Mars in terms of temperature and pressure. /turf/unsimulated/wall/planetary/magni carbon_dioxide = 0.90998361 diff --git a/code/global.dm b/code/global.dm index 7d4c371643..83712cb131 100644 --- a/code/global.dm +++ b/code/global.dm @@ -38,17 +38,6 @@ var/changelog_hash = "" var/game_year = (text2num(time2text(world.realtime, "YYYY")) + 544) var/round_progressing = 1 - //On some maps, it does not make sense for space turf to appear when something blows up (e.g. on an asteroid colony, or planetside) - //The turf listed here is what is created after ex_act() and other tile-destroying procs are called on a turf that - //is not already in a blacklisted area. - //Set to 1 to enable it. -var/destroy_floor_override = 1 - //Below is the path of turf used in place of space tiles. -var/destroy_floor_override_path = /turf/simulated/mineral/floor - //A list of z-levels to apply the override to. This is so z-levels like tcomms work as they did before. -var/list/destroy_floor_override_z_levels = list(1,4,5) - //Some areas you may want to not turn into the override path you made above, like space or the solars. -var/list/destroy_floor_override_ignore_areas = list(/area/space,/area/solar,/area/shuttle) var/master_mode = "extended" // "extended" var/secret_force_mode = "secret" // if this is anything but "secret", the secret rotation will forceably choose this mode. diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 1946a79730..85e05cf13d 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -103,7 +103,6 @@ var/list/admin_verbs_admin = list( /datum/admins/proc/paralyze_mob, /client/proc/fixatmos, /datum/admins/proc/quick_nif, //VOREStation Add, - /datum/admins/proc/assistant_ratio, //VOREStation Add, /datum/admins/proc/sendFax ) @@ -510,9 +509,11 @@ var/list/admin_verbs_event_manager = list( if(choice == "Show 'em!" && mob.plane_holder) mob.plane_holder.set_vis(VIS_GHOSTS,TRUE) + usr.see_invisible = SEE_INVISIBLE_CULT to_chat(src,"Ghosts are now visible (while in this mob).") else if(mob.plane_holder) mob.plane_holder.set_vis(VIS_GHOSTS,FALSE) + usr.see_invisible = initial(mob.see_invisible) to_chat(src,"Ghosts are now hidden (while in this mob).") /client/proc/invisimin() @@ -786,11 +787,11 @@ var/list/admin_verbs_event_manager = list( set category = "Debug" set name = "Kill Air" set desc = "Toggle Air Processing" - if(air_processing_killed) - air_processing_killed = 0 + if(!SSair.can_fire) + SSair.can_fire = TRUE usr << "Enabled air processing." else - air_processing_killed = 1 + SSair.can_fire = FALSE usr << "Disabled air processing." feedback_add_details("admin_verb","KA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! log_admin("[key_name(usr)] used 'kill air'.") @@ -1051,6 +1052,8 @@ var/list/admin_verbs_event_manager = list( set name = "Man Up" set desc = "Tells mob to man up and deal with it." + if(alert("Are you sure you want to tell them to man up?","Confirmation","Deal with it","No")=="No") return + T << "Man up and deal with it." T << "Move on." @@ -1062,6 +1065,8 @@ var/list/admin_verbs_event_manager = list( set name = "Man Up Global" set desc = "Tells everyone to man up and deal with it." + if(alert("Are you sure you want to tell the whole server up?","Confirmation","Deal with it","No")=="No") return + for (var/mob/T as mob in mob_list) T << "
Man up.
Deal with it.

Move on.

" T << 'sound/voice/ManUp1.ogg' diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 31c5c482e4..e52957853c 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -378,10 +378,15 @@ qdel(adminmob) feedback_add_details("admin_verb","ADC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +/client/proc/take_picture(var/atom/A in world) + set name = "Save PNG" + set category = "Debug" + set desc = "Opens a dialog to save a PNG of any object in the game." + if(!check_rights(R_DEBUG)) + return - - + downloadImage(A) /client/proc/cmd_admin_areatest() set category = "Mapping" diff --git a/code/modules/admin/verbs/debug_vr.dm b/code/modules/admin/verbs/debug_vr.dm index 5484f37771..eb8cd37e01 100644 --- a/code/modules/admin/verbs/debug_vr.dm +++ b/code/modules/admin/verbs/debug_vr.dm @@ -30,18 +30,3 @@ log_and_message_admins("[key_name(src)] Quick NIF'd [H.real_name].") feedback_add_details("admin_verb","QNIF") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - -/datum/admins/proc/assistant_ratio() - set category = "Admin" - set name = "Toggle Asst. Ratio" - set desc = "Toggles the assistant ratio enforcement on/off." - - if(!check_rights(R_ADMIN)) - return - - if(isnull(config.assistants_ratio)) - to_chat(usr,"Assistant ratio enforcement isn't even turned on...") - return - - config.assistants_ratio *= -1 - to_chat(usr,"Assistant ratio enforcement now [config.assistants_ratio > 0 ? "enabled" : "disabled"].") diff --git a/code/modules/admin/verbs/grief_fixers.dm b/code/modules/admin/verbs/grief_fixers.dm index dd28127e4a..7059fef907 100644 --- a/code/modules/admin/verbs/grief_fixers.dm +++ b/code/modules/admin/verbs/grief_fixers.dm @@ -45,10 +45,7 @@ usr << "\[4/5\] - All turfs reset to roundstart values." - qdel(air_master) - air_master = new - air_master.Setup() - spawn air_master.Start() + SSair.RebootZAS() usr << "\[5/5\] - ZAS Rebooted" world << "Atmosphere restart completed in [(world.timeofday - current_time)/10] seconds." \ No newline at end of file diff --git a/code/modules/admin/verbs/map_template_loadverb.dm b/code/modules/admin/verbs/map_template_loadverb.dm index 25fda4bfb3..7fde6c58e1 100644 --- a/code/modules/admin/verbs/map_template_loadverb.dm +++ b/code/modules/admin/verbs/map_template_loadverb.dm @@ -41,7 +41,12 @@ if(!map) return template = map_templates[map] - + + if(template.width > world.maxx || template.height > world.maxy) + if(alert(usr,"This template is larger than the existing z-levels. It will EXPAND ALL Z-LEVELS to match the size of the template. This may cause chaos. Are you sure you want to do this?","DANGER!!!","Cancel","Yes") == "Cancel") + to_chat(usr,"Template placement aborted.") + return + if(alert(usr,"Confirm map load.", "Template Confirm","No","Yes") == "Yes") if(template.load_new_z()) message_admins("[key_name_admin(usr)] has placed a map template ([template.name]) on Z level [world.maxz].") diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 09b7b7bf53..132f89b52a 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -162,7 +162,8 @@ var/list/debug_verbs = list ( ,/datum/admins/proc/setup_supermatter ,/client/proc/atmos_toggle_debug ,/client/proc/spawn_tanktransferbomb - ,/client/proc/debug_process_scheduler + ,/client/proc/debug_process_scheduler // VOREStation Edit - Nice + ,/client/proc/take_picture ) @@ -274,14 +275,7 @@ var/list/debug_verbs = list ( set name = "Reboot ZAS" if(alert("This will destroy and remake all zone geometry on the whole map.","Reboot ZAS","Reboot ZAS","Nevermind") == "Reboot ZAS") - var/datum/controller/air_system/old_air = air_master - for(var/zone/zone in old_air.zones) - zone.c_invalidate() - qdel(old_air) - air_master = new - air_master.Setup() - spawn air_master.Start() - + SSair.RebootZAS() /client/proc/count_objects_on_z_level() set category = "Mapping" diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 961dbdcdfb..42153e9682 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -392,8 +392,8 @@ Traitors and the like can also be revived with the previous role mostly intact. var/samejob = alert(src,"Found [picked_client.prefs.real_name] in data core. They were [record_found.fields["real_rank"]] this round. Assign same job? They will not be re-added to the manifest/records, either way.","Previously spawned","Yes","Assistant","No") if(samejob == "Yes") charjob = record_found.fields["real_rank"] - else if(samejob == "Assistant") - charjob = "Assistant" + else if(samejob == USELESS_JOB) //VOREStation Edit - Visitor not Assistant + charjob = USELESS_JOB //VOREStation Edit - Visitor not Assistant else records = alert(src,"No data core entry detected. Would you like add them to the manifest, and sec/med/HR records?","Records","Yes","No","Cancel") if(records == "Cancel") diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index 01dc830aaa..e386590ec7 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -87,7 +87,7 @@ /obj/effect/landmark/corpse/syndicatesoldier - name = "Syndicate Operative" + name = "Mercenary" corpseuniform = /obj/item/clothing/under/syndicate corpsesuit = /obj/item/clothing/suit/armor/vest corpseshoes = /obj/item/clothing/shoes/boots/swat diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm index b6e8ab59b2..88abd1eb32 100644 --- a/code/modules/awaymissions/gateway.dm +++ b/code/modules/awaymissions/gateway.dm @@ -95,6 +95,9 @@ obj/machinery/gateway/centerstation/process() if(world.time < wait) user << "Error: Warpspace triangulation in progress. Estimated time to completion: [round(((wait - world.time) / 10) / 60)] minutes." return + if(!awaygate.calibrated && LAZYLEN(awaydestinations)) + user << "Error: Destination gate uncalibrated. Gateway unsafe to use without far-end calibration update." + return for(var/obj/machinery/gateway/G in linked) G.active = 1 diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm index 175c94e2d6..f6bf71c9ff 100644 --- a/code/modules/client/client defines.dm +++ b/code/modules/client/client defines.dm @@ -48,8 +48,8 @@ var/player_age = "Requires database" //So admins know why it isn't working - Used to determine how old the account is - in days. var/related_accounts_ip = "Requires database" //So admins know why it isn't working - Used to determine what other accounts previously logged in from this ip var/related_accounts_cid = "Requires database" //So admins know why it isn't working - Used to determine what other accounts previously logged in from this computer id + var/list/department_hours // VOREStation Edit - Track hours of leave accured for each department. preload_rsc = PRELOAD_RSC var/global/obj/screen/click_catcher/void - diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 804ffdc574..cdf9f32a39 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -259,6 +259,15 @@ qdel(src) return 0 + // VOREStation Edit Start - Department Hours + if(config.time_off) + var/DBQuery/query_hours = dbcon.NewQuery("SELECT department, hours FROM vr_player_hours WHERE ckey = '[sql_ckey]'") + query_hours.Execute() + while(query_hours.NextRow()) + LAZYINITLIST(department_hours) + department_hours[query_hours.item[1]] = text2num(query_hours.item[2]) + // VOREStation Edit End - Department Hours + if(sql_id) //Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables var/DBQuery/query_update = dbcon.NewQuery("UPDATE erro_player SET lastseen = Now(), ip = '[sql_ip]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]' WHERE id = [sql_id]") diff --git a/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm b/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm index 642201d23e..86ea0381d0 100644 --- a/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm +++ b/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm @@ -1,72 +1,53 @@ // Collars /datum/gear/collar - display_name = "Collar, Silver" + display_name = "collar, silver" path = /obj/item/clothing/accessory/collar/silver slot = slot_tie sort_category = "Accessories" /datum/gear/collar/golden - display_name = "Collar, Golden" + display_name = "collar, golden" path = /obj/item/clothing/accessory/collar/gold /datum/gear/collar/bell - display_name = "Collar, Bell" + display_name = "collar, bell" path = /obj/item/clothing/accessory/collar/bell /datum/gear/collar/shock - display_name = "Collar, Shock" + display_name = "collar, shock" path = /obj/item/clothing/accessory/collar/shock /datum/gear/collar/spike - display_name = "Collar, Spike" + display_name = "collar, spike" path = /obj/item/clothing/accessory/collar/spike /datum/gear/collar/pink - display_name = "Collar, Pink" + display_name = "collar, pink" path = /obj/item/clothing/accessory/collar/pink /datum/gear/collar/holo - display_name = "Collar, Holo" + display_name = "collar, holo" path = /obj/item/clothing/accessory/collar/holo + /datum/gear/accessory/white_drop_pouches allowed_roles = list("Paramedic","Chief Medical Officer","Medical Doctor","Chemist") /datum/gear/accessory/white_vest allowed_roles = list("Paramedic","Chief Medical Officer","Medical Doctor","Chemist") -/datum/gear/accessory/saddlebag - display_name = "Saddle Bag, Horse" - path = /obj/item/weapon/storage/backpack/saddlebag - slot = slot_back - -/datum/gear/accessory/saddlebag_common - display_name = "Saddle Bag, Common" - path = /obj/item/weapon/storage/backpack/saddlebag_common - slot = slot_back - -/datum/gear/accessory/saddlebag_common/robust - display_name = "Saddle Bag, Robust" - path = /obj/item/weapon/storage/backpack/saddlebag_common/robust - slot = slot_back - -/datum/gear/accessory/saddlebag_common/vest - display_name = "Taur Duty Vest (backpack)" - path = /obj/item/weapon/storage/backpack/saddlebag_common/vest - slot = slot_back - /datum/gear/accessory/khcrystal display_name = "KH Life Crystal" path = /obj/item/weapon/storage/box/khcrystal description = "A small necklace device that will notify an offsite cloning facility should you expire after activating it." /datum/gear/accessory/tronket - display_name = "Metal necklace" + display_name = "metal necklace" description = "A shiny steel chain with a vague metallic object dangling off it." path = /obj/item/clothing/accessory/tronket /datum/gear/accessory/flops - display_name = "Drop straps" + display_name = "drop straps" description = "Wearing suspenders over shoulders? That's been so out for centuries and you know better." path = /obj/item/clothing/accessory/flops diff --git a/code/modules/client/preference_setup/loadout/loadout_eyes_vr.dm b/code/modules/client/preference_setup/loadout/loadout_eyes_vr.dm index 5f89d824c1..d8b29d0d92 100644 --- a/code/modules/client/preference_setup/loadout/loadout_eyes_vr.dm +++ b/code/modules/client/preference_setup/loadout/loadout_eyes_vr.dm @@ -7,9 +7,9 @@ path = /obj/item/clothing/glasses/omnihud/prescription /datum/gear/eyes/spiffygogs - display_name = "Slick orange goggles" + display_name = "slick orange goggles" path = /obj/item/clothing/glasses/fluff/spiffygogs /datum/gear/eyes/science_proper - display_name = "Science goggles (no overlay)" + display_name = "science goggles (no overlay)" path = /obj/item/clothing/glasses/fluff/science_proper \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout_head_vr.dm b/code/modules/client/preference_setup/loadout/loadout_head_vr.dm index 6ed8f3f59c..5a434217e2 100644 --- a/code/modules/client/preference_setup/loadout/loadout_head_vr.dm +++ b/code/modules/client/preference_setup/loadout/loadout_head_vr.dm @@ -3,7 +3,7 @@ path = /obj/item/clothing/head/soft/sol*/ /datum/gear/head/headbando - display_name = "Basic Headband" + display_name = "basic headband" path = /obj/item/clothing/head/fluff/headbando /datum/gear/head/headbando/New() diff --git a/code/modules/client/preference_setup/loadout/loadout_uniform_vr.dm b/code/modules/client/preference_setup/loadout/loadout_uniform_vr.dm index 7192810497..802d3c9b99 100644 --- a/code/modules/client/preference_setup/loadout/loadout_uniform_vr.dm +++ b/code/modules/client/preference_setup/loadout/loadout_uniform_vr.dm @@ -145,7 +145,7 @@ Swimsuits */ /datum/gear/uniform/swimsuits - display_name = "Swimsuits selection" + display_name = "swimsuits selection" path = /obj/item/weapon/storage/box/fluff/swimsuit /datum/gear/uniform/swimsuits/New() @@ -158,4 +158,9 @@ Swimsuits /datum/gear/uniform/suit/gnshorts display_name = "GN shorts" - path = /obj/item/clothing/under/fluff/gnshorts \ No newline at end of file + path = /obj/item/clothing/under/fluff/gnshorts + +//Latex maid dress +/datum/gear/uniform/latexmaid + display_name = "latex maid dress" + path = /obj/item/clothing/under/fluff/latexmaid \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout_utility.dm b/code/modules/client/preference_setup/loadout/loadout_utility.dm index 08dc413b6a..0558cf91f9 100644 --- a/code/modules/client/preference_setup/loadout/loadout_utility.dm +++ b/code/modules/client/preference_setup/loadout/loadout_utility.dm @@ -16,7 +16,7 @@ /datum/gear/utility/communicator/New() ..() var/list/communicators = list() - for(var/communicator in typesof(/obj/item/device/communicator) - list(/obj/item/device/communicator/integrated)) + for(var/communicator in typesof(/obj/item/device/communicator) - list(/obj/item/device/communicator/integrated,/obj/item/device/communicator/commlink)) //VOREStation Edit - Remove Commlink var/obj/item/device/communicator_type = communicator communicators[initial(communicator_type.name)] = communicator_type gear_tweaks += new/datum/gear_tweak/path(sortAssoc(communicators)) @@ -29,6 +29,12 @@ display_name = "the traveler's guide to vir" path = /obj/item/weapon/book/codex //VOREStation Edit cost = 0 + +/datum/gear/utility/news + display_name = "daedalus pocket newscaster" + path = /obj/item/weapon/book/codex/lore/news + cost = 0 + /* //VORESTATION REMOVAL /datum/gear/utility/corp_regs display_name = "corporate regulations and legal code" diff --git a/code/modules/client/preference_setup/loadout/loadout_utility_vr.dm b/code/modules/client/preference_setup/loadout/loadout_utility_vr.dm new file mode 100644 index 0000000000..65bc2af8bd --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_utility_vr.dm @@ -0,0 +1,57 @@ +/datum/gear/utility/saddlebag + display_name = "saddle bag, horse" + path = /obj/item/weapon/storage/backpack/saddlebag + slot = slot_back + cost = 2 + +/datum/gear/utility/saddlebag_common + display_name = "saddle bag, common" + path = /obj/item/weapon/storage/backpack/saddlebag_common + slot = slot_back + cost = 2 + +/datum/gear/utility/saddlebag_common/robust + display_name = "saddle bag, robust" + path = /obj/item/weapon/storage/backpack/saddlebag_common/robust + slot = slot_back + cost = 2 + +/datum/gear/utility/saddlebag_common/vest + display_name = "taur duty vest (backpack)" + path = /obj/item/weapon/storage/backpack/saddlebag_common/vest + slot = slot_back + cost = 1 + +/datum/gear/utility/dufflebag + display_name = "dufflebag" + path = /obj/item/weapon/storage/backpack/dufflebag + slot = slot_back + cost = 2 + +/datum/gear/utility/dufflebag/black + display_name = "black dufflebag" + path = /obj/item/weapon/storage/backpack/dufflebag/fluff + +/datum/gear/utility/dufflebag/med + display_name = "medical dufflebag" + path = /obj/item/weapon/storage/backpack/dufflebag/med + allowed_roles = list("Medical Doctor","Chief Medical Officer","Chemist","Paramedic","Geneticist","Psychiatrist","Search and Rescue") + +/datum/gear/utility/dufflebag/med/emt + display_name = "EMT dufflebag" + path = /obj/item/weapon/storage/backpack/dufflebag/emt + +/datum/gear/utility/dufflebag/sec + display_name = "security Dufflebag" + path = /obj/item/weapon/storage/backpack/dufflebag/sec + allowed_roles = list("Head of Security","Warden","Detective","Security Officer") + +/datum/gear/utility/dufflebag/eng + display_name = "engineering dufflebag" + path = /obj/item/weapon/storage/backpack/dufflebag/eng + allowed_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer") + +/datum/gear/utility/dufflebag/sci + display_name = "science dufflebag" + path = /obj/item/weapon/storage/backpack/dufflebag/sci + allowed_roles = list("Research Director","Scientist","Roboticist","Xenobiologist","Explorer") diff --git a/code/modules/client/preference_setup/occupation/occupation.dm b/code/modules/client/preference_setup/occupation/occupation.dm index 6975163cc2..3150a5ff12 100644 --- a/code/modules/client/preference_setup/occupation/occupation.dm +++ b/code/modules/client/preference_setup/occupation/occupation.dm @@ -54,7 +54,7 @@ if(alt_title && !(alt_title in job.alt_titles)) pref.player_alt_titles -= job.title -/datum/category_item/player_setup_item/occupation/content(mob/user, limit = 18, list/splitJobs = list("Chief Medical Officer")) +/datum/category_item/player_setup_item/occupation/content(mob/user, limit = 18, list/splitJobs = list("Chief Engineer")) if(!job_master) return @@ -94,7 +94,7 @@ if(job.minimum_character_age && user.client && (user.client.prefs.age < job.minimum_character_age)) . += "[rank] \[MINIMUM CHARACTER AGE: [job.minimum_character_age]]" continue - if((pref.job_civilian_low & ASSISTANT) && (rank != "Assistant")) + if((pref.job_civilian_low & ASSISTANT) && job.type != /datum/job/assistant) . += "[rank]" continue if((rank in command_positions) || (rank == "AI"))//Bold head jobs @@ -106,7 +106,7 @@ . += "" - if(rank == "Assistant")//Assistant is special + if(job.type == /datum/job/assistant)//Assistant is special if(pref.job_civilian_low & ASSISTANT) . += " \[Yes]" else @@ -180,7 +180,7 @@ if(!job) return 0 - if(role == "Assistant") + if(job.type == /datum/job/assistant) if(pref.job_civilian_low & job.flag) pref.job_civilian_low &= ~job.flag else diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index 22d7e63e67..052259d244 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -71,7 +71,7 @@ BLIND // can't see anything origin_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 2) toggleable = 1 vision_flags = SEE_TURFS - enables_planes = (VIS_FULLBRIGHT) + enables_planes = list(VIS_FULLBRIGHT, VIS_MESONS) /obj/item/clothing/glasses/meson/New() ..() diff --git a/code/modules/food/recipes_microwave.dm b/code/modules/food/recipes_microwave.dm index f3dd6b876d..f683429789 100644 --- a/code/modules/food/recipes_microwave.dm +++ b/code/modules/food/recipes_microwave.dm @@ -965,6 +965,16 @@ I said no! ) result = /obj/item/weapon/ruinedvirusdish +/datum/recipe/onionrings + fruit = list("onion" = 1) + reagents = list("flour" = 5) + result = /obj/item/weapon/reagent_containers/food/snacks/onionrings + +/datum/recipe/onionsoup + fruit = list("onion" = 1) + reagents = list("water" = 10) + result = /obj/item/weapon/reagent_containers/food/snacks/onionsoup + ////////////////////////////////////////// // bs12 food port stuff ////////////////////////////////////////// @@ -1011,6 +1021,146 @@ I said no! reagents = list("sugar" = 5, "frostoil" = 5) result = /obj/item/weapon/reagent_containers/food/snacks/mint +//////////////////////// +// TGstation food ports +//////////////////////// + +/datum/recipe/meatbun + fruit = list("cabbage" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/meatball, + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/meatbun + +/datum/recipe/sashimi + reagents = list("soysauce" = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/carpmeat + ) + result = /obj/item/weapon/reagent_containers/food/snacks/sashimi + +/datum/recipe/benedict + items = list( + /obj/item/weapon/reagent_containers/food/snacks/cutlet, + /obj/item/weapon/reagent_containers/food/snacks/friedegg, + /obj/item/weapon/reagent_containers/food/snacks/slice/bread + ) + result = /obj/item/weapon/reagent_containers/food/snacks/benedict + +/datum/recipe/bakedbeans + fruit = list("soybeans" = 2) + reagents = list("ketchup" = 5) + result = /obj/item/weapon/reagent_containers/food/snacks/beans + +/datum/recipe/sugarcookie + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough + ) + reagents = list("sugar" = 5, "egg" = 3) + result = /obj/item/weapon/reagent_containers/food/snacks/sugarcookie + +/datum/recipe/berrymuffin + reagents = list("milk" = 5, "sugar" = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough + ) + fruit = list("berries" = 1) + result = /obj/item/weapon/reagent_containers/food/snacks/berrymuffin + +/datum/recipe/ghostmuffin + reagents = list("milk" = 5, "sugar" = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/dough, + /obj/item/weapon/ectoplasm + ) + fruit = list("berries" = 1) + result = /obj/item/weapon/reagent_containers/food/snacks/ghostmuffin + +/datum/recipe/eggroll + reagents = list("soysauce" = 10) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/friedegg + ) + fruit = list("cabbage" = 1) + result = /obj/item/weapon/reagent_containers/food/snacks/eggroll + +/datum/recipe/fruitsalad + fruit = list("orange" = 1, "apple" = 1, "grapes" = 1, "watermelon" = 1) + result = /obj/item/weapon/reagent_containers/food/snacks/fruitsalad + +/datum/recipe/eggbowl + reagents = list("water" = 5, "rice" = 10, "egg" = 3) + result = /obj/item/weapon/reagent_containers/food/snacks/eggbowl + +/datum/recipe/porkbowl + reagents = list("water" = 5, "rice" = 10) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/cutlet + ) + result = /obj/item/weapon/reagent_containers/food/snacks/porkbowl + +/datum/recipe/tortilla + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough + ) + result = /obj/item/weapon/reagent_containers/food/snacks/tortilla + +/datum/recipe/meatburrito + fruit = list("soybeans" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/tortilla, + /obj/item/weapon/reagent_containers/food/snacks/cutlet, + /obj/item/weapon/reagent_containers/food/snacks/cutlet + ) + result = /obj/item/weapon/reagent_containers/food/snacks/meatburrito + +/datum/recipe/cheeseburrito + fruit = list("soybeans" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/tortilla, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge + ) + result = /obj/item/weapon/reagent_containers/food/snacks/cheeseburrito + +/datum/recipe/fuegoburrito + fruit = list("soybeans" = 1, "chili" = 2) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/tortilla + ) + result = /obj/item/weapon/reagent_containers/food/snacks/fuegoburrito + +/datum/recipe/nachos + reagents = list("sodiumchloride" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/tortilla + ) + result = /obj/item/weapon/reagent_containers/food/snacks/nachos + +/datum/recipe/cheesenachos + reagents = list("sodiumchloride" = 1) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/tortilla, + /obj/item/weapon/reagent_containers/food/snacks/cheesewedge + ) + result = /obj/item/weapon/reagent_containers/food/snacks/cheesenachos + +/datum/recipe/cubannachos + fruit = list("chili" = 1) + reagents = list("ketchup" = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/tortilla + ) + result = /obj/item/weapon/reagent_containers/food/snacks/cubannachos + +/datum/recipe/piginblanket + items = list( + /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, + /obj/item/weapon/reagent_containers/food/snacks/sausage + ) + result = /obj/item/weapon/reagent_containers/food/snacks/piginblanket + // Cakes. /datum/recipe/cake @@ -1060,4 +1210,4 @@ I said no! /datum/recipe/cake/brain items = list(/obj/item/organ/internal/brain) - result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake + result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake \ No newline at end of file diff --git a/code/modules/hydroponics/seed_controller.dm b/code/modules/hydroponics/seed_controller.dm index 82b2f62abd..6a743d4a1c 100644 --- a/code/modules/hydroponics/seed_controller.dm +++ b/code/modules/hydroponics/seed_controller.dm @@ -90,10 +90,10 @@ var/global/datum/controller/plants/plant_controller // Set in New(). var/list/plant_traits = ALL_GENES while(plant_traits && plant_traits.len) var/gene_tag = pick(plant_traits) - var/gene_mask = "[uppertext(num2hex(rand(0,255)))]" + var/gene_mask = "[uppertext(num2hex(rand(0,255), 2))]" while(gene_mask in used_masks) - gene_mask = "[uppertext(num2hex(rand(0,255)))]" + gene_mask = "[uppertext(num2hex(rand(0,255), 2))]" var/decl/plantgene/G diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm index d2aa8373af..60a6b39da6 100644 --- a/code/modules/hydroponics/seed_datums.dm +++ b/code/modules/hydroponics/seed_datums.dm @@ -691,7 +691,7 @@ name = "potato" seed_name = "potato" display_name = "potatoes" - chems = list("nutriment" = list(1,10), "potato" = list(10,10)) + chems = list("nutriment" = list(1,10), "potatojuice" = list(10,10)) kitchen_tag = "potato" /datum/seed/potato/New() @@ -706,6 +706,24 @@ set_trait(TRAIT_PLANT_ICON,"bush2") set_trait(TRAIT_WATER_CONSUMPTION, 6) +/datum/seed/onion + name = "onion" + seed_name = "onion" + display_name = "onions" + chems = list("nutriment" = list(1,10)) + kitchen_tag = "onion" + +/datum/seed/onion/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"onion") + set_trait(TRAIT_PRODUCT_COLOUR,"#E0C367") + set_trait(TRAIT_PLANT_ICON,"carrot") + set_trait(TRAIT_WATER_CONSUMPTION, 6) + /datum/seed/soybean name = "soybean" seed_name = "soybean" @@ -910,6 +928,7 @@ /datum/seed/citrus/lemon/New() ..() set_trait(TRAIT_PRODUCES_POWER,1) + set_trait(TRAIT_PRODUCT_ICON,"lemon") set_trait(TRAIT_PRODUCT_COLOUR,"#F0E226") set_trait(TRAIT_FLESH_COLOUR,"#F0E226") set_trait(TRAIT_IDEAL_LIGHT, 6) diff --git a/code/modules/hydroponics/seed_packets.dm b/code/modules/hydroponics/seed_packets.dm index 5870a546af..719373f5d3 100644 --- a/code/modules/hydroponics/seed_packets.dm +++ b/code/modules/hydroponics/seed_packets.dm @@ -237,6 +237,9 @@ var/global/list/plant_seed_sprites = list() /obj/item/seeds/lemonseed seed_type = "lemon" +/obj/item/seeds/onionseed + seed_type = "onion" + /obj/item/seeds/orangeseed seed_type = "orange" diff --git a/code/modules/hydroponics/seed_storage.dm b/code/modules/hydroponics/seed_storage.dm index 2aa247c432..6f13706545 100644 --- a/code/modules/hydroponics/seed_storage.dm +++ b/code/modules/hydroponics/seed_storage.dm @@ -60,6 +60,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/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm index 51451e832a..094d781cf2 100644 --- a/code/modules/lighting/lighting_overlay.dm +++ b/code/modules/lighting/lighting_overlay.dm @@ -11,7 +11,7 @@ color = LIGHTING_BASE_MATRIX icon_state = "light1" auto_init = 0 // doesn't need special init - blend_mode = BLEND_MULTIPLY + blend_mode = BLEND_OVERLAY var/lum_r = 0 var/lum_g = 0 diff --git a/code/modules/lore_codex/codex.dm b/code/modules/lore_codex/codex.dm index 937e46a66d..67a4a3ac25 100644 --- a/code/modules/lore_codex/codex.dm +++ b/code/modules/lore_codex/codex.dm @@ -24,6 +24,13 @@ has the words 'Don't Panic' in small, friendly letters on the cover." icon_state = "codex" root_type = /datum/lore/codex/category/main_vir_lore + +/obj/item/weapon/book/codex/lore/news + name = "Daedalus Pocket Newscaster" + desc = "A regularly-updating compendium of articles on current events. Essential for new arrivals in the Vir system and anyone interested in politics." + icon_state = "newscodex" + root_type = /datum/lore/codex/category/main_news + /* //VORESTATION REMOVAL // Combines SOP/Regs/Law /obj/item/weapon/book/codex/corp_regs diff --git a/code/modules/lore_codex/lore_data/main.dm b/code/modules/lore_codex/lore_data/main.dm index 7452c7b7ef..7b43a25d5f 100644 --- a/code/modules/lore_codex/lore_data/main.dm +++ b/code/modules/lore_codex/lore_data/main.dm @@ -28,5 +28,5 @@ to an immigrant from another system or even from outside human space, and anyone inbetween. The publisher wishes to note that any opinions expressed \ in this text does not reflect the opinions of the publisher, and are instead the author's.\

\ - Eshi Tache has also written other The Traveler's Guide books, including Sol Edition, Tau Ceti Edition, Sirius Edition, and more, \ + Eshi Tache has also written other The Traveler's Guide books, including Sol Edition, Tau Ceti Edition, Alpha Centauri Edition, and more, \ which you can find in your local book store, library, or e-reader device." \ No newline at end of file diff --git a/code/modules/lore_codex/news_data/main.dm b/code/modules/lore_codex/news_data/main.dm new file mode 100644 index 0000000000..52ff382199 --- /dev/null +++ b/code/modules/lore_codex/news_data/main.dm @@ -0,0 +1,34 @@ +/datum/lore/codex/category/main_news // The top-level categories for the news thing + name = "Index" + data = "Below you'll find a list of articles relevant to the current (as of 2562) political climate, especially concerning the Almach Rim \ + region. Each is labled by date of publication and title. This list is self-updating, and from time to time the publisher will push new \ + articles. You are encouraged to check back frequently." + children = list( + /datum/lore/codex/page/article1, + /datum/lore/codex/page/about_news, + ) + +/datum/lore/codex/page/about_news + name = "About the Publisher" + data = "The Daedalus Pocket Newscaster is produced and maintained by Occulum Broadcast, the foremost authority on media distribution \ + and owner-operator of the award-winning Daedalus Dispatch newsletter. We use our unparalleled network of freelance reporters, political scientists, \ + and other experts to deliver hour-by-hour analysis of a complex interstellar political climate, an analysis which you now hold in your hands. For more \ + information, feel free to visit our homepage at oc.about.tsc, or the sites of any of our constituents." + +/datum/lore/codex/page/article1 + name = "08/30/61-- VGA Legalizes Prometheans; Nanotrasen Begins Manufacture and Testing" + data = "Today's meeting of the Vir Bicameral led to the passing of the Wynther-Helsey Bill, an implementation of the legal framework \ + used in Aetolus to handle the production and cultivation of the Macrolimbus species dubbed \"Prometheans\". These ill-researched organisms \ + possess cognitive abilities easily equaling those of A-class drones, but so far have not been included under the EIO's list of dangerous \ + intelligences and are thus much more profitable for manufacture as expert systems by corporations such as NanoTrasen.\ +

\ + While many systems in the Almach Rim have already passed similar bills, this is the first system so close to Sol to have done so. More\ + concerning still is NanoTrasen's business practice regarding the intelligences: much like their positronic lines, sources within the\ + company indicate that they will be \"farmed out\" to employees of the corporation and residents of their Northern Star and Cynosure\ + habitation complexes. Quote our source, who wishes to remain anonymous, \"\[we\] call the program 'Lend-Lease', sometimes. The whole idea\ + is that we only have to pay the\ cost of the Promethean core, which is about 2000-3000 thalers after startup costs, and we still get\ + the data we need while \[our\] own employees pay to feed 'em and put hours into raising them.\"\ +

\ + The bill passed fairly quietly this afternoon, owing to the closed nature of the Bicamarial. A post-facto Occulum poll of voting-age\ + VGA citizens suggest that fully 80% of them did not even know what a Promethean was prior to the most recent general election. A\ + follow-up poll indicates that an appreciable number of Sivians do not support the framework's current implementation." \ No newline at end of file diff --git a/code/modules/maps/tg/map_template.dm b/code/modules/maps/tg/map_template.dm index 24068dcf1d..51282e5afb 100644 --- a/code/modules/maps/tg/map_template.dm +++ b/code/modules/maps/tg/map_template.dm @@ -23,6 +23,7 @@ var/list/global/map_templates = list() it runs out. The cost of a submap should roughly corrispond with several factors such as size, loot, difficulty, desired scarcity, etc. \ Set to -1 to force the submap to always be made. var/allow_duplicates = FALSE // If false, only one map template will be spawned by the game. Doesn't affect admins spawning then manually. + var/discard_prob = 0 // If non-zero, there is a chance that the map seeding algorithm will skip this template when selecting potential templates to use. var/static/dmm_suite/maploader = new @@ -102,19 +103,25 @@ var/list/global/map_templates = list() admin_notice("Submap initializations finished.", R_DEBUG) -/datum/map_template/proc/load_new_z() - var/x = round(world.maxx/2) - var/y = round(world.maxy/2) +/datum/map_template/proc/load_new_z(var/centered = FALSE, var/dont_init = FALSE) + var/x = 1 + var/y = 1 - var/list/bounds = maploader.load_map(file(mappath), x, y) + if(centered) + x = round((world.maxx - width)/2) + y = round((world.maxy - height)/2) + + var/list/bounds = maploader.load_map(file(mappath), x, y, no_changeturf = TRUE) if(!bounds) return FALSE // repopulate_sorted_areas() //initialize things that are normally initialized after map load - initTemplateBounds(bounds) + if(!dont_init) + initTemplateBounds(bounds) log_game("Z-level [name] loaded at at [x],[y],[world.maxz]") + on_map_loaded(world.maxz) //VOREStation Edit return TRUE /datum/map_template/proc/load(turf/T, centered = FALSE, dont_init = FALSE) @@ -197,6 +204,8 @@ var/list/global/map_templates = list() continue if(!istype(MT, desired_map_template_type)) // Not the type wanted. continue + if(MT.discard_prob && prob(MT.discard_prob)) + continue if(MT.cost && MT.cost < 0) // Negative costs always get spawned. priority_submaps += MT else diff --git a/code/modules/maps/tg/map_template_vr.dm b/code/modules/maps/tg/map_template_vr.dm new file mode 100644 index 0000000000..cd8a04857d --- /dev/null +++ b/code/modules/maps/tg/map_template_vr.dm @@ -0,0 +1,2 @@ +/datum/map_template/proc/on_map_loaded(z) + return \ No newline at end of file diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm index a52d66a0fa..6a10383f76 100644 --- a/code/modules/materials/material_recipes.dm +++ b/code/modules/materials/material_recipes.dm @@ -22,6 +22,7 @@ recipes += new/datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") recipes += new/datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") recipes += new/datum/stack_recipe("[display_name] double bed", /obj/structure/bed/double, 4, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") + recipes += new/datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") if(hardness>50) recipes += new/datum/stack_recipe("[display_name] fork", /obj/item/weapon/material/kitchen/utensil/fork/plastic, 1, on_floor = 1, supplied_material = "[name]") @@ -57,7 +58,6 @@ recipes += new/datum/stack_recipe("mirror frame", /obj/item/frame/mirror, 1, time = 5, one_per_turf = 0, on_floor = 1) recipes += new/datum/stack_recipe("fire extinguisher cabinet frame", /obj/item/frame/extinguisher_cabinet, 4, time = 5, one_per_turf = 0, on_floor = 1) //recipes += new/datum/stack_recipe("fire axe cabinet frame", /obj/item/frame/fireaxe_cabinet, 4, time = 5, one_per_turf = 0, on_floor = 1) - recipes += new/datum/stack_recipe("wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1) recipes += new/datum/stack_recipe("railing", /obj/structure/railing, 2, time = 50, one_per_turf = 0, on_floor = 1) recipes += new/datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 25, one_per_turf = 1, on_floor = 1) recipes += new/datum/stack_recipe_list("airlock assemblies", list( \ diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm index 54a890074a..af5e1b7475 100644 --- a/code/modules/materials/materials.dm +++ b/code/modules/materials/materials.dm @@ -192,11 +192,16 @@ var/list/name_to_material name = "placeholder" // Places a girder object when a wall is dismantled, also applies reinforced material. -/material/proc/place_dismantled_girder(var/turf/target, var/material/reinf_material) +/material/proc/place_dismantled_girder(var/turf/target, var/material/reinf_material, var/material/girder_material) var/obj/structure/girder/G = new(target) if(reinf_material) G.reinf_material = reinf_material G.reinforce_girder() + if(girder_material) + if(istype(girder_material, /material)) + girder_material = girder_material.name + G.set_material(girder_material) + // General wall debris product placement. // Not particularly necessary aside from snowflakey cult girders. diff --git a/code/modules/mining/mine_items_vr.dm b/code/modules/mining/mine_items_vr.dm new file mode 100644 index 0000000000..d8046a7b06 --- /dev/null +++ b/code/modules/mining/mine_items_vr.dm @@ -0,0 +1,28 @@ +//upgrades the speed of all drills and pickaxes. + +/obj/item/weapon/pickaxe + digspeed = 36 + +/obj/item/weapon/pickaxe/silver + digspeed = 27 + +/obj/item/weapon/pickaxe/drill + digspeed = 27 + +/obj/item/weapon/pickaxe/jackhammer + digspeed = 18 + +/obj/item/weapon/pickaxe/gold + digspeed = 18 + +/obj/item/weapon/pickaxe/plasmacutter + digspeed = 18 + +/obj/item/weapon/pickaxe/diamond + digspeed = 9 + +/obj/item/weapon/pickaxe/diamonddrill + digspeed = 4 + +/obj/item/weapon/pickaxe/borgdrill + digspeed = 13 diff --git a/code/modules/mob/_modifiers/cloning.dm b/code/modules/mob/_modifiers/cloning.dm index 661f957475..a5e8e5e2ba 100644 --- a/code/modules/mob/_modifiers/cloning.dm +++ b/code/modules/mob/_modifiers/cloning.dm @@ -39,7 +39,25 @@ // Prevents borging (specifically the MMI part), actual effect is on the MMI. /datum/modifier/no_borg - name = "Cyboernetic Incompatability" + name = "Cybernetic Incompatability" desc = "For whatever reason, your brain is incompatable with direct cybernetic interfaces, such as the MMI." - flags = MODIFIER_GENETIC \ No newline at end of file + flags = MODIFIER_GENETIC + +////////////////////////////////////// +//Species-Specific Cloning Modifiers// +///////////////////////////////////// + +/datum/modifier/cloning_sickness/promethean + name = "reformation sickness" + desc = "Your core feels damaged, as you were reformed with the improper machinery." + + on_created_text = "Your core aches." + on_expired_text = "You feel your core's strength returning to normal." + + incoming_damage_percent = 1 //Level the incoming damage from the parent modifier. They already take 200% burn. + incoming_brute_damage_percent = 1.5 //150% incoming brute damage. Decreases the effectiveness of their 0.75 modifier. + incoming_hal_damage_percent = 1.25 //125% incoming halloss. + + outgoing_melee_damage_percent = 0.5 //50% less outgoing melee damage. + attack_speed_percent = 1.2 //20% slower attack speed. diff --git a/code/modules/mob/_modifiers/traits.dm b/code/modules/mob/_modifiers/traits.dm index 3e9e8278e4..eac919b106 100644 --- a/code/modules/mob/_modifiers/traits.dm +++ b/code/modules/mob/_modifiers/traits.dm @@ -64,13 +64,13 @@ name = "Larger" desc = "Your body is larger than average." - icon_scale_percent = 1.2 + icon_scale_percent = 1.1 /datum/modifier/trait/large name = "Large" desc = "Your body is a bit larger than average." - icon_scale_percent = 1.1 + icon_scale_percent = 1.05 /datum/modifier/trait/small name = "Small" diff --git a/code/modules/mob/_modifiers/traits_phobias.dm b/code/modules/mob/_modifiers/traits_phobias.dm index 89fbb4553b..c96c6890e6 100644 --- a/code/modules/mob/_modifiers/traits_phobias.dm +++ b/code/modules/mob/_modifiers/traits_phobias.dm @@ -437,8 +437,7 @@ fear_amount += 1 if(istype(S.species, /datum/species/shapeshifter/promethean)) fear_amount += 4 - else - return + return fear_amount /datum/modifier/trait/phobia/trypanophobe diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index fd6f83ef44..63e79eb67c 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -15,6 +15,7 @@ canmove = 0 blinded = 0 anchored = 1 // don't get pushed around + invisibility = INVISIBILITY_OBSERVER var/can_reenter_corpse var/datum/hud/living/carbon/hud = null // hud var/bootime = 0 @@ -661,7 +662,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp else src << "You are now visible!" - plane = PLANE_GHOSTS ? PLANE_WORLD : PLANE_GHOSTS + plane = (plane == PLANE_GHOSTS) ? PLANE_WORLD : PLANE_GHOSTS + invisibility = (plane == PLANE_WORLD) ? 0 : INVISIBILITY_OBSERVER // Give the ghost a cult icon which should be visible only to itself toggle_icon("cult") diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm index 4d7a74be7d..25644de604 100644 --- a/code/modules/mob/death.dm +++ b/code/modules/mob/death.dm @@ -1,6 +1,6 @@ //This is the proc for gibbing a mob. Cannot gib ghosts. //added different sort of gibs and animations. N -/mob/proc/gib(anim="gibbed-m",do_gibs) +/mob/proc/gib(anim="gibbed-m", do_gibs, gib_file = 'icons/mob/mob.dmi') death(1) transforming = 1 canmove = 0 @@ -12,7 +12,7 @@ var/atom/movable/overlay/animation = null animation = new(loc) animation.icon_state = "blank" - animation.icon = 'icons/mob/mob.dmi' + animation.icon = gib_file animation.master = src flick(anim, animation) diff --git a/code/modules/mob/freelook/chunk.dm b/code/modules/mob/freelook/chunk.dm index 626a79e28f..7c50bd3135 100644 --- a/code/modules/mob/freelook/chunk.dm +++ b/code/modules/mob/freelook/chunk.dm @@ -101,7 +101,9 @@ var/turf/t = turf if(obscuredTurfs[t]) if(!t.obfuscations[obfuscation.type]) - t.obfuscations[obfuscation.type] = image(obfuscation.icon, t, obfuscation.icon_state, OBFUSCATION_LAYER) + var/image/ob_image = image(obfuscation.icon, t, obfuscation.icon_state, OBFUSCATION_LAYER) + ob_image.plane = PLANE_FULLSCREEN + t.obfuscations[obfuscation.type] = ob_image obscured += t.obfuscations[obfuscation.type] for(var/eye in seenby) @@ -140,7 +142,9 @@ for(var/turf in obscuredTurfs) var/turf/t = turf if(!t.obfuscations[obfuscation.type]) - t.obfuscations[obfuscation.type] = image(obfuscation.icon, t, obfuscation.icon_state, OBFUSCATION_LAYER) + var/image/ob_image = image(obfuscation.icon, t, obfuscation.icon_state, OBFUSCATION_LAYER) + ob_image.plane = PLANE_FULLSCREEN + t.obfuscations[obfuscation.type] = ob_image obscured += t.obfuscations[obfuscation.type] #undef UPDATE_BUFFER diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm index c2a7b5668a..4d01759ce9 100644 --- a/code/modules/mob/hear_say.dm +++ b/code/modules/mob/hear_say.dm @@ -1,7 +1,7 @@ // At minimum every mob has a hear_say proc. /mob/proc/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) - if(!client) + if(!client && !teleop) return if(speaker && !speaker.client && istype(src,/mob/observer/dead) && is_preference_enabled(/datum/client_preference/ghost_ears) && !(speaker in view(src))) @@ -80,14 +80,20 @@ /mob/proc/on_hear_say(var/message) to_chat(src, message) + if(teleop) + to_chat(teleop, create_text_tag("body", "BODY:", teleop) + "[message]") /mob/living/silicon/on_hear_say(var/message) var/time = say_timestamp() to_chat(src, "[time] [message]") + if(teleop) + to_chat(teleop, create_text_tag("body", "BODY:", teleop) + "[time] [message]") // Checks if the mob's own name is included inside message. Handles both first and last names. /mob/proc/check_mentioned(var/message) + var/not_included = list("a", "the", "of", "in", "for", "through", "throughout", "therefore", "here", "there", "then", "now", "I", "you", "they", "he", "she", "by") var/list/valid_names = splittext(real_name, " ") // Should output list("John", "Doe") as an example. + valid_names -= not_included var/list/nicknames = splittext(nickname, " ") valid_names += nicknames valid_names += special_mentions() diff --git a/code/modules/mob/living/carbon/give.dm b/code/modules/mob/living/carbon/give.dm index 58c26a56e2..5d4f17840a 100644 --- a/code/modules/mob/living/carbon/give.dm +++ b/code/modules/mob/living/carbon/give.dm @@ -1,4 +1,4 @@ -/mob/living/carbon/human/verb/give(var/mob/living/carbon/target in view(1)-usr) +/mob/living/carbon/human/verb/give(var/mob/living/carbon/target in living_mobs(1)) set category = "IC" set name = "Give" diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index eaea5ec06e..24a5bac586 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -24,7 +24,7 @@ drop_from_inventory(I) I.throw_at(get_edge_target_turf(src,pick(alldirs)), rand(1,3), round(30/I.w_class)) - ..(species.gibbed_anim) + ..(species.gibbed_anim) // uses the default mob.dmi file for these, so we only need to specify the first argument gibs(loc, dna, null, species.get_flesh_colour(src), species.get_blood_colour(src)) /mob/living/carbon/human/dust() diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index 5a3ff2175c..f3749983ac 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -15,6 +15,7 @@ var/speech_bubble_appearance = "normal" // Part of icon_state to use for speech bubbles when talking. See talk.dmi for available icons. var/fire_icon_state = "humanoid" // The icon_state used inside OnFire.dmi for when on fire. + var/suit_storage_icon = 'icons/mob/belt_mirror.dmi' // Icons used for worn items in suit storage slot. // Damage overlay and masks. var/damage_overlays = 'icons/mob/human_races/masks/dam_human.dmi' @@ -90,6 +91,7 @@ var/death_sound var/death_message = "seizes up and falls limp, their eyes dead and lifeless..." var/knockout_message = "has been knocked unconscious!" + var/cloning_modifier = /datum/modifier/cloning_sickness // Environment tolerance/life processes vars. var/reagent_tag //Used for metabolizing reagents. @@ -161,6 +163,7 @@ var/obj/effect/decal/cleanable/blood/tracks/move_trail = /obj/effect/decal/cleanable/blood/tracks/footprints // What marks are left when walking var/list/skin_overlays = list() var/has_floating_eyes = 0 // Whether the eyes can be shown above other icons + var/has_glowing_eyes = 0 // Whether the eyes are shown above all lighting var/water_movement = 0 // How much faster or slower the species is in water var/snow_movement = 0 // How much faster or slower the species is on snow 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 af1f98014b..8bc24d9924 100644 --- a/code/modules/mob/living/carbon/human/species/station/prometheans.dm +++ b/code/modules/mob/living/carbon/human/species/station/prometheans.dm @@ -44,6 +44,8 @@ var/datum/species/shapeshifter/promethean/prometheans burn_mod = 2 oxy_mod = 0 + cloning_modifier = /datum/modifier/cloning_sickness/promethean + cold_level_1 = 280 //Default 260 - Lower is better cold_level_2 = 220 //Default 200 cold_level_3 = 130 //Default 120 diff --git a/code/modules/mob/living/carbon/human/species/station/seromi.dm b/code/modules/mob/living/carbon/human/species/station/seromi.dm index 6a86f89cbb..ab51a27a29 100644 --- a/code/modules/mob/living/carbon/human/species/station/seromi.dm +++ b/code/modules/mob/living/carbon/human/species/station/seromi.dm @@ -33,6 +33,7 @@ damage_overlays = 'icons/mob/human_races/masks/dam_seromi.dmi' damage_mask = 'icons/mob/human_races/masks/dam_mask_seromi.dmi' blood_mask = 'icons/mob/human_races/masks/blood_seromi.dmi' + suit_storage_icon = 'icons/mob/species/seromi/belt_mirror.dmi' fire_icon_state = "generic" // Humanoid is too big for them and spriting a new one is really annoying. 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 1b9d24b2cd..702002f98d 100644 --- a/code/modules/mob/living/carbon/human/species/station/station.dm +++ b/code/modules/mob/living/carbon/human/species/station/station.dm @@ -13,7 +13,7 @@ secondary_langs = list(LANGUAGE_SOL_COMMON) name_language = null // Use the first-name last-name generator rather than a language scrambler min_age = 18 - max_age = 110 + max_age = 130 health_hud_intensity = 1.5 spawn_flags = SPECIES_CAN_JOIN 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 6eb0d9b6a7..ee849fb721 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 @@ -94,3 +94,18 @@ desc = "Allows you to dispose of the snack wrappings on the go instead of having to look for a bin or littering like an animal." cost = 0 var_changes = list("trashcan" = 1) + +/datum/trait/glowing_eyes + name = "Glowing Eyes" + desc = "Your eyes show up above darkness. SPOOKY! And kinda edgey too." + cost = 0 + var_changes = list("has_glowing_eyes" = 1) + +/datum/trait/glowing_body + name = "Glowing Body" + desc = "Your body glows about as much as a PDA light! Settable color and toggle in Abilities tab ingame." + cost = 0 +/datum/trait/glowing_body/apply(var/datum/species/S,var/mob/living/carbon/human/H) + ..(S,H) + H.verbs |= /mob/living/proc/glow_toggle + H.verbs |= /mob/living/proc/glow_color diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 4e58037e44..a4c2e6566d 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -125,19 +125,20 @@ Please contact me on #coderbus IRC. ~Carn x #define BACK_LAYER 17 #define HAIR_LAYER 18 //TODO: make part of head layer? #define EARS_LAYER 19 -#define FACEMASK_LAYER 20 -#define HEAD_LAYER 21 -#define COLLAR_LAYER 22 -#define HANDCUFF_LAYER 23 -#define LEGCUFF_LAYER 24 -#define L_HAND_LAYER 25 -#define R_HAND_LAYER 26 -#define MODIFIER_EFFECTS_LAYER 27 -#define FIRE_LAYER 28 //If you're on fire -#define WATER_LAYER 29 //If you're submerged in water. -#define TARGETED_LAYER 30 //BS12: Layer for the target overlay from weapon targeting system -#define WING_LAYER 31 //VOREStation edit. Simply move this up a number if things are added. -#define TOTAL_LAYERS 31 //VOREStation edit. +#define EYES_LAYER 20 +#define FACEMASK_LAYER 21 +#define HEAD_LAYER 22 +#define COLLAR_LAYER 23 +#define HANDCUFF_LAYER 24 +#define LEGCUFF_LAYER 25 +#define L_HAND_LAYER 26 +#define R_HAND_LAYER 27 +#define MODIFIER_EFFECTS_LAYER 28 +#define FIRE_LAYER 29 //If you're on fire +#define WATER_LAYER 30 //If you're submerged in water. +#define TARGETED_LAYER 31 //BS12: Layer for the target overlay from weapon targeting system +#define WING_LAYER 32 //VOREStation edit. Simply move this up a number if things are added. +#define TOTAL_LAYERS 32 //VOREStation edit. ////////////////////////////////// /mob/living/carbon/human @@ -500,6 +501,7 @@ var/global/list/damage_icon_parts = list() //Reset our hair overlays_standing[HAIR_LAYER] = null + update_eyes(0) //Pirated out of here, for glowing eyes. var/obj/item/organ/external/head/head_organ = get_organ(BP_HEAD) if(!head_organ || head_organ.is_stump() ) @@ -544,9 +546,50 @@ var/global/list/damage_icon_parts = list() face_standing += rgb(,,,120) overlays_standing[HAIR_LAYER] = image(face_standing) - if(update_icons) update_icons_layers() +/mob/living/carbon/human/update_eyes(var/update_icons=1) + if(QDESTROYING(src)) + return + + //Reset our eyes + overlays_standing[EYES_LAYER] = null + + //This is ONLY for glowing eyes for now. Boring flat eyes are done by the head's own proc. + if(!species.has_glowing_eyes) + if(update_icons) update_icons_layers() + return + + //Our glowy eyes should be hidden if some equipment hides them. + if(!should_have_organ(O_EYES) || (head && (head.flags_inv & BLOCKHAIR)) || (wear_mask && (wear_mask.flags_inv & BLOCKHAIR))) + if(update_icons) update_icons_layers() + return + + //Get the head, we'll need it later. + var/obj/item/organ/external/head/head_organ = get_organ(BP_HEAD) + if(!head_organ || head_organ.is_stump() ) + if(update_icons) update_icons_layers() + return + + //The eyes store the color themselves, funny enough. + var/obj/item/organ/internal/eyes/eyes = internal_organs_by_name[O_EYES] + if(!head_organ.eye_icon) + if(update_icons) update_icons_layers() + return + + var/icon/eyes_icon = new/icon(head_organ.eye_icon_location, head_organ.eye_icon) + if(eyes) + eyes_icon.Blend(rgb(eyes.eye_colour[1], eyes.eye_colour[2], eyes.eye_colour[3]), ICON_ADD) + else + eyes_icon.Blend(rgb(128,0,0), ICON_ADD) + + var/image/eyes_image = image(eyes_icon) + eyes_image.plane = PLANE_LIGHTING_ABOVE + + overlays_standing[EYES_LAYER] = eyes_image + + if(update_icons) update_icons_layers() + /mob/living/carbon/human/update_mutations(var/update_icons=1) if(QDESTROYING(src)) return @@ -909,7 +952,7 @@ var/global/list/damage_icon_parts = list() if(s_store) var/t_state = s_store.item_state if(!t_state) t_state = s_store.icon_state - overlays_standing[SUIT_STORE_LAYER] = image("icon" = 'icons/mob/belt_mirror.dmi', "icon_state" = "[t_state]") + overlays_standing[SUIT_STORE_LAYER] = image("icon" = species.suit_storage_icon, "icon_state" = "[t_state]") s_store.screen_loc = ui_sstore1 //TODO else overlays_standing[SUIT_STORE_LAYER] = null @@ -1347,7 +1390,7 @@ var/global/list/damage_icon_parts = list() overlays_standing[TAIL_LAYER] = get_tail_image() if(overlays_standing[TAIL_LAYER]) if(update_icons) - update_icons() + update_icons_layers() return // VOREStation Edit - END diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index e8ce8080a3..3dc35878ae 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -175,6 +175,7 @@ ..() handle_vision() + handle_darksight() handle_hud_icons() return 1 @@ -207,7 +208,34 @@ set_light(min(round(fire_stacks), 3), round(fire_stacks), l_color = "#FF9933") return TRUE + else if(glow_toggle) + set_light(2, l_color = glow_color) //2 is PDA brightness, so neutral in terms of balance + else set_light(0) return FALSE +/mob/living/proc/handle_darksight() + var/darksightedness = min(see_in_dark/world.view,1.0) //A ratio of how good your darksight is, from 'nada' to 'really darn good' + var/current = dsoverlay.alpha/255 //Our current adjustedness + + var/brightness = 0.0 //We'll assume it's superdark if we can't find something else. + + if(isturf(loc)) + var/turf/T = loc //Will be true 99% of the time, thus avoiding the whole elif chain + brightness = T.get_lumcount() + + //Snowflake treatment of potential locations + else if(istype(loc,/obj/mecha)) //I imagine there's like displays and junk in there. Use the lights! + brightness = 1 + else if(istype(loc,/obj/item/weapon/holder)) //Poor carried teshari and whatnot should adjust appropriately + var/turf/T = get_turf(src) + brightness = T.get_lumcount() + + var/darkness = 1-brightness //Silly, I know, but 'alpha' and 'darkness' go the same direction on a number line + var/adjust_to = min(darkness,darksightedness)//Capped by how darksighted they are + var/distance = abs(current-adjust_to) //Used for how long to animate for + if(distance < 0.01) return //We're already all set + + //world << "[src] in B:[round(brightness,0.1)] C:[round(current,0.1)] A2:[round(adjust_to,0.1)] D:[round(distance,0.01)] T:[round(distance*10 SECONDS,0.1)]" + animate(dsoverlay, alpha = (adjust_to*255), time = (distance*10 SECONDS)) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 4135968d8a..d68fd90efc 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1,3 +1,20 @@ +/mob/living/New() + ..() + + //I'll just hang my coat up over here + dsoverlay = image('icons/mob/darksight.dmi',global_hud.darksight) //This is a secret overlay! Go look at the file, you'll see. + var/mutable_appearance/dsma = new(dsoverlay) //Changing like ten things, might as well. + dsma.alpha = 0 + dsma.plane = PLANE_LIGHTING + dsma.layer = LIGHTING_LAYER + 0.1 + dsma.blend_mode = BLEND_ADD + dsoverlay.appearance = dsma + +/mob/living/Destroy() + dsoverlay.loc = null //I'll take my coat with me + dsoverlay = null + return ..() + //mob verbs are faster than object verbs. See mob/verb/examine. /mob/living/verb/pulled(atom/movable/AM as mob|obj in oview(1)) set name = "Pull" diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index d8913e7b5b..d1deeebffd 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -47,3 +47,8 @@ var/evasion = 0 // Makes attacks harder to land. Each number equals 15% more likely to miss. Negative numbers increase hit chance. var/force_max_speed = 0 // If 1, the mob runs extremely fast and cannot be slowed. + + var/image/dsoverlay = null //Overlay used for darksight eye adjustments + + var/glow_toggle = 0 // If they're glowing! + var/glow_color = "#FFFFFF" // The color they're glowing! diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm index b41baabef9..275e88be08 100644 --- a/code/modules/mob/living/login.dm +++ b/code/modules/mob/living/login.dm @@ -6,4 +6,6 @@ mind.active = 1 //indicates that the mind is currently synced with a client //If they're SSD, remove it so they can wake back up. update_antag_icons(mind) + client.screen |= global_hud.darksight + client.images |= dsoverlay return . 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 185691e85a..a1c69034b1 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 @@ -16,9 +16,12 @@ var/eject_port = "ingestion" var/list/items_preserved = list() var/UI_open = FALSE + var/compactor = FALSE + var/analyzer = FALSE var/datum/research/techonly/files //Analyzerbelly var. var/synced = FALSE var/startdrain = 500 + var/max_item_count = 1 /obj/item/device/dogborg/sleeper/New() ..() @@ -28,35 +31,135 @@ /obj/item/device/dogborg/sleeper/Exit(atom/movable/O) return 0 -/obj/item/device/dogborg/sleeper/afterattack(mob/living/carbon/target, mob/living/silicon/user, proximity) +/obj/item/device/dogborg/sleeper/afterattack(var/atom/movable/target, mob/living/silicon/user, proximity) hound = loc + if(!istype(target)) + return if(!proximity) return - if(!ishuman(target)) + if(target.anchored) return - if(target.buckled) - to_chat(user, "The user is buckled and can not be put into your [src.name].") + if(target in hound.module.modules) return - if(patient) - to_chat(user, "Your [src.name] is already occupied.") + if(length(contents) > (max_item_count - 1)) + to_chat(user, "Your [src.name] is full. Eject or process contents to continue.") return - user.visible_message("[hound.name] is ingesting [target.name] into their [src.name].", "You start ingesting [target] into your [src]...") - if(!patient && ishuman(target) && !target.buckled && do_after (user, 50, target)) - if(!proximity) return //If they moved away, you can't eat them. + if(analyzer == TRUE) + if(istype(target, /obj/item)) + var/obj/target_obj = target + if(target_obj.w_class > ITEMSIZE_LARGE) + to_chat(user, "\The [target] is too large to fit into your [src.name]") + return + user.visible_message("[hound.name] is ingesting [target.name] into their [src.name].", "You start ingesting [target] into your [src.name]...") + if(do_after(user, 30, target) && length(contents) < max_item_count) + target.forceMove(src) + user.visible_message("[hound.name]'s internal analyzer groans lightly as [target.name] slips inside.", "Your internal analyzer groans lightly as [target] slips inside.") + playsound(hound, 'sound/vore/gulp.ogg', 30, 1) + if(istype(target,/obj/item)) + var/obj/item/tech_item = target + for(var/T in tech_item.origin_tech) + to_chat(user, "\The [tech_item] has level [tech_item.origin_tech[T]] in [CallTechName(T)].") + update_patient() + if(UI_open == TRUE) + sleeperUI(usr) + return - if(patient) return //If you try to eat two people at once, you can only eat one. + else if(ishuman(target)) + var/mob/living/carbon/human/trashman = target + if(patient) + to_chat(user, "Your [src.name] is already occupied.") + return + if(trashman.buckled) + to_chat(user, "[trashman] is buckled and can not be put into your [src.name].") + return + user.visible_message("[hound.name] is ingesting [trashman] into their [src.name].", "You start ingesting [trashman] into your [src.name]...") + if(do_after(user, 30, trashman) && !patient && !trashman.buckled && length(contents) < max_item_count) + trashman.forceMove(src) + trashman.reset_view(src) + processing_objects.Add(src) + user.visible_message("[hound.name]'s internal analyzer groans lightly as [trashman] slips inside.", "Your internal analyzer groans lightly as [trashman] slips inside.") + playsound(hound, 'sound/vore/gulp.ogg', 80, 1) + update_patient() + if(UI_open == TRUE) + sleeperUI(usr) + return + return - else //If you don't have someone in you, proceed. - target.forceMove(src) - target.reset_view(src) - update_patient() - processing_objects.Add(src) - user.visible_message("[hound.name]'s medical pod lights up as [target.name] slips inside into their [src.name].", "Your medical pod lights up as [target] slips into your [src]. Life support functions engaged.") - message_admins("[key_name(hound)] has eaten [key_name(patient)] as a dogborg. ([hound ? "
JMP" : "null"])") - playsound(hound, 'sound/vore/gulp.ogg', 100, 1) //POLARISTODO - if(UI_open == TRUE) - sleeperUI(usr) + if(compactor == TRUE) + if(istype(target, /obj/item) || istype(target, /obj/effect/decal/remains)) + var/obj/target_obj = target + if(target_obj.w_class > ITEMSIZE_LARGE) + to_chat(user, "\The [target] is too large to fit into your [src.name]") + return + user.visible_message("[hound.name] is ingesting [target.name] into their [src.name].", "You start ingesting [target] into your [src.name]...") + if(do_after(user, 30, target) && length(contents) < max_item_count) + target.forceMove(src) + user.visible_message("[hound.name]'s garbage processor groans lightly as [target.name] slips inside.", "Your garbage compactor groans lightly as [target] slips inside.") + playsound(hound, 'sound/vore/gulp.ogg', 30, 1) + update_patient() + if(UI_open == TRUE) + sleeperUI(usr) + return + + if(istype(target, /mob/living/simple_animal/mouse)) //Edible mice, dead or alive whatever. Mostly for carcass picking you cruel bastard :v + var/mob/living/simple_animal/trashmouse = target + user.visible_message("[hound.name] is ingesting [trashmouse] into their [src.name].", "You start ingesting [trashmouse] into your [src.name]...") + if(do_after(user, 30, trashmouse) && length(contents) < max_item_count) + trashmouse.forceMove(src) + trashmouse.reset_view(src) + user.visible_message("[hound.name]'s garbage processor groans lightly as [trashmouse] slips inside.", "Your garbage compactor groans lightly as [trashmouse] slips inside.") + playsound(hound, 'sound/vore/gulp.ogg', 30, 1) + update_patient() + if(UI_open == TRUE) + sleeperUI(usr) + return + + else if(ishuman(target)) + var/mob/living/carbon/human/trashman = target + if(patient) + to_chat(user, "Your [src.name] is already occupied.") + return + if(trashman.buckled) + to_chat(user, "[trashman] is buckled and can not be put into your [src.name].") + return + user.visible_message("[hound.name] is ingesting [trashman] into their [src.name].", "You start ingesting [trashman] into your [src.name]...") + if(do_after(user, 30, trashman) && !patient && !trashman.buckled && length(contents) < max_item_count) + trashman.forceMove(src) + trashman.reset_view(src) + processing_objects.Add(src) + user.visible_message("[hound.name]'s garbage processor groans lightly as [trashman] slips inside.", "Your garbage compactor groans lightly as [trashman] slips inside.") + playsound(hound, 'sound/vore/gulp.ogg', 80, 1) + update_patient() + if(UI_open == TRUE) + sleeperUI(usr) + return + return + else if(ishuman(target)) + var/mob/living/carbon/human/H = target + if(H.buckled) + to_chat(user, "The user is buckled and can not be put into your [src.name].") + return + if(patient) + to_chat(user, "Your [src.name] is already occupied.") + return + user.visible_message("[hound.name] is ingesting [H.name] into their [src.name].", "You start ingesting [H] into your [src]...") + if(!patient && !H.buckled && do_after (user, 50, H)) + + if(!proximity) return //If they moved away, you can't eat them. + + if(patient) return //If you try to eat two people at once, you can only eat one. + + else //If you don't have someone in you, proceed. + H.forceMove(src) + H.reset_view(src) + update_patient() + processing_objects.Add(src) + user.visible_message("[hound.name]'s medical pod lights up as [H.name] slips inside into their [src.name].", "Your medical pod lights up as [H] slips into your [src]. Life support functions engaged.") + message_admins("[key_name(hound)] has eaten [key_name(patient)] as a dogborg. ([hound ? "JMP" : "null"])") + playsound(hound, 'sound/vore/gulp.ogg', 80, 1) + if(UI_open == TRUE) + sleeperUI(usr) /obj/item/device/dogborg/sleeper/proc/go_out(var/target) hound = src.loc @@ -125,12 +228,12 @@ dat += "
" - if(istype(src, /obj/item/device/dogborg/sleeper/compactor) && length(contents))//garbage counter for trashpup + if(compactor == TRUE && length(contents))//garbage counter for trashpup var/obj/item/device/dogborg/sleeper/compactor/garbo = src dat += "Current load: [length(contents)] / [garbo.max_item_count] objects.
" dat += "([list2text(contents,", ")])

" - if(istype(src, /obj/item/device/dogborg/sleeper/compactor/analyzer) && synced == FALSE) + if(analyzer == TRUE && synced == FALSE) dat += "Sync Files
" //Cleaning and there are still un-preserved items @@ -202,7 +305,7 @@ go_out() sleeperUI(usr) return - if( href_list["close"] ) + if(href_list["close"]) UI_open = FALSE return if(href_list["clean"]) @@ -215,6 +318,7 @@ cleaning = 1 drain(startdrain) processing_objects.Add(src) + update_patient() sleeperUI(usr) if(patient) to_chat(patient, "[hound.name]'s [src.name] fills with caustic enzymes around you!") @@ -258,7 +362,7 @@ else to_chat(usr, "ERROR: Subject cannot metabolise chemicals.") - src.updateUsrDialog() + updateUsrDialog() sleeperUI(usr) //Needs a callback to boop the page to refresh. return @@ -279,10 +383,15 @@ //For if the dogborg's existing patient uh, doesn't make it. /obj/item/device/dogborg/sleeper/proc/update_patient() hound = src.loc + //Well, we HAD one, what happened to them? if(patient in contents) if(patient_laststat != patient.stat) - if(patient.stat & DEAD) + if(cleaning) + hound.sleeper_r = TRUE + hound.sleeper_g = FALSE + patient_laststat = patient.stat + else if(patient.stat & DEAD) hound.sleeper_r = TRUE hound.sleeper_g = FALSE patient_laststat = patient.stat @@ -293,13 +402,19 @@ //Update icon hound.updateicon() //Return original patient + if(UI_open == TRUE) + sleeperUI(usr) return(patient) //Check for a new patient else for(var/mob/living/carbon/human/C in contents) patient = C - if(patient.stat & DEAD) + if(cleaning) + hound.sleeper_r = TRUE + hound.sleeper_g = FALSE + patient_laststat = patient.stat + else if(patient.stat & DEAD) hound.sleeper_r = TRUE hound.sleeper_g = FALSE patient_laststat = patient.stat @@ -309,15 +424,17 @@ patient_laststat = patient.stat //Update icon and return new patient hound.updateicon() + if(UI_open == TRUE) + sleeperUI(usr) return(C) //Cleaning looks better with red on, even with nobody in it - if((cleaning && !patient) || (length(contents) > 11)) + if(cleaning || (length(contents) > 11)) hound.sleeper_r = TRUE hound.sleeper_g = FALSE //Letting analyzer gut swell if overloaded. - if(istype(src,/obj/item/device/dogborg/sleeper/compactor/analyzer) && (length(contents) > 1)) + if(analyzer == TRUE && (length(contents) > 1)) hound.sleeper_r = TRUE hound.sleeper_g = FALSE @@ -374,11 +491,12 @@ //Burn all the mobs or add them to the exclusion list for(var/mob/living/T in (touchable_items)) if((T.status_flags & GODMODE) || !T.digestable) - src.items_preserved += T + items_preserved += T else T.adjustBruteLoss(2) T.adjustFireLoss(3) - src.update_patient() + drain(-100) //20*total loss as with voreorgan stats. + update_patient() //Pick a random item to deal with (if there are any) var/atom/target = pick(touchable_items) @@ -391,9 +509,9 @@ if(T.stat == DEAD) if(ishuman(target)) message_admins("[key_name(hound)] has digested [key_name(T)] as a dogborg. ([hound ? "JMP" : "null"])") - src.drain(mob_energy) //Fueeeeellll to_chat(hound, "You feel your belly slowly churn around [T], breaking them down into a soft slurry to be used as power for your systems.") to_chat(T, "You feel [hound]'s belly slowly churn around your form, breaking you down into a soft slurry to be used as power for [hound]'s systems.") + drain(mob_energy) //Fueeeeellll var/deathsound = pick( 'sound/vore/death1.ogg', 'sound/vore/death2.ogg', @@ -429,7 +547,7 @@ else T.drop_from_inventory(I, src) T.Del() - src.update_patient() + update_patient() if(UI_open == TRUE) sleeperUI(hound) @@ -437,7 +555,7 @@ else var/obj/item/T = target if(istype(T)) - if(istype(src,/obj/item/device/dogborg/sleeper/compactor/analyzer)) + if(analyzer == TRUE) var/obj/item/tech_item = T for(var/tech in tech_item.origin_tech) files.UpdateTech(tech, tech_item.origin_tech[tech]) @@ -446,15 +564,15 @@ if(!digested) items_preserved |= T else - hound.cell.charge += (50 * digested) + drain(-50 * digested) else if(istype(target,/obj/effect/decal/remains)) qdel(target) - hound.cell.charge += 50 + drain(-100) else items_preserved |= target if(UI_open == TRUE) - src.update_patient() + update_patient() sleeperUI(hound) return @@ -462,7 +580,7 @@ /obj/item/device/dogborg/sleeper/process() if(cleaning) //We're cleaning, return early after calling this as we don't care about the patient. - src.clean_cycle() + clean_cycle() return if(patient) //We're caring for the patient. Medical emergency! Or endo scene. @@ -472,11 +590,7 @@ patient.updatehealth() patient.AdjustStunned(-4) patient.AdjustWeakened(-4) - src.drain() - /* Don't anymore, causes unwanted drug mixing in bloodstream - if((patient.reagents.get_reagent_amount("inaprovaline") < 5) && (patient.health < patient.maxHealth)) //Stop pumping full HP people full of drugs. Don't heal people you're digesting, meanie. - patient.reagents.add_reagent("inaprovaline", 5) - */ + drain() return if(!patient && !cleaning) //We think we're done working. @@ -495,7 +609,8 @@ desc = "A mounted garbage compactor unit with fuel processor." icon_state = "compactor" injection_chems = null //So they don't have all the same chems as the medihound! - var/max_item_count = 25 + compactor = TRUE + max_item_count = 25 /obj/item/device/dogborg/sleeper/compactor/analyzer //sci-borg gut. name = "Digestive Analyzer" @@ -503,108 +618,4 @@ icon_state = "analyzer" max_item_count = 1 startdrain = 100 - -/obj/item/device/dogborg/sleeper/compactor/afterattack(var/atom/movable/target, mob/living/silicon/user, proximity)//GARBO NOMS - hound = loc - - if(!istype(target)) - return - if(!proximity) - return - if(target.anchored) - return - if(target in hound.module.modules) - return - if(length(contents) > (max_item_count - 1)) - to_chat(user, "Your [src.name] is full. Eject or process contents to continue.") - return - - if(istype(src,/obj/item/device/dogborg/sleeper/compactor/analyzer)) - if(istype(target, /obj/item)) - var/obj/target_obj = target - if(target_obj.w_class >= ITEMSIZE_LARGE) - to_chat(user, "\The [target] is too large to fit into your [src.name]") - return - user.visible_message("[hound.name] is ingesting [target.name] into their [src.name].", "You start ingesting [target] into your [src.name]...") - if(do_after(user, 30, target) && length(contents) < max_item_count) - target.forceMove(src) - user.visible_message("[hound.name]'s internal analyzer groans lightly as [target.name] slips inside.", "Your internal analyzer groans lightly as [target] slips inside.") - playsound(hound, 'sound/vore/gulp.ogg', 30, 1) - if(istype(target,/obj/item)) - var/obj/item/tech_item = target - for(var/T in tech_item.origin_tech) - to_chat(user, "\The [tech_item] has level [tech_item.origin_tech[T]] in [CallTechName(T)].") - src.update_patient() - if(UI_open == TRUE) - sleeperUI(usr) - return - - else if(ishuman(target)) - var/mob/living/carbon/human/trashman = target - if(patient) - to_chat(user, "Your [src.name] is already occupied.") - return - if(trashman.buckled) - to_chat(user, "[trashman] is buckled and can not be put into your [src.name].") - return - user.visible_message("[hound.name] is ingesting [trashman] into their [src.name].", "You start ingesting [trashman] into your [src.name]...") - if(do_after(user, 30, trashman) && !patient && !trashman.buckled && length(contents) < max_item_count) - trashman.forceMove(src) - trashman.reset_view(src) - processing_objects.Add(src) - user.visible_message("[hound.name]'s internal analyzer groans lightly as [trashman] slips inside.", "Your internal analyzer groans lightly as [trashman] slips inside.") - playsound(hound, 'sound/vore/gulp.ogg', 80, 1) - src.update_patient() - if(UI_open == TRUE) - sleeperUI(usr) - return - return - - if(istype(target, /obj/item) || istype(target, /obj/effect/decal/remains)) - var/obj/target_obj = target - if(target_obj.w_class > ITEMSIZE_LARGE) - to_chat(user, "\The [target] is too large to fit into your [src.name]") - return - user.visible_message("[hound.name] is ingesting [target.name] into their [src.name].", "You start ingesting [target] into your [src.name]...") - if(do_after(user, 30, target) && length(contents) < max_item_count) - target.forceMove(src) - user.visible_message("[hound.name]'s garbage processor groans lightly as [target.name] slips inside.", "Your garbage compactor groans lightly as [target] slips inside.") - playsound(hound, 'sound/vore/gulp.ogg', 30, 1) - src.update_patient() - if(UI_open == TRUE) - sleeperUI(usr) - return - - if(istype(target, /mob/living/simple_animal/mouse)) //Edible mice, dead or alive whatever. Mostly for carcass picking you cruel bastard :v - var/mob/living/simple_animal/trashmouse = target - user.visible_message("[hound.name] is ingesting [trashmouse] into their [src.name].", "You start ingesting [trashmouse] into your [src.name]...") - if(do_after(user, 30, trashmouse) && length(contents) < max_item_count) - trashmouse.forceMove(src) - trashmouse.reset_view(src) - user.visible_message("[hound.name]'s garbage processor groans lightly as [trashmouse] slips inside.", "Your garbage compactor groans lightly as [trashmouse] slips inside.") - playsound(hound, 'sound/vore/gulp.ogg', 30, 1) - src.update_patient() - if(UI_open == TRUE) - sleeperUI(usr) - return - - else if(ishuman(target)) - var/mob/living/carbon/human/trashman = target - if(patient) - to_chat(user, "Your [src.name] is already occupied.") - return - if(trashman.buckled) - to_chat(user, "[trashman] is buckled and can not be put into your [src.name].") - return - user.visible_message("[hound.name] is ingesting [trashman] into their [src.name].", "You start ingesting [trashman] into your [src.name]...") - if(do_after(user, 30, trashman) && !patient && !trashman.buckled && length(contents) < max_item_count) - trashman.forceMove(src) - trashman.reset_view(src) - processing_objects.Add(src) - user.visible_message("[hound.name]'s garbage processor groans lightly as [trashman] slips inside.", "Your garbage compactor groans lightly as [trashman] slips inside.") - playsound(hound, 'sound/vore/gulp.ogg', 80, 1) - src.update_patient() - if(UI_open == TRUE) - sleeperUI(usr) - return - return + analyzer = TRUE diff --git a/code/modules/mob/living/simple_animal/aliens/drone.dm b/code/modules/mob/living/simple_animal/aliens/drone.dm index 2a41e81667..81532ef62d 100644 --- a/code/modules/mob/living/simple_animal/aliens/drone.dm +++ b/code/modules/mob/living/simple_animal/aliens/drone.dm @@ -61,6 +61,9 @@ /mob/living/simple_animal/hostile/malf_drone/Process_Spacemove(var/check_drift = 0) return 1 +/mob/living/simple_animal/hostile/malf_drone/isSynthetic() + return TRUE + //self repair systems have a chance to bring the drone back to life /mob/living/simple_animal/hostile/malf_drone/Life() @@ -150,6 +153,7 @@ disabled = rand(150, 600) hostile = 0 walk(src,0) + ..() /mob/living/simple_animal/hostile/malf_drone/death() ..(null,"suddenly breaks apart.") diff --git a/code/modules/mob/living/simple_animal/animals/goose.dm b/code/modules/mob/living/simple_animal/animals/goose.dm index 2def095975..f2f7c18277 100644 --- a/code/modules/mob/living/simple_animal/animals/goose.dm +++ b/code/modules/mob/living/simple_animal/animals/goose.dm @@ -4,7 +4,6 @@ icon_state = "goose" icon_living = "goose" icon_dead = "goose_dead" - icon_gib = "generic_gib" faction = "geese" intelligence_level = SA_ANIMAL diff --git a/code/modules/mob/living/simple_animal/animals/penguin.dm b/code/modules/mob/living/simple_animal/animals/penguin.dm index 09adf4ed41..13ecb0d0ca 100644 --- a/code/modules/mob/living/simple_animal/animals/penguin.dm +++ b/code/modules/mob/living/simple_animal/animals/penguin.dm @@ -4,7 +4,6 @@ icon_state = "penguin" icon_living = "penguin" icon_dead = "penguin_dead" - icon_gib = "generic_gib" intelligence_level = SA_ANIMAL maxHealth = 20 diff --git a/code/modules/mob/living/simple_animal/corpse.dm b/code/modules/mob/living/simple_animal/corpse.dm index 1171d1f9ac..5f352705b8 100644 --- a/code/modules/mob/living/simple_animal/corpse.dm +++ b/code/modules/mob/living/simple_animal/corpse.dm @@ -86,7 +86,7 @@ //List of different corpse types /obj/effect/landmark/mobcorpse/syndicatesoldier - name = "Syndicate Operative" + name = "Mercenary" corpseuniform = /obj/item/clothing/under/syndicate corpsesuit = /obj/item/clothing/suit/armor/vest corpseshoes = /obj/item/clothing/shoes/boots/swat diff --git a/code/modules/mob/living/simple_animal/humanoids/mechamobs.dm b/code/modules/mob/living/simple_animal/humanoids/mechamobs.dm index 3cfafda91a..4d107d35fd 100644 --- a/code/modules/mob/living/simple_animal/humanoids/mechamobs.dm +++ b/code/modules/mob/living/simple_animal/humanoids/mechamobs.dm @@ -84,7 +84,7 @@ sparks.start() /mob/living/simple_animal/hostile/mecha/death() - ..(0,"is explodes!") + ..(0,"explodes!") sparks.start() explosion(get_turf(src), 0, 0, 1, 3) qdel(src) @@ -93,3 +93,26 @@ /mob/living/simple_animal/hostile/mecha/Move() ..() playsound(src,'sound/mecha/mechstep.ogg',40,1) + + +/mob/living/simple_animal/hostile/mecha/malf_drone + intelligence_level = SA_ROBOTIC + faction = "malf_drone" + speak_chance = 1 + speak = list( + "Resuming task: Protect area.", + "No threats found.", + "Error: No targets found." + ) + emote_hear = list("humms ominously", "whirrs softly", "grinds a gear") + emote_see = list("looks around the area", "turns from side to side") + say_understood = list("Affirmative.", "Positive.") + say_cannot = list("Denied.", "Negative.") + say_maybe_target = list("Possible threat detected. Investigating.", "Motion detected.", "Investigating.") + say_got_target = list("Threat detected.", "New task: Remove threat.", "Threat removal engaged.", "Engaging target.") + +/mob/living/simple_animal/hostile/mecha/malf_drone/isSynthetic() + return TRUE + +/mob/living/simple_animal/hostile/mecha/malf_drone/speech_bubble_appearance() + return "synthetic_evil" \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/humanoids/syndicate.dm b/code/modules/mob/living/simple_animal/humanoids/syndicate.dm index edc46025a9..c63ec3125f 100644 --- a/code/modules/mob/living/simple_animal/humanoids/syndicate.dm +++ b/code/modules/mob/living/simple_animal/humanoids/syndicate.dm @@ -1,5 +1,5 @@ /mob/living/simple_animal/hostile/syndicate - name = "syndicate operative" + name = "mercenary" desc = "Death to the Company." icon_state = "syndicate" icon_living = "syndicate" diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index f69226a049..d37b2e33fa 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -20,7 +20,7 @@ //Mob icon/appearance settings var/icon_living = "" // The iconstate if we're alive, required var/icon_dead = "" // The iconstate if we're dead, required - var/icon_gib = null // The iconstate for being gibbed, optional + var/icon_gib = "generic_gib" // The iconstate for being gibbed, optional. Defaults to a generic gib animation. var/icon_rest = null // The iconstate for resting, optional var/image/modifier_overlay = null // Holds overlays from modifiers. @@ -490,7 +490,7 @@ purge -= 1 /mob/living/simple_animal/gib() - ..(icon_gib,1) + ..(icon_gib,1,icon) // we need to specify where the gib animation is stored /mob/living/simple_animal/emote(var/act, var/type, var/desc) if(act) diff --git a/code/modules/mob/living/simple_animal/vore/fennec.dm b/code/modules/mob/living/simple_animal/vore/fennec.dm new file mode 100644 index 0000000000..c11ae7886b --- /dev/null +++ b/code/modules/mob/living/simple_animal/vore/fennec.dm @@ -0,0 +1,37 @@ +/mob/living/simple_animal/fennec + name = "fennec" + desc = "It's a dusty big-eared sandfox! Adorable!" + icon = 'icons/mob/vore.dmi' + icon_state = "fennec" + icon_living = "fennec" + icon_dead = "fennec_dead" + icon_rest = "fennec_rest" + + faction = "fennec" + maxHealth = 30 + health = 30 + + response_help = "pats the" + response_disarm = "gently pushes aside the" + response_harm = "hits the" + + harm_intent_damage = 5 + melee_damage_lower = 5 + melee_damage_upper = 2 + attacktext = "bapped" + + speak_chance = 1 + speak = list("SKREEEE!", + "Chrp?", + "Ararrrararr.") + emote_hear = list("screEEEEeeches!","chirps.") + emote_see = list("earflicks","sniffs at the ground") + +// Activate Noms! +/mob/living/simple_animal/fennec + vore_active = 1 + vore_bump_chance = 10 + vore_bump_emote = "playfully lunges at" + vore_pounce_chance = 40 + vore_default_mode = DM_HOLD + vore_icons = SA_ICON_LIVING diff --git a/code/modules/mob/living/simple_animal/vore/otie.dm b/code/modules/mob/living/simple_animal/vore/otie.dm index 36ed6bdbc9..8728fb1877 100644 --- a/code/modules/mob/living/simple_animal/vore/otie.dm +++ b/code/modules/mob/living/simple_animal/vore/otie.dm @@ -83,15 +83,32 @@ faction = "neutral" tamed = 1 -/mob/living/simple_animal/otie/friendly/cotie //same as above but has a little collar :v +/mob/living/simple_animal/otie/cotie //same as above but has a little collar :v name = "tamed otie" desc = "The classic bioengineered longdog. This one has a nice little collar on its neck. However a proper domesticated otie is an oxymoron and the collar is likely just a decoration." icon_state = "cotie" icon_living = "cotie" icon_rest = "cotie_rest" faction = "neutral" + tamed = 1 -/mob/living/simple_animal/otie/friendly/security //tame by default unless you're a marked crimester. can be befriended to follow with pets tho. +/mob/living/simple_animal/otie/cotie/phoron //friendly phoron pup with collar + name = "mutated otie" + desc = "Looks like someone did manage to domesticate one of those wild phoron mutants. What a badass." + icon_state = "pcotie" + icon_living = "pcotie" + icon_rest = "pcotie_rest" + icon_dead = "siftusian-dead" + min_oxy = 0 + max_oxy = 0 + min_tox = 0 + max_tox = 0 + min_co2 = 0 + max_co2 = 0 + min_n2 = 0 + max_n2 = 0 + +/mob/living/simple_animal/otie/security //tame by default unless you're a marked crimester. can be befriended to follow with pets tho. name = "guard otie" desc = "The VARMAcorp bioengineering division flagship product on trained optimal snowflake guard dogs." icon_state = "sotie" @@ -101,23 +118,22 @@ faction = "neutral" maxHealth = 200 //armored or something health = 200 + tamed = 1 loot_list = list(/obj/item/clothing/glasses/sunglasses/sechud,/obj/item/clothing/suit/armor/vest/alt) vore_pounce_chance = 60 // Good boys don't do too much police brutality. var/check_records = 0 // If true, arrests people without a record. var/check_arrest = 1 // If true, arrests people who are set to arrest. -/mob/living/simple_animal/otie/friendly/security/phoron +/mob/living/simple_animal/otie/security/phoron name = "mutated guard otie" desc = "An extra rare phoron resistant version of the VARMAcorp trained snowflake guard dogs." icon_state = "sifguard" icon_living = "sifguard" icon_rest = "sifguard_rest" icon_dead = "sifguard-dead" - melee_damage_lower = 10 melee_damage_upper = 25 - // Lazy way of making sure this otie survives outside. min_oxy = 0 max_oxy = 0 min_tox = 0 @@ -154,7 +170,7 @@ else return null -/mob/living/simple_animal/otie/friendly/security/Found(var/atom/found_atom) +/mob/living/simple_animal/otie/security/Found(var/atom/found_atom) if(check_threat(found_atom) >= 4) if(resting) lay_down() @@ -165,7 +181,9 @@ if(istype(O, /obj/item/weapon/reagent_containers/food)) qdel(O) playsound(src.loc,'sound/items/eatfood.ogg', rand(10,50), 1) - if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/donut) && istype(src, /mob/living/simple_animal/otie/friendly/security)) + 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] @@ -179,7 +197,7 @@ return ..() -/mob/living/simple_animal/otie/friendly/security/feed_grabbed_to_self(var/mob/living/user, var/mob/living/prey) // Make the gut start out safe for bellybrigging. +/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)) @@ -188,12 +206,12 @@ belly_target.digest_mode = DM_DIGEST ..() -/mob/living/simple_animal/otie/friendly/security/proc/check_threat(var/mob/living/M) +/mob/living/simple_animal/otie/security/proc/check_threat(var/mob/living/M) if(!M || !ishuman(M) || M.stat == DEAD || src == M) return 0 return M.assess_perp(0, 0, 0, check_records, check_arrest) -/mob/living/simple_animal/otie/friendly/security/set_target(var/mob/M) +/mob/living/simple_animal/otie/security/set_target(var/mob/M) ai_log("SetTarget([M])",2) if(!M || (world.time - last_target_time < 5 SECONDS) && target_mob) ai_log("SetTarget() can't set it again so soon",3) @@ -221,7 +239,7 @@ return 0 -/mob/living/simple_animal/otie/friendly/security/proc/target_name(mob/living/T) +/mob/living/simple_animal/otie/security/proc/target_name(mob/living/T) if(ishuman(T)) var/mob/living/carbon/human/H = T return H.get_id_name("unidentified person") @@ -229,8 +247,13 @@ //Basic friend AI -/mob/living/simple_animal/otie/friendly/Life() - ..() +/mob/living/simple_animal/otie/Life() + . = ..() + if(!. || ai_inactive) return + + if(prob(5) && (stance == STANCE_IDLE)) + lay_down() + if(!friend) return var/friend_dist = get_dist(src,friend) @@ -262,13 +285,6 @@ var/verb = pick("whines", "yelps", "whimpers") audible_emote("[verb] anxiously.") -/mob/living/simple_animal/otie/Life() - . = ..() - if(!. || ai_inactive) return - - if(prob(5) && (stance == STANCE_IDLE)) - lay_down() - //Pet 4 friendly /mob/living/simple_animal/otie/attack_hand(mob/living/carbon/human/M as mob) @@ -277,6 +293,8 @@ if(I_HELP) if(health > 0) M.visible_message("[M] [response_help] \the [src].") + if(ai_inactive) + return LoseTarget() handle_stance(STANCE_IDLE) if(prob(tame_chance)) @@ -288,6 +306,8 @@ if(I_GRAB) if(health > 0) + if(ai_inactive) + return audible_emote("growls disapprovingly at [M].") if(M == friend) friend = null diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 40f4dc42bd..1d28fe7a2e 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -51,7 +51,7 @@ /mob/proc/show_message(msg, type, alt, alt_type)//Message, type of message (1 or 2), alternative message, alt message type (1 or 2) - if(!client) return + if(!client && !teleop) return if (type) if((type & 1) && (is_blind() || paralysis) )//Vision related @@ -70,9 +70,11 @@ return // Added voice muffling for Issue 41. if(stat == UNCONSCIOUS || sleeping > 0) - src << "... You can almost hear someone talking ..." + to_chat(src,"... You can almost hear someone talking ...") else - src << msg + to_chat(src,msg) + if(teleop) + to_chat(teleop, create_text_tag("body", "BODY:", teleop) + "[msg]") return // Show a message to all mobs and objects in sight of this one diff --git a/code/modules/mob/mob_planes.dm b/code/modules/mob/mob_planes.dm index 25c494c2e8..048992c380 100644 --- a/code/modules/mob/mob_planes.dm +++ b/code/modules/mob/mob_planes.dm @@ -12,6 +12,7 @@ //It'd be nice to lazy init these but some of them are important to just EXIST. Like without ghost planemaster, you can see ghosts. Go figure. plane_masters[VIS_FULLBRIGHT] = new /obj/screen/plane_master/fullbright //Lighting system (lighting_overlay objects) + plane_masters[VIS_LIGHTING] = new /obj/screen/plane_master/lighting //Lighting system (but different!) plane_masters[VIS_GHOSTS] = new /obj/screen/plane_master/ghosts //Ghosts! plane_masters[VIS_AI_EYE] = new /obj/screen/plane_master{plane = PLANE_AI_EYE} //AI Eye! @@ -33,6 +34,8 @@ plane_masters[VIS_D_COLORBLIND] = new /obj/screen/plane_master/colorblindness //Colorblindness (affects world) plane_masters[VIS_D_COLORBLINDI]= new /obj/screen/plane_master/colorblindness/items //Colorblindness (items in HUD, subplane of above, don't toggle) + plane_masters[VIS_MESONS] = new /obj/screen/plane_master{plane = PLANE_MESONS} //Meson-specific things like open ceilings. + ..() /datum/plane_holder/Destroy() @@ -129,12 +132,17 @@ //Lighting is weird and has matrix shenanigans. Think of this as turning on/off darkness. /obj/screen/plane_master/fullbright plane = PLANE_LIGHTING - layer = LIGHTING_LAYER + layer = LIGHTING_LAYER+1 color = null //To break lighting when visible (this is sorta backwards) - alpha = 255 //Starts full opaque - invisibility = 101 //But invisible + alpha = 0 //Starts full opaque + invisibility = 101 invis_toggle = TRUE +/obj/screen/plane_master/lighting + plane = PLANE_LIGHTING + blend_mode = BLEND_MULTIPLY + alpha = 255 + ///////////////// //Ghosts has a special alpha level /obj/screen/plane_master/ghosts diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 9b8a9aa457..1cdb98eaa7 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -318,6 +318,7 @@ if(jobban_isbanned(src,rank)) return 0 if(!job.player_old_enough(src.client)) return 0 if(!is_job_whitelisted(src,rank)) return 0 //VOREStation Code + if(!job.player_has_enough_pto(src.client)) return 0 //VOREStation Code return 1 diff --git a/code/modules/mob/new_player/new_player_vr.dm b/code/modules/mob/new_player/new_player_vr.dm index 0b5b2c26b6..d92df60859 100644 --- a/code/modules/mob/new_player/new_player_vr.dm +++ b/code/modules/mob/new_player/new_player_vr.dm @@ -47,22 +47,6 @@ pass = FALSE to_chat(src,"Your custom species is not playable. Reconfigure your traits on the VORE tab.") - //Assistant ratio enforcement - if (config.assistants_ratio > 0) //Stored as a negative number when inactive by admin verb - - var/nonassistants = 0 - var/assistants = 0 - for(var/job in job_master.occupations) - var/datum/job/J = job - if(istype(J,/datum/job/assistant)) - assistants += J.current_positions - else - nonassistants += J.current_positions - - if(assistants != 0 && assistants >= config.assistants_assured && nonassistants/assistants < config.assistants_ratio) - pass = FALSE - to_chat(src,"There are currently [assistants] assistants, and [nonassistants] normal employees, while we enforce a specific ratio. Please join as a job instead of assistant.") - //Final popup notice if (!pass) alert(src,"There were problems with spawning your character. Check your message log for details.","Error","OK") diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index 1e8cc9f6b0..d7908f437c 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -202,7 +202,7 @@ if(equip_preview_mob) // Determine what job is marked as 'High' priority, and dress them up as such. if(job_civilian_low & ASSISTANT) - previewJob = job_master.GetJob("Assistant") + previewJob = job_master.GetJob(USELESS_JOB) //VOREStation Edit - Visitor not Assistant else for(var/datum/job/job in job_master.occupations) var/job_flag diff --git a/code/modules/mob/new_player/sprite_accessories_vr.dm b/code/modules/mob/new_player/sprite_accessories_vr.dm index a7b377f1f7..a67b838e15 100644 --- a/code/modules/mob/new_player/sprite_accessories_vr.dm +++ b/code/modules/mob/new_player/sprite_accessories_vr.dm @@ -6,7 +6,6 @@ /datum/sprite_accessory/hair - icon = 'icons/mob/human_face_or_vr.dmi' //var/icon_add = 'icons/mob/human_face.dmi' //Already defined in sprite_accessories.dm line 49. var/color_blend_mode = ICON_MULTIPLY species_allowed = list("Human","Skrell","Unathi","Tajara", "Teshari", "Nevrean", "Akula", "Sergal", "Flatland Zorren", "Highlander Zorren", "Vulpkanin", "Xenochimera", "Xenomorph Hybrid", "Vasilissan", "Rapala") //This lets all races use the default hairstyles. diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf.dm index 744e37945c..1c9f108a7a 100644 --- a/code/modules/multiz/turf.dm +++ b/code/modules/multiz/turf.dm @@ -52,6 +52,7 @@ below = GetBelow(src) turf_changed_event.register(below, src, /turf/simulated/open/update_icon) levelupdate() + below.update_icon() // So the 'ceiling-less' overlay gets added. for(var/atom/movable/A in src) A.fall() OS_controller.add_turf(src, 1) diff --git a/code/modules/nifsoft/nifsoft.dm b/code/modules/nifsoft/nifsoft.dm index 6b3b867ed8..4307435da9 100644 --- a/code/modules/nifsoft/nifsoft.dm +++ b/code/modules/nifsoft/nifsoft.dm @@ -176,7 +176,6 @@ item_state = "card-id" w_class = ITEMSIZE_SMALL var/datum/nifsoft/stored = null - var/laws = "" /obj/item/weapon/disk/nifsoft/afterattack(var/A, mob/user, flag, params) if(!in_range(user, A)) @@ -192,9 +191,13 @@ to_chat(user,"Either they don't have a NIF, or the disk can't connect.") return - Ht.visible_message("[Hu] begins uploading new NIFSoft into [Ht]!","[Hu] is uploading new NIFSoft into you!") - if(do_after(Hu,10 SECONDS,Ht)) - var/extra = extra_params() + var/extra = extra_params() + if(A == user) + to_chat(user,"You upload [src] into your NIF.") + else + Ht.visible_message("[Hu] begins uploading [src] into [Ht]!","[Hu] is uploading [src] into you!") + + if(A == user || do_after(Hu,10 SECONDS,Ht)) new stored(Ht.nif,extra) qdel(src) @@ -208,8 +211,11 @@ name = "NIFSoft Disk (Compliance)" desc = "Wow, adding laws to people? That seems illegal. It probably is. Okay, it really is." stored = /datum/nifsoft/compliance + var/laws /obj/item/weapon/disk/nifsoft/compliance/afterattack(var/A, mob/user, flag, params) + if(!ishuman(A)) + return if(!laws) to_chat(user,"You haven't set any laws yet. Use the disk in-hand first.") return diff --git a/code/modules/organs/internal/brain.dm b/code/modules/organs/internal/brain.dm index 7dd2bd948e..2019ca9c4a 100644 --- a/code/modules/organs/internal/brain.dm +++ b/code/modules/organs/internal/brain.dm @@ -13,6 +13,7 @@ throw_range = 5 origin_tech = list(TECH_BIO = 3) attack_verb = list("attacked", "slapped", "whacked") + var/clone_source = FALSE var/mob/living/carbon/brain/brainmob = null /obj/item/organ/internal/brain/robotize() @@ -133,6 +134,10 @@ icon = 'icons/mob/slimes.dmi' icon_state = "green slime extract" parent_organ = BP_TORSO + clone_source = TRUE + +/obj/item/orgam/internal/brain/slime/is_open_container() + return 1 /obj/item/organ/internal/brain/golem name = "chem" diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 172d9698b1..e5c0134186 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -251,7 +251,7 @@ t = replacetext(t, "\[u\]", "") t = replacetext(t, "\[/u\]", "") t = replacetext(t, "\[time\]", "[stationtime2text()]") - t = replacetext(t, "\[date\]", "[station_date]") + t = replacetext(t, "\[date\]", "[stationdate2text()]") t = replacetext(t, "\[large\]", "") t = replacetext(t, "\[/large\]", "") if(findtext(t, "\[sign\]")) diff --git a/code/modules/planet/sif.dm b/code/modules/planet/sif.dm index 1e84126fe7..3d3a2a0073 100644 --- a/code/modules/planet/sif.dm +++ b/code/modules/planet/sif.dm @@ -251,7 +251,7 @@ datum/weather/sif WEATHER_OVERCAST = 5 ) -/datum/weather/sif/rain/process_effects() +/datum/weather/sif/storm/process_effects() for(var/mob/living/L in living_mob_list) if(L.z in holder.our_planet.expected_z_levels) var/turf/T = get_turf(L) diff --git a/code/modules/power/breaker_box.dm b/code/modules/power/breaker_box.dm index 5042043aec..2e7903c38e 100644 --- a/code/modules/power/breaker_box.dm +++ b/code/modules/power/breaker_box.dm @@ -13,6 +13,7 @@ var/icon_state_off = "bbox_off" density = 1 anchored = 1 + circuit = /obj/item/weapon/circuitboard/breakerbox var/on = 0 var/busy = 0 var/directions = list(1,2,4,8,5,6,9,10) @@ -20,15 +21,22 @@ var/update_locked = 0 /obj/machinery/power/breakerbox/Destroy() + for(var/obj/structure/cable/C in src.loc) + qdel(C) . = ..() for(var/datum/nano_module/rcon/R in world) R.FindDevices() +/obj/machinery/power/breakerbox/initialize() + . = ..() + default_apply_parts() + /obj/machinery/power/breakerbox/activated icon_state = "bbox_on" - // Enabled on server startup. Used in substations to keep them in bypass mode. +// Enabled on server startup. Used in substations to keep them in bypass mode. /obj/machinery/power/breakerbox/activated/initialize() + . = ..() set_state(1) /obj/machinery/power/breakerbox/examine(mob/user) @@ -87,10 +95,15 @@ if(newtag) RCon_tag = newtag user << "You changed the RCON tag to: [newtag]" - - - - + if(on) + to_chat(user, "Disable the breaker before performing maintenance.") + return + if(default_deconstruction_screwdriver(user, W)) + return + if(default_deconstruction_crowbar(user, W)) + return + if(default_part_replacement(user, W)) + return /obj/machinery/power/breakerbox/proc/set_state(var/state) on = state diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index edcc43bb22..678e59ccf3 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -900,6 +900,7 @@ obj/structure/cable/proc/cableColor(var/colorC) slot_flags = SLOT_BELT attack_verb = list("whipped", "lashed", "disciplined", "flogged") stacktype = null + toolspeed = 0.25 /obj/item/stack/cable_coil/alien/New(loc, length = MAXCOIL, var/param_color = null) //There has to be a better way to do this. if(embed_chance == -1) //From /obj/item, don't want to do what the normal cable_coil does @@ -912,14 +913,17 @@ obj/structure/cable/proc/cableColor(var/colorC) /obj/item/stack/cable_coil/alien/update_icon() icon_state = initial(icon_state) +/obj/item/stack/cable_coil/alien/can_use(var/used) + return 1 + /obj/item/stack/cable_coil/alien/use() //It's endless - return + return 1 /obj/item/stack/cable_coil/alien/add() //Still endless - return + return 0 /obj/item/stack/cable_coil/alien/update_wclass() - return + return 0 /obj/item/stack/cable_coil/alien/examine(mob/user) var/msg = "A spool of cable." diff --git a/code/modules/power/fusion/core/_core.dm b/code/modules/power/fusion/core/_core.dm index 60af67cf92..760c46ea93 100644 --- a/code/modules/power/fusion/core/_core.dm +++ b/code/modules/power/fusion/core/_core.dm @@ -18,6 +18,8 @@ var/list/fusion_cores = list() active_power_usage = 500 //multiplied by field strength anchored = 0 + circuit = /obj/item/weapon/circuitboard/fusion_core + var/obj/effect/fusion_em_field/owned_field var/field_strength = 1//0.01 var/id_tag @@ -27,8 +29,12 @@ var/list/fusion_cores = list() /obj/machinery/power/fusion_core/initialize() . = ..() - connect_to_network() fusion_cores += src + default_apply_parts() + +/obj/machinery/power/fusion_core/mapped/initialize() + . = ..() + connect_to_network() /obj/machinery/power/fusion_core/Destroy() for(var/obj/machinery/computer/fusion_core_control/FCC in machines) @@ -47,6 +53,7 @@ var/list/fusion_cores = list() owned_field.radiation_scale() owned_field.temp_dump() owned_field.temp_color() + /obj/machinery/power/fusion_core/Topic(href, href_list) if(..()) return 1 @@ -106,23 +113,20 @@ var/list/fusion_cores = list() to_chat(user,"Shut \the [src] off first!") return + if(default_deconstruction_screwdriver(user, W)) + return + if(default_deconstruction_crowbar(user, W)) + return + if(default_part_replacement(user, W)) + return + if(ismultitool(W)) var/new_ident = input("Enter a new ident tag.", "Fusion Core", id_tag) as null|text if(new_ident && user.Adjacent(src)) id_tag = new_ident return - else if(iswrench(W)) - anchored = !anchored - playsound(src, W.usesound, 75, 1) - if(anchored) - user.visible_message("[user.name] secures [src.name] to the floor.", \ - "You secure the [src.name] to the floor.", \ - "You hear a ratchet") - else - user.visible_message("[user.name] unsecures [src.name] from the floor.", \ - "You unsecure the [src.name] from the floor.", \ - "You hear a ratchet") + if(default_unfasten_wrench(user, W)) return return ..() diff --git a/code/modules/power/fusion/core/core_field.dm b/code/modules/power/fusion/core/core_field.dm index c882a95ccc..37351c53af 100644 --- a/code/modules/power/fusion/core/core_field.dm +++ b/code/modules/power/fusion/core/core_field.dm @@ -186,8 +186,8 @@ if(percent_unstable < 0) percent_unstable = 0 else - if(percent_unstable > 100) - percent_unstable = 100 + if(percent_unstable > 1) + percent_unstable = 1 if(percent_unstable > 0) percent_unstable = max(0, percent_unstable-rand(0.01,0.03)) diff --git a/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm b/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm index 97afe227c4..6a0f1bc205 100644 --- a/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm +++ b/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm @@ -6,6 +6,12 @@ anchored = 1 layer = 4 + circuit = /obj/item/weapon/circuitboard/fusion_fuel_compressor + +/obj/machinery/fusion_fuel_compressor/initialize() + . = ..() + default_apply_parts() + /obj/machinery/fusion_fuel_compressor/MouseDrop_T(var/atom/movable/target, var/mob/user) if(user.incapacitated() || !user.Adjacent(src)) return @@ -34,6 +40,14 @@ return 0 /obj/machinery/fusion_fuel_compressor/attackby(var/obj/item/thing, var/mob/user) + + if(default_deconstruction_screwdriver(user, thing)) + return + if(default_deconstruction_crowbar(user, thing)) + return + if(default_part_replacement(user, thing)) + return + if(istype(thing, /obj/item/stack/material)) var/obj/item/stack/material/M = thing var/material/mat = M.get_material() diff --git a/code/modules/power/fusion/fuel_assembly/fuel_injector.dm b/code/modules/power/fusion/fuel_assembly/fuel_injector.dm index 9f54c48188..545638c7d8 100644 --- a/code/modules/power/fusion/fuel_assembly/fuel_injector.dm +++ b/code/modules/power/fusion/fuel_assembly/fuel_injector.dm @@ -11,15 +11,17 @@ var/list/fuel_injectors = list() idle_power_usage = 10 active_power_usage = 500 + circuit = /obj/item/weapon/circuitboard/fusion_injector + var/fuel_usage = 0.0001 var/id_tag var/injecting = 0 var/obj/item/weapon/fuel_assembly/cur_assembly -/obj/machinery/fusion_fuel_injector/New() - ..() +/obj/machinery/fusion_fuel_injector/initialize() + . = ..() fuel_injectors += src - tag = null + default_apply_parts() /obj/machinery/fusion_fuel_injector/Destroy() if(cur_assembly) @@ -66,17 +68,18 @@ var/list/fuel_injectors = list() cur_assembly = W return - if(iswrench(W)) + if(iswrench(W) || isscrewdriver(W) || iscrowbar(W) || istype(W, /obj/item/weapon/storage/part_replacer)) if(injecting) to_chat(user, "Shut \the [src] off first!") return - anchored = !anchored - playsound(src, W.usesound, 75, 1) - if(anchored) - user.visible_message("\The [user] secures \the [src] to the floor.") - else - user.visible_message("\The [user] unsecures \the [src] from the floor.") - return + if(default_unfasten_wrench(user, W)) + return + if(default_deconstruction_screwdriver(user, W)) + return + if(default_deconstruction_crowbar(user, W)) + return + if(default_part_replacement(user, W)) + return return ..() @@ -122,7 +125,6 @@ var/list/fuel_injectors = list() var/obj/effect/accelerated_particle/A = new/obj/effect/accelerated_particle(get_turf(src), dir) A.particle_type = reagent A.additional_particles = numparticles - 1 - A.move(1) if(cur_assembly) cur_assembly.rod_quantities[reagent] -= amount amount_left += cur_assembly.rod_quantities[reagent] @@ -150,4 +152,4 @@ var/list/fuel_injectors = list() if (usr.incapacitated() || usr.restrained() || anchored) return - src.dir = turn(src.dir, 90) \ No newline at end of file + src.dir = turn(src.dir, 90) diff --git a/code/modules/power/fusion/fusion_particle_catcher.dm b/code/modules/power/fusion/fusion_particle_catcher.dm index 38f35357d4..3651285485 100644 --- a/code/modules/power/fusion/fusion_particle_catcher.dm +++ b/code/modules/power/fusion/fusion_particle_catcher.dm @@ -38,4 +38,6 @@ return 0 /obj/effect/fusion_particle_catcher/CanPass(var/atom/movable/mover, var/turf/target, var/height=0, var/air_group=0) - return ismob(mover) + if(istype(mover, /obj/effect/accelerated_particle) || istype(mover, /obj/item/projectile/beam)) + return !density + return 1 diff --git a/code/modules/power/fusion/gyrotron/gyrotron.dm b/code/modules/power/fusion/gyrotron/gyrotron.dm index edf905ab06..5309b0f5b2 100644 --- a/code/modules/power/fusion/gyrotron/gyrotron.dm +++ b/code/modules/power/fusion/gyrotron/gyrotron.dm @@ -9,6 +9,8 @@ var/list/gyrotrons = list() use_power = 1 active_power_usage = 50000 + circuit = /obj/item/weapon/circuitboard/gyrotron + var/id_tag var/rate = 3 var/mega_energy = 1 @@ -21,6 +23,7 @@ var/list/gyrotrons = list() /obj/machinery/power/emitter/gyrotron/initialize() gyrotrons += src active_power_usage = mega_energy * 50000 + default_apply_parts() . = ..() /obj/machinery/power/emitter/gyrotron/Destroy() @@ -54,4 +57,12 @@ var/list/gyrotrons = list() if(new_ident && user.Adjacent(src)) id_tag = new_ident return + + if(default_deconstruction_screwdriver(user, W)) + return + if(default_deconstruction_crowbar(user, W)) + return + if(default_part_replacement(user, W)) + return + return ..() \ No newline at end of file diff --git a/code/modules/power/sensors/powernet_sensor.dm b/code/modules/power/sensors/powernet_sensor.dm index bfc8959139..d082b17922 100644 --- a/code/modules/power/sensors/powernet_sensor.dm +++ b/code/modules/power/sensors/powernet_sensor.dm @@ -32,6 +32,13 @@ /obj/machinery/power/sensor/proc/auto_set_name() name = "[name_tag] - Powernet Sensor" +/obj/machinery/power/sensor/Destroy() + . = ..() + // TODO - Switch power_monitor to register deletion events instead of this. + for(var/obj/machinery/computer/power_monitor/PM in world) + if(PM.power_monitor) + PM.power_monitor.refresh_sensors() + // Proc: check_grid_warning() // Parameters: None // Description: Checks connected powernet for warnings. If warning is found returns 1 diff --git a/code/modules/power/singularity/act.dm b/code/modules/power/singularity/act.dm index 95affc46f1..e65a65e7c4 100644 --- a/code/modules/power/singularity/act.dm +++ b/code/modules/power/singularity/act.dm @@ -19,7 +19,7 @@ if(mind) if((mind.assigned_role == "Station Engineer") || (mind.assigned_role == "Chief Engineer")) gain = 100 - if(mind.assigned_role == "Assistant") + if(mind.assigned_role == USELESS_JOB) //VOREStation Edit - Visitor not Assistant gain = rand(0, 300) investigate_log(I_SINGULO,"has been consumed by a singularity", I_SINGULO) gib() diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm index 751e2cf157..d57c133cd1 100644 --- a/code/modules/power/singularity/containment_field.dm +++ b/code/modules/power/singularity/containment_field.dm @@ -20,7 +20,7 @@ FG1.cleanup() if(FG2 && !FG2.clean_up) FG2.cleanup() - ..() + . = ..() /obj/machinery/containment_field/attack_hand(mob/user as mob) if(get_dist(src, user) > 1) diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm index a801c5b396..a9251e27ee 100644 --- a/code/modules/power/singularity/field_generator.dm +++ b/code/modules/power/singularity/field_generator.dm @@ -168,7 +168,7 @@ field_generator power level display /obj/machinery/field_generator/Destroy() src.cleanup() - ..() + . = ..() @@ -312,12 +312,12 @@ field_generator power level display /obj/machinery/field_generator/proc/cleanup() clean_up = 1 for (var/obj/machinery/containment_field/F in fields) - if (isnull(F)) + if (QDELETED(F)) continue qdel(F) fields = list() for(var/obj/machinery/field_generator/FG in connected_gens) - if (isnull(FG)) + if (QDELETED(FG)) continue FG.connected_gens.Remove(src) if(!FG.clean_up)//Makes the other gens clean up as well diff --git a/code/modules/power/singularity/particle_accelerator/particle.dm b/code/modules/power/singularity/particle_accelerator/particle.dm index 6c5d77fd1d..3b5992e4e4 100644 --- a/code/modules/power/singularity/particle_accelerator/particle.dm +++ b/code/modules/power/singularity/particle_accelerator/particle.dm @@ -4,7 +4,7 @@ name = "Accelerated Particles" desc = "Small things moving very fast." icon = 'icons/obj/machines/particle_accelerator2.dmi' - icon_state = "particle"//Need a new icon for this + icon_state = "particle1"//Need a new icon for this anchored = 1 density = 1 var/movement_range = 10 @@ -19,22 +19,25 @@ var/movetotarget = 1 /obj/effect/accelerated_particle/weak + icon_state = "particle0" movement_range = 8 energy = 5 /obj/effect/accelerated_particle/strong + icon_state = "particle2" movement_range = 15 energy = 15 +/obj/effect/accelerated_particle/powerful + icon_state = "particle3" + movement_range = 25 + energy = 50 /obj/effect/accelerated_particle/New(loc, dir = 2) src.loc = loc src.set_dir(dir) - if(movement_range > 20) - movement_range = 20 spawn(0) move(1) - return /obj/effect/accelerated_particle/Bump(atom/A) @@ -58,18 +61,15 @@ PC.parent.plasma_temperature += mega_energy PC.parent.energy += energy loc = null - return /obj/effect/accelerated_particle/Bumped(atom/A) if(ismob(A)) Bump(A) - return /obj/effect/accelerated_particle/ex_act(severity) qdel(src) - return /obj/effect/accelerated_particle/singularity_act() return @@ -79,7 +79,6 @@ M.apply_effect((radiation*3),IRRADIATE,0) M.updatehealth() //M << "You feel odd." - return /obj/effect/accelerated_particle/proc/move(var/lag) diff --git a/code/modules/power/singularity/particle_accelerator/particle_chamber.dm b/code/modules/power/singularity/particle_accelerator/particle_chamber.dm index 4df3a92c46..4404c33671 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_chamber.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_chamber.dm @@ -3,8 +3,4 @@ desc_holder = "This is where the Alpha particles are accelerated to radical speeds." icon = 'icons/obj/machines/particle_accelerator2.dmi' icon_state = "fuel_chamber" - reference = "fuel_chamber" - -/obj/structure/particle_accelerator/fuel_chamber/update_icon() - ..() - return \ No newline at end of file + reference = "fuel_chamber" \ No newline at end of file diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm index 39f08f509b..0bc4adabcf 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_control.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm @@ -56,11 +56,10 @@ active = 0 connected_parts = list() - return /obj/machinery/particle_accelerator/control_box/update_icon() if(active) - icon_state = "[reference]p1" + icon_state = "[reference]p[strength]" else if(use_power) if(assembled) @@ -77,7 +76,6 @@ icon_state = "[reference]w" else icon_state = "[reference]c" - return /obj/machinery/particle_accelerator/control_box/Topic(href, href_list) ..() @@ -94,9 +92,9 @@ if(href_list["togglep"]) if(!wires.IsIndexCut(PARTICLE_TOGGLE_WIRE)) - src.toggle_power() + toggle_power() else if(href_list["scan"]) - src.part_scan() + part_scan() else if(href_list["strengthup"]) if(!wires.IsIndexCut(PARTICLE_STRENGTH_WIRE)) @@ -106,9 +104,8 @@ if(!wires.IsIndexCut(PARTICLE_STRENGTH_WIRE)) remove_strength() - src.updateDialog() - src.update_icon() - return + updateDialog() + update_icon() /obj/machinery/particle_accelerator/control_box/proc/strength_change() for(var/obj/structure/particle_accelerator/part in connected_parts) @@ -144,7 +141,6 @@ update_use_power(0) else if(!stat && construction_state == 3) update_use_power(1) - return /obj/machinery/particle_accelerator/control_box/process() @@ -152,13 +148,12 @@ //a part is missing! if( length(connected_parts) < 6 ) investigate_log("lost a connected part; It powered down.","singulo") - src.toggle_power() + toggle_power() return //emit some particles for(var/obj/structure/particle_accelerator/particle_emitter/PE in connected_parts) if(PE) PE.emit_particle(src.strength) - return /obj/machinery/particle_accelerator/control_box/proc/part_scan() @@ -211,11 +206,11 @@ /obj/machinery/particle_accelerator/control_box/proc/toggle_power() - src.active = !src.active + active = !active investigate_log("turned [active?"ON":"OFF"] by [usr ? usr.key : "outside forces"]","singulo") message_admins("PA Control Computer turned [active ?"ON":"OFF"] by [key_name(usr, usr.client)](?) in ([x],[y],[z] - JMP)",0,1) log_game("PA Control Computer turned [active ?"ON":"OFF"] by [usr.ckey]([usr]) in ([x],[y],[z])") - if(src.active) + if(active) update_use_power(2) for(var/obj/structure/particle_accelerator/part in connected_parts) part.strength = src.strength diff --git a/code/modules/power/singularity/particle_accelerator/particle_emitter.dm b/code/modules/power/singularity/particle_accelerator/particle_emitter.dm index ff6a444a53..9d37c2e6b8 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_emitter.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_emitter.dm @@ -20,20 +20,16 @@ icon_state = "emitter_right" reference = "emitter_right" -/obj/structure/particle_accelerator/particle_emitter/update_icon() - ..() - return /obj/structure/particle_accelerator/particle_emitter/proc/set_delay(var/delay) if(delay && delay >= 0) - src.fire_delay = delay + fire_delay = delay return 1 return 0 - /obj/structure/particle_accelerator/particle_emitter/proc/emit_particle(var/strength = 0) - if((src.last_shot + src.fire_delay) <= world.time) - src.last_shot = world.time + if((last_shot + fire_delay) <= world.time) + last_shot = world.time var/obj/effect/accelerated_particle/A = null var/turf/T = get_step(src,dir) switch(strength) @@ -43,6 +39,8 @@ A = new/obj/effect/accelerated_particle(T, dir) if(2) A = new/obj/effect/accelerated_particle/strong(T, dir) + if(3) + A = new/obj/effect/accelerated_particle/powerful(T, dir) if(A) A.set_dir(src.dir) return 1 diff --git a/code/modules/power/singularity/particle_accelerator/particle_power.dm b/code/modules/power/singularity/particle_accelerator/particle_power.dm index a4dcb561e7..8badfab91e 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_power.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_power.dm @@ -3,8 +3,4 @@ desc_holder = "This uses electromagnetic waves to focus the Alpha-Particles." icon = 'icons/obj/machines/particle_accelerator2.dmi' icon_state = "power_box" - reference = "power_box" - -/obj/structure/particle_accelerator/power_box/update_icon() - ..() - return + reference = "power_box" \ No newline at end of file diff --git a/code/modules/power/smes_construction.dm b/code/modules/power/smes_construction.dm index bb1603b570..2e8102de81 100644 --- a/code/modules/power/smes_construction.dm +++ b/code/modules/power/smes_construction.dm @@ -1,6 +1,6 @@ // BUILDABLE SMES(Superconducting Magnetic Energy Storage) UNIT // -// Last Change 1.1.2015 by Atlantis - Happy New Year! +// Last Change 1.26.2018 by Neerti. Also signing this is dumb. // // This is subtype of SMES that should be normally used. It can be constructed, deconstructed and hacked. // It also supports RCON System which allows you to operate it remotely, if properly set. @@ -55,8 +55,10 @@ component_parts += new /obj/item/weapon/smes_coil(src) recalc_coils() - - +// Pre-installed and pre-charged SMES hidden from the station, for use in submaps. +/obj/machinery/power/smes/buildable/point_of_interest/New() + ..(1) + charge = 1e6 // Should be enough for an individual POI. diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm index 7c7807b803..dcb177f67d 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm @@ -581,7 +581,7 @@ /datum/reagent/drink/juice/potato name = "Potato Juice" - id = "potato" + id = "potatojuice" description = "Juice of the potato. Bleh." taste_description = "potatoes" nutrition = 2 @@ -1021,7 +1021,7 @@ /datum/reagent/drink/milkshake/berryshake name = "Berry Milkshake" - id = "Berryshake" + id = "berryshake" description = "A refreshing berry milkshake." taste_description = "cold refreshing berries and cream" color = "#ffb2b2" // rgb(255, 178, 178) diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm index 67a146a043..56d2c23fb3 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm @@ -579,6 +579,7 @@ name = "Rezadone" id = "rezadone" description = "A powder with almost magical properties, this substance can effectively treat genetic damage in humanoids, though excessive consumption has side effects." + taste_description = "bitterness" reagent_state = SOLID color = "#669900" overdose = REAGENTS_OVERDOSE @@ -671,27 +672,6 @@ M << "Your mind breaks apart..." M.hallucination += 200 -/datum/reagent/rezadone - name = "Rezadone" - id = "rezadone" - description = "A powder with almost magical properties, this substance can effectively treat genetic damage in humanoids, though excessive consumption has side effects." - taste_description = "bitterness" - reagent_state = SOLID - color = "#669900" - overdose = REAGENTS_OVERDOSE - scannable = 1 - -/datum/reagent/rezadone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) - M.adjustCloneLoss(-20 * removed) - M.adjustOxyLoss(-2 * removed) - M.heal_organ_damage(20 * removed, 20 * removed) - M.adjustToxLoss(-20 * removed) - if(dose > 3) - M.status_flags &= ~DISFIGURED - if(dose > 10) - M.make_dizzy(5) - M.make_jittery(5) - /datum/reagent/qerr_quem name = "Qerr-quem" id = "querr_quem" diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index 6937d2df3f..3fa7f26576 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -1958,6 +1958,34 @@ reagents.add_reagent("tomatojuice", 10) bitesize = 3 +/obj/item/weapon/reagent_containers/food/snacks/onionsoup + name = "Onion Soup" + desc = "A soup with layers." + icon_state = "onionsoup" + trash = /obj/item/trash/snack_bowl + filling_color = "#E0C367" + center_of_mass = list("x"=16, "y"=7) + nutriment_amt = 5 + nutriment_desc = list("onion" = 2, "soup" = 2) + +/obj/item/weapon/reagent_containers/food/snacks/onionsoup/New() + ..() + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/onionrings + name = "Onion Rings" + desc = "Crispy rings." + icon_state = "onionrings" + trash = /obj/item/trash/plate + filling_color = "#E0C367" + center_of_mass = list("x"=16, "y"=7) + nutriment_amt = 5 + nutriment_desc = list("onion" = 2) + +/obj/item/weapon/reagent_containers/food/snacks/onionrings/New() + ..() + bitesize = 2 + /obj/item/weapon/reagent_containers/food/snacks/rofflewaffles name = "Roffle Waffles" desc = "Waffles from Roffle. Co." @@ -3465,9 +3493,9 @@ ..() // potato + knife = raw sticks -/obj/item/weapon/reagent_containers/food/snacks/grown/potato/attackby(obj/item/weapon/W as obj, mob/user as mob) - if(istype(W,/obj/item/weapon/material/knife)) - new /obj/item/weapon/reagent_containers/food/snacks/rawsticks(src) +/obj/item/weapon/reagent_containers/food/snacks/grown/attackby(obj/item/weapon/W, mob/user) + if(seed && seed.kitchen_tag && seed.kitchen_tag == "potato" && istype(W,/obj/item/weapon/material/knife)) + new /obj/item/weapon/reagent_containers/food/snacks/rawsticks(get_turf(src)) user << "You cut the potato." qdel(src) else @@ -3553,3 +3581,251 @@ /obj/item/weapon/reagent_containers/food/snacks/croissant/New() ..() bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/meatbun + name = "meat bun" + desc = "Chinese street food, in neither China nor a street." + filling_color = "#DEDEAB" + icon_state = "meatbun" + nutriment_amt = 4 + +/obj/item/weapon/reagent_containers/food/snacks/meatbun/New() + ..() + bitesize = 2 + reagents.add_reagent("protein", 4) + +/obj/item/weapon/reagent_containers/food/snacks/sashimi + name = "carp sashimi" + desc = "Expertly prepared. Still toxic." + filling_color = "#FFDEFE" + icon_state = "sashimi" + nutriment_amt = 6 + +/obj/item/weapon/reagent_containers/food/snacks/sashimi/New() + ..() + reagents.add_reagent("protein", 2) + reagents.add_reagent("carpotoxin", 2) + bitesize = 3 + +/obj/item/weapon/reagent_containers/food/snacks/benedict + name = "eggs benedict" + desc = "Hey, there's only one egg in this!" + filling_color = "#FFDF78" + icon_state = "benedict" + nutriment_amt = 4 + +/obj/item/weapon/reagent_containers/food/snacks/benedict/New() + ..() + reagents.add_reagent("protein", 2) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/beans + name = "baked beans" + desc = "Musical fruit in a slightly less musical container." + filling_color = "#FC6F28" + icon_state = "beans" + nutriment_amt = 4 + nutriment_desc = list("beans" = 4) + +/obj/item/weapon/reagent_containers/food/snacks/beans/New() + ..() + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/sugarcookie + name = "sugar cookie" + desc = "Just like your little sister used to make." + filling_color = "#DBC94F" + icon_state = "sugarcookie" + nutriment_amt = 5 + nutriment_desc = list("sweetness" = 4, "cookie" = 1) + +/obj/item/weapon/reagent_containers/food/snacks/sugarcookie/New() + ..() + bitesize = 1 + +/obj/item/weapon/reagent_containers/food/snacks/berrymuffin + name = "berry muffin" + desc = "A delicious and spongy little cake, with berries." + icon_state = "berrymuffin" + filling_color = "#E0CF9B" + center_of_mass = list("x"=17, "y"=4) + nutriment_amt = 6 + nutriment_desc = list("sweetness" = 2, "muffin" = 2, "berries" = 2) + +/obj/item/weapon/reagent_containers/food/snacks/berrymuffin/New() + ..() + reagents.add_reagent("nutriment", 6) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/ghostmuffin + name = "booberry muffin" + desc = "My stomach is a graveyard! No living being can quench my bloodthirst!" + icon_state = "berrymuffin" + filling_color = "#799ACE" + center_of_mass = list("x"=17, "y"=4) + nutriment_amt = 6 + nutriment_desc = list("spookiness" = 4, "muffin" = 1, "berries" = 1) + +/obj/item/weapon/reagent_containers/food/snacks/ghostmuffin/New() + ..() + reagents.add_reagent("nutriment", 6) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/eggroll + name = "egg roll" + desc = "Free with orders over 10 thalers." + icon_state = "eggroll" + filling_color = "#799ACE" + center_of_mass = list("x"=17, "y"=4) + nutriment_amt = 4 + nutriment_desc = list("egg" = 4) + +/obj/item/weapon/reagent_containers/food/snacks/eggroll/New() + ..() + reagents.add_reagent("nutriment", 6) + reagents.add_reagent("protein", 2) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/fruitsalad + name = "fruit salad" + desc = "Your standard fruit salad." + icon_state = "fruitsalad" + filling_color = "#FF3867" + nutriment_amt = 10 + nutriment_desc = list("fruit" = 10) + +/obj/item/weapon/reagent_containers/food/snacks/fruitsalad/New() + ..() + reagents.add_reagent("nutriment", 10) + bitesize = 4 + +/obj/item/weapon/reagent_containers/food/snacks/eggbowl + name = "egg bowl" + desc = "A bowl of fried rice with egg mixed in." + icon_state = "eggbowl" + trash = /obj/item/trash/snack_bowl + filling_color = "#FFFBDB" + nutriment_amt = 6 + nutriment_desc = list("rice" = 2, "egg" = 4) + +/obj/item/weapon/reagent_containers/food/snacks/eggbowl/New() + ..() + reagents.add_reagent("nutriment", 6) + reagents.add_reagent("protein", 4) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/porkbowl + name = "pork bowl" + desc = "A bowl of fried rice with cuts of meat." + icon_state = "porkbowl" + trash = /obj/item/trash/snack_bowl + filling_color = "#FFFBDB" + nutriment_amt = 6 + nutriment_desc = list("rice" = 2, "meat" = 4) + +/obj/item/weapon/reagent_containers/food/snacks/porkbowl/New() + ..() + reagents.add_reagent("nutriment", 6) + reagents.add_reagent("protein", 4) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/tortilla + name = "tortilla" + desc = "The base for all your burritos." + icon_state = "tortilla" + nutriment_amt = 1 + nutriment_desc = list("bread" = 1) + +/obj/item/weapon/reagent_containers/food/snacks/tortilla/New() + ..() + reagents.add_reagent("nutriment", 2) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/meatburrito + name = "carne asada burrito" + desc = "The best burrito for meat lovers." + icon_state = "carneburrito" + nutriment_amt = 6 + nutriment_desc = list("tortilla" = 3, "meat" = 3) + +/obj/item/weapon/reagent_containers/food/snacks/meatburrito/New() + ..() + reagents.add_reagent("protein", 6) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/cheeseburrito + name = "Cheese burrito" + desc = "It's a burrito filled with cheese." + icon_state = "cheeseburrito" + nutriment_amt = 6 + nutriment_desc = list("tortilla" = 3, "cheese" = 3) + +/obj/item/weapon/reagent_containers/food/snacks/cheeseburrito/New() + ..() + reagents.add_reagent("nutriment", 6) + reagents.add_reagent("protein", 2) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/fuegoburrito + name = "fuego phoron burrito" + desc = "A super spicy burrito." + icon_state = "fuegoburrito" + nutriment_amt = 6 + nutriment_desc = list("chili peppers" = 5, "tortilla" = 1) + +/obj/item/weapon/reagent_containers/food/snacks/fuegoburrito/New() + ..() + reagents.add_reagent("nutriment", 6) + reagents.add_reagent("capsaicin", 4) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/nachos + name = "nachos" + desc = "Chips from Old Mexico." + icon_state = "nachos" + nutriment_amt = 2 + nutriment_desc = list("salt" = 1) + +/obj/item/weapon/reagent_containers/food/snacks/nachos/New() + ..() + reagents.add_reagent("nutriment", 1) + bitesize = 1 + +/obj/item/weapon/reagent_containers/food/snacks/cheesenachos + name = "cheesy nachos" + desc = "The delicious combination of nachos and melting cheese." + icon_state = "cheesenachos" + nutriment_amt = 5 + nutriment_desc = list("salt" = 2, "cheese" = 3) + +/obj/item/weapon/reagent_containers/food/snacks/cheesenachos/New() + ..() + reagents.add_reagent("nutriment", 5) + reagents.add_reagent("protein", 2) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/cubannachos + name = "cuban nachos" + desc = "That's some dangerously spicy nachos." + icon_state = "cubannachos" + nutriment_amt = 6 + nutriment_desc = list("salt" = 1, "cheese" = 2, "chili peppers" = 3) + +/obj/item/weapon/reagent_containers/food/snacks/cubannachos/New() + ..() + reagents.add_reagent("nutriment", 5) + reagents.add_reagent("capsaicin", 4) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/piginblanket + name = "pig in a blanket" + desc = "A sausage embedded in soft, fluffy pastry. Free this pig from its blanket prison by eating it." + icon_state = "piginblanket" + nutriment_amt = 6 + nutriment_desc = list("meat" = 3, "pastry" = 3) + +/obj/item/weapon/reagent_containers/food/snacks/piginblanket/New() + ..() + reagents.add_reagent("nutriment", 6) + reagents.add_reagent("protein", 4) + bitesize = 3 \ No newline at end of file diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index d33098381b..dc4401f0bc 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -1229,6 +1229,14 @@ CIRCUITS BELOW build_path = /obj/item/weapon/circuitboard/grid_checker sort_string = "JBABC" +/datum/design/circuit/breakerbox + name = "breaker box" + desc = "Allows for the construction of circuit boards used to build a breaker box." + id = "breakerbox" + req_tech = list(TECH_POWER = 3, TECH_ENGINEERING = 3) + build_path = /obj/item/weapon/circuitboard/breakerbox + sort_string = "JBABD" + /datum/design/circuit/gas_heater name = "gas heating system" id = "gasheater" diff --git a/code/modules/research/designs_vr.dm b/code/modules/research/designs_vr.dm index 31a90d5923..b100e5c8b0 100644 --- a/code/modules/research/designs_vr.dm +++ b/code/modules/research/designs_vr.dm @@ -87,7 +87,7 @@ /datum/design/item/translocator name = "Personal translocator" id = "translocator" - req_tech = list(TECH_MAGNET = 5, TECH_BLUESPACE = 5, TECH_ILLEGAL = 7) + req_tech = list(TECH_MAGNET = 5, TECH_BLUESPACE = 5, TECH_ILLEGAL = 6) materials = list(DEFAULT_WALL_MATERIAL = 4000, "glass" = 2000, "uranium" = 4000, "diamond" = 2000) build_path = /obj/item/device/perfect_tele sort_string = "HABAF" @@ -187,4 +187,69 @@ id = "bomb_tester" req_tech = list(TECH_PHORON = 3, TECH_DATA = 2, TECH_MAGNET = 2) build_path = /obj/item/weapon/circuitboard/bomb_tester - sort_string = "HABAG" \ No newline at end of file + sort_string = "HABAG" + +////// RIGSuit Stuff +/* +/datum/design/item/rig + req_tech = list(TECH_MATERIAL = 5, TECH_POWER = 5, TECH_MAGNET = 5) + materials = list(DEFAULT_WALL_MATERIAL = 6000, "glass" = 6000, "silver" = 6000, "uranium" = 4000) + +/datum/design/item/rig/eva + name = "eva hardsuit (empty)" + id = "eva_hardsuit" + build_path = /obj/item/weapon/rig/eva + sort_string = "HCAAA" + +/datum/design/item/rig/mining + name = "industrial hardsuit (empty)" + id = "ind_hardsuit" + build_path = /obj/item/weapon/rig/industrial + sort_string = "HCAAB" + +/datum/design/item/rig/research + name = "ami hardsuit (empty)" + id = "ami_hardsuit" + build_path = /obj/item/weapon/rig/hazmat + sort_string = "HCAAC" + +/datum/design/item/rig/medical + name = "medical hardsuit (empty)" + id = "med_hardsuit" + build_path = /obj/item/weapon/rig/medical + sort_string = "HCAAD" +*/ + +/datum/design/item/rig_module + req_tech = list(TECH_MATERIAL = 5, TECH_POWER = 5, TECH_MAGNET = 5) + materials = list(DEFAULT_WALL_MATERIAL = 6000, "glass" = 6000, "silver" = 4000, "uranium" = 2000) + +/datum/design/item/rig_module/plasma_cutter + name = "rig module - plasma cutter" + id = "rigmod_plasmacutter" + build_path = /obj/item/rig_module/device/plasmacutter + sort_string = "HCAAE" + +/datum/design/item/rig_module/diamond_drill + name = "rig module - diamond drill" + id = "rigmod_diamonddrill" + build_path = /obj/item/rig_module/device/drill + sort_string = "HCAAF" + +/datum/design/item/rig_module/maneuvering_jets + name = "rig module - maneuvering jets" + id = "rigmod_maneuveringjets" + build_path = /obj/item/rig_module/maneuvering_jets + sort_string = "HCAAG" + +/datum/design/item/rig_module/anomaly_scanner + name = "rig module - anomaly scanner" + id = "rigmod_anomalyscanner" + build_path = /obj/item/rig_module/device/anomaly_scanner + sort_string = "HCAAH" + +/datum/design/item/rig_module/orescanner + name = "rig module - ore scanner" + id = "rigmod_orescanner" + build_path = /obj/item/rig_module/device/orescanner + sort_string = "HCAAI" diff --git a/code/modules/shuttles/shuttle.dm b/code/modules/shuttles/shuttle.dm index cdd1b7879b..4a521f90c2 100644 --- a/code/modules/shuttles/shuttle.dm +++ b/code/modules/shuttles/shuttle.dm @@ -60,11 +60,13 @@ return TRUE // If you need an event to occur when the shuttle jumps in short or long jump, override this. -/datum/shuttle/proc/on_shuttle_departure() +/datum/shuttle/proc/on_shuttle_departure(var/area/origin) + origin.shuttle_departed() return // Similar to above, but when it finishes moving to the target. Short jump generally makes this occur immediately after the above proc. -/datum/shuttle/proc/on_shuttle_arrival() +/datum/shuttle/proc/on_shuttle_arrival(var/area/destination) + destination.shuttle_arrived() return /datum/shuttle/proc/short_jump(var/area/origin,var/area/destination) @@ -88,13 +90,13 @@ make_sounds(origin, HYPERSPACE_END) return //someone cancelled the launch - on_shuttle_departure() + on_shuttle_departure(origin) moving_status = SHUTTLE_INTRANSIT //shouldn't matter but just to be safe move(origin, destination) moving_status = SHUTTLE_IDLE - on_shuttle_arrival() + on_shuttle_arrival(destination) make_sounds(destination, HYPERSPACE_END) @@ -125,11 +127,12 @@ depart_time = world.time - on_shuttle_departure() + on_shuttle_departure(departing) moving_status = SHUTTLE_INTRANSIT move(departing, interim, direction) + interim.shuttle_arrived() if(process_longjump(departing, destination)) //VOREStation Edit - To hook custom shuttle code in return //VOREStation Edit - It handled it for us (shuttle crash or such) @@ -147,12 +150,13 @@ create_warning_effect(destination) sleep(5) + interim.shuttle_departed() move(interim, destination, direction) moving_status = SHUTTLE_IDLE - //on_shuttle_arrival()//VOREStation Edit. + on_shuttle_arrival(destination) - //make_sounds(destination, HYPERSPACE_END)//VOREStation Edit. See above comment. + make_sounds(destination, HYPERSPACE_END) /datum/shuttle/proc/dock() if (!docking_controller) @@ -255,4 +259,8 @@ if(HYPERSPACE_END) sound_to_play = 'sound/effects/shuttles/hyperspace_end.ogg' for(var/obj/machinery/door/E in A) //dumb, I know, but playing it on the engines doesn't do it justice - playsound(E, sound_to_play, 50, FALSE) \ No newline at end of file + playsound(E, sound_to_play, 50, FALSE) + +/datum/shuttle/proc/message_passengers(area/A, var/message) + for(var/mob/M in A) + M.show_message(message, 2) diff --git a/code/modules/shuttles/shuttle_arrivals.dm b/code/modules/shuttles/shuttle_arrivals.dm index d0f71d54b1..115d4476d2 100644 --- a/code/modules/shuttles/shuttle_arrivals.dm +++ b/code/modules/shuttles/shuttle_arrivals.dm @@ -57,10 +57,6 @@ ..() // Do everything else -/datum/shuttle/proc/message_passengers(area/A, var/message) - for(var/mob/M in A) - M.show_message(message, 2) - /* /datum/shuttle/ferry/arrivals/current_dock_target() if(location) // If we're off station. diff --git a/code/modules/shuttles/shuttles_web.dm b/code/modules/shuttles/shuttles_web.dm index 8eee5be9b7..ef54ab1383 100644 --- a/code/modules/shuttles/shuttles_web.dm +++ b/code/modules/shuttles/shuttles_web.dm @@ -43,9 +43,11 @@ last_move = world.time /datum/shuttle/web_shuttle/on_shuttle_departure() + ..() web_master.on_shuttle_departure() /datum/shuttle/web_shuttle/on_shuttle_arrival() + ..() web_master.on_shuttle_arrival() /datum/shuttle/web_shuttle/proc/build_destinations() @@ -379,3 +381,35 @@ icon_state = "right" density = TRUE anchored = TRUE + +//An object for creating a shuttle destination to dynamically loaded maps +/obj/shuttle_connector + name = "shuttle connector" + var/shuttle_name //Text name of the shuttle to connect to + var/start_time = 60 SECONDS //After round start (needs to be some time, to let other destinations set up) + var/list/destinations //Make sure this STARTS with a destination that builds a route to one that always exists as an anchor. + +/obj/shuttle_connector/initialize() + . = ..() + + processing_objects += src + +/obj/shuttle_connector/process() + if(world.time < start_time) + return + + if(destinations && shuttle_name) + var/datum/shuttle/web_shuttle/ES = shuttle_controller.shuttles[shuttle_name] + var/datum/shuttle_web_master/WM = ES.web_master + + for(var/new_dest in destinations) + var/datum/shuttle_destination/D = new new_dest(WM) + WM.destinations += D + + for(var/type_to_link in D.routes_to_make) + var/travel_delay = D.routes_to_make[type_to_link] + D.link_destinations(WM.get_destination_by_type(type_to_link), D.preferred_interim_area, travel_delay) + + processing_objects -= src + + qdel(src) diff --git a/code/modules/shuttles/web_datums.dm b/code/modules/shuttles/web_datums.dm index 693ce435b1..c56dc7419c 100644 --- a/code/modules/shuttles/web_datums.dm +++ b/code/modules/shuttles/web_datums.dm @@ -54,6 +54,7 @@ var/datum/shuttle_web_master/master = null // The datum that does the coordination with the actual shuttle datum. var/list/routes = list() // Routes that are connected to this destination. var/preferred_interim_area = null // When building a new route, use this interim area. + var/skip_me = FALSE // We will not autocreate this one. Some map must be doing it. var/dock_target = null // The tag_id that the shuttle will use to try to dock to the destination, if able. @@ -194,8 +195,10 @@ // First, instantiate all the destination subtypes relevant to this datum. var/list/destination_types = typesof(destination_class) - destination_class for(var/new_type in destination_types) - var/datum/shuttle_destination/D = new new_type(src) - destinations += D + var/datum/shuttle_destination/D = new_type + if(initial(D.skip_me)) + continue + destinations += new new_type(src) // Now start the process of connecting all of them. for(var/datum/shuttle_destination/D in destinations) diff --git a/code/modules/vore/eating/contaminate_vr.dm b/code/modules/vore/eating/contaminate_vr.dm index b31b722a35..38dc808b2b 100644 --- a/code/modules/vore/eating/contaminate_vr.dm +++ b/code/modules/vore/eating/contaminate_vr.dm @@ -12,7 +12,7 @@ var/image/gurgled_overlay = image('icons/effects/sludgeoverlay_vr.dmi') if(!gurgled) gurgled = TRUE overlays += gurgled_overlay - var/gurgleflavor = pick("soggy","soaked","dirty","nasty","slimy","drenched","sloppy") + var/gurgleflavor = pick("soggy","soaked","dirty","nasty","slimy","drenched","sloppy","grimy","sludgy","stinky","mucky","stained","soiled","filthy","saucy","foul","icky","tarnished","unsanitary","messy","begrimed","cruddy","funky","disgusting","repulsive","noxious","gruesome","gross","putrid","yucky","tainted","putrescent","unsavory","smelly","smutty","acrid","pungent","unclean","contaminated","gunky","gooey","sticky","drippy","oozing","sloshed","digested","sopping","damp","gloppy","begraggled","churned") cleanname = src.name cleandesc = src.desc name = "[gurgleflavor] [cleanname]" diff --git a/code/modules/vore/eating/digest_act_vr.dm b/code/modules/vore/eating/digest_act_vr.dm index e246ce746c..7be094f6a0 100644 --- a/code/modules/vore/eating/digest_act_vr.dm +++ b/code/modules/vore/eating/digest_act_vr.dm @@ -5,10 +5,18 @@ // Ye default implementation. /obj/item/proc/digest_act(var/list/internal_contents = null, var/atom/movable/item_storage = null) for(var/obj/item/O in contents) - if(internal_contents) - internal_contents |= O - if(item_storage) - O.forceMove(item_storage) + 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) qdel(src) return w_class @@ -71,6 +79,11 @@ . = ..() /obj/item/weapon/holder/digest_act(var/list/internal_contents = null, 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 . = ..() @@ -79,7 +92,6 @@ if((. = ..())) . += 70 //Organs give a little more - ///////////// // Some more complicated stuff ///////////// diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index 7c4d5004f1..c999b7b88b 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -565,4 +565,25 @@ 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 1 \ No newline at end of file + +/mob/living/proc/glow_toggle() + set name = "Glow (Toggle)" + set category = "Abilities" + set desc = "Toggle your glowing on/off!" + + //I don't really see a point to any sort of checking here. + //If they're passed out, the light won't help them. Same with buckled. Really, I think it's fine to do this whenever. + glow_toggle = !glow_toggle + + to_chat(src,"You [glow_toggle ? "en" : "dis"]able your body's glow.") + +/mob/living/proc/glow_color() + set name = "Glow (Set Color)" + set category = "Abilities" + set desc = "Pick a color for your body's glow." + + //Again, no real need for a check on this. I'm unsure how it could be somehow abused. + //Even if they open the box 900 times, who cares, they get the wrong color and do it again. + var/new_color = input(src,"Select a new color","Body Glow",glow_color) as color + if(new_color) + glow_color = new_color diff --git a/code/modules/vore/fluffstuff/custom_clothes_vr.dm b/code/modules/vore/fluffstuff/custom_clothes_vr.dm index 7e4c7f42f6..0edda7843a 100644 --- a/code/modules/vore/fluffstuff/custom_clothes_vr.dm +++ b/code/modules/vore/fluffstuff/custom_clothes_vr.dm @@ -1708,4 +1708,19 @@ Departamental Swimsuits, for general use /obj/item/clothing/gloves/fluff/vietsi/proc/change_name(var/signet_name = "Unknown") name = "[signet_name]'s Bone Signet Ring" - desc = "A signet ring belonging to [signet_name], carved from the bones of something long extinct, as a ward against bad luck." \ No newline at end of file + desc = "A signet ring belonging to [signet_name], carved from the bones of something long extinct, as a ward against bad luck." + +//KotetsuRedwood:Latex Maid Dresses, for everyone to 'enjoy'. :3c +/obj/item/clothing/under/fluff/latexmaid + name = "latex maid dress" + desc = "Squeak! A shiny outfit for cleaning, made by people with dirty minds." + + item_icons = list(slot_w_uniform_str = 'icons/vore/custom_clothes_vr.dmi') + icon = 'icons/vore/custom_clothes_vr.dmi' + icon_state = "latexmaid" + item_state = "latexmaid_mob" + + sprite_sheets = list( + "Teshari" = 'icons/vore/custom_clothes_tesh_vr.dmi' + ) + body_parts_covered = UPPER_TORSO|LOWER_TORSO \ No newline at end of file diff --git a/code/modules/vore/fluffstuff/custom_items_vr.dm b/code/modules/vore/fluffstuff/custom_items_vr.dm index 78b35fb51e..3facf080ee 100644 --- a/code/modules/vore/fluffstuff/custom_items_vr.dm +++ b/code/modules/vore/fluffstuff/custom_items_vr.dm @@ -906,12 +906,157 @@ rimplant.reagents.remove_any(rimplant.transfer_amount) +//Draycu: Schae Yonra +/obj/item/weapon/implant/reagent_generator/yonra + name = "egg laying implant" + desc = "This is an implant that allows the user to lay eggs." + generated_reagents = list("egg" = 2) + usable_volume = 500 + transfer_amount = 50 + empty_message = list("Your feathery lower belly feels smooth and empty. For now...", "The lack of clacking eggs in your abdomen lets you know you're free to continue your day as normal.", "The reduced pressure in your lower belly tells you there are no more eggs.", "With a soft sigh, you can feel your lower body is empty. You know it will only be a matter of time before another batch fills you up again, however.") + full_message = list("Your feathery lower belly looks swollen with irregular bumps, and feels very heavy.", "Your feathery covered lower abdomen feels really heavy, making it a bit hard to walk.", "The added weight from your collection of eggs constantly reminds you that you'll have to lay soon!", "The sounds of eggs clacking as you walk reminds you that you will have to lay soon!") + emote_descriptor = list("an egg right out of Yonra's feathery crotch!", "into Yonra's belly firmly, forcing her to lay an egg!", ", making Yonra gasp and softly moan while an egg slides out.") + var/verb_descriptor = list("squeezes", "pushes", "hugs") + var/self_verb_descriptor = list("squeeze", "push", "hug") + var/short_emote_descriptor = list("lays", "forces out", "pushes out") + self_emote_descriptor = list("lay", "force out", "push out") + random_emote = list("hisses softly with a blush on her face", "yelps in embarrassment", "grunts a little") + assigned_proc = /mob/living/carbon/human/proc/use_reagent_implant_yonra +/obj/item/weapon/implant/reagent_generator/yonra/implanted(mob/living/carbon/source) + processing_objects += src + to_chat(source, "You implant [source] with \the [src].") + source.verbs |= assigned_proc + return 1 +/obj/item/weapon/implanter/reagent_generator/yonra + implant_type = /obj/item/weapon/implant/reagent_generator/yonra +/mob/living/carbon/human/proc/use_reagent_implant_yonra() + set name = "Lay Egg" + set desc = "Force Yonra to lay an egg by squeezing into her lower body! This makes the Teshari stop whatever she is doing at the time, greatly embarassing her." + set category = "Object" + set src in view(1) + //do_reagent_implant(usr) + if(!isliving(usr) || !usr.canClick()) + return + if(usr.incapacitated() || usr.stat > CONSCIOUS) + return + + var/obj/item/weapon/implant/reagent_generator/yonra/rimplant + for(var/I in contents) + if(istype(I, /obj/item/weapon/implant/reagent_generator)) + rimplant = I + break + if (rimplant) + if(rimplant.reagents.total_volume <= rimplant.transfer_amount) + to_chat(src, "[pick(rimplant.empty_message)]") + return + + new /obj/item/weapon/reagent_containers/food/snacks/egg/teshari(get_turf(src)) + + var/index = rand(0,3) + + if (usr != src) + var/emote = rimplant.emote_descriptor[index] + var/verb_desc = rimplant.verb_descriptor[index] + var/self_verb_desc = rimplant.self_verb_descriptor[index] + usr.visible_message("[usr] [verb_desc] [emote]", + "You [self_verb_desc] [emote]") + else + visible_message("[src] [pick(rimplant.short_emote_descriptor)] an egg.", + "You [pick(rimplant.self_emote_descriptor)] an egg.") + if(prob(15)) + visible_message("[src] [pick(rimplant.random_emote)].") + + rimplant.reagents.remove_any(rimplant.transfer_amount) + +/obj/item/weapon/reagent_containers/food/snacks/egg/teshari + name = "teshari egg" + desc = "It's a large teshari egg." + icon = 'icons/vore/custom_items_vr.dmi' + icon_state = "tesh_egg" + filling_color = "#FDFFD1" + volume = 12 + +/obj/item/weapon/reagent_containers/food/snacks/egg/teshari/New() + ..() + reagents.add_reagent("egg", 10) + bitesize = 2 + +/obj/item/weapon/reagent_containers/food/snacks/egg/teshari/tesh2 + icon_state = "tesh_egg_2" + +//Konabird: Rischi +/obj/item/weapon/implant/reagent_generator/rischi + name = "egg laying implant" + desc = "This is an implant that allows the user to lay eggs." + generated_reagents = list("egg" = 2) + usable_volume = 3000 //They requested 1 egg every ~30 minutes. + transfer_amount = 3000 + + empty_message = list("Your abdomen feels normal and taught, like usual.", "The lack of eggs in your abdomen leaves your belly flat and smooth.", "The reduced pressure in your belly tells you there are no more eggs.", "With a soft sigh, you can feel your body is empty of eggs. You know it will only be a matter of time before an egg forms once again, however.") + full_message = list("Your lower abdomen feels a bit swollen", "You feel a pressure within your abdomen, and a broody mood slowly creeps over you.", "You can feel the egg inside of you shift as you move, the needy feeling to lay slowly growing stronger!", "You can feel the egg inside of you, swelling out your normally taught abdomen considerably. You'll definitely need to lay soon!") + emote_descriptor = list("Rischi, causing the small female to squeak and wriggle, an egg falling from between her legs!", "Rischi's midsection, forcing her to lay an egg!", "Rischi, the Teshari huffing and grunting as an egg is squeezed from her body!") + var/verb_descriptor = list("squeezes", "squashes", "hugs") + var/self_verb_descriptor = list("squeeze", "push", "hug") + var/short_emote_descriptor = list("lays", "forces out", "pushes out") + self_emote_descriptor = list("lay", "force out", "push out") + random_emote = list("trembles and huffs, panting from the exertion.", "sees what has happened and covers her face with both hands!", "whimpers softly, her legs shivering, knees pointed inward from the feeling.") + assigned_proc = /mob/living/carbon/human/proc/use_reagent_implant_rischi + +/obj/item/weapon/implant/reagent_generator/rischi/implanted(mob/living/carbon/source) + processing_objects += src + to_chat(source, "You implant [source] with \the [src].") + source.verbs |= assigned_proc + return 1 + +/obj/item/weapon/implanter/reagent_generator/rischi + implant_type = /obj/item/weapon/implant/reagent_generator/rischi + +/mob/living/carbon/human/proc/use_reagent_implant_rischi() + set name = "Lay Egg" + set desc = "Force Rischi to lay an egg by squeezing her! What a terribly rude thing to do!" + set category = "Object" + set src in view(1) + + //do_reagent_implant(usr) + if(!isliving(usr) || !usr.canClick()) + return + + if(usr.incapacitated() || usr.stat > CONSCIOUS) + return + + var/obj/item/weapon/implant/reagent_generator/yonra/rimplant + for(var/I in contents) + if(istype(I, /obj/item/weapon/implant/reagent_generator)) + rimplant = I + break + if (rimplant) + if(rimplant.reagents.total_volume <= rimplant.transfer_amount) + to_chat(src, "[pick(rimplant.empty_message)]") + return + + new /obj/item/weapon/reagent_containers/food/snacks/egg/teshari/tesh2(get_turf(src)) + + var/index = rand(0,3) + + if (usr != src) + var/emote = rimplant.emote_descriptor[index] + var/verb_desc = rimplant.verb_descriptor[index] + var/self_verb_desc = rimplant.self_verb_descriptor[index] + usr.visible_message("[usr] [verb_desc] [emote]", + "You [self_verb_desc] [emote]") + else + visible_message("[src] falls to her knees as the urge to lay overwhelms her, letting out a whimper as she [pick(rimplant.short_emote_descriptor)] an egg from between her legs.", + "You fall to your knees as the urge to lay overwhelms you, letting out a whimper as you [pick(rimplant.self_emote_descriptor)] an egg from between your legs.") + if(prob(15)) + visible_message("[src] [pick(rimplant.random_emote)].") + + rimplant.reagents.remove_any(rimplant.transfer_amount) /obj/item/weapon/implant/reagent_generator/pumila_apple name = "apple laying implant" @@ -1347,6 +1492,10 @@ to_chat(user,"\The [src] can't teleport you that far!") return + if(uT.block_tele || dT.block_tele) + to_chat(user,"Something is interfering with \the [src]!") + return + //Bzzt. ready = 0 power_source.use(charge_cost) diff --git a/code/modules/vore/weight/fitness_machines_vr.dm b/code/modules/vore/weight/fitness_machines_vr.dm index 737d10afbb..d43d76976f 100644 --- a/code/modules/vore/weight/fitness_machines_vr.dm +++ b/code/modules/vore/weight/fitness_machines_vr.dm @@ -1,14 +1,60 @@ -/obj/machinery/workout - name = "fitness lifter" - icon = 'icons/obj/machines/fitness_machines_vr.dmi' - icon_state = "fitnesslifter" //Sprites ripped from goon. +/obj/machinery/fitness + name = "workout equipment" desc = "A utility often used to lose weight." + icon = 'icons/obj/machines/fitness_machines_vr.dmi' anchored = 1 use_power = 0 idle_power_usage = 0 active_power_usage = 0 + var/messages + var/workout_sounds + var/cooldown = 10 + var/weightloss_power = 1 -/obj/machinery/workout/attackby(obj/item/W, var/mob/living/user) +/obj/machinery/fitness/attack_hand(var/mob/living/user) + if(user.nutrition < 70) + user << "You need more energy to workout with the [src]!" + + else if(user.weight < 70) + user << "You're too skinny to risk losing any more weight!" + + else //If they have enough nutrition and body weight, they can exercise. + user.setClickCooldown(cooldown) + user.nutrition -= 10 * weightloss_power + user.weight -= 0.025 * weightloss_power * (0.01*user.weight_loss) + flick("[icon_state]2",src) + var/message = pick(messages) + user << "[message]." + for(var/s in workout_sounds) + playsound(src.loc, s, 50, 1) + +/obj/machinery/fitness/punching_bag + name = "punching bag" + desc = "A bag often used to relieve stress and burn fat." + icon_state = "punchingbag" + anchored = 0 + density = 1 + workout_sounds = list( + "punch") + messages = list( + "You slam your fist into the punching bag", + "You jab the punching bag with your elbow") + +/obj/machinery/fitness/punching_bag/clown + name = "clown punching bag" + desc = "A bag often used to releive stress and burn fat. It has a clown on the front of it." + icon_state = "bopbag" + workout_sounds = list( + "punch", + "clownstep", + "sound/items/bikehorn.ogg") + messages = list( + "You slam your fist into the punching bag", + "You jab the punching bag with your elbow", + "You hammer the clown right in it's face with your fist", + "A honk emits from the punching bag as you hit it") + +/obj/machinery/fitness/heavy/attackby(obj/item/W, var/mob/living/user) if(istype(W, /obj/item/weapon/wrench)) src.add_fingerprint(user) user.visible_message("[user] has [anchored ? "un" : ""]secured \the [src].", "You [anchored ? "un" : ""]secure \the [src].") @@ -16,111 +62,25 @@ playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) return -/obj/machinery/workout/attack_hand(var/mob/living/user) +/obj/machinery/fitness/heavy/attack_hand(var/mob/living/user) if(!anchored) user << "For safety reasons, you are required to have this equipment wrenched down before using it!" return else if(user.loc != src.loc) - user << "For safety reasons, you need to be sitting in the fitness lifter for it to work!" + user << "For safety reasons, you need to be sitting in the [src] for it to work!" return - else if(user.nutrition > 70 && user.weight > 70) //If they have enough nutrition and body weight, they can exercise. - user.setClickCooldown(40) - user.dir = src.dir - user.nutrition = user.nutrition - 20 //Working out burns a lot of calories! - user.weight = user.weight - 0.05 //Burn a bit of weight. Not much, but quite a bit. This can't be spammed, as they'll need nutrition to be able to work out. - flick("fitnesslifter2",src) - user << "You lift some weights." - - else if(user.nutrition < 70) - user << "You need more energy to workout on the mat!" - - else if(user.weight < 70) - user << "You're too skinny to risk losing any more weight!" - else - user << "You're unable to use the fitness lifter." - return //Something went wrong. They shouldn't see this. + ..() -/obj/machinery/workout/shipped - anchored = 0 // For cargo. - - -/obj/machinery/punching_bag - name = "punching bag" - icon = 'icons/obj/machines/fitness_machines_vr.dmi' - icon_state = "punchingbag" - desc = "A bag often used to releive stress and burn fat." - anchored = 1 - density = 1 - use_power = 0 - idle_power_usage = 0 - active_power_usage = 0 - -/obj/machinery/punching_bag/attack_hand(var/mob/living/user) - - if(user.nutrition > 35 && user.weight > 70) //If they have enough nutrition and body weight, they can exercise. - user.setClickCooldown(10) - user.nutrition = user.nutrition - 10 //A punching bag uses less calories. - user.weight = user.weight - 0.025 //And burns less weight. - flick("punchingbag2",src) - var/message = pick( - "You slam your fist into the punching bag.", - "You jab the punching bag with your elbow.") - user << message - playsound(src.loc, "punch", 50, 1) - - else if(user.nutrition < 35) - user << "You need more energy to workout on the mat!" - - else if(user.weight < 70) - user << "You're too skinny to risk losing any more weight!" - - else - user << "You're unable to use the punching bag." - return //Something went wrong. They shouldn't see this. - - -/obj/machinery/punching_clown - name = "clown punching bag" - icon = 'icons/obj/machines/fitness_machines_vr.dmi' - icon_state = "bopbag" - desc = "A bag often used to releive stress and burn fat. It has a clown on the front of it." - anchored = 0 - density = 1 - use_power = 0 - idle_power_usage = 0 - active_power_usage = 0 - -/obj/machinery/punching_clown/attack_hand(var/mob/living/user) - - if(user.nutrition > 35 && user.weight > 70) //If they have enough nutrition and body weight, they can exercise. - user.setClickCooldown(10) - user.nutrition = user.nutrition - 10 - user.weight = user.weight - 0.025 - flick("bopbag2",src) - var/message = pick( - "You slam your fist into the punching bag.", - "You jab the punching bag with your elbow.", - "You hammer the clown right in it's face with your fist.", - "A honk emits from the punching bag as you hit it.") - var/sound = pick( - "punch", - "clownstep", - 'sound/items/bikehorn.ogg') - user << message - playsound(src.loc, sound, 50, 1) - - else if(user.nutrition < 35) - user << "You need more energy to workout on the mat!" - - else if(user.weight < 70) - user << "You're too skinny to risk losing any more weight!" - - else - user << "You're unable to use the punching bag." - return //Something went wrong. They shouldn't see this. +/obj/machinery/fitness/heavy/lifter + name = "fitness lifter" + desc = "A specialized machine that can be used for an assortment of excercises involving moving some weight repeatedly. Often used with the goal of losing weight." + icon_state = "fitnesslifter" //Sprites ripped from goon. + messages = list("You lift some weights") + weightloss_power = 2 + cooldown = 40 /obj/machinery/scale name = "scale" @@ -131,13 +91,11 @@ use_power = 0 idle_power_usage = 0 active_power_usage = 0 - var/kilograms /obj/machinery/scale/attack_hand(var/mob/living/user) - if(user.loc != src.loc) + if(user.loc != loc) user << "You need to be standing on top of the scale for it to work!" return if(user.weight) //Just in case. - kilograms = round(text2num(user.weight),4) / 2.20463 - user << "Your relative weight is [user.weight]lb / [kilograms]kg." - user.visible_message("[user]'s relative weight is [user.weight]lb / [kilograms]kg.") + var/kilograms = round(text2num(user.weight),4) / 2.20463 + visible_message("[src] displays a reading of [user.weight]lb / [kilograms]kg when [user] stands on it.") diff --git a/code/modules/xenoarcheaology/misc_vr.dm b/code/modules/xenoarcheaology/misc_vr.dm index 17acb08aa9..13f878e63e 100644 --- a/code/modules/xenoarcheaology/misc_vr.dm +++ b/code/modules/xenoarcheaology/misc_vr.dm @@ -1,18 +1,3 @@ -/obj/structure/closet/secure_closet/xenoarchaeologist - name = "Xenoarchaeologist Locker" - req_access = list(access_tox_storage) - icon_state = "secureres1" - icon_closed = "secureres" - icon_locked = "secureres1" - icon_opened = "secureresopen" - icon_broken = "secureresbroken" - icon_off = "secureresoff" - - New() - ..() - new /obj/item/weapon/rig/hazmat/equipped(src) - return - /obj/structure/closet/excavation name = "Excavation tools" icon_state = "toolcloset" diff --git a/code/modules/xenobio2/controller.dm b/code/modules/xenobio2/controller.dm index 112d667c0f..bcd13bb602 100644 --- a/code/modules/xenobio2/controller.dm +++ b/code/modules/xenobio2/controller.dm @@ -34,10 +34,10 @@ var/global/datum/controller/xenobio/xenobio_controller // Set in New(). var/list/xenobio_traits = ALL_XENO_GENES while(xenobio_traits && xenobio_traits.len) var/gene_tag = pick(xenobio_traits) - var/gene_mask = "[uppertext(num2hex(rand(0,255)))]" + var/gene_mask = "[uppertext(num2hex(rand(0,255), 2))]" while(gene_mask in used_masks) - gene_mask = "[uppertext(num2hex(rand(0,255)))]" + gene_mask = "[uppertext(num2hex(rand(0,255), 2))]" used_masks += gene_mask xenobio_traits -= gene_tag diff --git a/code/unit_tests/map_tests.dm b/code/unit_tests/map_tests.dm index 92d17a2aba..c5bccc437d 100644 --- a/code/unit_tests/map_tests.dm +++ b/code/unit_tests/map_tests.dm @@ -39,8 +39,10 @@ exempt_from_atmos += using_map.unit_test_exempt_from_atmos.Copy() exempt_from_apc += using_map.unit_test_exempt_from_apc.Copy() + var/list/zs_to_test = using_map.unit_test_z_levels || list(1) //Either you set it, or you just get z1 + for(var/area/A in world) - if(A.z == 1 && !(A.type in exempt_areas)) + if((A.z in zs_to_test) && !(A.type in exempt_areas)) area_test_count++ var/area_good = 1 var/bad_msg = "--------------- [A.name]([A.type])" diff --git a/config/alienwhitelist.txt b/config/alienwhitelist.txt index 7deb0fe05c..1a659b341c 100644 --- a/config/alienwhitelist.txt +++ b/config/alienwhitelist.txt @@ -1,8 +1,11 @@ aether_elemental - Daemon aruis - Xenochimera +azmodan412 - Xenochimera +azmodan412 - Xenomorph Hybrid bothnevarbackwards - Diona cameron653 - Xenomorph Hybrid hawkerthegreat - Vox +inuzari - Diona jemli - Gutter mewchild - Diona mewchild - Vox diff --git a/config/example/config.txt b/config/example/config.txt index 87c60726d7..3b4e07647a 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -402,3 +402,13 @@ DISABLE_PLAYER_MICE ## Default language prefix keys, separated with spaces. Only single character keys are supported. If unset, defaults to , # and - # DEFAULT_LANGUAGE_PREFIXES , # - + +# Control which submaps are loaded for the Dynamic Engine system +ENGINE_MAP Supermatter Engine,Edison's Bane + +# Controls if the 'time off' system is used for determining if players can play 'Off-Duty' jobs (requires SQL) +# TIME_OFF + +# Applies a limit to the number of assistants and visitors respectively +# LIMIT_INTERNS 6 +# LIMIT_VISITORS 6 \ No newline at end of file diff --git a/html/changelog.html b/html/changelog.html index 280b45a1bb..45d9cd6099 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -53,6 +53,71 @@ -->
+

25 January 2018

+

Anewbe updated:

+ +

Arokha updated:

+ +

Atermonera updated:

+ +

Cerebulon updated:

+ +

Leshana updated:

+ +

Mechoid updated:

+ +

Neerti updated:

+ +

SunnyDaff updated:

+ +

ZeroBits updated:

+ +

battlefieldCommander updated:

+ +

12 January 2018

Atermonera updated: