diff --git a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm index 5abaa00c606..92c26fb2809 100644 --- a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm +++ b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm @@ -67,6 +67,8 @@ pressure_delta = input_starting_pressure - target_pressure if (REGULATE_OUTPUT) pressure_delta = target_pressure - output_starting_pressure + if (REGULATE_NONE) + pressure_delta = input_starting_pressure - output_starting_pressure //-1 if pump_gas() did not move any gas, >= 0 otherwise var/returnval = -1 @@ -82,9 +84,46 @@ transfer_moles = min(transfer_moles, calculate_transfer_moles(air2, air1, pressure_delta, (network1)? network1.volume : 0)) if (REGULATE_OUTPUT) transfer_moles = min(transfer_moles, calculate_transfer_moles(air1, air2, pressure_delta, (network2)? network2.volume : 0)) + if (REGULATE_NONE) + var/source = air1 + var/sink = air2 + // If node1 is a network of more than 1 pipe, we want to transfer from that whole network, otw use just node1, as current + if(istype(node1, /obj/machinery/atmospherics/pipe)) + var/obj/machinery/atmospherics/pipe/p = node1 + if(istype(p.parent, /datum/pipeline)) // Nested if-blocks to avoid the mystical : + var/datum/pipeline/l = p.parent + if(istype(l.air, /datum/gas_mixture)) + source = l.air + // If node2 is a network of more than 1 pipe, we want to transfer to that whole network, otw use just node2, as current + if(istype(node2, /obj/machinery/atmospherics/pipe)) + var/obj/machinery/atmospherics/pipe/p = node2 + if(istype(p.parent, /datum/pipeline)) + var/datum/pipeline/l = p.parent + if(istype(l.air, /datum/gas_mixture)) + sink = l.air + transfer_moles = max(0, calculate_equalize_moles(source, sink)) // Not regulated, don't care about flow rate //pump_gas() will return a negative number if no flow occurred - returnval = pump_gas_passive(src, air1, air2, transfer_moles) + if(regulate_mode == REGULATE_NONE) // ACTUALLY move gases from the whole network, not just the immediate pipes + var/source = air1 + var/sink = air2 + // If node1 is a network of more than 1 pipe, we want to transfer from that whole network, otw use just node1, as current + if(istype(node1, /obj/machinery/atmospherics/pipe)) + var/obj/machinery/atmospherics/pipe/p = node1 + if(istype(p.parent, /datum/pipeline)) // Nested if-blocks to avoid the mystical : + var/datum/pipeline/l = p.parent + if(istype(l.air, /datum/gas_mixture)) + source = l.air + // If node2 is a network of more than 1 pipe, we want to transfer to that whole network, otw use just node2, as current + if(istype(node2, /obj/machinery/atmospherics/pipe)) + var/obj/machinery/atmospherics/pipe/p = node2 + if(istype(p.parent, /datum/pipeline)) + var/datum/pipeline/l = p.parent + if(istype(l.air, /datum/gas_mixture)) + sink = l.air + returnval = pump_gas_passive(src, source, sink, transfer_moles) + else + returnval = pump_gas_passive(src, air1, air2, transfer_moles) if (returnval >= 0) if(network1) diff --git a/code/ATMOSPHERICS/components/shutoff.dm b/code/ATMOSPHERICS/components/shutoff.dm index de69f5e395e..87d26988413 100644 --- a/code/ATMOSPHERICS/components/shutoff.dm +++ b/code/ATMOSPHERICS/components/shutoff.dm @@ -7,6 +7,7 @@ GLOBAL_LIST_EMPTY(shutoff_valves) name = "automatic shutoff valve" desc = "An automatic valve with control circuitry and pipe integrity sensor, capable of automatically isolating damaged segments of the pipe network." + description_info = "Clicking this will toggle the automatic control. Alt-clicking this when the automatic control is disabled will manually open or close the valve." var/close_on_leaks = TRUE // If false it will be always open level = 1 @@ -37,21 +38,97 @@ GLOBAL_LIST_EMPTY(shutoff_valves) to_chat(user, "You [close_on_leaks ? "enable" : "disable"] the automatic shutoff circuit.") return TRUE +// Alt+Click now toggles the open/close function, when the autoseal is disabled +/obj/machinery/atmospherics/valve/shutoff/AltClick(var/mob/user) + if(isliving(user)) + if(close_on_leaks) + to_chat(user, "You try to manually [open ? "close" : "open"] the valve, but it [open ? "opens" : "closes"] automatically again.") + return + + open ? close() : open() + to_chat(user, "You manually [open ? "open" : "close"] the valve.") + /obj/machinery/atmospherics/valve/shutoff/process() ..() - if (!network_node1 || !network_node2) - if(open) + if(!network_node1 || !network_node2 || !node1 || !node2) + if(open && close_on_leaks) close() return - if (!close_on_leaks) - if (!open) + if(close_on_leaks) + if(open && (network_node1.leaks.len || network_node2.leaks.len)) + find_leaks() // If we can see the leak, then this will find it, close the valve, and cut off that network + // If we cannot see the leak, then this will not close the valve, and any valves that can see the leak will cut it off from us + else if(!open && !network_node1.leaks.len && !network_node2.leaks.len) open() + return + +// Breadth-first search for any leaking pipes that we can directly see +/obj/machinery/atmospherics/valve/shutoff/proc/find_leaks() + var/obj/machinery/atmospherics/list/search = list() + + // We're the leak! + if(!node1 || !node2) + close() return - if (network_node1.leaks.len || network_node2.leaks.len) - if (open) - close() - else if (!open) - open() + // Only searching pipes + if(istype(node1, /obj/machinery/atmospherics)) + search |= node1 + if(istype(node2, /obj/machinery/atmospherics)) + search |= node2 + + // Breadth-first search + for(var/i = 1, i <= search.len, i++) // wooo, proper for loop syntax! + var/obj/machinery/atmospherics/A = search[i] + if(!A) + continue + + if(istype(A, /obj/machinery/atmospherics/pipe)) + var/obj/machinery/atmospherics/pipe/L = A + if(L.leaking) + close() // Found the leak! + return + + + if(istype(A, /obj/machinery/atmospherics/valve/shutoff)) + var/obj/machinery/atmospherics/valve/shutoff/S = A + if(S.close_on_leaks || !S.open) + continue // Either it will close, or it is closed. We don't care what's on the other side + search |= list(S.node1, S.node2) // |= skips existing nodes, so we don't search loops infinitely + + else if(istype(A, /obj/machinery/atmospherics/valve)) // Putting the shutoff before this means this won't catch shutoffs + var/obj/machinery/atmospherics/valve/V = A + if(V.open) + search |= list(V.node1, V.node2) + else + continue // Closed valve, dead end + + else if(istype(A, /obj/machinery/atmospherics/tvalve)) + var/obj/machinery/atmospherics/tvalve/T = A + if(T.state) + search |= list(T.node1, T.node2) + else + search |= list(T.node1, T.node3) + + else if(istype(A, /obj/machinery/atmospherics/pipe/zpipe)) + var/obj/machinery/atmospherics/pipe/zpipe/P = A + search |= list(P.node1, P.node2) + + else if(istype(A, /obj/machinery/atmospherics/pipe/simple)) + var/obj/machinery/atmospherics/pipe/P = A + search |= list(P.node1, P.node2) + + else if(istype(A, /obj/machinery/atmospherics/pipe/manifold)) + var/obj/machinery/atmospherics/pipe/manifold/M = A + search |= list(M.node1, M.node2, M.node3) + + else if(istype(A, /obj/machinery/atmospherics/pipe/manifold4w)) + var/obj/machinery/atmospherics/pipe/manifold4w/M = A + search |= list(M.node1, M.node2, M.node3, M.node4) + + // else continue, dead end + // We broke out of the loop, so we see no leaks + // The leaks therefore must be on the other side of another shutoff valve + return diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index d43faaf4a53..5278b8c5263 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -115,10 +115,10 @@ #define INV_BACK_DEF_ICON 'icons/mob/back.dmi' #define INV_L_HAND_DEF_ICON 'icons/mob/items/lefthand.dmi' #define INV_R_HAND_DEF_ICON 'icons/mob/items/righthand.dmi' -#define INV_W_UNIFORM_DEF_ICON 'icons/mob/uniform.dmi' +#define INV_W_UNIFORM_DEF_ICON "icons/mob/uniform" #define INV_ACCESSORIES_DEF_ICON 'icons/mob/ties.dmi' #define INV_TIE_DEF_ICON 'icons/mob/ties.dmi' -#define INV_SUIT_DEF_ICON 'icons/mob/suit.dmi' +#define INV_SUIT_DEF_ICON "icons/mob/suit" #define INV_SPACESUIT_DEF_ICON 'icons/mob/spacesuit.dmi' #define INV_WEAR_ID_DEF_ICON 'icons/mob/mob.dmi' #define INV_GLOVES_DEF_ICON 'icons/mob/hands.dmi' diff --git a/code/_helpers/_lists.dm b/code/_helpers/_lists.dm index 1eb8ac54560..bc6b46ea186 100644 --- a/code/_helpers/_lists.dm +++ b/code/_helpers/_lists.dm @@ -5,18 +5,79 @@ * Sorting */ +// Determiner constants +#define DET_NONE 0x00; +#define DET_DEFINITE 0x01; // the +#define DET_INDEFINITE 0x02; // a, an, some +#define DET_AUTO 0x04; + /* * Misc */ //Returns a list in plain english as a string -/proc/english_list(var/list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" ) +/proc/english_list(var/list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "") + // this proc cannot be merged with counting_english_list to maintain compatibility + // with shoddy use of this proc for code logic and for cases that require original order switch(input.len) if(0) return nothing_text if(1) return "[input[1]]" if(2) return "[input[1]][and_text][input[2]]" else return "[jointext(input, comma_text, 1, -1)][final_comma_text][and_text][input[input.len]]" +//Returns a newline-separated list that counts equal-ish items, outputting count and item names, optionally with icons and specific determiners +/proc/counting_english_list(var/list/input, output_icons = TRUE, determiners = DET_NONE, nothing_text = "nothing", line_prefix = "\t", first_item_prefix = "\n", last_item_suffix = "\n", and_text = "\n", comma_text = "\n", final_comma_text = "") + var/list/counts = list() // counted input items + var/list/items = list() // actual objects for later reference (for icons and formatting) + + // count items + for(var/item in input) + var/name = "[item]" // index items by name; usually works fairly well for loose equality + if(name in counts) + counts[name]++ + else + counts[name] = 1 + items.Add(item) + + // assemble the output list + var/list/out = list() + var/i = 0 + for(var/item in items) + var/name = "[item]" + var/count = counts[name] + var/item_str = line_prefix + if(count > 1) + item_str += "[count]x " + + if(isatom(item)) + // atoms/items/objects can be pretty and whatnot + var/atom/A = item + if(output_icons && isicon(A.icon) && !ismob(A)) // mobs tend to have unusable icons + item_str += "\icon[A] " + switch(determiners) + if(DET_NONE) item_str += A.name + if(DET_DEFINITE) item_str += "\the [A]" + if(DET_INDEFINITE) item_str += "\a [A]" + else item_str += name + else + // non-atoms use plain string conversion + item_str += name + + if(i == 0) + item_str = first_item_prefix + item_str + if(i == items.len - 1) + item_str = item_str + last_item_suffix + + out.Add(item_str) + i++ + + // finally return the list using regular english_list builder + return english_list(out, nothing_text, and_text, comma_text, final_comma_text) + +//A "preset" for counting_english_list that displays the list "inline" (comma separated) +/proc/inline_counting_english_list(var/list/input, output_icons = TRUE, determiners = DET_NONE, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "", line_prefix = "", first_item_prefix = "", last_item_suffix = "") + return counting_english_list(input, output_icons, determiners, nothing_text, and_text, comma_text, final_comma_text) + //Returns list element or null. Should prevent "index out of bounds" error. proc/listgetindex(var/list/list,index) if(istype(list) && list.len) @@ -762,4 +823,4 @@ proc/dd_sortedTextList(list/incoming) /proc/popleft(list/L) if(L.len) . = L[1] - L.Cut(1,2) + L.Cut(1,2) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index bf48f4e8f87..0af9009297c 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -22,6 +22,7 @@ var/list/gamemode_cache = list() var/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits var/log_runtime = 0 // logs world.log to a file var/log_world_output = 0 // log world.log << messages + var/log_graffiti = 0 // logs graffiti var/sql_enabled = 0 // for sql switching var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour var/allow_vote_restart = 0 // allow votes to restart @@ -375,6 +376,9 @@ var/list/gamemode_cache = list() if ("log_runtime") config.log_runtime = 1 + if ("log_graffiti") + config.log_graffiti = 1 + if ("generate_map") config.generate_map = 1 diff --git a/code/controllers/configuration_vr.dm b/code/controllers/configuration_vr.dm index cde9c7c963e..cc3566cf4fb 100644 --- a/code/controllers/configuration_vr.dm +++ b/code/controllers/configuration_vr.dm @@ -10,6 +10,7 @@ var/limit_visitors = -1 //Unlimited by default var/pto_cap = 100 //Hours var/require_flavor = FALSE + var/ipqualityscore_apikey //API key for ipqualityscore.com /hook/startup/proc/read_vs_config() var/list/Lines = file2list("config/config.txt") @@ -58,4 +59,6 @@ config.pto_job_change = TRUE if ("require_flavor") config.require_flavor = TRUE + if ("ipqualityscore_apikey") + config.ipqualityscore_apikey = value return 1 diff --git a/code/datums/ghost_query_vr.dm b/code/datums/ghost_query_vr.dm new file mode 100644 index 00000000000..e74aa9ff1a2 --- /dev/null +++ b/code/datums/ghost_query_vr.dm @@ -0,0 +1,4 @@ +/datum/ghost_query/morph + role_name = "Morph" + question = "A weird morphic creature appears to have snuck onstation. Do you want to play as it? ((Expect to be treated as vore predator))" + cutoff_number = 1 \ No newline at end of file diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index 089a6be7224..e512c7acbc1 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -158,6 +158,13 @@ precision = rand(1,100) var/list/bagholding = teleatom.search_contents_for(/obj/item/weapon/storage/backpack/holding) + //VOREStation Addition Start: Prevent taurriding abuse + if(istype(teleatom, /mob/living)) + var/mob/living/L = teleatom + if(LAZYLEN(L.buckled_mobs)) + for(var/mob/rider in L.buckled_mobs) + bagholding += rider.search_contents_for(/obj/item/weapon/storage/backpack/holding) + //VOREStation Addition End: Prevent taurriding abuse if(bagholding.len) precision = max(rand(1,100)*bagholding.len,100) if(istype(teleatom, /mob/living)) diff --git a/code/defines/procs/dbcore.dm b/code/defines/procs/dbcore.dm index 45139ab3fb1..35470e8c598 100644 --- a/code/defines/procs/dbcore.dm +++ b/code/defines/procs/dbcore.dm @@ -56,7 +56,7 @@ DBConnection/New(dbi_handler,username,password_handler,cursor_handler) _db_con = _dm_db_new_con() DBConnection/proc/Connect(dbi_handler=src.dbi,user_handler=src.user,password_handler=src.password,cursor_handler) - if(!sqllogging) + if(!config.sql_enabled) return 0 if(!src) return 0 cursor_handler = src.default_cursor @@ -66,7 +66,7 @@ DBConnection/proc/Connect(dbi_handler=src.dbi,user_handler=src.user,password_han DBConnection/proc/Disconnect() return _dm_db_close(_db_con) DBConnection/proc/IsConnected() - if(!sqllogging) return 0 + if(!config.sql_enabled) return 0 var/success = _dm_db_is_connected(_db_con) return success diff --git a/code/game/machinery/frame.dm b/code/game/machinery/frame.dm index 41c7a33a19c..1331f5adb76 100644 --- a/code/game/machinery/frame.dm +++ b/code/game/machinery/frame.dm @@ -429,6 +429,7 @@ circuit = null if(frame_type.frame_class == FRAME_CLASS_MACHINE) req_components = null + update_desc() else if(state == FRAME_WIRED) if(frame_type.frame_class == FRAME_CLASS_MACHINE) @@ -498,27 +499,21 @@ else if(P.is_wirecutter()) if(state == FRAME_WIRED) - if(frame_type.frame_class == FRAME_CLASS_COMPUTER) + if( \ + frame_type.frame_class == FRAME_CLASS_COMPUTER || \ + frame_type.frame_class == FRAME_CLASS_DISPLAY || \ + frame_type.frame_class == FRAME_CLASS_ALARM || \ + frame_type.frame_class == FRAME_CLASS_MACHINE \ + ) playsound(src, P.usesound, 50, 1) - to_chat(user, "You remove the cables.") - state = FRAME_FASTENED - new /obj/item/stack/cable_coil(src.loc, 5) - - else if(frame_type.frame_class == FRAME_CLASS_DISPLAY) - playsound(src, P.usesound, 50, 1) - to_chat(user, "You remove the cables.") - state = FRAME_FASTENED - new /obj/item/stack/cable_coil(src.loc, 5) - - else if(frame_type.frame_class == FRAME_CLASS_ALARM) - playsound(src, P.usesound, 50, 1) - to_chat(user, "You remove the cables.") - state = FRAME_FASTENED - new /obj/item/stack/cable_coil(src.loc, 5) - - else if(frame_type.frame_class == FRAME_CLASS_MACHINE) - playsound(src, P.usesound, 50, 1) - to_chat(user, "You remove the cables.") + if (components.len == 0) + to_chat(user, "You remove the cables.") + else + to_chat(user, "You remove the cables and components.") + for(var/obj/item/weapon/W in components) + W.forceMove(src.loc) + check_components() + update_desc() state = FRAME_FASTENED new /obj/item/stack/cable_coil(src.loc, 5) diff --git a/code/game/machinery/holosign.dm b/code/game/machinery/holosign.dm index 39a91b8aff4..9a656ac3bed 100644 --- a/code/game/machinery/holosign.dm +++ b/code/game/machinery/holosign.dm @@ -13,6 +13,7 @@ var/id = null var/on_icon = "sign_on" var/off_icon = "sign_off" + var/signlight = "#E9E4AF" /obj/machinery/holosign/proc/toggle() if(stat & (BROKEN|NOPOWER)) @@ -24,13 +25,17 @@ /obj/machinery/holosign/update_icon() if(!lit) icon_state = off_icon + set_light(0) else icon_state = on_icon + set_light(2, 0.25, signlight) /obj/machinery/holosign/power_change() + ..() if(stat & NOPOWER) lit = 0 use_power = 0 + update_icon() /obj/machinery/holosign/surgery @@ -49,7 +54,7 @@ icon_state = "barclosed" on_icon = "baropen" off_icon = "barclosed" - + signlight = "#b1edf9" ////////////////////SWITCH/////////////////////////////////////// diff --git a/code/game/machinery/neonsign.dm b/code/game/machinery/neonsign.dm new file mode 100644 index 00000000000..fe5d5370a86 --- /dev/null +++ b/code/game/machinery/neonsign.dm @@ -0,0 +1,73 @@ +////////////////////NOTHOLOSIGN/////////////////////////////////////// +/obj/machinery/neonsign + name = "neon sign" + desc = "Small wall-mounted electronic sign" + icon = 'icons/obj/neonsigns.dmi' + icon_state = "sign_off" + plane = MOB_PLANE + use_power = 1 + idle_power_usage = 2 + active_power_usage = 4 + anchored = 1 + var/lit = 0 + var/id = null + var/on_icon = "sign_on" + var/off_icon = "sign_off" + var/signlight = "#E9E4AF" + +/obj/machinery/neonsign/proc/toggle() + if(stat & (BROKEN|NOPOWER)) + return + lit = !lit + use_power = lit ? 2 : 1 + update_icon() + +/obj/machinery/neonsign/update_icon() + if(!lit) + icon_state = off_icon + set_light(0) + else + icon_state = on_icon + set_light(2, 0.25, signlight) + +/obj/machinery/neonsign/power_change() + ..() + if(stat & NOPOWER) + lit = 0 + use_power = 0 + + update_icon() + +/obj/machinery/neonsign/cafe + name = "cafe neon sign" + desc = "Small wall-mounted electronic sign. This one reads CAFE." + icon_state = "cafesign_off" + on_icon = "cafesign_on" + off_icon = "cafesign_off" + signlight = "#DFA571" + +////////////////////SWITCH/////////////////////////////////////// + +/obj/machinery/button/neonsign + name = "sign switch" + desc = "A remote control switch for neon sign." + icon = 'icons/obj/power.dmi' + icon_state = "crema_switch" + +/obj/machinery/button/neonsign/attack_hand(mob/user as mob) + if(..()) + return + add_fingerprint(user) + + use_power(5) + + active = !active + icon_state = "light[active]" + + for(var/obj/machinery/neonsign/M in machines) + if(M.id == id) + spawn(0) + M.toggle() + return + + return \ No newline at end of file diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 302823c82df..ff4caf3f670 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -209,6 +209,14 @@ O.show_message("Failure: Cannot authenticate locked on coordinates. Please reinstate coordinate matrix.") return if(istype(M, /atom/movable)) + //VOREStation Addition Start: Prevent taurriding abuse + if(istype(M, /mob/living)) + var/mob/living/L = M + if(LAZYLEN(L.buckled_mobs)) + var/datum/riding/R = L.riding_datum + for(var/rider in L.buckled_mobs) + R.force_dismount(rider) + //VOREStation Addition End: Prevent taurriding abuse if(prob(5) && !accurate) //oh dear a problem, put em in deep space do_teleport(M, locate(rand((2*TRANSITIONEDGE), world.maxx - (2*TRANSITIONEDGE)), rand((2*TRANSITIONEDGE), world.maxy - (2*TRANSITIONEDGE)), 3), 2) else diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index 5ba58dc4e0c..1a9488a0a6c 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -60,6 +60,14 @@ GLOBAL_LIST_BOILERPLATE(all_portals, /obj/effect/portal) qdel(src) return if (istype(M, /atom/movable)) + //VOREStation Addition Start: Prevent taurriding abuse + if(istype(M, /mob/living)) + var/mob/living/L = M + if(LAZYLEN(L.buckled_mobs)) + var/datum/riding/R = L.riding_datum + for(var/rider in L.buckled_mobs) + R.force_dismount(rider) + //VOREStation Addition End: Prevent taurriding abuse if(prob(failchance)) //oh dear a problem, put em in deep space src.icon_state = "portal1" do_teleport(M, locate(rand(5, world.maxx - 5), rand(5, world.maxy -5), 3), 0) diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index 1e31744e268..2d62af7f22a 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -95,6 +95,12 @@ if(instant || do_after(user, 50)) new /obj/effect/decal/cleanable/crayon(target,colour,shadeColour,drawtype) to_chat(user, "You finish drawing.") + + if(config.log_graffiti) + var/msg = "[user.client.key] ([user]) has drawn [drawtype] (with [src]) at [target.x],[target.y],[target.z]." + message_admins(msg) + log_game(msg) + target.add_fingerprint(user) // Adds their fingerprints to the floor the crayon is drawn on. if(uses) uses-- @@ -200,4 +206,4 @@ to_chat(user,"You ate the marker!") qdel(src) else - ..() \ No newline at end of file + ..() diff --git a/code/game/objects/items/devices/scanners_vr.dm b/code/game/objects/items/devices/scanners_vr.dm index 72a0d9e7b1f..1a5fd2c61f3 100644 --- a/code/game/objects/items/devices/scanners_vr.dm +++ b/code/game/objects/items/devices/scanners_vr.dm @@ -177,7 +177,7 @@ var/global/mob/living/carbon/human/dummy/mannequin/sleevemate_mob to_chat(usr,"There is already someone's mind stored inside") return - var/choice = alert(usr,"This will remove the target's mind from their body. The only way to put it back is via a resleeving pod. Continue?","Confirmation","Continue","Cancel") + var/choice = alert(usr,"This will remove the target's mind from their body (and from the game as long as they're in the sleevemate). You can put them into a (mindless) body, a NIF, or back them up for normal resleeving, but you should probably have a plan in advance so you don't leave them unable to interact for too long. Continue?","Confirmation","Continue","Cancel") if(choice == "Continue" && usr.get_active_hand() == src && usr.Adjacent(target)) usr.visible_message("[usr] begins downloading [target]'s mind!","You begin downloading [target]'s mind!") @@ -229,7 +229,7 @@ var/global/mob/living/carbon/human/dummy/mannequin/sleevemate_mob if(istype(target, /mob/living/carbon/human)) var/mob/living/carbon/human/H = target - if(H.resleeve_lock && stored_mind.loaded_from_ckey != H.resleeve_lock) + if(H.resleeve_lock && stored_mind.loaded_from_ckey != H.resleeve_lock) to_chat(usr,"\[H] is protected from impersonation!") return @@ -262,8 +262,6 @@ var/global/mob/living/carbon/human/dummy/mannequin/sleevemate_mob return to_chat(usr,"Unable to find that mind in Soulcatcher!") - - /obj/item/device/sleevemate/update_icon() if(stored_mind) icon_state = "[initial(icon_state)]_on" diff --git a/code/game/objects/items/devices/translocator_vr.dm b/code/game/objects/items/devices/translocator_vr.dm index ef0ec42b51c..808ced86a30 100644 --- a/code/game/objects/items/devices/translocator_vr.dm +++ b/code/game/objects/items/devices/translocator_vr.dm @@ -209,6 +209,14 @@ ready = 0 power_source.use(charge_cost) + //Unbuckle taur riders + if(istype(target, /mob/living)) + var/mob/living/L = target + if(LAZYLEN(L.buckled_mobs)) + var/datum/riding/R = L.riding_datum + for(var/rider in L.buckled_mobs) + R.force_dismount(rider) + //Failure chance if(prob(failure_chance) && beacons.len >= 2) var/list/wrong_choices = beacons - destination.tele_name diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 92269ead776..fca7ae8ca79 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -405,7 +405,7 @@ return else if (istype(A, /obj/structure/reagent_dispensers/watertank) && get_dist(src,A) <= 1) - A.reagents.trans_to(src, 10) + A.reagents.trans_to_obj(src, 10) user << "You refill your flower!" return diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index 371082f1f6b..26ba924746b 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -178,7 +178,7 @@ var/mob/living/carbon/human/H = target affecting = H.get_organ(hit_zone) - if(user.a_intent == I_HURT || user.a_intent == I_DISARM) + if(user.a_intent == I_GRAB || user.a_intent == I_HURT) . = ..() //whacking someone causes a much poorer electrical contact than deliberately prodding them. agony *= 0.5 diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 95d38c4473d..b75e3de6ed1 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -58,7 +58,7 @@ update_icon() /obj/structure/closet/examine(mob/user) - if(..(user, 1) && !opened) + if(!src.opened && (..(user, 1) || isobserver(user))) var/content_size = 0 for(var/obj/item/I in src.contents) if(!I.anchored) @@ -74,6 +74,9 @@ else to_chat(user, "It is full.") + if(!src.opened && isobserver(user)) + to_chat(user, "It contains: [counting_english_list(contents)]") + /obj/structure/closet/CanPass(atom/movable/mover, turf/target) if(wall_mounted) return TRUE @@ -360,12 +363,6 @@ if(!src.toggle()) to_chat(usr, "It won't budge!") -/obj/structure/closet/attack_ghost(mob/ghost) - if(ghost.client && ghost.client.inquisitive_ghost) - ghost.examinate(src) - if (!src.opened) - to_chat(ghost, "It contains: [english_list(contents)].") - /obj/structure/closet/verb/verb_toggleopen() set src in oview(1) set category = "Object" @@ -474,4 +471,4 @@ return dump_contents() spawn(1) qdel(src) - return 1 \ No newline at end of file + return 1 diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm index 72edab89e3a..d0de7a71eab 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm @@ -46,8 +46,7 @@ // Base icon. var/cache_key = "[base_icon]-[material.name]" if(isnull(stool_cache[cache_key])) - var/image/I = image(icon, base_icon) //VOREStation Edit - //var/image/I = image('icons/obj/furniture.dmi', base_icon) //From Polaris Sync. Not sure if this is a better way of doing it or not. Uncomment if so. + var/image/I = image(icon, base_icon) if(applies_material_colour) //VOREStation Add - Goes with added var I.color = material.icon_colour stool_cache[cache_key] = I @@ -347,4 +346,4 @@ return // Doesn't care about material or anything else. /obj/structure/bed/alien/attackby(obj/item/weapon/W, mob/user) - return // No deconning. \ No newline at end of file + return // No deconning. diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index 8950533b8e6..fd5ce2f3d63 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -43,16 +43,18 @@ /obj/structure/bed/chair/update_icon() ..() - if(has_buckled_mobs() && padding_material) - var/cache_key = "[base_icon]-armrest-[padding_material.name]" + if(has_buckled_mobs()) + var/cache_key = "[base_icon]-armrest-[padding_material ? padding_material.name : "no_material"]" if(isnull(stool_cache[cache_key])) var/image/I = image(icon, "[base_icon]_armrest") I.layer = MOB_LAYER + 0.1 I.plane = MOB_PLANE - I.color = padding_material.icon_colour - stool_cache[cache_key] = I + if(padding_material) + I.color = padding_material.icon_colour + stool_cache[cache_key] = I overlays |= stool_cache[cache_key] + /obj/structure/bed/chair/proc/update_layer() if(src.dir == NORTH) plane = MOB_PLANE @@ -85,15 +87,16 @@ /obj/structure/bed/chair/shuttle name = "chair" desc = "You sit in this. Either by will or force." - icon_state = "shuttle_chair" + icon_state = "shuttlechair" color = null - base_icon = "shuttle_chair" + base_icon = "shuttlechair" applies_material_colour = 0 // Leaving this in for the sake of compilation. /obj/structure/bed/chair/comfy desc = "It's a chair. It looks comfy." - icon_state = "comfychair_preview" + icon_state = "comfychair" + base_icon = "comfychair" /obj/structure/bed/chair/comfy/brown/New(var/newloc,var/newmaterial) ..(newloc,"steel","leather") @@ -203,3 +206,160 @@ /obj/structure/bed/chair/wood/wings icon_state = "wooden_chair_wings" + +//sofa + +/obj/structure/bed/chair/sofa + name = "sofa" + desc = "It's a sofa. You sit on it. Possibly with someone else." + icon = 'icons/obj/sofas.dmi' + base_icon = "sofamiddle" + icon_state = "sofamiddle" + applies_material_colour = 1 + var/sofa_material = "carpet" + +/obj/structure/bed/chair/sofa/update_icon() + if(applies_material_colour && sofa_material) + material = get_material_by_name(sofa_material) + color = material.icon_colour + + if(sofa_material == "carpet") + name = "red [initial(name)]" + else + name = "[sofa_material] [initial(name)]" + +/obj/structure/bed/chair/sofa/left + icon_state = "sofaend_left" + base_icon = "sofaend_left" + +/obj/structure/bed/chair/sofa/right + icon_state = "sofaend_right" + base_icon = "sofaend_right" + +/obj/structure/bed/chair/sofa/corner + icon_state = "sofacorner" + base_icon = "sofacorner" + +//color variations + +/obj/structure/bed/chair/sofa + sofa_material = "carpet" + +/obj/structure/bed/chair/sofa/brown + sofa_material = "leather" + +/obj/structure/bed/chair/sofa/teal + sofa_material = "teal" + +/obj/structure/bed/chair/sofa/black + sofa_material = "black" + +/obj/structure/bed/chair/sofa/green + sofa_material = "green" + +/obj/structure/bed/chair/sofa/purp + sofa_material = "purple" + +/obj/structure/bed/chair/sofa/blue + sofa_material = "blue" + +/obj/structure/bed/chair/sofa/beige + sofa_material = "beige" + +/obj/structure/bed/chair/sofa/lime + sofa_material = "lime" + +/obj/structure/bed/chair/sofa/yellow + sofa_material = "yellow" + +//sofa directions + +/obj/structure/bed/chair/sofa/left + icon_state = "sofaend_left" + +/obj/structure/bed/chair/sofa/right + icon_state = "sofaend_right" + +/obj/structure/bed/chair/sofa/corner + icon_state = "sofacorner" + +/obj/structure/bed/chair/sofa/brown/left + icon_state = "sofaend_left" + +/obj/structure/bed/chair/sofa/brown/right + icon_state = "sofaend_right" + +/obj/structure/bed/chair/sofa/brown/corner + icon_state = "sofacorner" + +/obj/structure/bed/chair/sofa/teal/left + icon_state = "sofaend_left" + +/obj/structure/bed/chair/sofa/teal/right + icon_state = "sofaend_right" + +/obj/structure/bed/chair/sofa/teal/corner + icon_state = "sofacorner" + +/obj/structure/bed/chair/sofa/black/left + icon_state = "sofaend_left" + +/obj/structure/bed/chair/sofa/black/right + icon_state = "sofaend_right" + +/obj/structure/bed/chair/sofa/black/corner + icon_state = "sofacorner" + +/obj/structure/bed/chair/sofa/green/left + icon_state = "sofaend_left" + +/obj/structure/bed/chair/sofa/green/right + icon_state = "sofaend_right" + +/obj/structure/bed/chair/sofa/green/corner + icon_state = "sofacorner" + +/obj/structure/bed/chair/sofa/purp/left + icon_state = "sofaend_left" + +/obj/structure/bed/chair/sofa/purp/right + icon_state = "sofaend_right" + +/obj/structure/bed/chair/sofa/purp/corner + icon_state = "sofacorner" + +/obj/structure/bed/chair/sofa/blue/left + icon_state = "sofaend_left" + +/obj/structure/bed/chair/sofa/blue/right + icon_state = "sofaend_right" + +/obj/structure/bed/chair/sofa/blue/corner + icon_state = "sofacorner" + +/obj/structure/bed/chair/sofa/beige/left + icon_state = "sofaend_left" + +/obj/structure/bed/chair/sofa/beige/right + icon_state = "sofaend_right" + +/obj/structure/bed/chair/sofa/beige/corner + icon_state = "sofacorner" + +/obj/structure/bed/chair/sofa/lime/left + icon_state = "sofaend_left" + +/obj/structure/bed/chair/sofa/lime/right + icon_state = "sofaend_right" + +/obj/structure/bed/chair/sofa/lime/corner + icon_state = "sofacorner" + +/obj/structure/bed/chair/sofa/yellow/left + icon_state = "sofaend_left" + +/obj/structure/bed/chair/sofa/yellow/right + icon_state = "sofaend_right" + +/obj/structure/bed/chair/sofa/yellow/corner + icon_state = "sofacorner" diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm index b6695e39cb9..484c7ba7a9f 100644 --- a/code/modules/awaymissions/gateway.dm +++ b/code/modules/awaymissions/gateway.dm @@ -133,6 +133,14 @@ obj/machinery/gateway/centerstation/process() M.set_dir(SOUTH) return else + //VOREStation Addition Start: Prevent taurriding abuse + if(istype(M, /mob/living)) + var/mob/living/L = M + if(LAZYLEN(L.buckled_mobs)) + var/datum/riding/R = L.riding_datum + for(var/rider in L.buckled_mobs) + R.force_dismount(rider) + //VOREStation Addition End: Prevent taurriding abuse var/obj/effect/landmark/dest = pick(awaydestinations) if(dest) M.forceMove(dest.loc) diff --git a/code/modules/client/client procs_vr.dm b/code/modules/client/client procs_vr.dm new file mode 100644 index 00000000000..830521f20dc --- /dev/null +++ b/code/modules/client/client procs_vr.dm @@ -0,0 +1,100 @@ +//Uses a couple different services +/client/update_ip_reputation() + var/scores[] = list("GII" = ipr_getipintel(), "IPQS" = ipr_ipqualityscore()) + + var/log_output = "IP Reputation [key] from [address]" + var/worst = 0 + + for(var/service in scores) + var/score = scores[service] + if(score > worst) + worst = score + log_output += " - [service] ([num2text(score)])" + + log_admin(log_output) + ip_reputation = worst + return TRUE + +//Service returns a single float in html body +/client/proc/ipr_getipintel() + if(!config.ipr_email) + return -1 + + var/request = "http://check.getipintel.net/check.php?ip=[address]&contact=[config.ipr_email]" + var/http[] = world.Export(request) + + if(!http || !islist(http)) //If we couldn't check, the service might be down, fail-safe. + log_admin("Couldn't connect to getipintel.net to check [address] for [key]") + return -1 + + //429 is rate limit exceeded + if(text2num(http["STATUS"]) == 429) + log_and_message_admins("getipintel.net reports HTTP status 429. IP reputation checking is now disabled. If you see this, let a developer know.") + config.ip_reputation = FALSE + return -1 + + var/content = file2text(http["CONTENT"]) //world.Export actually returns a file object in CONTENT + var/score = text2num(content) + if(isnull(score)) + return -1 + + //Error handling + if(score < 0) + var/fatal = TRUE + var/ipr_error = "getipintel.net IP reputation check error while checking [address] for [key]: " + switch(score) + if(-1) + ipr_error += "No input provided" + if(-2) + fatal = FALSE + ipr_error += "Invalid IP provided" + if(-3) + fatal = FALSE + ipr_error += "Unroutable/private IP (spoofing?)" + if(-4) + fatal = FALSE + ipr_error += "Unable to reach database" + if(-5) + ipr_error += "Our IP is banned or otherwise forbidden" + if(-6) + ipr_error += "Missing contact info" + + log_and_message_admins(ipr_error) + if(fatal) + config.ip_reputation = FALSE + log_and_message_admins("With this error, IP reputation checking is disabled for this shift. Let a developer know.") + return -1 + + //Went fine + else + return score + +//Service returns JSON in html body +/client/proc/ipr_ipqualityscore() + if(!config.ipqualityscore_apikey) + return -1 + + var/request = "http://www.ipqualityscore.com/api/json/ip/[config.ipqualityscore_apikey]/[address]?strictness=1&fast=true&byond_key=[key]" + var/http[] = world.Export(request) + + if(!http || !islist(http)) //If we couldn't check, the service might be down, fail-safe. + log_admin("Couldn't connect to ipqualityscore.com to check [address] for [key]") + return -1 + + var/content = file2text(http["CONTENT"]) //world.Export actually returns a file object in CONTENT + var/response = json_decode(content) + if(isnull(response)) + return -1 + + //Error handling + if(!response["success"]) + log_admin("IPQualityscore.com returned an error while processing [key] from [address]: " + response["message"]) + return -1 + + var/score = 0 + if(response["proxy"]) + score = 100 + else + score = response["fraud_score"] + + return score/100 //To normalize with the 0.0 to 1.0 scores. \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout_general.dm b/code/modules/client/preference_setup/loadout/loadout_general.dm index 34a806fe325..06c5948aeb8 100644 --- a/code/modules/client/preference_setup/loadout/loadout_general.dm +++ b/code/modules/client/preference_setup/loadout/loadout_general.dm @@ -50,6 +50,36 @@ plushies[initial(plushie_type.name)] = plushie_type gear_tweaks += new/datum/gear_tweak/path(sortAssoc(plushies)) +/datum/gear/figure + display_name = "action figure selection" + description = "A \"Space Life\" brand action figure." + path = /obj/item/toy/figure/ + +/datum/gear/figure/New() + ..() + var/list/figures = list() + for(var/figure in typesof(/obj/item/toy/figure/) - /obj/item/toy/figure) + var/obj/item/toy/figure/figure_type = figure + figures[initial(figure_type.name)] = figure_type + gear_tweaks += new/datum/gear_tweak/path(sortAssoc(figures)) + +/datum/gear/toy + display_name = "toy selection" + description = "Choose from a number of toys." + path = /obj/item/toy/ + +/datum/gear/toy/New() + ..() + var/toytype = list() + toytype["Blink toy"] = /obj/item/toy/blink + toytype["Gravitational singularity"] = /obj/item/toy/spinningtoy + toytype["Water flower"] = /obj/item/toy/waterflower + toytype["Bosun's whistle"] = /obj/item/toy/bosunwhistle + toytype["Magic 8 Ball"] = /obj/item/toy/eight_ball + toytype["Magic Conch shell"] = /obj/item/toy/eight_ball/conch + gear_tweaks += new/datum/gear_tweak/path(toytype) + + /datum/gear/flask display_name = "flask" path = /obj/item/weapon/reagent_containers/food/drinks/flask/barflask diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 21c59ee1151..e130e7128d6 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -24,8 +24,11 @@ var/ear_protection = 0 var/blood_sprite_state + var/index //null by default, if set, will change which dmi it uses + var/update_icon_define = null // Only needed if you've got multiple files for the same type of clothing + //Updates the icons of the mob wearing the clothing item, if any. /obj/item/clothing/proc/update_clothing_icon() return @@ -35,12 +38,14 @@ ..() gunshot_residue = null + /obj/item/clothing/New() ..() if(starting_accessories) for(var/T in starting_accessories) var/obj/item/clothing/accessory/tie = new T(src) src.attach_accessory(null, tie) + set_clothing_index() /obj/item/clothing/equipped(var/mob/user,var/slot) ..() @@ -224,6 +229,9 @@ SPECIES_VOX = 'icons/mob/species/vox/gloves.dmi' ) +/obj/item/clothing/proc/set_clothing_index() + return + /obj/item/clothing/gloves/update_clothing_icon() if (ismob(src.loc)) var/mob/M = src.loc @@ -602,6 +610,7 @@ var/mob/M = src.loc M.update_inv_shoes() + /////////////////////////////////////////////////////////////////////// //Suit /obj/item/clothing/suit @@ -630,11 +639,27 @@ valid_accessory_slots = (ACCESSORY_SLOT_OVER | ACCESSORY_SLOT_ARMBAND) restricted_accessory_slots = (ACCESSORY_SLOT_ARMBAND) +/obj/item/clothing/suit/set_clothing_index() + ..() + + if(index && !icon_override) + icon = new /icon("icons/obj/clothing/suits_[index].dmi") + item_icons = list( + slot_l_hand_str = new /icon("icons/mob/items/lefthand_suits_[index].dmi"), + slot_r_hand_str = new /icon("icons/mob/items/righthand_suits_[index].dmi"), + ) + + return 1 + + return 0 + /obj/item/clothing/suit/update_clothing_icon() if (ismob(src.loc)) var/mob/M = src.loc M.update_inv_wear_suit() + set_clothing_index() + /////////////////////////////////////////////////////////////////////// //Under clothing /obj/item/clothing/under @@ -707,7 +732,7 @@ //autodetect rollability if(rolled_down < 0) - if(("[worn_state]_d_s" in icon_states(INV_W_UNIFORM_DEF_ICON)) || ("[worn_state]_s" in icon_states(rolled_down_icon)) || ("[worn_state]_d_s" in icon_states(icon_override))) + if(("[worn_state]_d_s" in icon_states(icon)) || ("[worn_state]_s" in icon_states(rolled_down_icon)) || ("[worn_state]_d_s" in icon_states(icon_override))) rolled_down = 0 if(rolled_down == -1) @@ -715,6 +740,23 @@ if(rolled_sleeves == -1) verbs -= /obj/item/clothing/under/verb/rollsleeves +/obj/item/clothing/under/set_clothing_index() + ..() + + if(index && !icon_override) + icon = new /icon("icons/obj/clothing/uniforms_[index].dmi") + + item_icons = list( + slot_l_hand_str = new /icon("icons/mob/items/lefthand_uniforms_[index].dmi"), + slot_r_hand_str = new /icon("icons/mob/items/righthand_uniforms_[index].dmi"), + ) + + rolled_down_icon = new /icon("icons/mob/uniform_rolled_down_[index].dmi") + rolled_down_sleeves_icon = new /icon("icons/mob/uniform_sleeves_rolled_[index].dmi") + return 1 + + return 0 + /obj/item/clothing/under/proc/update_rolldown_status() var/mob/living/carbon/human/H if(istype(src.loc, /mob/living/carbon/human)) @@ -729,8 +771,6 @@ under_icon = item_icons[slot_w_uniform_str] else if ("[worn_state]_s" in icon_states(rolled_down_icon)) under_icon = rolled_down_icon - else - under_icon = INV_W_UNIFORM_DEF_ICON // The _s is because the icon update procs append it. if((under_icon == rolled_down_icon && "[worn_state]_s" in icon_states(under_icon)) || ("[worn_state]_d_s" in icon_states(under_icon))) @@ -754,8 +794,8 @@ under_icon = item_icons[slot_w_uniform_str] else if ("[worn_state]_s" in icon_states(rolled_down_sleeves_icon)) under_icon = rolled_down_sleeves_icon - else - under_icon = INV_W_UNIFORM_DEF_ICON + else if(index) + under_icon = new /icon("[INV_W_UNIFORM_DEF_ICON]_[index].dmi") // The _s is because the icon update procs append it. if((under_icon == rolled_down_sleeves_icon && "[worn_state]_s" in icon_states(under_icon)) || ("[worn_state]_r_s" in icon_states(under_icon))) @@ -770,6 +810,8 @@ var/mob/M = src.loc M.update_inv_w_uniform() + set_clothing_index() + /obj/item/clothing/under/examine(mob/user) ..(user) diff --git a/code/modules/clothing/spacesuits/rig/rig_pieces_vr.dm b/code/modules/clothing/spacesuits/rig/rig_pieces_vr.dm index 33539575a19..e4621b9d166 100644 --- a/code/modules/clothing/spacesuits/rig/rig_pieces_vr.dm +++ b/code/modules/clothing/spacesuits/rig/rig_pieces_vr.dm @@ -8,7 +8,7 @@ SPECIES_SERGAL = 'icons/mob/species/sergal/helmet_vr.dmi', SPECIES_ZORREN_FLAT = 'icons/mob/species/fennec/helmet_vr.dmi', SPECIES_ZORREN_HIGH = 'icons/mob/species/fox/helmet_vr.dmi', - SPECIES_VULPKANI = 'icons/mob/species/vulpkanin/helmet.dmi', + SPECIES_VULPKANIN = 'icons/mob/species/vulpkanin/helmet.dmi', SPECIES_PROMETHEAN = 'icons/mob/species/skrell/helmet.dmi', SPECIES_XENOHYBRID = 'icons/mob/species/unathi/helmet.dmi', SPECIES_VOX = 'icons/mob/species/vox/head.dmi', diff --git a/code/modules/clothing/suits/labcoat.dm b/code/modules/clothing/suits/labcoat.dm index 63d5faa51c5..cc7dfa3be59 100644 --- a/code/modules/clothing/suits/labcoat.dm +++ b/code/modules/clothing/suits/labcoat.dm @@ -8,6 +8,7 @@ flags_inv = HIDEHOLSTER allowed = list(/obj/item/device/analyzer,/obj/item/stack/medical,/obj/item/weapon/dnainjector,/obj/item/weapon/reagent_containers/dropper,/obj/item/weapon/reagent_containers/syringe,/obj/item/weapon/reagent_containers/hypospray,/obj/item/device/healthanalyzer,/obj/item/device/flashlight/pen,/obj/item/weapon/reagent_containers/glass/bottle,/obj/item/weapon/reagent_containers/glass/beaker,/obj/item/weapon/reagent_containers/pill,/obj/item/weapon/storage/pill_bottle,/obj/item/weapon/paper) armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 50, rad = 0) + index = 1 /obj/item/clothing/suit/storage/toggle/labcoat/red name = "red labcoat" diff --git a/code/modules/clothing/under/accessories/clothing.dm b/code/modules/clothing/under/accessories/clothing.dm index d5991e4f100..bee36652833 100644 --- a/code/modules/clothing/under/accessories/clothing.dm +++ b/code/modules/clothing/under/accessories/clothing.dm @@ -62,6 +62,19 @@ "Teshari" = 'icons/mob/species/seromi/suit.dmi' ) +/obj/item/clothing/accessory/poncho/equipped() //Solution for race-specific sprites for an accessory which is also a suit. Suit icons break if you don't use icon override which then also overrides race-specific sprites. + ..() + var/mob/living/carbon/human/H = loc + if(istype(H) && H.wear_suit == src) + if(H.species.name == "Teshari") + icon_override = 'icons/mob/species/seromi/suit.dmi' + else + icon_override = 'icons/mob/ties.dmi' + update_clothing_icon() + +/obj/item/clothing/accessory/poncho/dropped() //Resets the override to prevent the wrong .dmi from being used because equipped only triggers when wearing ponchos as suits. + icon_override = null + /obj/item/clothing/accessory/poncho/green name = "green poncho" desc = "A simple, comfortable cloak without sleeves. This one is green." diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index fc7c458bf3d..a0e794929f2 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -357,6 +357,7 @@ name = "maid costume" desc = "Maid in China." icon_state = "maid" + index = 1 /obj/item/clothing/under/dress/maid/janitor name = "maid uniform" diff --git a/code/modules/clothing/under/pants.dm b/code/modules/clothing/under/pants.dm index 035aac4cf88..1af0517ab06 100644 --- a/code/modules/clothing/under/pants.dm +++ b/code/modules/clothing/under/pants.dm @@ -5,6 +5,7 @@ icon_state = "jeans" gender = PLURAL body_parts_covered = LOWER_TORSO|LEGS + index = 1 /obj/item/clothing/under/pants/ripped name = "ripped jeans" diff --git a/code/modules/clothing/under/shorts.dm b/code/modules/clothing/under/shorts.dm index 26a00a4a636..0e345779d2b 100644 --- a/code/modules/clothing/under/shorts.dm +++ b/code/modules/clothing/under/shorts.dm @@ -2,8 +2,10 @@ /obj/item/clothing/under/shorts name = "athletic shorts" desc = "95% Polyester, 5% Spandex!" + icon_state = "redshorts" // Hackyfix for icon states until someone wants to come do a recolor later. gender = PLURAL body_parts_covered = LOWER_TORSO + index = 1 /obj/item/clothing/under/shorts/red name = "red athletic shorts" @@ -99,6 +101,7 @@ icon_state = "skirt_short_black" body_parts_covered = LOWER_TORSO rolled_sleeves = -1 + index = 1 /obj/item/clothing/under/skirt/khaki name = "khaki skirt" @@ -165,12 +168,14 @@ desc = "It's a jumpskirt worn by the quartermaster. It's specially designed to prevent back injuries caused by pushing paper." icon_state = "qmf" item_state_slots = list(slot_r_hand_str = "qm", slot_l_hand_str = "qm") + index = 1 /obj/item/clothing/under/rank/cargotech/skirt name = "cargo technician's jumpskirt" desc = "Skirrrrrts! They're comfy and easy to wear!" icon_state = "cargof" item_state_slots = list(slot_r_hand_str = "cargo", slot_l_hand_str = "cargo") + index = 1 /obj/item/clothing/under/rank/engineer/skirt desc = "It's an orange high visibility jumpskirt worn by engineers. It has minor radiation shielding." @@ -178,51 +183,61 @@ icon_state = "enginef" armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 10) item_state_slots = list(slot_r_hand_str = "engine", slot_l_hand_str = "engine") + index = 1 /obj/item/clothing/under/rank/chief_engineer/skirt desc = "It's a high visibility jumpskirt given to those engineers insane enough to achieve the rank of \"Chief engineer\". It has minor radiation shielding." name = "chief engineer's jumpskirt" icon_state = "chieff" item_state_slots = list(slot_r_hand_str = "chiefengineer", slot_l_hand_str = "chiefengineer") + index = 1 /obj/item/clothing/under/rank/atmospheric_technician/skirt desc = "It's a jumpskirt worn by atmospheric technicians." name = "atmospheric technician's jumpskirt" icon_state = "atmosf" item_state_slots = list(slot_r_hand_str = "atmos", slot_l_hand_str = "atmos") + index = 1 /obj/item/clothing/under/rank/roboticist/skirt desc = "It's a slimming black jumpskirt with reinforced seams; great for industrial work." name = "roboticist's jumpskirt" icon_state = "roboticsf" item_state_slots = list(slot_r_hand_str = "robotics", slot_l_hand_str = "robotics") + index = 1 /obj/item/clothing/under/rank/scientist/skirt name = "scientist's jumpskirt" icon_state = "sciencef" permeability_coefficient = 0.50 armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 10, bio = 0, rad = 0) + index = 1 /obj/item/clothing/under/rank/medical/skirt name = "medical doctor's jumpskirt" icon_state = "medicalf" + index = 1 /obj/item/clothing/under/rank/chemist/skirt name = "chemist's jumpskirt" icon_state = "chemistryf" + index = 1 /obj/item/clothing/under/rank/chief_medical_officer/skirt desc = "It's a jumpskirt worn by those with the experience to be \"Chief Medical Officer\". It provides minor biological protection." name = "chief medical officer's jumpskirt" icon_state = "cmof" + index = 1 /obj/item/clothing/under/rank/geneticist/skirt name = "geneticist's jumpskirt" icon_state = "geneticsf" + index = 1 /obj/item/clothing/under/rank/virologist/skirt name = "virologist's jumpskirt" icon_state = "virologyf" + index = 1 /obj/item/clothing/under/rank/security/skirt name = "security officer's jumpskirt" @@ -230,13 +245,16 @@ icon_state = "securityf" armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) siemens_coefficient = 0.9 + index = 1 /obj/item/clothing/under/rank/warden/skirt desc = "Standard feminine fashion for a Warden. It is made of sturdier material than standard jumpskirts. It has the word \"Warden\" written on the shoulders." name = "warden's jumpskirt" icon_state = "wardenf" + index = 1 /obj/item/clothing/under/rank/head_of_security/skirt desc = "It's a fashionable jumpskirt worn by those few with the dedication to achieve the position of \"Head of Security\". It has additional armor to protect the wearer." name = "head of security's jumpskirt" - icon_state = "hosf" \ No newline at end of file + icon_state = "hosf" + index = 1 \ No newline at end of file diff --git a/code/modules/economy/ATM.dm b/code/modules/economy/ATM.dm index 68e4c12c86a..07d70b2eda0 100644 --- a/code/modules/economy/ATM.dm +++ b/code/modules/economy/ATM.dm @@ -64,7 +64,7 @@ log transactions break /obj/machinery/atm/emag_act(var/remaining_charges, var/mob/user) - if(!emagged) + if(emagged) return //short out the machine, shoot sparks, spew money! diff --git a/code/modules/events/event_container_vr.dm b/code/modules/events/event_container_vr.dm index 3cb0243e667..284d74906f9 100644 --- a/code/modules/events/event_container_vr.dm +++ b/code/modules/events/event_container_vr.dm @@ -81,7 +81,8 @@ new /datum/event_meta(EVENT_LEVEL_MODERATE, "Spider Infestation", /datum/event/spider_infestation, 30, list(ASSIGNMENT_SECURITY = 30), 1), //Evil grubs that drain station power slightly new /datum/event_meta(EVENT_LEVEL_MODERATE, "Grub Infestation", /datum/event/grub_infestation, 0, list(ASSIGNMENT_SECURITY = 10, ASSIGNMENT_ENGINEER = 30), 1), - new /datum/event_meta(EVENT_LEVEL_MODERATE, "Drone Pod Drop", /datum/event/drone_pod_drop, 10, list(ASSIGNMENT_SCIENTIST = 40), 1) + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Drone Pod Drop", /datum/event/drone_pod_drop, 10, list(ASSIGNMENT_SCIENTIST = 40), 1), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Morph Spawn", /datum/event/morph_spawn, 75, list(ASSIGNMENT_SECURITY = 35), 1) ) add_disabled_events(list( new /datum/event_meta(EVENT_LEVEL_MODERATE, "Appendicitis", /datum/event/spontaneous_appendicitis, 0, list(ASSIGNMENT_MEDICAL = 30), 1), diff --git a/code/modules/events/morph_spawn_vr.dm b/code/modules/events/morph_spawn_vr.dm new file mode 100644 index 00000000000..609afe073f8 --- /dev/null +++ b/code/modules/events/morph_spawn_vr.dm @@ -0,0 +1,47 @@ +/datum/event/morph_spawn + startWhen = 1 + announceWhen = 20 + endWhen = 30 + var/announceProb = 50 + +/datum/event/morph_spawn/start() + + var/obj/effect/landmark/spawnspot = null + var/list/possibleSpawnspots = list() + for(var/obj/effect/landmark/newSpawnspot in landmarks_list) + if(newSpawnspot.name == "morphspawn") + possibleSpawnspots += newSpawnspot + if(possibleSpawnspots.len) + spawnspot = pick(possibleSpawnspots) + else + kill() // To prevent fake announcements + return + + if(!spawnspot) + kill() // To prevent fake announcements + return + + var/datum/ghost_query/Q = new /datum/ghost_query/morph() + var/list/winner = Q.query() + + if(winner.len) + var/mob/living/simple_mob/vore/hostile/morph/newMorph = new /mob/living/simple_mob/vore/hostile/morph(get_turf(spawnspot)) + var/mob/observer/dead/D = winner[1] + if(D.mind) + D.mind.transfer_to(newMorph) + to_chat(D, "You are a Morph, somehow having gotten aboard the station in your wandering. \ + You are wary of environment around you, but your primal hunger still calls for you to find prey. Seek a convincing disguise, \ + using your amorphous form to traverse vents to find and consume weak prey.") + to_chat(D, "You can use shift + click on objects to disguise yourself as them, but your strikes are nearly useless when you are disguised. \ + You can undisguise yourself by shift + clicking yourself, but disguise being switched, or turned on and off has a short cooldown. You can also ventcrawl, \ + by using alt + click on the vent or scrubber.") + newMorph.ckey = D.ckey + newMorph.visible_message("A morph appears to crawl out of somewhere.") + else + kill() // To prevent fake announcements + return + + +/datum/event/morph_spawn/announce() + if(announceProb) + command_announcement.Announce("Unknown entitity detected boarding [station_name()]. Exercise extra caution.", "Lifesign Alert", new_sound = 'sound/AI/aliens.ogg') \ No newline at end of file diff --git a/code/modules/food/drinkingglass/glass_boxes.dm b/code/modules/food/drinkingglass/glass_boxes.dm index d534c10cadf..7157e209c1e 100644 --- a/code/modules/food/drinkingglass/glass_boxes.dm +++ b/code/modules/food/drinkingglass/glass_boxes.dm @@ -78,3 +78,11 @@ /obj/item/weapon/storage/box/glass_extras/sticks name = "box of drink sticks" extra_type = /obj/item/weapon/glass_extra/stick + +/obj/item/weapon/storage/box/glasses/coffeecup + name = "box of coffee cups" + glass_type = /obj/item/weapon/reagent_containers/food/drinks/cup + +/obj/item/weapon/storage/box/glasses/coffeemug + name = "box of coffee mugs" + glass_type = /obj/item/weapon/reagent_containers/food/drinks/britcup \ No newline at end of file diff --git a/code/modules/food/food/snacks_vr.dm b/code/modules/food/food/snacks_vr.dm index 65db2fe5601..22f164f12af 100644 --- a/code/modules/food/food/snacks_vr.dm +++ b/code/modules/food/food/snacks_vr.dm @@ -490,6 +490,7 @@ name = "wolpin cube" monkey_type = "Wolpin" +/* /obj/item/weapon/reagent_containers/food/snacks/pizza/margfrozen name = "frozen margherita pizza" desc = "It's frozen rock solid, better thaw it in a microwave." @@ -669,18 +670,7 @@ /obj/item/weapon/reagent_containers/food/snacks/slice/vegcargo/filled filled = TRUE - -/obj/item/pizzabox/margherita/Initialize() - pizza = new /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/margcargo(src) - -/obj/item/pizzabox/vegetable/Initialize() - pizza = new /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/vegcargo(src) - -/obj/item/pizzabox/mushroom/Initialize() - pizza = new /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/mushcargo(src) - -/obj/item/pizzabox/meat/Initialize() - pizza = new /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatcargo(src) +*/ // food cubes /obj/item/weapon/reagent_containers/food/snacks/cube diff --git a/code/modules/food/recipes_microwave_vr.dm b/code/modules/food/recipes_microwave_vr.dm index 14fe3a0b988..b4feb634884 100644 --- a/code/modules/food/recipes_microwave_vr.dm +++ b/code/modules/food/recipes_microwave_vr.dm @@ -196,6 +196,7 @@ ) result = /obj/item/weapon/reagent_containers/food/snacks/sharkmeatcubes +/* /datum/recipe/microwave/margheritapizzacargo reagents = list() items = list( @@ -223,10 +224,11 @@ /obj/item/weapon/reagent_containers/food/snacks/pizza/vegfrozen ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/vegcargo +*/ //// food cubes /datum/recipe/microwave/foodcubes - reagents = list("enzyme" = 20,"virusfood" = 5, "nutriment" = 15, "protein" = 15) // labor intensive + reagents = list("enzyme" = 20, "virusfood" = 5, "nutriment" = 15, "protein" = 15) // labor intensive items = list() result = /obj/item/weapon/storage/box/wings/tray \ No newline at end of file diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm index 70b5c991703..c702abd9f9a 100644 --- a/code/modules/hydroponics/seed.dm +++ b/code/modules/hydroponics/seed.dm @@ -452,15 +452,16 @@ var/additional_chems = rand(0,5) if(additional_chems) - //VOREStation Edit Start TFF 24/1/20 - More chems to the blacklist for prefs reasoning. + // VOREStation Edit Start: Modified exclusion list var/list/banned_chems = list( "adminordrazine", "nutriment", "macrocillin", "microcillin", - "normalcillin" + "normalcillin", + "magicdust" ) - //VOREStation Edit End + // VOREStation Edit End: Modified exclusion list for(var/x=1;x<=additional_chems;x++) diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm index d13a3f76879..f08720cae2e 100644 --- a/code/modules/hydroponics/seed_datums.dm +++ b/code/modules/hydroponics/seed_datums.dm @@ -168,7 +168,7 @@ name = "bloodtomato" seed_name = "blood tomato" display_name = "blood tomato plant" - mutants = list("killer") + mutants = list("killertomato") chems = list("nutriment" = list(1,10), "blood" = list(1,5)) splat_type = /obj/effect/decal/cleanable/blood/splatter @@ -1520,4 +1520,4 @@ set_trait(TRAIT_SPREAD,1) set_trait(TRAIT_POTENCY,10) set_trait(TRAIT_REQUIRES_NUTRIENTS,0) - set_trait(TRAIT_REQUIRES_WATER,0) \ No newline at end of file + set_trait(TRAIT_REQUIRES_WATER,0) diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm index d1125acd440..b5b6d8efb69 100644 --- a/code/modules/library/lib_machines.dm +++ b/code/modules/library/lib_machines.dm @@ -229,7 +229,7 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f dat += "

External Archive

" //VOREStation Edit establish_old_db_connection() - dat += "

Warning: System Administrator has slated this archive for removal. Personal uploads should be taken to the NT board of internal literature.

" +// dat += "

Warning: System Administrator has slated this archive for removal. Personal uploads should be taken to the NT board of internal literature.

" //VOREStation Removal TFF 29/1/20 - Redundant warning, we're not removing our library entries. if(!dbcon_old.IsConnected()) dat += "ERROR: Unable to contact External Archive. Please contact your system administrator for assistance." diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machine_stacking.dm index 68c5a31c258..347601176a2 100644 --- a/code/modules/mining/machine_stacking.dm +++ b/code/modules/mining/machine_stacking.dm @@ -130,7 +130,8 @@ S.amount = stack_amt stack_storage[sheet] -= stack_amt S.update_icon() - - console.updateUsrDialog() + + if(console) + console.updateUsrDialog() return diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index b6f9aa35ec9..bd1cb900ae6 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -580,6 +580,15 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() if(wear_suit && (wear_suit.flags_inv & HIDEJUMPSUIT) && !istype(wear_suit, /obj/item/clothing/suit/space/rig)) return //Wearing a suit that prevents uniform rendering + var/obj/item/clothing/under/under = w_uniform + + var/uniform_sprite + + if(under.index) + uniform_sprite = "[INV_W_UNIFORM_DEF_ICON]_[under.index].dmi" + else + uniform_sprite = "[INV_W_UNIFORM_DEF_ICON].dmi" + //Build a uniform sprite //VOREStation Edit start. var/icon/c_mask = null @@ -587,9 +596,8 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() var/obj/item/clothing/suit/S = wear_suit if(!(wear_suit && ((wear_suit.flags_inv & HIDETAIL) || (istype(S) && S.taurized)))) //Clip the lower half of the uniform off using the tail's clip mask. c_mask = new /icon(tail_style.clip_mask_icon, tail_style.clip_mask_state) - overlays_standing[UNIFORM_LAYER] = w_uniform.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_w_uniform_str, default_icon = INV_W_UNIFORM_DEF_ICON, default_layer = UNIFORM_LAYER, clip_mask = c_mask) + overlays_standing[UNIFORM_LAYER] = w_uniform.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_w_uniform_str, default_icon = uniform_sprite, default_layer = UNIFORM_LAYER, clip_mask = c_mask) //VOREStation Edit end. - apply_layer(UNIFORM_LAYER) /mob/living/carbon/human/update_inv_wear_id() @@ -758,22 +766,24 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() if(!wear_suit) return //No point, no suit. - // Part of splitting the suit sprites up - var/iconFile = INV_SUIT_DEF_ICON - var/obj/item/clothing/suit/S //VOREStation edit - break this var out a level for use below. - if(istype(wear_suit, /obj/item/clothing/suit)) - S = wear_suit - if(S.update_icon_define) - iconFile = S.update_icon_define + var/obj/item/clothing/suit/suit = wear_suit + var/suit_sprite + + if(suit.index) + suit_sprite = "[INV_SUIT_DEF_ICON]_[suit.index].dmi" + else if(istype(suit, /obj/item/clothing) && !isnull(suit.update_icon_define)) + suit_sprite = suit.update_icon_define + else + suit_sprite = "[INV_SUIT_DEF_ICON].dmi" //VOREStation Edit start. var/icon/c_mask = null var/tail_is_rendered = (overlays_standing[TAIL_LAYER] || overlays_standing[TAIL_LAYER_ALT]) var/valid_clip_mask = (tail_style && tail_style.clip_mask_icon && tail_style.clip_mask_state) - if(tail_is_rendered && valid_clip_mask && !(S && S.taurized)) //Clip the lower half of the suit off using the tail's clip mask for taurs since taur bodies aren't hidden. + if(tail_is_rendered && valid_clip_mask && !(suit && suit.taurized)) //Clip the lower half of the suit off using the tail's clip mask for taurs since taur bodies aren't hidden. c_mask = new /icon(tail_style.clip_mask_icon, tail_style.clip_mask_state) - overlays_standing[SUIT_LAYER] = wear_suit.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_wear_suit_str, default_icon = iconFile, default_layer = SUIT_LAYER, clip_mask = c_mask) + overlays_standing[SUIT_LAYER] = wear_suit.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_wear_suit_str, default_icon = suit_sprite, default_layer = SUIT_LAYER, clip_mask = c_mask) //VOREStation Edit end. apply_layer(SUIT_LAYER) diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/passive/fish_vr.dm b/code/modules/mob/living/simple_mob/subtypes/animal/passive/fish_vr.dm index c1cef3831ae..adb180f9fed 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/passive/fish_vr.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/passive/fish_vr.dm @@ -69,6 +69,7 @@ icon_dead = "measelshark-dead" meat_amount = 6 //Big fish, tons of meat. Great for feasts. meat_type = /obj/item/weapon/reagent_containers/food/snacks/sliceable/sharkchunk + vore_active = 1 vore_bump_chance = 100 vore_default_mode = DM_HOLD //docile shark vore_capacity = 5 diff --git a/code/modules/mob/new_player/preferences_setup_vr.dm b/code/modules/mob/new_player/preferences_setup_vr.dm index 8b1760c65c7..04910731c1c 100644 --- a/code/modules/mob/new_player/preferences_setup_vr.dm +++ b/code/modules/mob/new_player/preferences_setup_vr.dm @@ -1,5 +1,7 @@ /datum/preferences/update_preview_icon() // Lines up and un-overlaps character edit previews. Also un-splits taurs. var/mob/living/carbon/human/dummy/mannequin/mannequin = get_mannequin(client_ckey) + if(!mannequin.dna) // Special handling for preview icons before SSAtoms has initailized. + mannequin.dna = new /datum/dna(null) mannequin.delete_inventory(TRUE) dress_preview_mob(mannequin) COMPILE_OVERLAYS(mannequin) diff --git a/code/modules/telesci/quantum_pad.dm b/code/modules/telesci/quantum_pad.dm index f36c05ade4c..c2a61b833b7 100644 --- a/code/modules/telesci/quantum_pad.dm +++ b/code/modules/telesci/quantum_pad.dm @@ -36,15 +36,15 @@ for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) E += M.rating power_efficiency = E - + E = 0 for(var/obj/item/weapon/stock_parts/capacitor/C in component_parts) E += C.rating - + teleport_speed = initial(teleport_speed) - teleport_speed -= (E*10) + teleport_speed = max(15, (teleport_speed - (E * 10))) teleport_cooldown = initial(teleport_cooldown) - teleport_cooldown -= (E * 100) + teleport_cooldown = max(50, (teleport_cooldown - (E * 100))) /obj/machinery/power/quantumpad/attackby(obj/item/I, mob/user, params) if(default_deconstruction_screwdriver(user, I)) @@ -86,7 +86,7 @@ if(panel_open) to_chat(user, "The panel must be closed before operating this machine!") return - + if(istype(get_area(src), /area/shuttle)) to_chat(user, "This is too unstable a platform for \the [src] to operate on!") return diff --git a/code/modules/virus2/disease2.dm b/code/modules/virus2/disease2.dm index 2769c97a840..d62502084a0 100644 --- a/code/modules/virus2/disease2.dm +++ b/code/modules/virus2/disease2.dm @@ -172,6 +172,7 @@ disease.stageprob = stageprob disease.antigen = antigen disease.uniqueID = uniqueID + disease.resistance = resistance disease.affected_species = affected_species.Copy() for(var/datum/disease2/effectholder/holder in effects) var/datum/disease2/effectholder/newholder = new /datum/disease2/effectholder diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index 6582a840c46..c70a18d2dd4 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -425,7 +425,7 @@ /mob/living/proc/perform_the_nom(var/mob/living/user, var/mob/living/prey, var/mob/living/pred, var/obj/belly/belly, var/delay) //Sanity if(!user || !prey || !pred || !istype(belly) || !(belly in pred.vore_organs)) - log_debug("[user] attempted to feed [prey] to [pred], via [lowertext(belly.name)] but it went wrong.") + log_debug("[user] attempted to feed [prey] to [pred], via [belly ? lowertext(belly.name) : "*null*"] but it went wrong.") return // The belly selected at the time of noms diff --git a/code/modules/vore/fluffstuff/guns/bsharpoon.dm b/code/modules/vore/fluffstuff/guns/bsharpoon.dm index e8ffea51cde..99598504b4a 100644 --- a/code/modules/vore/fluffstuff/guns/bsharpoon.dm +++ b/code/modules/vore/fluffstuff/guns/bsharpoon.dm @@ -62,22 +62,30 @@ var/turf/FromTurf = mode ? get_turf(user) : get_turf(A) var/turf/ToTurf = mode ? get_turf(A) : get_turf(user) + var/recievefailchance = 5 + var/sendfailchance = 5 + if(istype(user, /mob/living)) + var/mob/living/L = user + if(LAZYLEN(L.buckled_mobs)) + for(var/rider in L.buckled_mobs) + sendfailchance += 15 + if(mode) if(user in FromTurf) - if(prob(5)) + if(prob(sendfailchance)) user.forceMove(pick(trange(24,user))) else user.forceMove(ToTurf) else for(var/obj/O in FromTurf) if(O.anchored) continue - if(prob(5)) + if(prob(recievefailchance)) O.forceMove(pick(trange(24,user))) else O.forceMove(ToTurf) for(var/mob/living/M in FromTurf) - if(prob(5)) + if(prob(recievefailchance)) M.forceMove(pick(trange(24,user))) else M.forceMove(ToTurf) diff --git a/config/example/config.txt b/config/example/config.txt index 68b06f82004..7d711f480f8 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -69,6 +69,9 @@ LOG_ATTACK ## log pda messages LOG_PDA +## log graffiti drawings +LOG_GRAFFITI + ## log world.log messages # LOG_WORLD_OUTPUT diff --git a/html/changelog.html b/html/changelog.html index e40bd402647..f9498dafe50 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -53,6 +53,21 @@ -->
+

21 January 2020

+

Heroman3003 updated:

+ +

TheFurryFeline updated:

+ +

schnayy updated:

+ +

31 December 2019

Atermonera updated: