diff --git a/code/__DEFINES/camera.dm b/code/__DEFINES/camera.dm index f50d7d8e2c72..b13adf43e8cd 100644 --- a/code/__DEFINES/camera.dm +++ b/code/__DEFINES/camera.dm @@ -3,6 +3,7 @@ #define CAMERA_NET_CONTAINMENT "Containment" #define CAMERA_NET_CONTAINMENT_HIDDEN "Containment Hidden" #define CAMERA_NET_RESEARCH "Research" +#define CAMERA_NET_BRIG "Brig" #define CAMERA_NET_ALAMO "Alamo" #define CAMERA_NET_NORMANDY "Normandy" #define CAMERA_NET_COLONY "Colony" diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 47aa0e732c76..88496c79d630 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -123,6 +123,7 @@ #define SS_INIT_NIGHTMARE 21.5 #define SS_INIT_TIMETRACK 21.1 #define SS_INIT_HUMANS 21 +#define SS_INIT_WHO 20 #define SS_INIT_POWER 19 #define SS_INIT_INFLUXMCSTATS 12 #define SS_INIT_INFLUXSTATS 11 diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm index e2c89df90e9b..17464b44dae8 100644 --- a/code/__DEFINES/tgs.dm +++ b/code/__DEFINES/tgs.dm @@ -1,6 +1,6 @@ // tgstation-server DMAPI -#define TGS_DMAPI_VERSION "7.1.2" +#define TGS_DMAPI_VERSION "7.1.3" // All functions and datums outside this document are subject to change with any version and should not be relied on. diff --git a/code/controllers/subsystem/init/lobby_art.dm b/code/controllers/subsystem/init/lobby_art.dm index 7c49d5fe1787..4b26d576b8df 100644 --- a/code/controllers/subsystem/init/lobby_art.dm +++ b/code/controllers/subsystem/init/lobby_art.dm @@ -6,5 +6,5 @@ SUBSYSTEM_DEF(lobby_art) /datum/controller/subsystem/lobby_art/Initialize() var/list/lobby_arts = CONFIG_GET(str_list/lobby_art_images) if(length(lobby_arts)) - force_lobby_art(rand(1,length(lobby_arts))) + force_lobby_art(rand(1, length(lobby_arts))) return SS_INIT_SUCCESS diff --git a/code/controllers/subsystem/who.dm b/code/controllers/subsystem/who.dm new file mode 100644 index 000000000000..43ecbb435587 --- /dev/null +++ b/code/controllers/subsystem/who.dm @@ -0,0 +1,312 @@ +SUBSYSTEM_DEF(who) + name = "Who" + flags = SS_BACKGROUND + runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY + init_order = SS_INIT_WHO + wait = 5 SECONDS + + var/datum/player_list/who = new + var/datum/player_list/staff/staff_who = new + +/datum/controller/subsystem/who/Initialize() + who.update_data() + staff_who.update_data() + return SS_INIT_SUCCESS + +/datum/controller/subsystem/who/fire(resumed = TRUE) + who.update_data() + staff_who.update_data() + +//datum +/datum/player_list + var/tgui_name = "Who" + var/tgui_interface_name = "Who" + var/list/mobs_ckey = list() + var/list/list_data = list() + +/datum/player_list/proc/update_data() + var/list/new_list_data = list() + var/list/new_mobs_ckey = list() + var/list/additional_data = list( + "lobby" = 0, + "admin_observers" = 0, + "observers" = 0, + "yautja" = 0, + "infected_preds" = 0, + "humans" = 0, + "infected_humans" = 0, + "uscm" = 0, + "uscm_marines" = 0, + ) + new_list_data["additional_info"] = list() + var/list/counted_factions = list() + for(var/client/client as anything in sortTim(GLOB.clients, GLOBAL_PROC_REF(cmp_ckey_asc))) + CHECK_TICK + new_list_data["all_clients"]++ + var/list/client_payload = list() + client_payload["ckey"] = "[client.key]" + client_payload["text"] = "[client.key]" + client_payload["ckey_color"] = "white" + var/mob/client_mob = client.mob + new_mobs_ckey[client.key] = client_mob + if(client_mob) + if(istype(client_mob, /mob/new_player)) + client_payload["text"] += " - in Lobby" + additional_data["lobby"]++ + + else if(isobserver(client_mob)) + client_payload["text"] += " - Playing as [client_mob.real_name]" + if(CLIENT_IS_STAFF(client)) + additional_data["admin_observers"]++ + else + additional_data["observers"]++ + + var/mob/dead/observer/observer = client_mob + if(observer.started_as_observer) + client_payload["color"] += "#ce89cd" + client_payload["text"] += " - Spectating" + else + client_payload["color"] += "#A000D0" + client_payload["text"] += " - DEAD" + + else + client_payload["text"] += " - Playing as [client_mob.real_name]" + + switch(client_mob.stat) + if(UNCONSCIOUS) + client_payload["color"] += "#B0B0B0" + client_payload["text"] += " - Unconscious" + if(DEAD) + client_payload["color"] += "#A000D0" + client_payload["text"] += " - DEAD" + + if(client_mob.stat != DEAD) + if(isxeno(client_mob)) + client_payload["color"] += "#ec3535" + client_payload["text"] += " - Xenomorph" + + else if(ishuman(client_mob)) + if(client_mob.faction == FACTION_ZOMBIE) + counted_factions[FACTION_ZOMBIE]++ + client_payload["color"] += "#2DACB1" + client_payload["text"] += " - Zombie" + else if(client_mob.faction == FACTION_YAUTJA) + client_payload["color"] += "#7ABA19" + client_payload["text"] += " - Yautja" + additional_data["yautja"]++ + if(client_mob.status_flags & XENO_HOST) + additional_data["infected_preds"]++ + else + additional_data["humans"]++ + if(client_mob.status_flags & XENO_HOST) + additional_data["infected_humans"]++ + if(client_mob.faction == FACTION_MARINE) + additional_data["uscm"]++ + if(client_mob.job in (GLOB.ROLES_MARINES)) + additional_data["uscm_marines"]++ + else + counted_factions[client_mob.faction]++ + + new_list_data["total_players"] += list(client_payload) + + new_list_data["additional_info"] += list(list( + "content" = "In Lobby: [additional_data["lobby"]]", + "color" = "#777", + "text" = "Player in lobby", + )) + + new_list_data["additional_info"] += list(list( + "content" = "Spectating Players: [additional_data["observers"]]", + "color" = "#777", + "text" = "Spectating players", + )) + + new_list_data["additional_info"] += list(list( + "content" = "Spectating Admins: [additional_data["admin_observers"]]", + "color" = "#777", + "text" = "Spectating administrators", + )) + + new_list_data["additional_info"] += list(list( + "content" = "Humans: [additional_data["humans"]]", + "color" = "#2C7EFF", + "text" = "Players playing as Human", + )) + + new_list_data["additional_info"] += list(list( + "content" = "Infected Humans: [additional_data["infected_humans"]]", + "color" = "#ec3535", + "text" = "Players playing as Infected Human", + )) + + new_list_data["additional_info"] += list(list( + "content" = "[MAIN_SHIP_NAME] Personnel: [additional_data["uscm"]]", + "color" = "#5442bd", + "text" = "Players playing as [MAIN_SHIP_NAME] Personnel", + )) + + new_list_data["additional_info"] += list(list( + "content" = "Marines: [additional_data["uscm_marines"]]", + "color" = "#5442bd", + "text" = "Players playing as Marines", + )) + + new_list_data["additional_info"] += list(list( + "content" = "Yautjas: [additional_data["yautja"]]", + "color" = "#7ABA19", + "text" = "Players playing as Yautja", + )) + + new_list_data["additional_info"] += list(list( + "content" = "Infected Predators: [additional_data["infected_preds"]]", + "color" = "#7ABA19", + "text" = "Players playing as Infected Yautja", + )) + + for(var/i in 1 to length(counted_factions)) + if(counted_factions[counted_factions[i]]) + new_list_data["factions"] += list(list( + "content" = "[counted_factions[i]]: [counted_factions[counted_factions[i]]]", + "color" = "#2C7EFF", + "text" = "Other", + )) + if(counted_factions[FACTION_NEUTRAL]) + new_list_data["factions"] += list(list( + "content" = "[FACTION_NEUTRAL] Humans: [counted_factions[FACTION_NEUTRAL]]", + "color" = "#688944", + "text" = "Neutrals", + )) + + for(var/faction_to_get in ALL_XENO_HIVES) + var/datum/hive_status/hive = GLOB.hive_datum[faction_to_get] + if(hive && length(hive.totalXenos)) + new_list_data["xenomorphs"] += list(list( + "content" = "[hive.name]: [length(hive.totalXenos)]", + "color" = hive.color ? hive.color : "#8200FF", + "text" = "Queen: [hive.living_xeno_queen ? "Alive" : "Dead"]", + )) + + list_data = new_list_data + mobs_ckey = new_mobs_ckey + +/datum/player_list/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, tgui_name, tgui_interface_name) + ui.open() + ui.set_autoupdate(TRUE) + +/datum/player_list/ui_data(mob/user) + . = list_data + +/datum/player_list/ui_static_data(mob/user) + . = list() + + .["admin"] = CLIENT_IS_STAFF(user.client) + +/datum/player_list/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + switch(action) + if("get_player_panel") + if(mobs_ckey[params["ckey"]]) + GLOB.admin_datums[usr.client.ckey].show_player_panel(mobs_ckey[params["ckey"]]) + +/datum/player_list/ui_status(mob/user, datum/ui_state/state) + return UI_INTERACTIVE + + +/datum/player_list/staff + tgui_name = "StaffWho" + tgui_interface_name = "Staff Who" + + var/list/category_colors = list( + "Management" = "purple", + "Maintainers" = "blue", + "Administrators" = "red", + "Moderators" = "orange", + "Mentors" = "green" + ) + +/datum/player_list/staff/update_data() + var/list/new_list_data = list() + mobs_ckey = list() + + var/list/listings + var/list/mappings + if(CONFIG_GET(flag/show_manager)) + LAZYSET(mappings, "Management", R_PERMISSIONS) + if(CONFIG_GET(flag/show_devs)) + LAZYSET(mappings, "Maintainers", R_PROFILER) + LAZYSET(mappings, "Administrators", R_ADMIN) + if(CONFIG_GET(flag/show_mods)) + LAZYSET(mappings, "Moderators", R_MOD && R_BAN) + if(CONFIG_GET(flag/show_mentors)) + LAZYSET(mappings, "Mentors", R_MENTOR) + + for(var/category in mappings) + LAZYSET(listings, category, list()) + + for(var/client/client as anything in GLOB.admins) + if(client.admin_holder?.fakekey && !CLIENT_IS_STAFF(client)) + continue + + for(var/category in mappings) + if(CLIENT_HAS_RIGHTS(client, mappings[category])) + LAZYADD(listings[category], client) + break + + for(var/category in listings) + var/list/admins = list() + for(var/client/entry as anything in listings[category]) + var/list/admin = list() + var/rank = entry.admin_holder.rank + if(entry.admin_holder.extra_titles?.len) + for(var/srank in entry.admin_holder.extra_titles) + rank += " & [srank]" + + admin["content"] = "[entry.key] ([rank])" + admin["text"] = "" + + if(entry.admin_holder?.fakekey) + admin["text"] += " (HIDDEN)" + + if(istype(entry.mob, /mob/dead/observer)) + admin["color"] = "#808080" + admin["text"] += " Spectating" + + else if(istype(entry.mob, /mob/new_player)) + admin["color"] = "#688944" + admin["text"] += " in Lobby" + else + admin["color"] = "#688944" + admin["text"] += " Playing" + + if(entry.is_afk()) + admin["color"] = "#A040D0" + admin["text"] += " (AFK)" + + admins += list(admin) + + new_list_data["administrators"] += list(list( + "category" = category, + "category_color" = category_colors[category], + "category_administrators" = length(listings[category]), + "admins" = admins, + )) + + list_data = new_list_data + +/mob/verb/who() + set category = "OOC" + set name = "Who" + + SSwho.who.tgui_interact(src) + +/mob/verb/staffwho() + set category = "Admin" + set name = "StaffWho" + + SSwho.staff_who.tgui_interact(src) diff --git a/code/datums/elements/strippable.dm b/code/datums/elements/strippable.dm index e0daaee74a8c..d93b07234c9d 100644 --- a/code/datums/elements/strippable.dm +++ b/code/datums/elements/strippable.dm @@ -126,6 +126,14 @@ to_chat(user, SPAN_WARNING("You can't do this right now.")) return FALSE + if (user.is_mob_incapacitated()) + to_chat(user, SPAN_WARNING("You can't do this right now.")) + return FALSE + + if (HAS_TRAIT(user, TRAIT_IMMOBILIZED) || HAS_TRAIT(user, TRAIT_FLOORED)) + to_chat(user, SPAN_WARNING("You can't do this right now.")) + return FALSE + if ((item.flags_inventory & CANTSTRIP) || ((item.flags_item & NODROP) && !(item.flags_item & FORCEDROP_CONDITIONAL)) || (item.flags_item & ITEM_ABSTRACT)) return FALSE diff --git a/code/datums/quadtree.dm b/code/datums/quadtree.dm index 200a51b358a0..9056dfd6bd59 100644 --- a/code/datums/quadtree.dm +++ b/code/datums/quadtree.dm @@ -82,7 +82,7 @@ /// Returns TRUE if this shape's bounding box intersects the provided shape's bounding box, otherwise FALSE. Generally faster than a full intersection test. /datum/shape/proc/intersects_aabb(datum/shape/aabb) - return (abs(src.center_x - aabb.center_x) <= (src.bounds_x + aabb.bounds_x) * 0.5) && (abs(src.center_y - aabb.center_y) <= (src.bounds_x + aabb.bounds_x) * 0.5) + return (abs(src.center_x - aabb.center_x) <= (src.bounds_x + aabb.bounds_x) * 0.5) && (abs(src.center_y - aabb.center_y) <= (src.bounds_y + aabb.bounds_y) * 0.5) /// Returns TRUE if this shape intersects the provided rectangle shape, otherwise FALSE. /datum/shape/proc/intersects_rect(datum/shape/rectangle/rect) diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm index a1d7f00cf94a..f8ce33eb9911 100644 --- a/code/game/machinery/camera/presets.dm +++ b/code/game/machinery/camera/presets.dm @@ -99,6 +99,10 @@ name = "ares core camera" network = list(CAMERA_NET_ARES) +/obj/structure/machinery/camera/autoname/almayer/brig + name = "brig camera" + network = list(CAMERA_NET_BRIG) + //used by the landing camera dropship equipment. Do not place them right under where the dropship lands. //Should place them near each corner of your LZs. /obj/structure/machinery/camera/autoname/lz_camera diff --git a/code/game/machinery/computer/camera_console.dm b/code/game/machinery/computer/camera_console.dm index c818df9fbfb9..e549436669de 100644 --- a/code/game/machinery/computer/camera_console.dm +++ b/code/game/machinery/computer/camera_console.dm @@ -352,6 +352,10 @@ /obj/structure/machinery/computer/cameras/almayer_network/vehicle network = list(CAMERA_NET_ALMAYER, CAMERA_NET_VEHICLE) +/obj/structure/machinery/computer/cameras/almayer_brig + name = "Brig Cameras Console" + network = list(CAMERA_NET_BRIG) + /obj/structure/machinery/computer/cameras/mortar name = "Mortar Camera Interface" alpha = 0 diff --git a/code/game/machinery/vending/vendor_types/crew/senior_officers.dm b/code/game/machinery/vending/vendor_types/crew/senior_officers.dm index c43d7e730d89..7157a56aa7f9 100644 --- a/code/game/machinery/vending/vendor_types/crew/senior_officers.dm +++ b/code/game/machinery/vending/vendor_types/crew/senior_officers.dm @@ -451,7 +451,6 @@ GLOBAL_LIST_INIT(cm_vending_clothing_auxiliary_officer, list( list("Insulated Gloves", 0, /obj/item/clothing/gloves/yellow, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Officer Uniform", 0, /obj/item/clothing/under/marine/officer/bridge, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/almayer/qm, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), - list("Patrol Cap", 0, /obj/item/clothing/head/cmcap, MARINE_CAN_BUY_MASK, VENDOR_ITEM_MANDATORY), list("Auxiliary Support Officer Jacket", 0, /obj/item/clothing/suit/storage/jacket/marine/service/aso, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), list("BAG (CHOOSE 1)", 0, null, null, null), @@ -463,6 +462,13 @@ GLOBAL_LIST_INIT(cm_vending_clothing_auxiliary_officer, list( list("Mod 88 Pistol", 0, /obj/item/storage/belt/gun/m4a3/mod88, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_RECOMMENDED), list("M44 Custom Revolver", 0, /obj/item/storage/belt/gun/m44/custom, MARINE_CAN_BUY_SECONDARY, VENDOR_ITEM_RECOMMENDED), + list("HAT (CHOOSE 1)", 0, null, null, null), + list("Beret, Green", 0, /obj/item/clothing/head/beret/cm, MARINE_CAN_BUY_MASK, VENDOR_ITEM_RECOMMENDED), + list("Beret, Tan", 0, /obj/item/clothing/head/beret/cm/tan, MARINE_CAN_BUY_MASK, VENDOR_ITEM_RECOMMENDED), + list("Patrol Cap", 0, /obj/item/clothing/head/cmcap, MARINE_CAN_BUY_MASK, VENDOR_ITEM_RECOMMENDED), + list("Officer Cap", 0, /obj/item/clothing/head/cmcap/bridge, MARINE_CAN_BUY_MASK, VENDOR_ITEM_RECOMMENDED), + list("Service Peaked Cap", 0, /obj/item/clothing/head/marine/peaked/service, MARINE_CAN_BUY_MASK, VENDOR_ITEM_RECOMMENDED), + list("COMBAT EQUIPMENT (TAKE ALL)", 0, null, null, null), list("Officer M3 Armor", 0, /obj/item/clothing/suit/storage/marine/MP/SO, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), list("Officer M10 Helmet", 0, /obj/item/clothing/head/helmet/marine/MP/SO, MARINE_CAN_BUY_HELMET, VENDOR_ITEM_MANDATORY), diff --git a/code/game/objects/effects/effect_system/particle_effects.dm b/code/game/objects/effects/effect_system/particle_effects.dm index 972d242bf359..9440c16f2d4e 100644 --- a/code/game/objects/effects/effect_system/particle_effects.dm +++ b/code/game/objects/effects/effect_system/particle_effects.dm @@ -8,10 +8,10 @@ mouse_opacity = MOUSE_OPACITY_TRANSPARENT unacidable = TRUE // So effect are not targeted by alien acid. -/obj/effect/particle_effect/initialize_pass_flags(datum/pass_flags_container/PF) +/obj/effect/particle_effect/initialize_pass_flags(datum/pass_flags_container/pass_flags) ..() - if (PF) - PF.flags_pass = PASS_OVER|PASS_AROUND|PASS_UNDER|PASS_THROUGH|PASS_MOB_THRU + if (pass_flags) + pass_flags.flags_pass = PASS_OVER|PASS_AROUND|PASS_UNDER|PASS_THROUGH|PASS_MOB_THRU //Water @@ -22,17 +22,14 @@ var/life = 15 mouse_opacity = MOUSE_OPACITY_TRANSPARENT -/obj/effect/particle_effect/water/initialize_pass_flags(datum/pass_flags_container/PF) +/obj/effect/particle_effect/water/initialize_pass_flags(datum/pass_flags_container/pass_flags) ..() - if (PF) - PF.flags_pass = PASS_THROUGH|PASS_OVER|PASS_MOB_THRU|PASS_UNDER + if (pass_flags) + pass_flags.flags_pass = PASS_THROUGH|PASS_OVER|PASS_MOB_THRU|PASS_UNDER /obj/effect/particle_effect/water/Move(turf/newloc) - //var/turf/T = src.loc - //if (istype(T, /turf)) - // T.firelevel = 0 //TODO: FIX - if (--src.life < 1) - //SN src = null + life -= 1 + if (life < 1) qdel(src) if(newloc.density) return 0 diff --git a/code/game/objects/items/devices/suit_cooling.dm b/code/game/objects/items/devices/suit_cooling.dm deleted file mode 100644 index 564b3e41f591..000000000000 --- a/code/game/objects/items/devices/suit_cooling.dm +++ /dev/null @@ -1,179 +0,0 @@ -/obj/item/device/suit_cooling_unit - name = "portable suit cooling unit" - desc = "A portable heat sink and liquid cooled radiator that can be hooked up to a space suit's existing temperature controls to provide industrial levels of cooling." - w_class = SIZE_LARGE - icon_state = "suitcooler0" - flags_equip_slot = SLOT_BACK //you can carry it on your back if you want, but it won't do anything unless attached to suit storage - - //copied from tank.dm - flags_atom = FPRINT|CONDUCT - force = 5 - throwforce = 10 - throw_speed = SPEED_FAST - throw_range = 4 - - - - var/on = 0 //is it turned on? - var/cover_open = 0 //is the cover open? - var/obj/item/cell/cell - var/max_cooling = 12 //in degrees per second - probably don't need to mess with heat capacity here - var/charge_consumption = 16.6 //charge per second at max_cooling - var/thermostat = T20C - - //TODO: make it heat up the surroundings when not in space - -/obj/item/device/suit_cooling_unit/Initialize(mapload, ...) - . = ..() - - START_PROCESSING(SSobj, src) - - cell = new/obj/item/cell(src) //comes with the crappy default power cell - high-capacity ones shouldn't be hard to find - -/obj/item/device/suit_cooling_unit/Destroy() - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/item/device/suit_cooling_unit/process() - if (!on || !cell) - return - - if (!ismob(loc)) - return - - if (!attached_to_suit(loc)) //make sure they have a suit and we are attached to it - return - - var/mob/living/carbon/human/H = loc - - var/efficiency = 1 - H.get_pressure_weakness() //you need to have a good seal for effective cooling - var/env_temp = get_environment_temperature() //wont save you from a fire - var/temp_adj = min(H.bodytemperature - max(thermostat, env_temp), max_cooling) - - if (temp_adj < 0.5) //only cools, doesn't heat, also we don't need extreme precision - return - - var/charge_usage = (temp_adj/max_cooling)*charge_consumption - - H.bodytemperature -= temp_adj*efficiency - H.recalculate_move_delay = TRUE - - cell.use(charge_usage) - - if(cell.charge <= 0) - turn_off() - -/obj/item/device/suit_cooling_unit/proc/get_environment_temperature() - if (ishuman(loc)) - var/mob/living/carbon/human/H = loc - return H.return_temperature() - - var/turf/T = get_turf(src) - return T.return_temperature() - -/obj/item/device/suit_cooling_unit/proc/attached_to_suit(mob/M) - if (!ishuman(M)) - return 0 - - var/mob/living/carbon/human/H = M - - if (!H.wear_suit || H.s_store != src) - return 0 - - return 1 - -/obj/item/device/suit_cooling_unit/proc/turn_on() - if(!cell) - return - if(cell.charge <= 0) - return - - on = 1 - updateicon() - -/obj/item/device/suit_cooling_unit/proc/turn_off() - if (ismob(src.loc)) - var/mob/M = src.loc - M.show_message("\The [src] clicks and whines as it powers down.", SHOW_MESSAGE_AUDIBLE) //let them know in case it's run out of power. - on = 0 - updateicon() - -/obj/item/device/suit_cooling_unit/attack_self(mob/user) - ..() - - if(cover_open && cell) - if(ishuman(user)) - user.put_in_hands(cell) - else - cell.forceMove(get_turf(loc)) - - cell.add_fingerprint(user) - cell.update_icon() - - to_chat(user, "You remove [cell].") - src.cell = null - updateicon() - return - - //TODO use a UI like the air tanks - if(on) - turn_off() - else - turn_on() - if (on) - to_chat(user, "You switch on [src].") - -/obj/item/device/suit_cooling_unit/attackby(obj/item/W as obj, mob/user as mob) - if (HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER)) - if(cover_open) - cover_open = 0 - to_chat(user, "You screw the panel into place.") - else - cover_open = 1 - to_chat(user, "You unscrew the panel.") - updateicon() - return - - if (istype(W, /obj/item/cell)) - if(cover_open) - if(cell) - to_chat(user, "There is \a [cell] already installed here.") - else - if(user.drop_held_item()) - W.forceMove(src) - cell = W - to_chat(user, "You insert [cell].") - updateicon() - return - - return ..() - -/obj/item/device/suit_cooling_unit/proc/updateicon() - if (cover_open) - if (cell) - icon_state = "suitcooler1" - else - icon_state = "suitcooler2" - else - icon_state = "suitcooler0" - -/obj/item/device/suit_cooling_unit/get_examine_text(mob/user) - . = ..() - if (on) - if (attached_to_suit(src.loc)) - . += "It's switched on and running." - else - . += "It's switched on, but not attached to anything." - else - . += "It is switched off." - - if (cover_open) - if(cell) - . += "The panel is open, exposing [cell]." - else - . += "The panel is open." - - if (cell) - . += "The charge meter reads [floor(cell.percent())]%." - else - . += "It doesn't have a power cell installed." diff --git a/code/game/objects/items/tools/cleaning_tools.dm b/code/game/objects/items/tools/cleaning_tools.dm index f392f096bcf6..fba21de3328d 100644 --- a/code/game/objects/items/tools/cleaning_tools.dm +++ b/code/game/objects/items/tools/cleaning_tools.dm @@ -99,13 +99,15 @@ desc = "This cone is trying to warn you of something!" icon_state = "cone" icon = 'icons/obj/janitor.dmi' + item_icons = 'icons/mob/humans/onmob/head_0.dmi' force = 1 throwforce = 3 throw_speed = SPEED_FAST throw_range = 5 w_class = SIZE_SMALL attack_verb = list("warned", "cautioned", "smashed") - + flags_equip_slot = SLOT_HEAD + flags_inv_hide = HIDEEARS|HIDETOPHAIR diff --git a/code/game/turfs/walls/wall_types.dm b/code/game/turfs/walls/wall_types.dm index 21839d35af03..6db61002c2fe 100644 --- a/code/game/turfs/walls/wall_types.dm +++ b/code/game/turfs/walls/wall_types.dm @@ -297,11 +297,10 @@ INITIALIZE_IMMEDIATE(/turf/closed/wall/indestructible/splashscreen) /turf/closed/wall/indestructible/splashscreen name = "Lobby Art" desc = "Assorted artworks." - icon = 'icons/lobby/title.dmi' - icon_state = "" -// icon_state = "title_holiday" + icon = 'icons/lobby/title_loading.dmi' + icon_state = "title" layer = FLY_LAYER - special_icon = 1 + special_icon = TRUE /turf/closed/wall/indestructible/splashscreen/Initialize() . = ..() @@ -309,16 +308,19 @@ INITIALIZE_IMMEDIATE(/turf/closed/wall/indestructible/splashscreen) /proc/force_lobby_art(art_id) GLOB.displayed_lobby_art = art_id - var/turf/closed/wall/indestructible/splashscreen/SS = locate("LOBBYART") + var/turf/closed/wall/indestructible/splashscreen/lobby_art = locate("LOBBYART") var/list/lobby_arts = CONFIG_GET(str_list/lobby_art_images) var/list/lobby_authors = CONFIG_GET(str_list/lobby_art_authors) - SS.icon_state = lobby_arts[GLOB.displayed_lobby_art] - SS.desc = "Artwork by [lobby_authors[GLOB.displayed_lobby_art]]" - for(var/client/C in GLOB.clients) + lobby_art.icon = 'icons/lobby/title.dmi' + lobby_art.icon_state = lobby_arts[GLOB.displayed_lobby_art] + lobby_art.desc = "Artwork by [lobby_authors[GLOB.displayed_lobby_art]]" + lobby_art.pixel_x = -288 + lobby_art.pixel_y = -288 + for(var/client/player in GLOB.clients) if(GLOB.displayed_lobby_art != -1) var/author = lobby_authors[GLOB.displayed_lobby_art] if(author != "Unknown") - to_chat_forced(C, SPAN_ROUNDBODY("
This round's lobby art is brought to you by [author]
")) + to_chat_forced(player, SPAN_ROUNDBODY("
This round's lobby art is brought to you by [author]
")) /turf/closed/wall/indestructible/other icon_state = "r_wall" diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm deleted file mode 100644 index 3a9274dbec62..000000000000 --- a/code/game/verbs/who.dm +++ /dev/null @@ -1,209 +0,0 @@ -/client/verb/who()//likely don't touch any... this is easy can die. (:troll_fale:) - set name = "Who" - set category = "OOC" - - var/list/counted_humanoids = list( - "Observers" = 0, - "Admin observers" = 0, - "Humans" = 0, - "Infected humans" = 0, - FACTION_MARINE = 0, - "USCM Marines" = 0, - "Lobby" = 0, - - FACTION_YAUTJA = 0, - "Infected preds" = 0, - - FACTION_PMC = 0, - FACTION_CLF = 0, - FACTION_UPP = 0, - FACTION_TWE = 0, - FACTION_FREELANCER = 0, - FACTION_SURVIVOR = 0, - FACTION_WY_DEATHSQUAD = 0, - FACTION_COLONIST = 0, - FACTION_MERCENARY = 0, - FACTION_DUTCH = 0, - FACTION_HEFA = 0, - FACTION_GLADIATOR = 0, - FACTION_PIRATE = 0, - FACTION_PIZZA = 0, - FACTION_SOUTO = 0, - - FACTION_NEUTRAL = 0, - - FACTION_ZOMBIE = 0 - ) - - var/list/counted_xenos = list() - - var/players = length(GLOB.clients) - - var/dat = "Current Players:
" - var/list/Lines = list() - if(admin_holder && ((R_ADMIN & admin_holder.rights) || (R_MOD & admin_holder.rights))) - for(var/client/C in GLOB.clients) - if(!CLIENT_HAS_RIGHTS(src, R_STEALTH) && (CLIENT_IS_STEALTHED(C))) - continue - var/entry = "[C.key]" - if(C.mob) //Juuuust in case - if(istype(C.mob, /mob/new_player)) - entry += " - In Lobby" - counted_humanoids["Lobby"]++ - else - entry += " - Playing as [C.mob.real_name]" - - if(isobserver(C.mob)) - counted_humanoids["Observers"]++ - if(C.admin_holder?.rights & R_MOD) - counted_humanoids["Admin observers"]++ - counted_humanoids["Observers"]-- - var/mob/dead/observer/O = C.mob - if(O.started_as_observer) - entry += " - Observing" - else - entry += " - DEAD" - else - switch(C.mob.stat) - if(UNCONSCIOUS) - entry += " - Unconscious" - if(DEAD) - entry += " - DEAD" - - if(C.mob && C.mob.stat != DEAD) - if(ishuman(C.mob)) - if(C.mob.faction == FACTION_ZOMBIE) - counted_humanoids[FACTION_ZOMBIE]++ - entry += " - Zombie" - else if(C.mob.faction == FACTION_YAUTJA) - counted_humanoids[FACTION_YAUTJA]++ - entry += " - Predator" - if(C.mob.status_flags & XENO_HOST) - counted_humanoids["Infected preds"]++ - else - counted_humanoids["Humans"]++ - if(C.mob.status_flags & XENO_HOST) - counted_humanoids["Infected humans"]++ - if(C.mob.faction == FACTION_MARINE) - counted_humanoids[FACTION_MARINE]++ - if(C.mob.job in (GLOB.ROLES_MARINES)) - counted_humanoids["USCM Marines"]++ - else - counted_humanoids[C.mob.faction]++ - else if(isxeno(C.mob)) - var/mob/living/carbon/xenomorph/X = C.mob - counted_xenos[X.hivenumber]++ - if(X.faction == FACTION_PREDALIEN) - counted_xenos[FACTION_PREDALIEN]++ - entry += " - Xenomorph" - entry += " (?)" - Lines += entry - - for(var/line in sortList(Lines)) - dat += "[line]
" - dat += "Total Players: [players]" - dat += "
In Lobby: [counted_humanoids["Lobby"]]" - dat += "
Observers: [counted_humanoids["Observers"]] players and [counted_humanoids["Admin observers"]] staff members" - dat += "
Humans: [counted_humanoids["Humans"]] (Infected: [counted_humanoids["Infected humans"]])" - if(counted_humanoids[FACTION_MARINE]) - dat += "
USCM personnel: [counted_humanoids[FACTION_MARINE]] (Marines: [counted_humanoids["USCM Marines"]])" - if(counted_humanoids[FACTION_YAUTJA]) - dat += "
Predators: [counted_humanoids[FACTION_YAUTJA]] [counted_humanoids["Infected preds"] ? "(Infected: [counted_humanoids["Infected preds"]])" : ""]" - if(counted_humanoids[FACTION_ZOMBIE]) - dat += "
Zombies: [counted_humanoids[FACTION_ZOMBIE]]" - - var/show_fact = TRUE - for(var/i in 10 to LAZYLEN(counted_humanoids) - 2) - if(counted_humanoids[counted_humanoids[i]]) - if(show_fact) - dat += "

Other factions:" - show_fact = FALSE - dat += "
[counted_humanoids[i]]: [counted_humanoids[counted_humanoids[i]]]" - if(counted_humanoids[FACTION_NEUTRAL]) - dat += "
[FACTION_NEUTRAL] Humans: [counted_humanoids[FACTION_NEUTRAL]]" - - show_fact = TRUE - var/datum/hive_status/hive - for(var/hivenumber in counted_xenos) - // Print predalien counts last - if(hivenumber == FACTION_PREDALIEN) - continue - if(show_fact) - dat += "

Xenomorphs:" - show_fact = FALSE - hive = GLOB.hive_datum[hivenumber] - if(hive) - dat += "
[hive.name]: [counted_xenos[hivenumber]] (Queen: [hive.living_xeno_queen ? "Alive" : "Dead"])" - else - dat += "
Error: no hive datum detected for [hivenumber]." - hive = null - if(counted_xenos[FACTION_PREDALIEN]) - dat += "
Predaliens: [counted_xenos[FACTION_PREDALIEN]]" - - else - for(var/client/C in GLOB.clients) - if((C.admin_holder && C.admin_holder.fakekey) || (CLIENT_IS_STEALTHED(C))) - continue - - Lines += C.key - for(var/line in sortList(Lines)) - dat += "[line]
" - dat += "Total Players: [players]
" - - dat += "" - show_browser(usr, dat, "Who", "who", "size=600x800") - - -/client/verb/staffwho() - set name = "Staffwho" - set category = "Admin" - - var/dat = "" - var/list/mappings - if(CONFIG_GET(flag/show_manager)) - LAZYSET(mappings, "Management", R_PERMISSIONS) - if(CONFIG_GET(flag/show_devs)) - LAZYSET(mappings, "Maintainers", R_PROFILER) - LAZYSET(mappings, "Admins", R_ADMIN) - if(CONFIG_GET(flag/show_mods)) - LAZYSET(mappings, "Moderators", R_MOD) - if(CONFIG_GET(flag/show_mentors)) - LAZYSET(mappings, "Mentors", R_MENTOR) - - var/list/listings - for(var/category in mappings) - LAZYSET(listings, category, list()) - - for(var/client/C in GLOB.admins) - if(CLIENT_IS_STEALTHED(C) && !CLIENT_HAS_RIGHTS(src, R_STEALTH)) - continue - if(C.admin_holder?.fakekey && !CLIENT_IS_STAFF(src)) - continue - for(var/category in mappings) - if(CLIENT_HAS_RIGHTS(C, mappings[category])) - LAZYADD(listings[category], C) - break - - for(var/category in listings) - dat += "
Current [category] ([length(listings[category])]):
\n" - for(var/client/entry in listings[category]) - dat += "\t[entry.key] is \a [entry.admin_holder.rank]" - if(LAZYLEN(entry.admin_holder.extra_titles)) - for(var/srank in entry.admin_holder.extra_titles) - dat += " & [srank]" - if(CLIENT_IS_STAFF(src)) - if(CLIENT_IS_STEALTHED(entry)) - dat += " (STEALTHED)" - else if(entry.admin_holder?.fakekey) - dat += " (HIDDEN)" - if(istype(entry.mob, /mob/dead/observer)) - dat += " - Observing" - else if(istype(entry.mob, /mob/new_player)) - dat += " - Lobby" - else - dat += " - Playing" - if(entry.is_afk()) - dat += " (AFK)" - dat += "
" - dat += "" - show_browser(usr, dat, "Staffwho", "staffwho", "size=600x800") diff --git a/code/modules/clothing/spacesuits/spacesuits.dm b/code/modules/clothing/spacesuits/spacesuits.dm index 9c28ca42bc41..a8b056d0bb9d 100644 --- a/code/modules/clothing/spacesuits/spacesuits.dm +++ b/code/modules/clothing/spacesuits/spacesuits.dm @@ -32,7 +32,7 @@ gas_transfer_coefficient = 0.01 permeability_coefficient = 0.02 flags_armor_protection = BODY_FLAG_CHEST|BODY_FLAG_GROIN|BODY_FLAG_LEGS|BODY_FLAG_FEET|BODY_FLAG_ARMS|BODY_FLAG_HANDS - allowed = list(/obj/item/device/flashlight,/obj/item/tank/emergency_oxygen,/obj/item/device/suit_cooling_unit) + allowed = list(/obj/item/device/flashlight,/obj/item/tank/emergency_oxygen) slowdown = 3 armor_melee = CLOTHING_ARMOR_NONE armor_bullet = CLOTHING_ARMOR_NONE diff --git a/code/modules/mob/living/carbon/human/life/life_helpers.dm b/code/modules/mob/living/carbon/human/life/life_helpers.dm index cab3ae21a782..9388204a967d 100644 --- a/code/modules/mob/living/carbon/human/life/life_helpers.dm +++ b/code/modules/mob/living/carbon/human/life/life_helpers.dm @@ -6,25 +6,6 @@ * Mostly for procs that are not called in the direct Life() loop, except for exact functionality matches (handle_breath, breathe, get_breath_from_internal for example) */ -//Calculate how vulnerable the human is to under- and overpressure. -//Returns 0 (equals 0 %) if sealed in an undamaged suit, 1 if unprotected (equals 100%). -//Suitdamage can modifiy this in 10% steps. -/mob/living/carbon/human/proc/get_pressure_weakness() - - var/pressure_adjustment_coefficient = 1 // Assume no protection at first. - - if(wear_suit && (wear_suit.flags_inventory & NOPRESSUREDMAGE) && head && (head.flags_inventory & NOPRESSUREDMAGE)) //Complete set of pressure-proof suit worn, assume fully sealed. - pressure_adjustment_coefficient = 0 - - //Handles breaches in your space suit. 10 suit damage equals a 100% loss of pressure protection. - if(istype(wear_suit, /obj/item/clothing/suit/space)) - var/obj/item/clothing/suit/space/S = wear_suit - if(S.can_breach && S.damage) - pressure_adjustment_coefficient += S.damage * 0.1 - - pressure_adjustment_coefficient = min(1, max(pressure_adjustment_coefficient, 0)) //So it isn't less than 0 or larger than 1. - return pressure_adjustment_coefficient - /mob/living/carbon/human/proc/stabilize_body_temperature() diff --git a/code/modules/mob/living/carbon/human/species/synthetic.dm b/code/modules/mob/living/carbon/human/species/synthetic.dm index f2d5c50f7391..ab5a8d462713 100644 --- a/code/modules/mob/living/carbon/human/species/synthetic.dm +++ b/code/modules/mob/living/carbon/human/species/synthetic.dm @@ -8,7 +8,7 @@ unarmed_type = /datum/unarmed_attack/punch/synthetic pain_type = /datum/pain/synthetic stamina_type = /datum/stamina/none - mob_inherent_traits = list(TRAIT_SUPER_STRONG) + mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_IRON_TEETH) rarity_value = 2 insulated = TRUE @@ -64,7 +64,7 @@ name = SYNTH_GEN_ONE uses_skin_color = FALSE special_body_types = FALSE - mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INTENT_EYES) + mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INTENT_EYES, TRAIT_IRON_TEETH) hair_color = "#000000" icobase = 'icons/mob/humans/species/r_synthetic.dmi' @@ -81,7 +81,7 @@ uses_skin_color = TRUE special_body_types = TRUE burn_mod = 0.8 - mob_inherent_traits = list(TRAIT_SUPER_STRONG) + mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_IRON_TEETH) pain_type = /datum/pain/synthetic/colonial rarity_value = 1.5 @@ -103,7 +103,7 @@ name = SYNTH_COLONY_GEN_ONE uses_skin_color = FALSE special_body_types = FALSE - mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INTENT_EYES) + mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INTENT_EYES, TRAIT_IRON_TEETH) //sets colonial_gen_one synth's hair to black hair_color = "#000000" //sets colonial_gen_one synth's icon to WJ sprite @@ -116,7 +116,7 @@ name_plural = "Combat Synthetics" uses_skin_color = FALSE special_body_types = FALSE - mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INTENT_EYES) + mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INTENT_EYES, TRAIT_IRON_TEETH) burn_mod = 0.6 //made for combat total_health = 250 //made for combat @@ -137,7 +137,7 @@ name = SYNTH_INFILTRATOR name_plural = "Infiltrator Synthetics" uses_skin_color = TRUE - mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INFILTRATOR_SYNTH) + mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INFILTRATOR_SYNTH, TRAIT_IRON_TEETH) bloodsplatter_type = /obj/effect/temp_visual/dir_setting/bloodsplatter/human diff --git a/code/modules/mob/living/carbon/human/species/working_joe/_species.dm b/code/modules/mob/living/carbon/human/species/working_joe/_species.dm index f2c0e8d4cf26..0273fe6b903f 100644 --- a/code/modules/mob/living/carbon/human/species/working_joe/_species.dm +++ b/code/modules/mob/living/carbon/human/species/working_joe/_species.dm @@ -4,7 +4,7 @@ death_message = "violently gargles fluid and seizes up, the glow in their eyes dimming..." uses_skin_color = FALSE burn_mod = 0.65 // made for hazardous environments, withstanding temperatures up to 1210 degrees - mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INTENT_EYES, TRAIT_EMOTE_CD_EXEMPT, TRAIT_CANNOT_EAT, TRAIT_UNSTRIPPABLE) + mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INTENT_EYES, TRAIT_EMOTE_CD_EXEMPT, TRAIT_CANNOT_EAT, TRAIT_UNSTRIPPABLE, TRAIT_IRON_TEETH) slowdown = 0.45 hair_color = "#000000" diff --git a/code/modules/mob/living/carbon/human/species/yautja/_species.dm b/code/modules/mob/living/carbon/human/species/yautja/_species.dm index 86653af92b4b..042c9917af61 100644 --- a/code/modules/mob/living/carbon/human/species/yautja/_species.dm +++ b/code/modules/mob/living/carbon/human/species/yautja/_species.dm @@ -14,6 +14,7 @@ TRAIT_FOREIGN_BIO, TRAIT_DEXTROUS, TRAIT_EMOTE_CD_EXEMPT, + TRAIT_IRON_TEETH, ) unarmed_type = /datum/unarmed_attack/punch/strong secondary_unarmed_type = /datum/unarmed_attack/bite/strong diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm index a66903a938c5..5b9c410e235a 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm @@ -468,6 +468,9 @@ /mob/living/carbon/xenomorph/queen/proc/make_combat_effective() queen_aged = TRUE + if(queen_age_timer_id != TIMER_ID_NULL) + deltimer(queen_age_timer_id) + queen_age_timer_id = TIMER_ID_NULL give_combat_abilities() recalculate_actions() @@ -545,9 +548,8 @@ . += "Pooled Larvae: [stored_larvae]" . += "Leaders: [xeno_leader_num] / [hive?.queen_leader_limit]" - if(queen_age_timer_id != TIMER_ID_NULL) - var/time_left = time2text(timeleft(queen_age_timer_id) + 1 MINUTES, "mm") // We add a minute so that it basically ceilings the value. - . += "Maturity: [time_left == 1? "[time_left] minute" : "[time_left] minutes"] remaining" + if(!queen_aged && queen_age_timer_id != TIMER_ID_NULL) + . += "Maturity: [time2text(timeleft(queen_age_timer_id), "mm:ss")] remaining" /mob/living/carbon/xenomorph/queen/proc/set_orders() set category = "Alien" diff --git a/code/modules/mob/living/carbon/xenomorph/death.dm b/code/modules/mob/living/carbon/xenomorph/death.dm index 82b9291dc555..ebf58133308f 100644 --- a/code/modules/mob/living/carbon/xenomorph/death.dm +++ b/code/modules/mob/living/carbon/xenomorph/death.dm @@ -137,25 +137,31 @@ /mob/living/carbon/xenomorph/gib(datum/cause_data/cause = create_cause_data("gibbing", src)) var/obj/effect/decal/remains/xeno/remains = new(get_turf(src)) - remains.icon = icon + var/icon_path + var/gib_state = "gibbed-a-corpse" remains.pixel_x = pixel_x //For 2x2. if(!caste) CRASH("CASTE ERROR: gib() was called without a caste. (name: [name], disposed: [QDELETED(src)], health: [health])") - switch(caste.caste_type) //This will need to be changed later, when we have proper xeno pathing. Might do it on caste or something. + if(mob_size >= MOB_SIZE_BIG) + icon_path = 'icons/mob/xenos/xenomorph_64x64.dmi' + else + icon_path = 'icons/mob/xenos/xenomorph_48x48.dmi' + switch(caste.caste_type) + if(XENO_CASTE_RUNNER) + icon_path = 'icons/mob/xenos/xenomorph_64x64.dmi' + gib_state = "gibbed-a-corpse-runner" if(XENO_CASTE_BOILER) var/mob/living/carbon/xenomorph/boiler/src_boiler = src visible_message(SPAN_DANGER("[src] begins to bulge grotesquely, and explodes in a cloud of corrosive gas!")) src_boiler.smoke.set_up(2, 0, get_turf(src), new_cause_data = src_boiler.smoke.cause_data) src_boiler.smoke.start() - remains.icon_state = "gibbed-a-corpse" - if(XENO_CASTE_RUNNER) - remains.icon_state = "gibbed-a-corpse-runner" if(XENO_CASTE_LARVA, XENO_CASTE_PREDALIEN_LARVA) - remains.icon_state = "larva_gib_corpse" - else - remains.icon_state = "gibbed-a-corpse" + icon_path = 'icons/mob/xenos/larva.dmi' + + remains.icon_state = gib_state + remains.icon = icon_path check_blood_splash(35, BURN, 65, 2) //Some testing numbers. 35 burn, 65 chance. @@ -170,8 +176,12 @@ icon_path = 'icons/mob/xenos/xenomorph_48x48.dmi' switch(caste.caste_type) if(XENO_CASTE_RUNNER) + icon_path = 'icons/mob/xenos/xenomorph_64x64.dmi' to_flick = "gibbed-a-runner" + if(XENO_CASTE_BOILER) + to_flick = "gibbed-a-boiler" if(XENO_CASTE_LARVA, XENO_CASTE_PREDALIEN_LARVA) + icon_path = 'icons/mob/xenos/larva.dmi' to_flick = "larva_gib" new /obj/effect/overlay/temp/gib_animation/xeno(loc, src, to_flick, icon_path) diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm index 0e0fccf027db..5db904869973 100644 --- a/code/modules/projectiles/ammunition.dm +++ b/code/modules/projectiles/ammunition.dm @@ -365,7 +365,7 @@ Turn() or Shift() as there is virtually no overhead. ~N overlay_ammo_type = "_blank" overlay_gun_type = "_458" overlay_content = "_458" - magazine_type = /obj/item/ammo_magazine/handful/lever_action/xm88 + magazine_type = /obj/item/ammo_magazine/lever_action/xm88 /obj/item/ammo_box/magazine/lever_action/xm88/empty empty = TRUE diff --git a/code/modules/shuttle/computer.dm b/code/modules/shuttle/computer.dm index 00dcd987f089..5f17c9a73285 100644 --- a/code/modules/shuttle/computer.dm +++ b/code/modules/shuttle/computer.dm @@ -364,14 +364,47 @@ icon_state = "terminal" req_access = list() breakable = FALSE + unslashable = TRUE + unacidable = TRUE ///If true, the lifeboat is in the process of launching, and so the code will not allow another launch. var/launch_initiated = FALSE + ///If true, the lifeboat is in the process of having the xeno override removed by the pilot. + var/override_being_removed = FALSE + ///How long it takes to unlock the console + var/remaining_time = 180 SECONDS + +/obj/structure/machinery/computer/shuttle/lifeboat/ex_act(severity) + return /obj/structure/machinery/computer/shuttle/lifeboat/attack_hand(mob/user) . = ..() var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = SSshuttle.getShuttle(shuttleId) if(lifeboat.status == LIFEBOAT_LOCKED) - to_chat(user, SPAN_WARNING("[src] flickers with error messages.")) + if(!skillcheck(user, SKILL_PILOT, SKILL_PILOT_TRAINED)) + to_chat(user, SPAN_WARNING("[src] displays an error message and asks you to contact your pilot to resolve the problem.")) + return + if(user.action_busy || override_being_removed) + return + to_chat(user, SPAN_NOTICE("You start to remove the lockout.")) + override_being_removed = TRUE + user.visible_message(SPAN_NOTICE("[user] starts to type on [src]."), + SPAN_NOTICE("You try to take back control over the lifeboat. It will take around [remaining_time / 10] seconds.")) + while(remaining_time > 20 SECONDS) + if(!do_after(user, 20 SECONDS, INTERRUPT_ALL|INTERRUPT_CHANGED_LYING, BUSY_ICON_HOSTILE, numticks = 20)) + to_chat(user, SPAN_WARNING("You fail to remove the lockout!")) + override_being_removed = FALSE + return + remaining_time = remaining_time - 20 SECONDS + if(remaining_time > 0) + to_chat(user, SPAN_NOTICE("You partially bypass the lockout, only [remaining_time / 10] seconds left.")) + to_chat(user, SPAN_NOTICE("You successfully removed the lockout!")) + playsound(loc, 'sound/machines/terminal_success.ogg', KEYBOARD_SOUND_VOLUME, 1) + lifeboat.status = LIFEBOAT_ACTIVE + lifeboat.available = TRUE + user.visible_message(SPAN_NOTICE("[src] blinks with blue lights."), + SPAN_NOTICE("You have successfully taken back control over the lifeboat.")) + override_being_removed = FALSE + return else if(lifeboat.status == LIFEBOAT_INACTIVE) to_chat(user, SPAN_NOTICE("[src]'s screen says \"Awaiting evacuation order\".")) else if(lifeboat.status == LIFEBOAT_ACTIVE) @@ -451,6 +484,8 @@ var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock = lifeboat.get_docked() lifeboat_dock.open_dock() xeno_message(SPAN_XENOANNOUNCE("We have wrested away control of one of the metal birds! They shall not escape!"), 3, xeno.hivenumber) + launch_initiated = FALSE + remaining_time = initial(remaining_time) return XENO_NO_DELAY_ACTION else return ..() diff --git a/code/modules/tgs/README.md b/code/modules/tgs/README.md index 6319028d8106..35ca73d7e9a8 100644 --- a/code/modules/tgs/README.md +++ b/code/modules/tgs/README.md @@ -1,6 +1,6 @@ # DMAPI Internals -This folder should be placed on it's own inside a codebase that wishes to use the TGS DMAPI. Warranty void if modified. +This folder should be placed on its own inside a codebase that wishes to use the TGS DMAPI. Warranty void if modified. - [includes.dm](./includes.dm) is the file that should be included by DM code, it handles including the rest. - The [core](./core) folder includes all code not directly part of any API version. diff --git a/code/modules/tgs/v5/api.dm b/code/modules/tgs/v5/api.dm index 95b8edd3ee5c..05d0dee25b3c 100644 --- a/code/modules/tgs/v5/api.dm +++ b/code/modules/tgs/v5/api.dm @@ -50,7 +50,9 @@ version = null // we want this to be the TGS version, not the interop version // sleep once to prevent an issue where world.Export on the first tick can hang indefinitely + TGS_DEBUG_LOG("Starting Export bug prevention sleep tick. time:[world.time] sleep_offline:[world.sleep_offline]") sleep(world.tick_lag) + TGS_DEBUG_LOG("Export bug prevention sleep complete") var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands(), DMAPI5_PARAMETER_TOPIC_PORT = GetTopicPort())) if(!istype(bridge_response)) diff --git a/colonialmarines.dme b/colonialmarines.dme index c7d4a8957987..54760dde8594 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -311,6 +311,7 @@ #include "code\controllers\subsystem\tracking.dm" #include "code\controllers\subsystem\vote.dm" #include "code\controllers\subsystem\weather.dm" +#include "code\controllers\subsystem\who.dm" #include "code\controllers\subsystem\x_evolution.dm" #include "code\controllers\subsystem\xeno.dm" #include "code\controllers\subsystem\init\landmarks.dm" @@ -1139,7 +1140,6 @@ #include "code\game\objects\items\devices\pipe_painter.dm" #include "code\game\objects\items\devices\portable_vendor.dm" #include "code\game\objects\items\devices\scanners.dm" -#include "code\game\objects\items\devices\suit_cooling.dm" #include "code\game\objects\items\devices\taperecorder.dm" #include "code\game\objects\items\devices\teleportation.dm" #include "code\game\objects\items\devices\transfer_valve.dm" @@ -1407,7 +1407,6 @@ #include "code\game\verbs\ooc.dm" #include "code\game\verbs\preferences.dm" #include "code\game\verbs\records.dm" -#include "code\game\verbs\who.dm" #include "code\modules\trigger.dm" #include "code\modules\admin\admin.dm" #include "code\modules\admin\admin_ranks.dm" diff --git a/html/changelogs/AutoChangeLog-pr-6661.yml b/html/changelogs/AutoChangeLog-pr-6661.yml new file mode 100644 index 000000000000..a4663ee888d2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6661.yml @@ -0,0 +1,4 @@ +author: "zzzmike" +delete-after: True +changes: + - rscadd: "pilots can unhack lifeboats, similar to dropship unhacking" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-6762.yml b/html/changelogs/AutoChangeLog-pr-6762.yml new file mode 100644 index 000000000000..af02078356e6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6762.yml @@ -0,0 +1,6 @@ +author: "efzapa" +delete-after: True +changes: + - rscadd: "All Brig Detainment Cameras are now linked to a new Brig Camera Console Computer, available in the Brig Lobby, Warden's Office, CIC, and CMP Office." + - maptweak: "Removed one of the Security Records Consoles in the Brig Lobby in place for a Brig Camera Console." + - mapadd: "Both Brig Perma Cells now have brig cameras in them." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-6810.yml b/html/changelogs/AutoChangeLog-pr-6810.yml new file mode 100644 index 000000000000..b1daf0b6d8b9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6810.yml @@ -0,0 +1,4 @@ +author: "zzzmike" +delete-after: True +changes: + - bugfix: "stops attempted stripping when stunned etc." \ No newline at end of file diff --git a/html/changelogs/archive/2024-07.yml b/html/changelogs/archive/2024-07.yml index 5b2844998cbc..3a08f35ded14 100644 --- a/html/changelogs/archive/2024-07.yml +++ b/html/changelogs/archive/2024-07.yml @@ -210,3 +210,44 @@ cuberound: - rscdel: removes trade destinations (they were never used) - balance: m56 cupola uses m56d ammo rather then standard sg ammo +2024-07-22: + BlackCrystalic: + - bugfix: Queen maturity timer + Blackcrystalic: + - qol: port who/staffwho to TGUI + ThePiachu: + - refactor: Made XM88 box code more uniform with other handful boxes. + zzzmike: + - bugfix: lifeboat launch console is no longer slashable / acidable +2024-07-23: + cuberound: + - code_imp: cleans up water particle code +2024-07-24: + Doubleumc: + - bugfix: sounds & motion detectors should be more reliable +2024-07-25: + cuberound: + - rscdel: removes /obj/item/device/suit_cooling_unit and get_pressure_weakness() +2024-07-26: + BlackCrystalic: + - qol: if server take too long to pre init all before lobby art, players will see + lobbyart "loading" + Blundir: + - bugfix: fixed runner having no gib animation + - bugfix: fixed gib remains being invisible + - imageadd: boiler gib animation + - imageadd: larva gib remains + - imageadd: shoes icons resprite + Steelpoint: + - imageadd: The Sniper and Anti-Material Rifle Specialists will now use an urban + camouflage sprite for their ghillie suit instead of a green camouflage. + realforest2001: + - rscadd: Synthetics and Yautja now spawn with the Iron Teeth trait, not dropping + items held in their mouth. + rythenx: + - rscadd: more options for hats to ASO vendor to bring it in line with what SO has + available +2024-07-29: + TheManWithNoHands: + - code_imp: adds flags to cone, allowing it to be worn on head + - imageadd: added on mob sprites for cone diff --git a/icons/lobby/title_loading.dmi b/icons/lobby/title_loading.dmi new file mode 100644 index 000000000000..3aa2f5ad52c2 Binary files /dev/null and b/icons/lobby/title_loading.dmi differ diff --git a/icons/mob/humans/onmob/head_0.dmi b/icons/mob/humans/onmob/head_0.dmi index 9fc0bc82c123..4a4338eac4c2 100644 Binary files a/icons/mob/humans/onmob/head_0.dmi and b/icons/mob/humans/onmob/head_0.dmi differ diff --git a/icons/mob/humans/onmob/head_1.dmi b/icons/mob/humans/onmob/head_1.dmi index 951c7e89f985..696ab464252d 100644 Binary files a/icons/mob/humans/onmob/head_1.dmi and b/icons/mob/humans/onmob/head_1.dmi differ diff --git a/icons/mob/humans/onmob/suit_1.dmi b/icons/mob/humans/onmob/suit_1.dmi index c372b8a6d72c..85266a2077ac 100644 Binary files a/icons/mob/humans/onmob/suit_1.dmi and b/icons/mob/humans/onmob/suit_1.dmi differ diff --git a/icons/mob/xenos/larva.dmi b/icons/mob/xenos/larva.dmi index 72cfb7b4e318..f2e6a31ea36d 100644 Binary files a/icons/mob/xenos/larva.dmi and b/icons/mob/xenos/larva.dmi differ diff --git a/icons/mob/xenos/xenomorph_64x64.dmi b/icons/mob/xenos/xenomorph_64x64.dmi index 3fc4d942cd66..17fd4ae7fd5f 100644 Binary files a/icons/mob/xenos/xenomorph_64x64.dmi and b/icons/mob/xenos/xenomorph_64x64.dmi differ diff --git a/icons/obj/items/clothing/cm_hats.dmi b/icons/obj/items/clothing/cm_hats.dmi index 469d7cb7616a..923a26b55c20 100644 Binary files a/icons/obj/items/clothing/cm_hats.dmi and b/icons/obj/items/clothing/cm_hats.dmi differ diff --git a/icons/obj/items/clothing/cm_suits.dmi b/icons/obj/items/clothing/cm_suits.dmi index c1910d21b599..8c39aa77c7d1 100644 Binary files a/icons/obj/items/clothing/cm_suits.dmi and b/icons/obj/items/clothing/cm_suits.dmi differ diff --git a/icons/obj/items/clothing/shoes.dmi b/icons/obj/items/clothing/shoes.dmi index c4e01786e579..90e626503963 100644 Binary files a/icons/obj/items/clothing/shoes.dmi and b/icons/obj/items/clothing/shoes.dmi differ diff --git a/maps/map_files/CORSAT/Corsat.dmm b/maps/map_files/CORSAT/Corsat.dmm index 435659e102e2..f335e4c41e8b 100644 --- a/maps/map_files/CORSAT/Corsat.dmm +++ b/maps/map_files/CORSAT/Corsat.dmm @@ -24911,7 +24911,6 @@ /area/corsat/sigma/south/complex) "bTM" = ( /obj/structure/surface/table/reinforced, -/obj/item/device/suit_cooling_unit, /turf/open/floor/corsat/retrosquareslight, /area/corsat/sigma/south/complex) "bTN" = ( diff --git a/maps/map_files/USS_Almayer/USS_Almayer.dmm b/maps/map_files/USS_Almayer/USS_Almayer.dmm index b4a195ae5969..c1d18d4f9483 100644 --- a/maps/map_files/USS_Almayer/USS_Almayer.dmm +++ b/maps/map_files/USS_Almayer/USS_Almayer.dmm @@ -3320,6 +3320,14 @@ /obj/structure/surface/table/reinforced/almayer_B, /obj/structure/machinery/faxmachine/uscm/command, /obj/item/device/megaphone, +/obj/structure/machinery/computer/cameras/almayer_brig{ + dir = 8; + desc = "Used to access the various cameras in the security brig."; + name = "brig cameras console"; + pixel_y = 12; + pixel_x = 17; + layer = 2.99 + }, /turf/open/floor/almayer/plate, /area/almayer/command/cic) "awQ" = ( @@ -19918,7 +19926,14 @@ "ekZ" = ( /obj/structure/surface/table/almayer, /obj/structure/machinery/computer/secure_data{ - dir = 4 + dir = 4; + pixel_y = 10 + }, +/obj/structure/machinery/computer/cameras/almayer_brig{ + dir = 4; + desc = "Used to access the various cameras in the security brig."; + name = "brig cameras console"; + pixel_y = -11 }, /turf/open/floor/almayer/red/west, /area/almayer/shipboard/brig/warden_office) @@ -31590,7 +31605,16 @@ "jhI" = ( /obj/structure/surface/table/almayer, /obj/structure/machinery/computer/secure_data{ - dir = 4 + dir = 4; + pixel_y = 19; + layer = 2.99 + }, +/obj/structure/machinery/computer/cameras/almayer_brig{ + dir = 4; + desc = "Used to access the various cameras in the security brig."; + name = "brig cameras console"; + pixel_y = 5; + layer = 2.99 }, /turf/open/floor/almayer, /area/almayer/shipboard/brig/chief_mp_office) @@ -33768,7 +33792,7 @@ /obj/structure/pipes/standard/simple/hidden/supply{ dir = 4 }, -/obj/structure/machinery/camera/autoname/almayer, +/obj/structure/machinery/camera/autoname/almayer/brig, /turf/open/floor/almayer, /area/almayer/shipboard/brig/cells) "kcg" = ( @@ -34442,6 +34466,7 @@ id = "Perma 1"; pixel_y = 24 }, +/obj/structure/machinery/camera/autoname/almayer/brig, /turf/open/floor/almayer/plate, /area/almayer/shipboard/brig/perma) "krA" = ( @@ -34630,7 +34655,8 @@ "kvL" = ( /obj/structure/surface/table/almayer, /obj/structure/machinery/computer/cameras/almayer_network{ - dir = 4 + dir = 4; + pixel_y = 0 }, /turf/open/floor/almayer/red/west, /area/almayer/shipboard/brig/warden_office) @@ -61350,9 +61376,8 @@ /turf/open/floor/plating/plating_catwalk, /area/almayer/maint/hull/lower/stern) "vsz" = ( -/obj/structure/machinery/camera/autoname/almayer{ - dir = 8; - name = "ship-grade camera" +/obj/structure/machinery/camera/autoname/almayer/brig{ + dir = 8 }, /turf/open/floor/almayer, /area/almayer/shipboard/brig/cells) @@ -61882,10 +61907,8 @@ /turf/open/floor/almayer/silver, /area/almayer/shipboard/brig/cic_hallway) "vCy" = ( -/obj/structure/machinery/camera/autoname/almayer{ - dir = 4; - name = "ship-grade camera"; - pixel_y = 6 +/obj/structure/machinery/camera/autoname/almayer/brig{ + dir = 4 }, /turf/open/floor/almayer/green/west, /area/almayer/shipboard/brig/cells) @@ -63920,6 +63943,7 @@ id = "Perma 2"; pixel_y = 24 }, +/obj/structure/machinery/camera/autoname/almayer/brig, /turf/open/floor/almayer/plate, /area/almayer/shipboard/brig/perma) "wnL" = ( @@ -64322,7 +64346,8 @@ "wvE" = ( /obj/structure/surface/table/almayer, /obj/structure/machinery/computer/cameras/almayer_network{ - dir = 4 + dir = 4; + pixel_y = 1 }, /obj/structure/machinery/light{ dir = 1 @@ -66191,9 +66216,6 @@ dir = 1 }, /obj/structure/surface/table/almayer, -/obj/structure/machinery/computer/secure_data{ - dir = 4 - }, /obj/structure/sign/safety/terminal{ pixel_x = 3; pixel_y = 27 @@ -66202,6 +66224,11 @@ pixel_x = 15; pixel_y = 27 }, +/obj/structure/machinery/computer/cameras/almayer_brig{ + dir = 4; + desc = "Used to access the various cameras in the security brig."; + name = "brig cameras console" + }, /turf/open/floor/almayer/red/west, /area/almayer/shipboard/brig/processing) "xjK" = ( @@ -68586,10 +68613,8 @@ /turf/open/floor/almayer/cargo, /area/almayer/engineering/lower/engine_core) "yhg" = ( -/obj/structure/machinery/camera/autoname/almayer{ - dir = 4; - name = "ship-grade camera"; - pixel_y = 6 +/obj/structure/machinery/camera/autoname/almayer/brig{ + dir = 4 }, /turf/open/floor/plating/plating_catwalk, /area/almayer/shipboard/brig/cells) diff --git a/maps/map_files/generic/Admin_level.dmm b/maps/map_files/generic/Admin_level.dmm index be0f85e60028..c97821b827fb 100644 --- a/maps/map_files/generic/Admin_level.dmm +++ b/maps/map_files/generic/Admin_level.dmm @@ -2211,7 +2211,7 @@ hp hp hp hp -kx +hp "} (2,1,1) = {" aa @@ -3570,7 +3570,7 @@ hp hp hp hp -hp +kx hp hp hp diff --git a/tgui/packages/tgui/interfaces/StaffWho.jsx b/tgui/packages/tgui/interfaces/StaffWho.jsx new file mode 100644 index 000000000000..1ce71c9b5001 --- /dev/null +++ b/tgui/packages/tgui/interfaces/StaffWho.jsx @@ -0,0 +1,78 @@ +import { useBackend } from '../backend'; +import { Button, Collapsible, Stack } from '../components'; +import { Window } from '../layouts'; + +export const StaffWho = (props, context) => { + const { data } = useBackend(context); + const { admin, administrators } = data; + + return ( + + + {administrators !== undefined ? ( + + + {administrators.map((x, index) => ( + + {x.admins.map((x, index) => ( + + ))} + + ))} + + + ) : null} + + + ); +}; + +const StaffWhoCollapsible = (props, context) => { + const { title, color, children } = props; + return ( + + {children} + + ); +}; + +const GetAdminInfo = (props, context) => { + const { admin, content, color, text } = props; + return admin ? ( + + ) : ( + + ); +}; diff --git a/tgui/packages/tgui/interfaces/Who.jsx b/tgui/packages/tgui/interfaces/Who.jsx new file mode 100644 index 000000000000..dccf3d1e39f0 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Who.jsx @@ -0,0 +1,189 @@ +import { useBackend, useLocalState } from '../backend'; +import { + Box, + Button, + Collapsible, + Icon, + Input, + Section, + Stack, +} from '../components'; +import { Window } from '../layouts'; + +export const Who = (props, context) => { + const { act, data } = useBackend(context); + const { + admin, + all_clients, + total_players = [], + additional_info = [], + factions = [], + xenomorphs = [], + } = data; + + const [searchQuery, setSearchQuery] = useLocalState('searchQuery', ''); + + const searchPlayers = () => + total_players.filter((player) => isMatch(player, searchQuery)); + + const filteredTotalPlayers = searchPlayers(); + + return ( + + + + +
+ + + + + + + act('get_player_panel', { + ckey: searchPlayers()?.[0].ckey, + }) + } + onInput={(e) => setSearchQuery(e.target.value)} + placeholder="Search..." + value={searchQuery} + /> + + +
+
+ +
+ + {filteredTotalPlayers.length ? ( + + {filteredTotalPlayers.map((x) => ( + + ))} + + ) : null} + +
+ {admin !== 0 ? ( +
+ + + {additional_info.length + ? additional_info.map((x, index) => ( + + )) + : null} + {factions.length + ? factions.map((x, index) => ( + + )) + : null} + {xenomorphs.length + ? xenomorphs.map((x, index) => ( + + )) + : null} + + +
+ ) : null} +
+
+
+
+ ); +}; + +const WhoCollapsible = (props, context) => { + const { title, color, children } = props; + return ( + + {children} + + ); +}; + +const GetAddInfo = (props, context) => { + const { act } = useBackend(context); + const { content, color, text } = props; + + return ( + + ); +}; + +const GetPlayerInfo = (props, context) => { + const { act } = useBackend(context); + const { + admin, + player: { ckey, ckey_color, color, text }, + } = props; + return admin !== 0 ? ( + + ) : ( + + ); +}; + +const isMatch = (player, searchQuery) => { + if (!searchQuery) { + return true; + } + + return ( + player.ckey.toLowerCase().includes(searchQuery?.toLowerCase()) || false + ); +};