From 068f5df349b88fda8cc509ea5a1bceac337b176e Mon Sep 17 00:00:00 2001 From: Mothblocks <35135081+Mothblocks@users.noreply.github.com> Date: Sun, 6 Feb 2022 12:04:06 -0800 Subject: [PATCH] Add new surgery tgui (#64579) * Move element to component, start UI, move assets into their own directory * Complete UI * Stop when another surgery is started * Set your real zone since I forgot you actually need to start the surgery too * Bring this back since I was just removing it as part of a cleanup for asset cache, but I can't prove it's not used anymore * Remove unnecessary constructor I was using for something else * Fix signal override --- code/__DEFINES/dcs/signals/signals_medical.dm | 6 + .../signals/signals_mob/signals_mob_main.dm | 5 +- code/__HELPERS/text.dm | 5 + code/_onclick/hud/screen_objects.dm | 1 + code/datums/components/surgery_initiator.dm | 338 ++++++++++ code/datums/elements/surgery_initiator.dm | 145 ----- code/game/objects/structures/bedsheet_bin.dm | 2 +- code/modules/asset_cache/asset_list.dm | 1 - code/modules/asset_cache/asset_list_items.dm | 590 ------------------ .../asset_cache/assets/achievements.dm | 5 + code/modules/asset_cache/assets/adventure.dm | 7 + code/modules/asset_cache/assets/arcade.dm | 9 + code/modules/asset_cache/assets/body_zones.dm | 23 + code/modules/asset_cache/assets/chat.dm | 14 + code/modules/asset_cache/assets/circuits.dm | 4 + code/modules/asset_cache/assets/common.dm | 3 + code/modules/asset_cache/assets/condiments.dm | 20 + code/modules/asset_cache/assets/contracts.dm | 7 + code/modules/asset_cache/assets/fish.dm | 12 + .../modules/asset_cache/assets/fontawesome.dm | 9 + code/modules/asset_cache/assets/genetics.dm | 6 + code/modules/asset_cache/assets/headers.dm | 31 + code/modules/asset_cache/assets/inventory.dm | 20 + code/modules/asset_cache/assets/irv.dm | 10 + code/modules/asset_cache/assets/jquery.dm | 5 + code/modules/asset_cache/assets/language.dm | 9 + code/modules/asset_cache/assets/lobby.dm | 4 + code/modules/asset_cache/assets/mafia.dm | 5 + code/modules/asset_cache/assets/moods.dm | 27 + code/modules/asset_cache/assets/notes.dm | 7 + code/modules/asset_cache/assets/orbit.dm | 4 + code/modules/asset_cache/assets/paper.dm | 19 + code/modules/asset_cache/assets/patches.dm | 8 + code/modules/asset_cache/assets/pda.dm | 34 + .../modules/asset_cache/assets/permissions.dm | 11 + code/modules/asset_cache/assets/pills.dm | 26 + code/modules/asset_cache/assets/pipes.dm | 6 + code/modules/asset_cache/assets/portraits.dm | 12 + code/modules/asset_cache/assets/radar.dm | 6 + .../asset_cache/assets/research_designs.dm | 63 ++ code/modules/asset_cache/assets/safe.dm | 4 + .../asset_cache/assets/sheetmaterials.dm | 8 + code/modules/asset_cache/assets/supplypods.dm | 27 + code/modules/asset_cache/assets/tgfont.dm | 8 + code/modules/asset_cache/assets/tgui.dm | 13 + .../asset_cache/assets/tutorial_advisors.dm | 4 + code/modules/asset_cache/assets/uplink.dm | 40 ++ code/modules/asset_cache/assets/vending.dm | 36 ++ code/modules/asset_cache/assets/vv.dm | 4 + code/modules/surgery/surgery.dm | 6 +- code/modules/surgery/tools.dm | 2 +- tgstation.dme | 44 +- .../tgui/components/BodyZoneSelector.tsx | 150 +++++ .../tgui/interfaces/SurgeryInitiator.tsx | 172 +++++ 54 files changed, 1293 insertions(+), 744 deletions(-) create mode 100644 code/__DEFINES/dcs/signals/signals_medical.dm create mode 100644 code/datums/components/surgery_initiator.dm delete mode 100644 code/datums/elements/surgery_initiator.dm delete mode 100644 code/modules/asset_cache/asset_list_items.dm create mode 100644 code/modules/asset_cache/assets/achievements.dm create mode 100644 code/modules/asset_cache/assets/adventure.dm create mode 100644 code/modules/asset_cache/assets/arcade.dm create mode 100644 code/modules/asset_cache/assets/body_zones.dm create mode 100644 code/modules/asset_cache/assets/chat.dm create mode 100644 code/modules/asset_cache/assets/circuits.dm create mode 100644 code/modules/asset_cache/assets/common.dm create mode 100644 code/modules/asset_cache/assets/condiments.dm create mode 100644 code/modules/asset_cache/assets/contracts.dm create mode 100644 code/modules/asset_cache/assets/fish.dm create mode 100644 code/modules/asset_cache/assets/fontawesome.dm create mode 100644 code/modules/asset_cache/assets/genetics.dm create mode 100644 code/modules/asset_cache/assets/headers.dm create mode 100644 code/modules/asset_cache/assets/inventory.dm create mode 100644 code/modules/asset_cache/assets/irv.dm create mode 100644 code/modules/asset_cache/assets/jquery.dm create mode 100644 code/modules/asset_cache/assets/language.dm create mode 100644 code/modules/asset_cache/assets/lobby.dm create mode 100644 code/modules/asset_cache/assets/mafia.dm create mode 100644 code/modules/asset_cache/assets/moods.dm create mode 100644 code/modules/asset_cache/assets/notes.dm create mode 100644 code/modules/asset_cache/assets/orbit.dm create mode 100644 code/modules/asset_cache/assets/paper.dm create mode 100644 code/modules/asset_cache/assets/patches.dm create mode 100644 code/modules/asset_cache/assets/pda.dm create mode 100644 code/modules/asset_cache/assets/permissions.dm create mode 100644 code/modules/asset_cache/assets/pills.dm create mode 100644 code/modules/asset_cache/assets/pipes.dm create mode 100644 code/modules/asset_cache/assets/portraits.dm create mode 100644 code/modules/asset_cache/assets/radar.dm create mode 100644 code/modules/asset_cache/assets/research_designs.dm create mode 100644 code/modules/asset_cache/assets/safe.dm create mode 100644 code/modules/asset_cache/assets/sheetmaterials.dm create mode 100644 code/modules/asset_cache/assets/supplypods.dm create mode 100644 code/modules/asset_cache/assets/tgfont.dm create mode 100644 code/modules/asset_cache/assets/tgui.dm create mode 100644 code/modules/asset_cache/assets/tutorial_advisors.dm create mode 100644 code/modules/asset_cache/assets/uplink.dm create mode 100644 code/modules/asset_cache/assets/vending.dm create mode 100644 code/modules/asset_cache/assets/vv.dm create mode 100644 tgui/packages/tgui/components/BodyZoneSelector.tsx create mode 100644 tgui/packages/tgui/interfaces/SurgeryInitiator.tsx diff --git a/code/__DEFINES/dcs/signals/signals_medical.dm b/code/__DEFINES/dcs/signals/signals_medical.dm new file mode 100644 index 00000000000..762203ec736 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_medical.dm @@ -0,0 +1,6 @@ +/// From /datum/surgery/New(): (datum/surgery/surgery, surgery_location (body zone), obj/item/bodypart/targeted_limb) +#define COMSIG_MOB_SURGERY_STARTED "mob_surgery_started" + +/// From /datum/surgery_step/success(): (datum/surgery_step/step, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results) +#define COMSIG_MOB_SURGERY_STEP_SUCCESS "mob_surgery_step_success" + diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm index ee321b100fa..f89ca596e16 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm @@ -132,5 +132,6 @@ #define COMSIG_MOB_CTRL_CLICKED "mob_ctrl_clicked" ///From base of mob/update_movespeed():area #define COMSIG_MOB_MOVESPEED_UPDATED "mob_update_movespeed" -/// From /datum/surgery_step/success(): (datum/surgey_step/step, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results) -#define COMSIG_MOB_SURGERY_STEP_SUCCESS "mob_surgery_step_success" +/// From /atom/movable/screen/zone_sel/proc/set_selected_zone. +/// Fires when the user has changed their selected body target. +#define COMSIG_MOB_SELECTED_ZONE_SET "mob_set_selected_zone" diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 529c08b689c..98385dd8fa2 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -1035,3 +1035,8 @@ GLOBAL_LIST_INIT(binary, list("0","1")) . = "gigantic" else . = "" + +/// Removes all non-alphanumerics from the text, keep in mind this can lead to id conflicts +/proc/sanitize_css_class_name(name) + var/static/regex/regex = new(@"[^a-zA-Z0-9]","g") + return replacetext(name, regex, "") diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 843f235a573..c765ee1570e 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -573,6 +573,7 @@ if(choice != hud.mymob.zone_selected) hud.mymob.zone_selected = choice update_appearance() + SEND_SIGNAL(user, COMSIG_MOB_SELECTED_ZONE_SET, choice) return TRUE diff --git a/code/datums/components/surgery_initiator.dm b/code/datums/components/surgery_initiator.dm new file mode 100644 index 00000000000..4e41d6b2f81 --- /dev/null +++ b/code/datums/components/surgery_initiator.dm @@ -0,0 +1,338 @@ +/// Allows an item to be used to initiate surgeries. +/datum/component/surgery_initiator + /// The currently selected target that the user is proposing a surgery on + var/datum/weakref/surgery_target_ref + + /// The last user, as a weakref + var/datum/weakref/last_user_ref + +/datum/component/surgery_initiator/Initialize() + . = ..() + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + +/datum/component/surgery_initiator/Destroy(force, silent) + last_user_ref = null + surgery_target_ref = null + + return ..() + +/datum/component/surgery_initiator/RegisterWithParent() + RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/initiate_surgery_moment) + +/datum/component/surgery_initiator/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_ITEM_ATTACK) + unregister_signals() + +/datum/component/surgery_initiator/proc/unregister_signals() + var/mob/living/last_user = last_user_ref?.resolve() + if (!isnull(last_user_ref)) + UnregisterSignal(last_user, COMSIG_MOB_SELECTED_ZONE_SET) + + var/mob/living/surgery_target = surgery_target_ref?.resolve() + if (!isnull(surgery_target_ref)) + UnregisterSignal(surgery_target, COMSIG_MOB_SURGERY_STARTED) + +/// Does the surgery initiation. +/datum/component/surgery_initiator/proc/initiate_surgery_moment(datum/source, atom/target, mob/user) + SIGNAL_HANDLER + if(!isliving(target)) + return + INVOKE_ASYNC(src, .proc/do_initiate_surgery_moment, target, user) + return COMPONENT_CANCEL_ATTACK_CHAIN + +/datum/component/surgery_initiator/proc/do_initiate_surgery_moment(mob/living/target, mob/user) + var/datum/surgery/current_surgery + + for(var/i_one in target.surgeries) + var/datum/surgery/surgeryloop = i_one + if(surgeryloop.location == user.zone_selected) + current_surgery = surgeryloop + break + + if (!isnull(current_surgery) && !current_surgery.step_in_progress) + attempt_cancel_surgery(current_surgery, target, user) + return + + var/list/available_surgeries = get_available_surgeries(user, target) + + if(!length(available_surgeries)) + if (target.body_position == LYING_DOWN) + target.balloon_alert(user, "no surgeries available!") + else + target.balloon_alert(user, "make them lie down!") + + return + + unregister_signals() + + last_user_ref = WEAKREF(user) + surgery_target_ref = WEAKREF(target) + + RegisterSignal(user, COMSIG_MOB_SELECTED_ZONE_SET, .proc/on_set_selected_zone) + RegisterSignal(target, COMSIG_MOB_SURGERY_STARTED, .proc/on_mob_surgery_started) + + ui_interact(user) + +/datum/component/surgery_initiator/proc/get_available_surgeries(mob/user, mob/living/target) + var/list/available_surgeries = list() + + var/mob/living/carbon/carbon_target + var/obj/item/bodypart/affecting + if (iscarbon(target)) + carbon_target = target + affecting = carbon_target.get_bodypart(check_zone(user.zone_selected)) + + for(var/datum/surgery/surgery as anything in GLOB.surgeries_list) + if(!surgery.possible_locs.Find(user.zone_selected)) + continue + if(affecting) + if(!surgery.requires_bodypart) + continue + if(surgery.requires_bodypart_type && affecting.status != surgery.requires_bodypart_type) + continue + if(surgery.requires_real_bodypart && affecting.is_pseudopart) + continue + else if(carbon_target && surgery.requires_bodypart) //mob with no limb in surgery zone when we need a limb + continue + if(surgery.lying_required && target.body_position != LYING_DOWN) + continue + if(!surgery.can_start(user, target)) + continue + for(var/path in surgery.target_mobtypes) + if(istype(target, path)) + available_surgeries += surgery + break + + return available_surgeries + +/// Does the surgery de-initiation. +/datum/component/surgery_initiator/proc/attempt_cancel_surgery(datum/surgery/the_surgery, mob/living/patient, mob/user) + var/selected_zone = user.zone_selected + + if(the_surgery.status == 1) + patient.surgeries -= the_surgery + REMOVE_TRAIT(patient, TRAIT_ALLOWED_HONORBOUND_ATTACK, type) + user.visible_message( + span_notice("[user] removes [parent] from [patient]'s [parse_zone(selected_zone)]."), + span_notice("You remove [parent] from [patient]'s [parse_zone(selected_zone)]."), + ) + + patient.balloon_alert(user, "stopped work on [parse_zone(selected_zone)]") + + qdel(the_surgery) + return + + if(!the_surgery.can_cancel) + return + + var/required_tool_type = TOOL_CAUTERY + var/obj/item/close_tool = user.get_inactive_held_item() + var/is_robotic = the_surgery.requires_bodypart_type == BODYPART_ROBOTIC + + if(is_robotic) + required_tool_type = TOOL_SCREWDRIVER + + if(iscyborg(user)) + close_tool = locate(/obj/item/cautery) in user.held_items + if(!close_tool) + patient.balloon_alert(user, "need a cautery in an inactive slot to stop the surgery!") + return + else if(!close_tool || close_tool.tool_behaviour != required_tool_type) + patient.balloon_alert(user, "need a [is_robotic ? "screwdriver": "cautery"] in your inactive hand to stop the surgery!") + return + + if(the_surgery.operated_bodypart) + the_surgery.operated_bodypart.generic_bleedstacks -= 5 + + patient.surgeries -= the_surgery + REMOVE_TRAIT(patient, TRAIT_ALLOWED_HONORBOUND_ATTACK, ELEMENT_TRAIT(type)) + + user.visible_message( + span_notice("[user] closes [patient]'s [parse_zone(selected_zone)] with [close_tool] and removes [parent]."), + span_notice("You close [patient]'s [parse_zone(selected_zone)] with [close_tool] and remove [parent]."), + ) + + patient.balloon_alert(user, "closed up [parse_zone(selected_zone)]") + + qdel(the_surgery) + +/datum/component/surgery_initiator/proc/on_mob_surgery_started(mob/source, datum/surgery/surgery, surgery_location) + SIGNAL_HANDLER + + var/mob/living/last_user = last_user_ref.resolve() + + if (surgery_location != last_user.zone_selected) + return + + if (!isnull(last_user)) + source.balloon_alert(last_user, "someone else started a surgery!") + + ui_close() + +/datum/component/surgery_initiator/proc/on_set_selected_zone(mob/source, new_zone) + ui_interact(source) + +/datum/component/surgery_initiator/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if (!ui) + ui = new(user, src, "SurgeryInitiator") + ui.open() + +/datum/component/surgery_initiator/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if (.) + return . + + var/mob/user = usr + var/mob/living/surgery_target = surgery_target_ref.resolve() + + if (isnull(surgery_target)) + return TRUE + + switch (action) + if ("change_zone") + var/zone = params["new_zone"] + if (!(zone in list( + BODY_ZONE_HEAD, + BODY_ZONE_CHEST, + BODY_ZONE_L_ARM, + BODY_ZONE_R_ARM, + BODY_ZONE_L_LEG, + BODY_ZONE_R_LEG, + BODY_ZONE_PRECISE_EYES, + BODY_ZONE_PRECISE_MOUTH, + BODY_ZONE_PRECISE_GROIN, + ))) + return TRUE + + var/atom/movable/screen/zone_sel/zone_selector = user.hud_used?.zone_select + zone_selector?.set_selected_zone(zone, user) + + return TRUE + if ("start_surgery") + for (var/datum/surgery/surgery as anything in get_available_surgeries(user, surgery_target)) + if (surgery.name == params["surgery_name"]) + try_choose_surgery(user, surgery_target, surgery) + return TRUE + +/datum/component/surgery_initiator/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/simple/body_zones), + ) + +/datum/component/surgery_initiator/ui_data(mob/user) + var/mob/living/surgery_target = surgery_target_ref.resolve() + + var/list/surgeries = list() + if (!isnull(surgery_target)) + for (var/datum/surgery/surgery as anything in get_available_surgeries(user, surgery_target)) + var/list/surgery_info = list( + "name" = surgery.name, + ) + + if (surgery_needs_exposure(surgery, surgery_target)) + surgery_info["blocked"] = TRUE + + surgeries += list(surgery_info) + + return list( + "selected_zone" = user.zone_selected, + "target_name" = surgery_target?.name, + "surgeries" = surgeries, + ) + +/datum/component/surgery_initiator/ui_close(mob/user) + unregister_signals() + surgery_target_ref = null + + return ..() + +/datum/component/surgery_initiator/ui_status(mob/user, datum/ui_state/state) + var/obj/item/item_parent = parent + if (user != item_parent.loc) + return UI_CLOSE + + var/mob/living/surgery_target = surgery_target_ref?.resolve() + if (isnull(surgery_target)) + return UI_CLOSE + + if (!can_start_surgery(user, surgery_target)) + return UI_CLOSE + + return ..() + +/datum/component/surgery_initiator/proc/can_start_surgery(mob/user, mob/living/target) + if (!user.Adjacent(target)) + return FALSE + + // The item was moved somewhere else + if (!(parent in user)) + return FALSE + + // While we were choosing, another surgery was started at the same location + for (var/datum/surgery/surgery in target.surgeries) + if (surgery.location == user.zone_selected) + return FALSE + + return TRUE + +/datum/component/surgery_initiator/proc/try_choose_surgery(mob/user, mob/living/target, datum/surgery/surgery) + if (!can_start_surgery(user, target)) + // This could have a more detailed message, but the UI closes when this is true anyway, so + // if it ever comes up, it'll be because of lag. + target.balloon_alert(user, "can't start the surgery!") + return + + var/obj/item/bodypart/affecting_limb + + var/selected_zone = user.zone_selected + + if (iscarbon(target)) + var/mob/living/carbon/carbon_target = target + affecting_limb = carbon_target.get_bodypart(check_zone(selected_zone)) + + if (surgery.requires_bodypart == isnull(affecting_limb)) + if (surgery.requires_bodypart) + target.balloon_alert(user, "patient has no [parse_zone(selected_zone)]!") + else + target.balloon_alert(user, "patient has \a [parse_zone(selected_zone)]!") + + return + + if (!isnull(affecting_limb) && surgery.requires_bodypart_type && affecting_limb.status != surgery.requires_bodypart_type) + target.balloon_alert(user, "not the right type of limb!") + return + + if (surgery.lying_required && target.body_position != LYING_DOWN) + target.balloon_alert(user, "patient is not lying down!") + return + + if (!surgery.can_start(user, target)) + target.balloon_alert(user, "can't start the surgery!") + return + + if (surgery_needs_exposure(surgery, target)) + target.balloon_alert(user, "expose [target.p_their()] [parse_zone(selected_zone)]!") + return + + ui_close() + + var/datum/surgery/procedure = new surgery.type(target, selected_zone, affecting_limb) + ADD_TRAIT(target, TRAIT_ALLOWED_HONORBOUND_ATTACK, type) + + target.balloon_alert(user, "starting \"[lowertext(procedure.name)]\"") + + user.visible_message( + span_notice("[user] drapes [parent] over [target]'s [parse_zone(selected_zone)] to prepare for surgery."), + span_notice("You drape [parent] over [target]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name]."), + ) + + log_combat(user, target, "operated on", null, "(OPERATION TYPE: [procedure.name]) (TARGET AREA: [selected_zone])") + +/datum/component/surgery_initiator/proc/surgery_needs_exposure(datum/surgery/surgery, mob/living/target) + var/mob/living/user = last_user_ref?.resolve() + if (isnull(user)) + return FALSE + + return !surgery.ignore_clothes && !get_location_accessible(target, user.zone_selected) diff --git a/code/datums/elements/surgery_initiator.dm b/code/datums/elements/surgery_initiator.dm deleted file mode 100644 index 9748adaaaaf..00000000000 --- a/code/datums/elements/surgery_initiator.dm +++ /dev/null @@ -1,145 +0,0 @@ -/// Allows an item to be used to initiate surgeries. -/datum/element/surgery_initiator - element_flags = ELEMENT_DETACH - -/datum/element/surgery_initiator/Attach(datum/target) - . = ..() - if(!isitem(target)) - return ELEMENT_INCOMPATIBLE - RegisterSignal(target, COMSIG_ITEM_ATTACK, .proc/initiate_surgery_moment) - -/datum/element/surgery_initiator/Detach(datum/source) - UnregisterSignal(source, COMSIG_ITEM_ATTACK) - return ..() - -/// Does the surgery initiation. -/datum/element/surgery_initiator/proc/initiate_surgery_moment(datum/source, atom/target, mob/user) - SIGNAL_HANDLER - if(!isliving(target)) - return - INVOKE_ASYNC(src, .proc/do_initiate_surgery_moment, source, target, user) - return COMPONENT_CANCEL_ATTACK_CHAIN - -/datum/element/surgery_initiator/proc/do_initiate_surgery_moment(datum/source, atom/target, mob/user) - var/mob/living/livingtarget = target - var/mob/living/carbon/carbontarget - var/obj/item/bodypart/affecting - var/selected_zone = user.zone_selected - if(iscarbon(livingtarget)) - carbontarget = livingtarget - affecting = carbontarget.get_bodypart(check_zone(selected_zone)) - - var/datum/surgery/current_surgery - - for(var/i_one in livingtarget.surgeries) - var/datum/surgery/surgeryloop = i_one - if(surgeryloop.location == selected_zone) - current_surgery = surgeryloop - - if(!current_surgery) - var/list/all_surgeries = GLOB.surgeries_list.Copy() - var/list/available_surgeries = list() - - for(var/i_two in all_surgeries) - var/datum/surgery/surgeryloop_two = i_two - if(!surgeryloop_two.possible_locs.Find(selected_zone)) - continue - if(affecting) - if(!surgeryloop_two.requires_bodypart) - continue - if(surgeryloop_two.requires_bodypart_type && affecting.status != surgeryloop_two.requires_bodypart_type) - continue - if(surgeryloop_two.requires_real_bodypart && affecting.is_pseudopart) - continue - else if(carbontarget && surgeryloop_two.requires_bodypart) //mob with no limb in surgery zone when we need a limb - continue - if(surgeryloop_two.lying_required && livingtarget.body_position != LYING_DOWN) - continue - if(!surgeryloop_two.can_start(user, livingtarget)) - continue - for(var/path in surgeryloop_two.target_mobtypes) - if(istype(livingtarget, path)) - available_surgeries[surgeryloop_two.name] = surgeryloop_two - break - - if(!length(available_surgeries)) - return - - var/pick_your_surgery = tgui_input_list(user, "Which procedure?", "Surgery", sort_list(available_surgeries)) - if(isnull(pick_your_surgery)) - return - if(user?.Adjacent(livingtarget) && (source in user)) - var/datum/surgery/surgeryinstance_notonmob = available_surgeries[pick_your_surgery] - - for(var/i_three in livingtarget.surgeries) - var/datum/surgery/surgeryloop_three = i_three - if(surgeryloop_three.location == selected_zone) - return //during the input() another surgery was started at the same location. - - //we check that the surgery is still doable after the input() wait. - if(carbontarget) - affecting = carbontarget.get_bodypart(check_zone(selected_zone)) - if(affecting) - if(!surgeryinstance_notonmob.requires_bodypart) - return - if(surgeryinstance_notonmob.requires_bodypart_type && affecting.status != surgeryinstance_notonmob.requires_bodypart_type) - return - else if(carbontarget && surgeryinstance_notonmob.requires_bodypart) - return - if(surgeryinstance_notonmob.lying_required && livingtarget.body_position != LYING_DOWN) - return - if(!surgeryinstance_notonmob.can_start(user, livingtarget)) - return - - if(surgeryinstance_notonmob.ignore_clothes || get_location_accessible(livingtarget, selected_zone)) - var/datum/surgery/procedure = new surgeryinstance_notonmob.type(livingtarget, selected_zone, affecting) - ADD_TRAIT(livingtarget, TRAIT_ALLOWED_HONORBOUND_ATTACK, ELEMENT_TRAIT(type)) - user.visible_message(span_notice("[user] drapes [source] over [livingtarget]'s [parse_zone(selected_zone)] to prepare for surgery."), \ - span_notice("You drape [source] over [livingtarget]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].")) - - log_combat(user, livingtarget, "operated on", null, "(OPERATION TYPE: [procedure.name]) (TARGET AREA: [selected_zone])") - else - to_chat(user, span_warning("You need to expose [livingtarget]'s [parse_zone(selected_zone)] first!")) - - else if(!current_surgery.step_in_progress) - attempt_cancel_surgery(current_surgery, source, livingtarget, user) - -/// Does the surgery de-initiation. -/datum/element/surgery_initiator/proc/attempt_cancel_surgery(datum/surgery/the_surgery, obj/item/the_item, mob/living/the_patient, mob/user) - var/selected_zone = user.zone_selected - - if(the_surgery.status == 1) - the_patient.surgeries -= the_surgery - REMOVE_TRAIT(the_patient, TRAIT_ALLOWED_HONORBOUND_ATTACK, ELEMENT_TRAIT(type)) - user.visible_message(span_notice("[user] removes [the_item] from [the_patient]'s [parse_zone(selected_zone)]."), \ - span_notice("You remove [the_item] from [the_patient]'s [parse_zone(selected_zone)].")) - qdel(the_surgery) - return - - if(!the_surgery.can_cancel) - return - - var/required_tool_type = TOOL_CAUTERY - var/obj/item/close_tool = user.get_inactive_held_item() - var/is_robotic = the_surgery.requires_bodypart_type == BODYPART_ROBOTIC - - if(is_robotic) - required_tool_type = TOOL_SCREWDRIVER - - if(iscyborg(user)) - close_tool = locate(/obj/item/cautery) in user.held_items - if(!close_tool) - to_chat(user, span_warning("You need to equip a cautery in an inactive slot to stop [the_patient]'s surgery!")) - return - else if(!close_tool || close_tool.tool_behaviour != required_tool_type) - to_chat(user, span_warning("You need to hold a [is_robotic ? "screwdriver" : "cautery"] in your inactive hand to stop [the_patient]'s surgery!")) - return - - if(the_surgery.operated_bodypart) - the_surgery.operated_bodypart.generic_bleedstacks -= 5 - - the_patient.surgeries -= the_surgery - REMOVE_TRAIT(the_patient, TRAIT_ALLOWED_HONORBOUND_ATTACK, ELEMENT_TRAIT(type)) - user.visible_message(span_notice("[user] closes [the_patient]'s [parse_zone(selected_zone)] with [close_tool] and removes [the_item]."), \ - span_notice("You close [the_patient]'s [parse_zone(selected_zone)] with [close_tool] and remove [the_item].")) - qdel(the_surgery) diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index e8a6a0c4f15..2e132c54f2f 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -33,7 +33,7 @@ LINEN BINS /obj/item/bedsheet/Initialize(mapload) . = ..() - AddElement(/datum/element/surgery_initiator) + AddComponent(/datum/component/surgery_initiator) AddElement(/datum/element/bed_tuckable, 0, 0, 0) if(bedsheet_type == BEDSHEET_DOUBLE) stack_amount *= 2 diff --git a/code/modules/asset_cache/asset_list.dm b/code/modules/asset_cache/asset_list.dm index 372207fe1b5..bf804e34f2f 100644 --- a/code/modules/asset_cache/asset_list.dm +++ b/code/modules/asset_cache/asset_list.dm @@ -79,7 +79,6 @@ GLOBAL_LIST_EMPTY(asset_datums) for (var/asset_name in assets) .[asset_name] = SSassets.transport.get_asset_url(asset_name, assets[asset_name]) - // For registering or sending multiple others at once /datum/asset/group _abstract = /datum/asset/group diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm deleted file mode 100644 index 18a941f8a74..00000000000 --- a/code/modules/asset_cache/asset_list_items.dm +++ /dev/null @@ -1,590 +0,0 @@ -//DEFINITIONS FOR ASSET DATUMS START HERE. - -/datum/asset/simple/tgui - keep_local_name = TRUE - assets = list( - "tgui.bundle.js" = file("tgui/public/tgui.bundle.js"), - "tgui.bundle.css" = file("tgui/public/tgui.bundle.css"), - ) - -/datum/asset/simple/tgui_panel - keep_local_name = TRUE - assets = list( - "tgui-panel.bundle.js" = file("tgui/public/tgui-panel.bundle.js"), - "tgui-panel.bundle.css" = file("tgui/public/tgui-panel.bundle.css"), - ) - -/datum/asset/simple/headers - assets = list( - "alarm_green.gif" = 'icons/program_icons/alarm_green.gif', - "alarm_red.gif" = 'icons/program_icons/alarm_red.gif', - "batt_5.gif" = 'icons/program_icons/batt_5.gif', - "batt_20.gif" = 'icons/program_icons/batt_20.gif', - "batt_40.gif" = 'icons/program_icons/batt_40.gif', - "batt_60.gif" = 'icons/program_icons/batt_60.gif', - "batt_80.gif" = 'icons/program_icons/batt_80.gif', - "batt_100.gif" = 'icons/program_icons/batt_100.gif', - "charging.gif" = 'icons/program_icons/charging.gif', - "downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif', - "downloader_running.gif" = 'icons/program_icons/downloader_running.gif', - "ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif', - "ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif', - "power_norm.gif" = 'icons/program_icons/power_norm.gif', - "power_warn.gif" = 'icons/program_icons/power_warn.gif', - "sig_high.gif" = 'icons/program_icons/sig_high.gif', - "sig_low.gif" = 'icons/program_icons/sig_low.gif', - "sig_lan.gif" = 'icons/program_icons/sig_lan.gif', - "sig_none.gif" = 'icons/program_icons/sig_none.gif', - "smmon_0.gif" = 'icons/program_icons/smmon_0.gif', - "smmon_1.gif" = 'icons/program_icons/smmon_1.gif', - "smmon_2.gif" = 'icons/program_icons/smmon_2.gif', - "smmon_3.gif" = 'icons/program_icons/smmon_3.gif', - "smmon_4.gif" = 'icons/program_icons/smmon_4.gif', - "smmon_5.gif" = 'icons/program_icons/smmon_5.gif', - "smmon_6.gif" = 'icons/program_icons/smmon_6.gif', - "borg_mon.gif" = 'icons/program_icons/borg_mon.gif', - "robotact.gif" = 'icons/program_icons/robotact.gif' - ) - -/datum/asset/simple/radar_assets - assets = list( - "ntosradarbackground.png" = 'icons/ui_icons/tgui/ntosradar_background.png', - "ntosradarpointer.png" = 'icons/ui_icons/tgui/ntosradar_pointer.png', - "ntosradarpointerS.png" = 'icons/ui_icons/tgui/ntosradar_pointer_S.png' - ) - -/datum/asset/simple/circuit_assets - assets = list( - "grid_background.png" = 'icons/ui_icons/tgui/grid_background.png' - ) - -/datum/asset/spritesheet/simple/pda - name = "pda" - assets = list( - "atmos" = 'icons/pda_icons/pda_atmos.png', - "back" = 'icons/pda_icons/pda_back.png', - "bell" = 'icons/pda_icons/pda_bell.png', - "blank" = 'icons/pda_icons/pda_blank.png', - "boom" = 'icons/pda_icons/pda_boom.png', - "bucket" = 'icons/pda_icons/pda_bucket.png', - "medbot" = 'icons/pda_icons/pda_medbot.png', - "floorbot" = 'icons/pda_icons/pda_floorbot.png', - "cleanbot" = 'icons/pda_icons/pda_cleanbot.png', - "crate" = 'icons/pda_icons/pda_crate.png', - "cuffs" = 'icons/pda_icons/pda_cuffs.png', - "eject" = 'icons/pda_icons/pda_eject.png', - "flashlight" = 'icons/pda_icons/pda_flashlight.png', - "honk" = 'icons/pda_icons/pda_honk.png', - "mail" = 'icons/pda_icons/pda_mail.png', - "medical" = 'icons/pda_icons/pda_medical.png', - "menu" = 'icons/pda_icons/pda_menu.png', - "mule" = 'icons/pda_icons/pda_mule.png', - "notes" = 'icons/pda_icons/pda_notes.png', - "power" = 'icons/pda_icons/pda_power.png', - "rdoor" = 'icons/pda_icons/pda_rdoor.png', - "reagent" = 'icons/pda_icons/pda_reagent.png', - "refresh" = 'icons/pda_icons/pda_refresh.png', - "scanner" = 'icons/pda_icons/pda_scanner.png', - "signaler" = 'icons/pda_icons/pda_signaler.png', - "skills" = 'icons/pda_icons/pda_skills.png', - "status" = 'icons/pda_icons/pda_status.png', - "dronephone" = 'icons/pda_icons/pda_dronephone.png', - "emoji" = 'icons/pda_icons/pda_emoji.png', - "droneblacklist" = 'icons/pda_icons/pda_droneblacklist.png', - ) - -/datum/asset/spritesheet/simple/paper - name = "paper" - assets = list( - "stamp-clown" = 'icons/stamp_icons/large_stamp-clown.png', - "stamp-deny" = 'icons/stamp_icons/large_stamp-deny.png', - "stamp-ok" = 'icons/stamp_icons/large_stamp-ok.png', - "stamp-hop" = 'icons/stamp_icons/large_stamp-hop.png', - "stamp-cmo" = 'icons/stamp_icons/large_stamp-cmo.png', - "stamp-ce" = 'icons/stamp_icons/large_stamp-ce.png', - "stamp-hos" = 'icons/stamp_icons/large_stamp-hos.png', - "stamp-rd" = 'icons/stamp_icons/large_stamp-rd.png', - "stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png', - "stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png', - "stamp-law" = 'icons/stamp_icons/large_stamp-law.png', - "stamp-chap" = 'icons/stamp_icons/large_stamp-chap.png', - "stamp-mime" = 'icons/stamp_icons/large_stamp-mime.png', - "stamp-centcom" = 'icons/stamp_icons/large_stamp-centcom.png', - "stamp-syndicate" = 'icons/stamp_icons/large_stamp-syndicate.png' - ) - - -/datum/asset/simple/irv - assets = list( - "jquery-ui.custom-core-widgit-mouse-sortable.min.js" = 'html/jquery/jquery-ui.custom-core-widgit-mouse-sortable.min.js', - ) - -/datum/asset/group/irv - children = list( - /datum/asset/simple/jquery, - /datum/asset/simple/irv - ) - -/datum/asset/simple/jquery - legacy = TRUE - assets = list( - "jquery.min.js" = 'html/jquery/jquery.min.js', - ) - -/datum/asset/simple/namespaced/fontawesome - assets = list( - "fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot', - "fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff', - "fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot', - "fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff', - "v4shim.css" = 'html/font-awesome/css/v4-shims.min.css', - ) - parents = list("font-awesome.css" = 'html/font-awesome/css/all.min.css') - -/datum/asset/simple/namespaced/tgfont - assets = list( - "tgfont.eot" = file("tgui/packages/tgfont/static/tgfont.eot"), - "tgfont.woff2" = file("tgui/packages/tgfont/static/tgfont.woff2"), - ) - parents = list( - "tgfont.css" = file("tgui/packages/tgfont/static/tgfont.css"), - ) - -/datum/asset/spritesheet/chat - name = "chat" - -/datum/asset/spritesheet/chat/create_spritesheets() - InsertAll("emoji", EMOJI_SET) - // pre-loading all lanugage icons also helps to avoid meta - InsertAll("language", 'icons/misc/language.dmi') - // catch languages which are pulling icons from another file - for(var/path in typesof(/datum/language)) - var/datum/language/L = path - var/icon = initial(L.icon) - if (icon != 'icons/misc/language.dmi') - var/icon_state = initial(L.icon_state) - Insert("language-[icon_state]", icon, icon_state=icon_state) - -/datum/asset/simple/lobby - assets = list( - "playeroptions.css" = 'html/browser/playeroptions.css' - ) - -/datum/asset/simple/namespaced/common - assets = list("padlock.png" = 'icons/ui_icons/common/padlock.png') - parents = list("common.css" = 'html/browser/common.css') - -/datum/asset/simple/permissions - assets = list( - "search.js" = 'html/admin/search.js', - "panels.css" = 'html/admin/panels.css' - ) - -/datum/asset/group/permissions - children = list( - /datum/asset/simple/permissions, - /datum/asset/simple/namespaced/common - ) - -/datum/asset/simple/notes - assets = list( - "high_button.png" = 'icons/ui_icons/notes/high_button.png', - "medium_button.png" = 'icons/ui_icons/notes/medium_button.png', - "minor_button.png" = 'icons/ui_icons/notes/minor_button.png', - "none_button.png" = 'icons/ui_icons/notes/none_button.png', - ) - -/datum/asset/simple/arcade - assets = list( - "boss1.gif" = 'icons/ui_icons/arcade/boss1.gif', - "boss2.gif" = 'icons/ui_icons/arcade/boss2.gif', - "boss3.gif" = 'icons/ui_icons/arcade/boss3.gif', - "boss4.gif" = 'icons/ui_icons/arcade/boss4.gif', - "boss5.gif" = 'icons/ui_icons/arcade/boss5.gif', - "boss6.gif" = 'icons/ui_icons/arcade/boss6.gif', - ) - -/datum/asset/spritesheet/simple/achievements - name ="achievements" - -/datum/asset/spritesheet/simple/achievements/create_spritesheets() - InsertAll("", ACHIEVEMENTS_SET) - -/datum/asset/spritesheet/simple/pills - name = "pills" - assets = list( - "pill1" = 'icons/ui_icons/pills/pill1.png', - "pill2" = 'icons/ui_icons/pills/pill2.png', - "pill3" = 'icons/ui_icons/pills/pill3.png', - "pill4" = 'icons/ui_icons/pills/pill4.png', - "pill5" = 'icons/ui_icons/pills/pill5.png', - "pill6" = 'icons/ui_icons/pills/pill6.png', - "pill7" = 'icons/ui_icons/pills/pill7.png', - "pill8" = 'icons/ui_icons/pills/pill8.png', - "pill9" = 'icons/ui_icons/pills/pill9.png', - "pill10" = 'icons/ui_icons/pills/pill10.png', - "pill11" = 'icons/ui_icons/pills/pill11.png', - "pill12" = 'icons/ui_icons/pills/pill12.png', - "pill13" = 'icons/ui_icons/pills/pill13.png', - "pill14" = 'icons/ui_icons/pills/pill14.png', - "pill15" = 'icons/ui_icons/pills/pill15.png', - "pill16" = 'icons/ui_icons/pills/pill16.png', - "pill17" = 'icons/ui_icons/pills/pill17.png', - "pill18" = 'icons/ui_icons/pills/pill18.png', - "pill19" = 'icons/ui_icons/pills/pill19.png', - "pill20" = 'icons/ui_icons/pills/pill20.png', - "pill21" = 'icons/ui_icons/pills/pill21.png', - "pill22" = 'icons/ui_icons/pills/pill22.png', - ) - -/datum/asset/spritesheet/simple/patches - name = "patches" - assets = list( - "bandaid" = 'icons/ui_icons/patches/bandaid.png', - "bandaid_brute" = 'icons/ui_icons/patches/bandaid_brute.png', - "bandaid_burn" = 'icons/ui_icons/patches/bandaid_burn.png', - "bandaid_both" = 'icons/ui_icons/patches/bandaid_both.png' - ) - -/datum/asset/spritesheet/simple/condiments - name = "condiments" - assets = list( - CONDIMASTER_STYLE_FALLBACK = 'icons/ui_icons/condiments/emptycondiment.png', - "enzyme" = 'icons/ui_icons/condiments/enzyme.png', - "flour" = 'icons/ui_icons/condiments/flour.png', - "mayonnaise" = 'icons/ui_icons/condiments/mayonnaise.png', - "milk" = 'icons/ui_icons/condiments/milk.png', - "blackpepper" = 'icons/ui_icons/condiments/peppermillsmall.png', - "rice" = 'icons/ui_icons/condiments/rice.png', - "sodiumchloride" = 'icons/ui_icons/condiments/saltshakersmall.png', - "soymilk" = 'icons/ui_icons/condiments/soymilk.png', - "soysauce" = 'icons/ui_icons/condiments/soysauce.png', - "sugar" = 'icons/ui_icons/condiments/sugar.png', - "ketchup" = 'icons/ui_icons/condiments/ketchup.png', - "capsaicin" = 'icons/ui_icons/condiments/hotsauce.png', - "frostoil" = 'icons/ui_icons/condiments/coldsauce.png', - "bbqsauce" = 'icons/ui_icons/condiments/bbqsauce.png', - "cornoil" = 'icons/ui_icons/condiments/oliveoil.png', - ) - -//this exists purely to avoid meta by pre-loading all language icons. -/datum/asset/language/register() - for(var/path in typesof(/datum/language)) - set waitfor = FALSE - var/datum/language/L = new path () - L.get_icon() - -/datum/asset/spritesheet/pipes - name = "pipes" - -/datum/asset/spritesheet/pipes/create_spritesheets() - for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi', 'icons/obj/plumbing/fluid_ducts.dmi')) - InsertAll("", each, GLOB.alldirs) - -/datum/asset/spritesheet/supplypods - name = "supplypods" - -/datum/asset/spritesheet/supplypods/create_spritesheets() - for (var/style in 1 to length(GLOB.podstyles)) - if (style == STYLE_SEETHROUGH) - Insert("pod_asset[style]", icon('icons/obj/supplypods.dmi' , "seethrough-icon")) - continue - var/base = GLOB.podstyles[style][POD_BASE] - if (!base) - Insert("pod_asset[style]", icon('icons/obj/supplypods.dmi', "invisible-icon")) - continue - var/icon/podIcon = icon('icons/obj/supplypods.dmi', base) - var/door = GLOB.podstyles[style][POD_DOOR] - if (door) - door = "[base]_door" - podIcon.Blend(icon('icons/obj/supplypods.dmi', door), ICON_OVERLAY) - var/shape = GLOB.podstyles[style][POD_SHAPE] - if (shape == POD_SHAPE_NORML) - var/decal = GLOB.podstyles[style][POD_DECAL] - if (decal) - podIcon.Blend(icon('icons/obj/supplypods.dmi', decal), ICON_OVERLAY) - var/glow = GLOB.podstyles[style][POD_GLOW] - if (glow) - glow = "pod_glow_[glow]" - podIcon.Blend(icon('icons/obj/supplypods.dmi', glow), ICON_OVERLAY) - Insert("pod_asset[style]", podIcon) - -// Representative icons for each research design -/datum/asset/spritesheet/research_designs - name = "design" - -/datum/asset/spritesheet/research_designs/create_spritesheets() - for (var/path in subtypesof(/datum/design)) - var/datum/design/D = path - - var/icon_file - var/icon_state - var/icon/I - - if(initial(D.research_icon) && initial(D.research_icon_state)) //If the design has an icon replacement skip the rest - icon_file = initial(D.research_icon) - icon_state = initial(D.research_icon_state) - if(!(icon_state in icon_states(icon_file))) - warning("design [D] with icon '[icon_file]' missing state '[icon_state]'") - continue - I = icon(icon_file, icon_state, SOUTH) - - else - // construct the icon and slap it into the resource cache - var/atom/item = initial(D.build_path) - if (!ispath(item, /atom)) - // biogenerator outputs to beakers by default - if (initial(D.build_type) & BIOGENERATOR) - item = /obj/item/reagent_containers/glass/beaker/large - else - continue // shouldn't happen, but just in case - - // circuit boards become their resulting machines or computers - if (ispath(item, /obj/item/circuitboard)) - var/obj/item/circuitboard/C = item - var/machine = initial(C.build_path) - if (machine) - item = machine - - // Check for GAGS support where necessary - var/greyscale_config = initial(item.greyscale_config) - var/greyscale_colors = initial(item.greyscale_colors) - if (greyscale_config && greyscale_colors) - icon_file = SSgreyscale.GetColoredIconByType(greyscale_config, greyscale_colors) - else - icon_file = initial(item.icon) - - icon_state = initial(item.icon_state) - if(!(icon_state in icon_states(icon_file))) - warning("design [D] with icon '[icon_file]' missing state '[icon_state]'") - continue - I = icon(icon_file, icon_state, SOUTH) - - // computers (and snowflakes) get their screen and keyboard sprites - if (ispath(item, /obj/machinery/computer) || ispath(item, /obj/machinery/power/solar_control)) - var/obj/machinery/computer/C = item - var/screen = initial(C.icon_screen) - var/keyboard = initial(C.icon_keyboard) - var/all_states = icon_states(icon_file) - if (screen && (screen in all_states)) - I.Blend(icon(icon_file, screen, SOUTH), ICON_OVERLAY) - if (keyboard && (keyboard in all_states)) - I.Blend(icon(icon_file, keyboard, SOUTH), ICON_OVERLAY) - - Insert(initial(D.id), I) - -/datum/asset/spritesheet/vending - name = "vending" - -/datum/asset/spritesheet/vending/create_spritesheets() - for (var/k in GLOB.vending_products) - var/atom/item = k - if (!ispath(item, /atom)) - continue - - var/icon_file - if (initial(item.greyscale_colors) && initial(item.greyscale_config)) - icon_file = SSgreyscale.GetColoredIconByType(initial(item.greyscale_config), initial(item.greyscale_colors)) - else - icon_file = initial(item.icon) - var/icon_state = initial(item.icon_state) - var/icon/I - - var/icon_states_list = icon_states(icon_file) - if(icon_state in icon_states_list) - I = icon(icon_file, icon_state, SOUTH) - var/c = initial(item.color) - if (!isnull(c) && c != "#FFFFFF") - I.Blend(c, ICON_MULTIPLY) - else - var/icon_states_string - for (var/an_icon_state in icon_states_list) - if (!icon_states_string) - icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])" - else - icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])" - stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)](\ref[icon_state]), icon_states=[icon_states_string]") - I = icon('icons/turf/floors.dmi', "", SOUTH) - - var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-") - - Insert(imgid, I) - -/datum/asset/simple/genetics - assets = list( - "dna_discovered.gif" = 'icons/ui_icons/dna/dna_discovered.gif', - "dna_undiscovered.gif" = 'icons/ui_icons/dna/dna_undiscovered.gif', - "dna_extra.gif" = 'icons/ui_icons/dna/dna_extra.gif' - ) - -/datum/asset/simple/orbit - assets = list( - "ghost.png" = 'icons/ui_icons/orbit/ghost.png' - ) - -/datum/asset/simple/vv - assets = list( - "view_variables.css" = 'html/admin/view_variables.css' - ) - -/datum/asset/spritesheet/sheetmaterials - name = "sheetmaterials" - -/datum/asset/spritesheet/sheetmaterials/create_spritesheets() - InsertAll("", 'icons/obj/stack_objects.dmi') - - // Special case to handle Bluespace Crystals - Insert("polycrystal", 'icons/obj/telescience.dmi', "polycrystal") - -/datum/asset/spritesheet/mafia - name = "mafia" - -/datum/asset/spritesheet/mafia/create_spritesheets() - InsertAll("", 'icons/obj/mafia.dmi') - -/datum/asset/simple/portraits - assets = list() - -/datum/asset/simple/portraits/New() - if(!length(SSpersistent_paintings.paintings)) - return - for(var/datum/painting/portrait as anything in SSpersistent_paintings.paintings) - var/png = "data/paintings/images/[portrait.md5].png" - if(fexists(png)) - var/asset_name = "paintings_[portrait.md5]" - assets[asset_name] = png - ..() //this is where it registers all these assets we added to the list - -/datum/asset/simple/safe - assets = list( - "safe_dial.png" = 'icons/ui_icons/safe/safe_dial.png' - ) - -/datum/asset/simple/contracts - assets = list( - "bluespace.png" = 'icons/ui_icons/contracts/bluespace.png', - "destruction.png" = 'icons/ui_icons/contracts/destruction.png', - "healing.png" = 'icons/ui_icons/contracts/healing.png', - "robeless.png" = 'icons/ui_icons/contracts/robeless.png', - ) - -/datum/asset/spritesheet/fish - name = "fish" - -/datum/asset/spritesheet/fish/create_spritesheets() - for (var/path in subtypesof(/datum/aquarium_behaviour/fish)) - var/datum/aquarium_behaviour/fish/fish_type = path - var/fish_icon = initial(fish_type.icon) - var/fish_icon_state = initial(fish_type.icon_state) - var/id = sanitize_css_class_name("[fish_icon][fish_icon_state]") - if(sprites[id]) //no dupes - continue - Insert(id, fish_icon, fish_icon_state) - -/datum/asset/simple/adventure - assets = list( - "default" = 'icons/ui_icons/adventure/default.png', - "grue" = 'icons/ui_icons/adventure/grue.png', - "signal_lost" ='icons/ui_icons/adventure/signal_lost.png', - "trade" = 'icons/ui_icons/adventure/trade.png', - ) - -/datum/asset/simple/inventory - assets = list( - "inventory-glasses.png" = 'icons/ui_icons/inventory/glasses.png', - "inventory-head.png" = 'icons/ui_icons/inventory/head.png', - "inventory-neck.png" = 'icons/ui_icons/inventory/neck.png', - "inventory-mask.png" = 'icons/ui_icons/inventory/mask.png', - "inventory-ears.png" = 'icons/ui_icons/inventory/ears.png', - "inventory-uniform.png" = 'icons/ui_icons/inventory/uniform.png', - "inventory-suit.png" = 'icons/ui_icons/inventory/suit.png', - "inventory-gloves.png" = 'icons/ui_icons/inventory/gloves.png', - "inventory-hand_l.png" = 'icons/ui_icons/inventory/hand_l.png', - "inventory-hand_r.png" = 'icons/ui_icons/inventory/hand_r.png', - "inventory-shoes.png" = 'icons/ui_icons/inventory/shoes.png', - "inventory-suit_storage.png" = 'icons/ui_icons/inventory/suit_storage.png', - "inventory-id.png" = 'icons/ui_icons/inventory/id.png', - "inventory-belt.png" = 'icons/ui_icons/inventory/belt.png', - "inventory-back.png" = 'icons/ui_icons/inventory/back.png', - "inventory-pocket.png" = 'icons/ui_icons/inventory/pocket.png', - "inventory-collar.png" = 'icons/ui_icons/inventory/collar.png', - ) - -/// Removes all non-alphanumerics from the text, keep in mind this can lead to id conflicts -/proc/sanitize_css_class_name(name) - var/static/regex/regex = new(@"[^a-zA-Z0-9]","g") - return replacetext(name, regex, "") - -/datum/asset/simple/tutorial_advisors - assets = list( - "chem_help_advisor.gif" = 'icons/ui_icons/advisors/chem_help_advisor.gif', - ) - -/datum/asset/spritesheet/moods - name = "moods" - var/iconinserted = 1 - -/datum/asset/spritesheet/moods/create_spritesheets() - for(var/i in 1 to 9) - var/target_to_insert = "mood"+"[iconinserted]" - Insert(target_to_insert, 'icons/hud/screen_gen.dmi', target_to_insert) - iconinserted++ - -/datum/asset/spritesheet/moods/ModifyInserted(icon/pre_asset) - var/blended_color - switch(iconinserted) - if(1) - blended_color = "#f15d36" - if(2 to 3) - blended_color = "#f38943" - if(4) - blended_color = "#dfa65b" - if(5) - blended_color = "#4b96c4" - if(6) - blended_color = "#86d656" - else - blended_color = "#2eeb9a" - pre_asset.Blend(blended_color, ICON_MULTIPLY) - return pre_asset - -/// Sends information needed for uplinks -/datum/asset/json/uplink - name = "uplink" - -/datum/asset/json/uplink/generate() - var/list/data = list() - var/list/categories = list() - var/list/items = list() - for(var/datum/uplink_category/category as anything in subtypesof(/datum/uplink_category)) - categories += category - categories = sortTim(categories, .proc/cmp_uplink_category_desc) - - var/list/new_categories = list() - for(var/datum/uplink_category/category as anything in categories) - new_categories += initial(category.name) - categories = new_categories - - for(var/datum/uplink_item/item_path as anything in subtypesof(/datum/uplink_item)) - var/datum/uplink_item/item = new item_path() - if(item.item) { - items += list(list( - "id" = item_path, - "name" = item.name, - "cost" = item.cost, - "desc" = item.desc, - "category" = item.category? initial(item.category.name) : null, - "purchasable_from" = item.purchasable_from, - "restricted" = item.restricted, - "limited_stock" = item.limited_stock, - "restricted_roles" = item.restricted_roles, - "restricted_species" = item.restricted_species, - "progression_minimum" = item.progression_minimum, - )) - } - SStraitor.uplink_items += item - SStraitor.uplink_items_by_type[item_path] = item - - data["items"] = items - data["categories"] = categories - return data diff --git a/code/modules/asset_cache/assets/achievements.dm b/code/modules/asset_cache/assets/achievements.dm new file mode 100644 index 00000000000..1ba7b91af92 --- /dev/null +++ b/code/modules/asset_cache/assets/achievements.dm @@ -0,0 +1,5 @@ +/datum/asset/spritesheet/simple/achievements + name ="achievements" + +/datum/asset/spritesheet/simple/achievements/create_spritesheets() + InsertAll("", ACHIEVEMENTS_SET) diff --git a/code/modules/asset_cache/assets/adventure.dm b/code/modules/asset_cache/assets/adventure.dm new file mode 100644 index 00000000000..65f6c3fe9cc --- /dev/null +++ b/code/modules/asset_cache/assets/adventure.dm @@ -0,0 +1,7 @@ +/datum/asset/simple/adventure + assets = list( + "default" = 'icons/ui_icons/adventure/default.png', + "grue" = 'icons/ui_icons/adventure/grue.png', + "signal_lost" ='icons/ui_icons/adventure/signal_lost.png', + "trade" = 'icons/ui_icons/adventure/trade.png', + ) diff --git a/code/modules/asset_cache/assets/arcade.dm b/code/modules/asset_cache/assets/arcade.dm new file mode 100644 index 00000000000..bcd23919f97 --- /dev/null +++ b/code/modules/asset_cache/assets/arcade.dm @@ -0,0 +1,9 @@ +/datum/asset/simple/arcade + assets = list( + "boss1.gif" = 'icons/ui_icons/arcade/boss1.gif', + "boss2.gif" = 'icons/ui_icons/arcade/boss2.gif', + "boss3.gif" = 'icons/ui_icons/arcade/boss3.gif', + "boss4.gif" = 'icons/ui_icons/arcade/boss4.gif', + "boss5.gif" = 'icons/ui_icons/arcade/boss5.gif', + "boss6.gif" = 'icons/ui_icons/arcade/boss6.gif', + ) diff --git a/code/modules/asset_cache/assets/body_zones.dm b/code/modules/asset_cache/assets/body_zones.dm new file mode 100644 index 00000000000..10f384aa0e5 --- /dev/null +++ b/code/modules/asset_cache/assets/body_zones.dm @@ -0,0 +1,23 @@ +/// Spritesheet for body zones. Necessary if your tgui uses BodyZoneSelector +// This is a simple sheet instead of a spritesheet because spritesheets don't support +// -ms-interpolation-mode when resized, since you need `transform: scale`. +// Also spritesheets have some weird fudge on the edges of them because of an IE bug I can't track down. +/datum/asset/simple/body_zones + +/datum/asset/simple/body_zones/register() + assets["body_zones.base.png"] = icon('icons/hud/screen_midnight.dmi', "zone_sel") + + add_limb(BODY_ZONE_HEAD) + add_limb(BODY_ZONE_CHEST) + add_limb(BODY_ZONE_L_ARM) + add_limb(BODY_ZONE_R_ARM) + add_limb(BODY_ZONE_L_LEG) + add_limb(BODY_ZONE_R_LEG) + add_limb(BODY_ZONE_PRECISE_EYES) + add_limb(BODY_ZONE_PRECISE_MOUTH) + add_limb(BODY_ZONE_PRECISE_GROIN) + + return ..() + +/datum/asset/simple/body_zones/proc/add_limb(limb) + assets[SANITIZE_FILENAME("body_zones.[limb].png")] = icon('icons/hud/screen_gen.dmi', limb) diff --git a/code/modules/asset_cache/assets/chat.dm b/code/modules/asset_cache/assets/chat.dm new file mode 100644 index 00000000000..3765f113dda --- /dev/null +++ b/code/modules/asset_cache/assets/chat.dm @@ -0,0 +1,14 @@ +/datum/asset/spritesheet/chat + name = "chat" + +/datum/asset/spritesheet/chat/create_spritesheets() + InsertAll("emoji", EMOJI_SET) + // pre-loading all lanugage icons also helps to avoid meta + InsertAll("language", 'icons/misc/language.dmi') + // catch languages which are pulling icons from another file + for(var/path in typesof(/datum/language)) + var/datum/language/L = path + var/icon = initial(L.icon) + if (icon != 'icons/misc/language.dmi') + var/icon_state = initial(L.icon_state) + Insert("language-[icon_state]", icon, icon_state=icon_state) diff --git a/code/modules/asset_cache/assets/circuits.dm b/code/modules/asset_cache/assets/circuits.dm new file mode 100644 index 00000000000..df9aa1fa6d8 --- /dev/null +++ b/code/modules/asset_cache/assets/circuits.dm @@ -0,0 +1,4 @@ +/datum/asset/simple/circuit_assets + assets = list( + "grid_background.png" = 'icons/ui_icons/tgui/grid_background.png' + ) diff --git a/code/modules/asset_cache/assets/common.dm b/code/modules/asset_cache/assets/common.dm new file mode 100644 index 00000000000..1b0fb301a19 --- /dev/null +++ b/code/modules/asset_cache/assets/common.dm @@ -0,0 +1,3 @@ +/datum/asset/simple/namespaced/common + assets = list("padlock.png" = 'icons/ui_icons/common/padlock.png') + parents = list("common.css" = 'html/browser/common.css') diff --git a/code/modules/asset_cache/assets/condiments.dm b/code/modules/asset_cache/assets/condiments.dm new file mode 100644 index 00000000000..d72716f778c --- /dev/null +++ b/code/modules/asset_cache/assets/condiments.dm @@ -0,0 +1,20 @@ +/datum/asset/spritesheet/simple/condiments + name = "condiments" + assets = list( + CONDIMASTER_STYLE_FALLBACK = 'icons/ui_icons/condiments/emptycondiment.png', + "enzyme" = 'icons/ui_icons/condiments/enzyme.png', + "flour" = 'icons/ui_icons/condiments/flour.png', + "mayonnaise" = 'icons/ui_icons/condiments/mayonnaise.png', + "milk" = 'icons/ui_icons/condiments/milk.png', + "blackpepper" = 'icons/ui_icons/condiments/peppermillsmall.png', + "rice" = 'icons/ui_icons/condiments/rice.png', + "sodiumchloride" = 'icons/ui_icons/condiments/saltshakersmall.png', + "soymilk" = 'icons/ui_icons/condiments/soymilk.png', + "soysauce" = 'icons/ui_icons/condiments/soysauce.png', + "sugar" = 'icons/ui_icons/condiments/sugar.png', + "ketchup" = 'icons/ui_icons/condiments/ketchup.png', + "capsaicin" = 'icons/ui_icons/condiments/hotsauce.png', + "frostoil" = 'icons/ui_icons/condiments/coldsauce.png', + "bbqsauce" = 'icons/ui_icons/condiments/bbqsauce.png', + "cornoil" = 'icons/ui_icons/condiments/oliveoil.png', + ) diff --git a/code/modules/asset_cache/assets/contracts.dm b/code/modules/asset_cache/assets/contracts.dm new file mode 100644 index 00000000000..6ac1a9cb678 --- /dev/null +++ b/code/modules/asset_cache/assets/contracts.dm @@ -0,0 +1,7 @@ +/datum/asset/simple/contracts + assets = list( + "bluespace.png" = 'icons/ui_icons/contracts/bluespace.png', + "destruction.png" = 'icons/ui_icons/contracts/destruction.png', + "healing.png" = 'icons/ui_icons/contracts/healing.png', + "robeless.png" = 'icons/ui_icons/contracts/robeless.png', + ) diff --git a/code/modules/asset_cache/assets/fish.dm b/code/modules/asset_cache/assets/fish.dm new file mode 100644 index 00000000000..2914b686038 --- /dev/null +++ b/code/modules/asset_cache/assets/fish.dm @@ -0,0 +1,12 @@ +/datum/asset/spritesheet/fish + name = "fish" + +/datum/asset/spritesheet/fish/create_spritesheets() + for (var/path in subtypesof(/datum/aquarium_behaviour/fish)) + var/datum/aquarium_behaviour/fish/fish_type = path + var/fish_icon = initial(fish_type.icon) + var/fish_icon_state = initial(fish_type.icon_state) + var/id = sanitize_css_class_name("[fish_icon][fish_icon_state]") + if(sprites[id]) //no dupes + continue + Insert(id, fish_icon, fish_icon_state) diff --git a/code/modules/asset_cache/assets/fontawesome.dm b/code/modules/asset_cache/assets/fontawesome.dm new file mode 100644 index 00000000000..bc761a35c6d --- /dev/null +++ b/code/modules/asset_cache/assets/fontawesome.dm @@ -0,0 +1,9 @@ +/datum/asset/simple/namespaced/fontawesome + assets = list( + "fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot', + "fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff', + "fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot', + "fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff', + "v4shim.css" = 'html/font-awesome/css/v4-shims.min.css', + ) + parents = list("font-awesome.css" = 'html/font-awesome/css/all.min.css') diff --git a/code/modules/asset_cache/assets/genetics.dm b/code/modules/asset_cache/assets/genetics.dm new file mode 100644 index 00000000000..d74f10f631b --- /dev/null +++ b/code/modules/asset_cache/assets/genetics.dm @@ -0,0 +1,6 @@ +/datum/asset/simple/genetics + assets = list( + "dna_discovered.gif" = 'icons/ui_icons/dna/dna_discovered.gif', + "dna_undiscovered.gif" = 'icons/ui_icons/dna/dna_undiscovered.gif', + "dna_extra.gif" = 'icons/ui_icons/dna/dna_extra.gif' + ) diff --git a/code/modules/asset_cache/assets/headers.dm b/code/modules/asset_cache/assets/headers.dm new file mode 100644 index 00000000000..8ba6b3b5129 --- /dev/null +++ b/code/modules/asset_cache/assets/headers.dm @@ -0,0 +1,31 @@ +/datum/asset/simple/headers + assets = list( + "alarm_green.gif" = 'icons/program_icons/alarm_green.gif', + "alarm_red.gif" = 'icons/program_icons/alarm_red.gif', + "batt_5.gif" = 'icons/program_icons/batt_5.gif', + "batt_20.gif" = 'icons/program_icons/batt_20.gif', + "batt_40.gif" = 'icons/program_icons/batt_40.gif', + "batt_60.gif" = 'icons/program_icons/batt_60.gif', + "batt_80.gif" = 'icons/program_icons/batt_80.gif', + "batt_100.gif" = 'icons/program_icons/batt_100.gif', + "charging.gif" = 'icons/program_icons/charging.gif', + "downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif', + "downloader_running.gif" = 'icons/program_icons/downloader_running.gif', + "ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif', + "ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif', + "power_norm.gif" = 'icons/program_icons/power_norm.gif', + "power_warn.gif" = 'icons/program_icons/power_warn.gif', + "sig_high.gif" = 'icons/program_icons/sig_high.gif', + "sig_low.gif" = 'icons/program_icons/sig_low.gif', + "sig_lan.gif" = 'icons/program_icons/sig_lan.gif', + "sig_none.gif" = 'icons/program_icons/sig_none.gif', + "smmon_0.gif" = 'icons/program_icons/smmon_0.gif', + "smmon_1.gif" = 'icons/program_icons/smmon_1.gif', + "smmon_2.gif" = 'icons/program_icons/smmon_2.gif', + "smmon_3.gif" = 'icons/program_icons/smmon_3.gif', + "smmon_4.gif" = 'icons/program_icons/smmon_4.gif', + "smmon_5.gif" = 'icons/program_icons/smmon_5.gif', + "smmon_6.gif" = 'icons/program_icons/smmon_6.gif', + "borg_mon.gif" = 'icons/program_icons/borg_mon.gif', + "robotact.gif" = 'icons/program_icons/robotact.gif' + ) diff --git a/code/modules/asset_cache/assets/inventory.dm b/code/modules/asset_cache/assets/inventory.dm new file mode 100644 index 00000000000..a63fc45620f --- /dev/null +++ b/code/modules/asset_cache/assets/inventory.dm @@ -0,0 +1,20 @@ +/datum/asset/simple/inventory + assets = list( + "inventory-glasses.png" = 'icons/ui_icons/inventory/glasses.png', + "inventory-head.png" = 'icons/ui_icons/inventory/head.png', + "inventory-neck.png" = 'icons/ui_icons/inventory/neck.png', + "inventory-mask.png" = 'icons/ui_icons/inventory/mask.png', + "inventory-ears.png" = 'icons/ui_icons/inventory/ears.png', + "inventory-uniform.png" = 'icons/ui_icons/inventory/uniform.png', + "inventory-suit.png" = 'icons/ui_icons/inventory/suit.png', + "inventory-gloves.png" = 'icons/ui_icons/inventory/gloves.png', + "inventory-hand_l.png" = 'icons/ui_icons/inventory/hand_l.png', + "inventory-hand_r.png" = 'icons/ui_icons/inventory/hand_r.png', + "inventory-shoes.png" = 'icons/ui_icons/inventory/shoes.png', + "inventory-suit_storage.png" = 'icons/ui_icons/inventory/suit_storage.png', + "inventory-id.png" = 'icons/ui_icons/inventory/id.png', + "inventory-belt.png" = 'icons/ui_icons/inventory/belt.png', + "inventory-back.png" = 'icons/ui_icons/inventory/back.png', + "inventory-pocket.png" = 'icons/ui_icons/inventory/pocket.png', + "inventory-collar.png" = 'icons/ui_icons/inventory/collar.png', + ) diff --git a/code/modules/asset_cache/assets/irv.dm b/code/modules/asset_cache/assets/irv.dm new file mode 100644 index 00000000000..c53a744f591 --- /dev/null +++ b/code/modules/asset_cache/assets/irv.dm @@ -0,0 +1,10 @@ +/datum/asset/simple/irv + assets = list( + "jquery-ui.custom-core-widgit-mouse-sortable.min.js" = 'html/jquery/jquery-ui.custom-core-widgit-mouse-sortable.min.js', + ) + +/datum/asset/group/irv + children = list( + /datum/asset/simple/jquery, + /datum/asset/simple/irv + ) diff --git a/code/modules/asset_cache/assets/jquery.dm b/code/modules/asset_cache/assets/jquery.dm new file mode 100644 index 00000000000..b7241fdb61d --- /dev/null +++ b/code/modules/asset_cache/assets/jquery.dm @@ -0,0 +1,5 @@ +/datum/asset/simple/jquery + legacy = TRUE + assets = list( + "jquery.min.js" = 'html/jquery/jquery.min.js', + ) diff --git a/code/modules/asset_cache/assets/language.dm b/code/modules/asset_cache/assets/language.dm new file mode 100644 index 00000000000..595f753f98f --- /dev/null +++ b/code/modules/asset_cache/assets/language.dm @@ -0,0 +1,9 @@ +//this exists purely to avoid meta by pre-loading all language icons. +/datum/asset/language + +/datum/asset/language/register() + set waitfor = FALSE + + for(var/path in typesof(/datum/language)) + var/datum/language/language = new path() + language.get_icon() diff --git a/code/modules/asset_cache/assets/lobby.dm b/code/modules/asset_cache/assets/lobby.dm new file mode 100644 index 00000000000..ce1d61e552c --- /dev/null +++ b/code/modules/asset_cache/assets/lobby.dm @@ -0,0 +1,4 @@ +/datum/asset/simple/lobby + assets = list( + "playeroptions.css" = 'html/browser/playeroptions.css' + ) diff --git a/code/modules/asset_cache/assets/mafia.dm b/code/modules/asset_cache/assets/mafia.dm new file mode 100644 index 00000000000..0e6a36420df --- /dev/null +++ b/code/modules/asset_cache/assets/mafia.dm @@ -0,0 +1,5 @@ +/datum/asset/spritesheet/mafia + name = "mafia" + +/datum/asset/spritesheet/mafia/create_spritesheets() + InsertAll("", 'icons/obj/mafia.dmi') diff --git a/code/modules/asset_cache/assets/moods.dm b/code/modules/asset_cache/assets/moods.dm new file mode 100644 index 00000000000..13e4518c554 --- /dev/null +++ b/code/modules/asset_cache/assets/moods.dm @@ -0,0 +1,27 @@ +/datum/asset/spritesheet/moods + name = "moods" + var/iconinserted = 1 + +/datum/asset/spritesheet/moods/create_spritesheets() + for(var/i in 1 to 9) + var/target_to_insert = "mood"+"[iconinserted]" + Insert(target_to_insert, 'icons/hud/screen_gen.dmi', target_to_insert) + iconinserted++ + +/datum/asset/spritesheet/moods/ModifyInserted(icon/pre_asset) + var/blended_color + switch(iconinserted) + if(1) + blended_color = "#f15d36" + if(2 to 3) + blended_color = "#f38943" + if(4) + blended_color = "#dfa65b" + if(5) + blended_color = "#4b96c4" + if(6) + blended_color = "#86d656" + else + blended_color = "#2eeb9a" + pre_asset.Blend(blended_color, ICON_MULTIPLY) + return pre_asset diff --git a/code/modules/asset_cache/assets/notes.dm b/code/modules/asset_cache/assets/notes.dm new file mode 100644 index 00000000000..aec6838f967 --- /dev/null +++ b/code/modules/asset_cache/assets/notes.dm @@ -0,0 +1,7 @@ +/datum/asset/simple/notes + assets = list( + "high_button.png" = 'icons/ui_icons/notes/high_button.png', + "medium_button.png" = 'icons/ui_icons/notes/medium_button.png', + "minor_button.png" = 'icons/ui_icons/notes/minor_button.png', + "none_button.png" = 'icons/ui_icons/notes/none_button.png', + ) diff --git a/code/modules/asset_cache/assets/orbit.dm b/code/modules/asset_cache/assets/orbit.dm new file mode 100644 index 00000000000..7d0e0d98a0e --- /dev/null +++ b/code/modules/asset_cache/assets/orbit.dm @@ -0,0 +1,4 @@ +/datum/asset/simple/orbit + assets = list( + "ghost.png" = 'icons/ui_icons/orbit/ghost.png' + ) diff --git a/code/modules/asset_cache/assets/paper.dm b/code/modules/asset_cache/assets/paper.dm new file mode 100644 index 00000000000..8cf50b8f3dc --- /dev/null +++ b/code/modules/asset_cache/assets/paper.dm @@ -0,0 +1,19 @@ +/datum/asset/spritesheet/simple/paper + name = "paper" + assets = list( + "stamp-clown" = 'icons/stamp_icons/large_stamp-clown.png', + "stamp-deny" = 'icons/stamp_icons/large_stamp-deny.png', + "stamp-ok" = 'icons/stamp_icons/large_stamp-ok.png', + "stamp-hop" = 'icons/stamp_icons/large_stamp-hop.png', + "stamp-cmo" = 'icons/stamp_icons/large_stamp-cmo.png', + "stamp-ce" = 'icons/stamp_icons/large_stamp-ce.png', + "stamp-hos" = 'icons/stamp_icons/large_stamp-hos.png', + "stamp-rd" = 'icons/stamp_icons/large_stamp-rd.png', + "stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png', + "stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png', + "stamp-law" = 'icons/stamp_icons/large_stamp-law.png', + "stamp-chap" = 'icons/stamp_icons/large_stamp-chap.png', + "stamp-mime" = 'icons/stamp_icons/large_stamp-mime.png', + "stamp-centcom" = 'icons/stamp_icons/large_stamp-centcom.png', + "stamp-syndicate" = 'icons/stamp_icons/large_stamp-syndicate.png' + ) diff --git a/code/modules/asset_cache/assets/patches.dm b/code/modules/asset_cache/assets/patches.dm new file mode 100644 index 00000000000..2c5bf7e252a --- /dev/null +++ b/code/modules/asset_cache/assets/patches.dm @@ -0,0 +1,8 @@ +/datum/asset/spritesheet/simple/patches + name = "patches" + assets = list( + "bandaid" = 'icons/ui_icons/patches/bandaid.png', + "bandaid_brute" = 'icons/ui_icons/patches/bandaid_brute.png', + "bandaid_burn" = 'icons/ui_icons/patches/bandaid_burn.png', + "bandaid_both" = 'icons/ui_icons/patches/bandaid_both.png' + ) diff --git a/code/modules/asset_cache/assets/pda.dm b/code/modules/asset_cache/assets/pda.dm new file mode 100644 index 00000000000..392efa35b91 --- /dev/null +++ b/code/modules/asset_cache/assets/pda.dm @@ -0,0 +1,34 @@ +/datum/asset/spritesheet/simple/pda + name = "pda" + assets = list( + "atmos" = 'icons/pda_icons/pda_atmos.png', + "back" = 'icons/pda_icons/pda_back.png', + "bell" = 'icons/pda_icons/pda_bell.png', + "blank" = 'icons/pda_icons/pda_blank.png', + "boom" = 'icons/pda_icons/pda_boom.png', + "bucket" = 'icons/pda_icons/pda_bucket.png', + "medbot" = 'icons/pda_icons/pda_medbot.png', + "floorbot" = 'icons/pda_icons/pda_floorbot.png', + "cleanbot" = 'icons/pda_icons/pda_cleanbot.png', + "crate" = 'icons/pda_icons/pda_crate.png', + "cuffs" = 'icons/pda_icons/pda_cuffs.png', + "eject" = 'icons/pda_icons/pda_eject.png', + "flashlight" = 'icons/pda_icons/pda_flashlight.png', + "honk" = 'icons/pda_icons/pda_honk.png', + "mail" = 'icons/pda_icons/pda_mail.png', + "medical" = 'icons/pda_icons/pda_medical.png', + "menu" = 'icons/pda_icons/pda_menu.png', + "mule" = 'icons/pda_icons/pda_mule.png', + "notes" = 'icons/pda_icons/pda_notes.png', + "power" = 'icons/pda_icons/pda_power.png', + "rdoor" = 'icons/pda_icons/pda_rdoor.png', + "reagent" = 'icons/pda_icons/pda_reagent.png', + "refresh" = 'icons/pda_icons/pda_refresh.png', + "scanner" = 'icons/pda_icons/pda_scanner.png', + "signaler" = 'icons/pda_icons/pda_signaler.png', + "skills" = 'icons/pda_icons/pda_skills.png', + "status" = 'icons/pda_icons/pda_status.png', + "dronephone" = 'icons/pda_icons/pda_dronephone.png', + "emoji" = 'icons/pda_icons/pda_emoji.png', + "droneblacklist" = 'icons/pda_icons/pda_droneblacklist.png', + ) diff --git a/code/modules/asset_cache/assets/permissions.dm b/code/modules/asset_cache/assets/permissions.dm new file mode 100644 index 00000000000..6cc6c0e754b --- /dev/null +++ b/code/modules/asset_cache/assets/permissions.dm @@ -0,0 +1,11 @@ +/datum/asset/simple/permissions + assets = list( + "search.js" = 'html/admin/search.js', + "panels.css" = 'html/admin/panels.css' + ) + +/datum/asset/group/permissions + children = list( + /datum/asset/simple/permissions, + /datum/asset/simple/namespaced/common + ) diff --git a/code/modules/asset_cache/assets/pills.dm b/code/modules/asset_cache/assets/pills.dm new file mode 100644 index 00000000000..bbc551e544d --- /dev/null +++ b/code/modules/asset_cache/assets/pills.dm @@ -0,0 +1,26 @@ +/datum/asset/spritesheet/simple/pills + name = "pills" + assets = list( + "pill1" = 'icons/ui_icons/pills/pill1.png', + "pill2" = 'icons/ui_icons/pills/pill2.png', + "pill3" = 'icons/ui_icons/pills/pill3.png', + "pill4" = 'icons/ui_icons/pills/pill4.png', + "pill5" = 'icons/ui_icons/pills/pill5.png', + "pill6" = 'icons/ui_icons/pills/pill6.png', + "pill7" = 'icons/ui_icons/pills/pill7.png', + "pill8" = 'icons/ui_icons/pills/pill8.png', + "pill9" = 'icons/ui_icons/pills/pill9.png', + "pill10" = 'icons/ui_icons/pills/pill10.png', + "pill11" = 'icons/ui_icons/pills/pill11.png', + "pill12" = 'icons/ui_icons/pills/pill12.png', + "pill13" = 'icons/ui_icons/pills/pill13.png', + "pill14" = 'icons/ui_icons/pills/pill14.png', + "pill15" = 'icons/ui_icons/pills/pill15.png', + "pill16" = 'icons/ui_icons/pills/pill16.png', + "pill17" = 'icons/ui_icons/pills/pill17.png', + "pill18" = 'icons/ui_icons/pills/pill18.png', + "pill19" = 'icons/ui_icons/pills/pill19.png', + "pill20" = 'icons/ui_icons/pills/pill20.png', + "pill21" = 'icons/ui_icons/pills/pill21.png', + "pill22" = 'icons/ui_icons/pills/pill22.png', + ) diff --git a/code/modules/asset_cache/assets/pipes.dm b/code/modules/asset_cache/assets/pipes.dm new file mode 100644 index 00000000000..66a37de9f86 --- /dev/null +++ b/code/modules/asset_cache/assets/pipes.dm @@ -0,0 +1,6 @@ +/datum/asset/spritesheet/pipes + name = "pipes" + +/datum/asset/spritesheet/pipes/create_spritesheets() + for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi', 'icons/obj/plumbing/fluid_ducts.dmi')) + InsertAll("", each, GLOB.alldirs) diff --git a/code/modules/asset_cache/assets/portraits.dm b/code/modules/asset_cache/assets/portraits.dm new file mode 100644 index 00000000000..81bb0e058a6 --- /dev/null +++ b/code/modules/asset_cache/assets/portraits.dm @@ -0,0 +1,12 @@ +/datum/asset/simple/portraits + assets = list() + +/datum/asset/simple/portraits/New() + if(!length(SSpersistent_paintings.paintings)) + return + for(var/datum/painting/portrait as anything in SSpersistent_paintings.paintings) + var/png = "data/paintings/images/[portrait.md5].png" + if(fexists(png)) + var/asset_name = "paintings_[portrait.md5]" + assets[asset_name] = png + ..() //this is where it registers all these assets we added to the list diff --git a/code/modules/asset_cache/assets/radar.dm b/code/modules/asset_cache/assets/radar.dm new file mode 100644 index 00000000000..cef2679a92d --- /dev/null +++ b/code/modules/asset_cache/assets/radar.dm @@ -0,0 +1,6 @@ +/datum/asset/simple/radar_assets + assets = list( + "ntosradarbackground.png" = 'icons/ui_icons/tgui/ntosradar_background.png', + "ntosradarpointer.png" = 'icons/ui_icons/tgui/ntosradar_pointer.png', + "ntosradarpointerS.png" = 'icons/ui_icons/tgui/ntosradar_pointer_S.png' + ) diff --git a/code/modules/asset_cache/assets/research_designs.dm b/code/modules/asset_cache/assets/research_designs.dm new file mode 100644 index 00000000000..bca782207a1 --- /dev/null +++ b/code/modules/asset_cache/assets/research_designs.dm @@ -0,0 +1,63 @@ +// Representative icons for each research design +/datum/asset/spritesheet/research_designs + name = "design" + +/datum/asset/spritesheet/research_designs/create_spritesheets() + for (var/path in subtypesof(/datum/design)) + var/datum/design/D = path + + var/icon_file + var/icon_state + var/icon/I + + if(initial(D.research_icon) && initial(D.research_icon_state)) //If the design has an icon replacement skip the rest + icon_file = initial(D.research_icon) + icon_state = initial(D.research_icon_state) + if(!(icon_state in icon_states(icon_file))) + warning("design [D] with icon '[icon_file]' missing state '[icon_state]'") + continue + I = icon(icon_file, icon_state, SOUTH) + + else + // construct the icon and slap it into the resource cache + var/atom/item = initial(D.build_path) + if (!ispath(item, /atom)) + // biogenerator outputs to beakers by default + if (initial(D.build_type) & BIOGENERATOR) + item = /obj/item/reagent_containers/glass/beaker/large + else + continue // shouldn't happen, but just in case + + // circuit boards become their resulting machines or computers + if (ispath(item, /obj/item/circuitboard)) + var/obj/item/circuitboard/C = item + var/machine = initial(C.build_path) + if (machine) + item = machine + + // Check for GAGS support where necessary + var/greyscale_config = initial(item.greyscale_config) + var/greyscale_colors = initial(item.greyscale_colors) + if (greyscale_config && greyscale_colors) + icon_file = SSgreyscale.GetColoredIconByType(greyscale_config, greyscale_colors) + else + icon_file = initial(item.icon) + + icon_state = initial(item.icon_state) + if(!(icon_state in icon_states(icon_file))) + warning("design [D] with icon '[icon_file]' missing state '[icon_state]'") + continue + I = icon(icon_file, icon_state, SOUTH) + + // computers (and snowflakes) get their screen and keyboard sprites + if (ispath(item, /obj/machinery/computer) || ispath(item, /obj/machinery/power/solar_control)) + var/obj/machinery/computer/C = item + var/screen = initial(C.icon_screen) + var/keyboard = initial(C.icon_keyboard) + var/all_states = icon_states(icon_file) + if (screen && (screen in all_states)) + I.Blend(icon(icon_file, screen, SOUTH), ICON_OVERLAY) + if (keyboard && (keyboard in all_states)) + I.Blend(icon(icon_file, keyboard, SOUTH), ICON_OVERLAY) + + Insert(initial(D.id), I) diff --git a/code/modules/asset_cache/assets/safe.dm b/code/modules/asset_cache/assets/safe.dm new file mode 100644 index 00000000000..b1d6ba9a8aa --- /dev/null +++ b/code/modules/asset_cache/assets/safe.dm @@ -0,0 +1,4 @@ +/datum/asset/simple/safe + assets = list( + "safe_dial.png" = 'icons/ui_icons/safe/safe_dial.png' + ) diff --git a/code/modules/asset_cache/assets/sheetmaterials.dm b/code/modules/asset_cache/assets/sheetmaterials.dm new file mode 100644 index 00000000000..d746b5783e5 --- /dev/null +++ b/code/modules/asset_cache/assets/sheetmaterials.dm @@ -0,0 +1,8 @@ +/datum/asset/spritesheet/sheetmaterials + name = "sheetmaterials" + +/datum/asset/spritesheet/sheetmaterials/create_spritesheets() + InsertAll("", 'icons/obj/stack_objects.dmi') + + // Special case to handle Bluespace Crystals + Insert("polycrystal", 'icons/obj/telescience.dmi', "polycrystal") diff --git a/code/modules/asset_cache/assets/supplypods.dm b/code/modules/asset_cache/assets/supplypods.dm new file mode 100644 index 00000000000..fd4c961f103 --- /dev/null +++ b/code/modules/asset_cache/assets/supplypods.dm @@ -0,0 +1,27 @@ +/datum/asset/spritesheet/supplypods + name = "supplypods" + +/datum/asset/spritesheet/supplypods/create_spritesheets() + for (var/style in 1 to length(GLOB.podstyles)) + if (style == STYLE_SEETHROUGH) + Insert("pod_asset[style]", icon('icons/obj/supplypods.dmi' , "seethrough-icon")) + continue + var/base = GLOB.podstyles[style][POD_BASE] + if (!base) + Insert("pod_asset[style]", icon('icons/obj/supplypods.dmi', "invisible-icon")) + continue + var/icon/podIcon = icon('icons/obj/supplypods.dmi', base) + var/door = GLOB.podstyles[style][POD_DOOR] + if (door) + door = "[base]_door" + podIcon.Blend(icon('icons/obj/supplypods.dmi', door), ICON_OVERLAY) + var/shape = GLOB.podstyles[style][POD_SHAPE] + if (shape == POD_SHAPE_NORML) + var/decal = GLOB.podstyles[style][POD_DECAL] + if (decal) + podIcon.Blend(icon('icons/obj/supplypods.dmi', decal), ICON_OVERLAY) + var/glow = GLOB.podstyles[style][POD_GLOW] + if (glow) + glow = "pod_glow_[glow]" + podIcon.Blend(icon('icons/obj/supplypods.dmi', glow), ICON_OVERLAY) + Insert("pod_asset[style]", podIcon) diff --git a/code/modules/asset_cache/assets/tgfont.dm b/code/modules/asset_cache/assets/tgfont.dm new file mode 100644 index 00000000000..efa98e22e2c --- /dev/null +++ b/code/modules/asset_cache/assets/tgfont.dm @@ -0,0 +1,8 @@ +/datum/asset/simple/namespaced/tgfont + assets = list( + "tgfont.eot" = file("tgui/packages/tgfont/static/tgfont.eot"), + "tgfont.woff2" = file("tgui/packages/tgfont/static/tgfont.woff2"), + ) + parents = list( + "tgfont.css" = file("tgui/packages/tgfont/static/tgfont.css"), + ) diff --git a/code/modules/asset_cache/assets/tgui.dm b/code/modules/asset_cache/assets/tgui.dm new file mode 100644 index 00000000000..9c79925602c --- /dev/null +++ b/code/modules/asset_cache/assets/tgui.dm @@ -0,0 +1,13 @@ +/datum/asset/simple/tgui + keep_local_name = TRUE + assets = list( + "tgui.bundle.js" = file("tgui/public/tgui.bundle.js"), + "tgui.bundle.css" = file("tgui/public/tgui.bundle.css"), + ) + +/datum/asset/simple/tgui_panel + keep_local_name = TRUE + assets = list( + "tgui-panel.bundle.js" = file("tgui/public/tgui-panel.bundle.js"), + "tgui-panel.bundle.css" = file("tgui/public/tgui-panel.bundle.css"), + ) diff --git a/code/modules/asset_cache/assets/tutorial_advisors.dm b/code/modules/asset_cache/assets/tutorial_advisors.dm new file mode 100644 index 00000000000..da80e8904d3 --- /dev/null +++ b/code/modules/asset_cache/assets/tutorial_advisors.dm @@ -0,0 +1,4 @@ +/datum/asset/simple/tutorial_advisors + assets = list( + "chem_help_advisor.gif" = 'icons/ui_icons/advisors/chem_help_advisor.gif', + ) diff --git a/code/modules/asset_cache/assets/uplink.dm b/code/modules/asset_cache/assets/uplink.dm new file mode 100644 index 00000000000..e2ede24d90f --- /dev/null +++ b/code/modules/asset_cache/assets/uplink.dm @@ -0,0 +1,40 @@ +/// Sends information needed for uplinks +/datum/asset/json/uplink + name = "uplink" + +/datum/asset/json/uplink/generate() + var/list/data = list() + var/list/categories = list() + var/list/items = list() + for(var/datum/uplink_category/category as anything in subtypesof(/datum/uplink_category)) + categories += category + categories = sortTim(categories, .proc/cmp_uplink_category_desc) + + var/list/new_categories = list() + for(var/datum/uplink_category/category as anything in categories) + new_categories += initial(category.name) + categories = new_categories + + for(var/datum/uplink_item/item_path as anything in subtypesof(/datum/uplink_item)) + var/datum/uplink_item/item = new item_path() + if(item.item) { + items += list(list( + "id" = item_path, + "name" = item.name, + "cost" = item.cost, + "desc" = item.desc, + "category" = item.category? initial(item.category.name) : null, + "purchasable_from" = item.purchasable_from, + "restricted" = item.restricted, + "limited_stock" = item.limited_stock, + "restricted_roles" = item.restricted_roles, + "restricted_species" = item.restricted_species, + "progression_minimum" = item.progression_minimum, + )) + } + SStraitor.uplink_items += item + SStraitor.uplink_items_by_type[item_path] = item + + data["items"] = items + data["categories"] = categories + return data diff --git a/code/modules/asset_cache/assets/vending.dm b/code/modules/asset_cache/assets/vending.dm new file mode 100644 index 00000000000..87fddfc1132 --- /dev/null +++ b/code/modules/asset_cache/assets/vending.dm @@ -0,0 +1,36 @@ +/datum/asset/spritesheet/vending + name = "vending" + +/datum/asset/spritesheet/vending/create_spritesheets() + for (var/k in GLOB.vending_products) + var/atom/item = k + if (!ispath(item, /atom)) + continue + + var/icon_file + if (initial(item.greyscale_colors) && initial(item.greyscale_config)) + icon_file = SSgreyscale.GetColoredIconByType(initial(item.greyscale_config), initial(item.greyscale_colors)) + else + icon_file = initial(item.icon) + var/icon_state = initial(item.icon_state) + var/icon/I + + var/icon_states_list = icon_states(icon_file) + if(icon_state in icon_states_list) + I = icon(icon_file, icon_state, SOUTH) + var/c = initial(item.color) + if (!isnull(c) && c != "#FFFFFF") + I.Blend(c, ICON_MULTIPLY) + else + var/icon_states_string + for (var/an_icon_state in icon_states_list) + if (!icon_states_string) + icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])" + else + icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])" + stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)](\ref[icon_state]), icon_states=[icon_states_string]") + I = icon('icons/turf/floors.dmi', "", SOUTH) + + var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-") + + Insert(imgid, I) diff --git a/code/modules/asset_cache/assets/vv.dm b/code/modules/asset_cache/assets/vv.dm new file mode 100644 index 00000000000..0dd974c7c79 --- /dev/null +++ b/code/modules/asset_cache/assets/vv.dm @@ -0,0 +1,4 @@ +/datum/asset/simple/vv + assets = list( + "view_variables.css" = 'html/admin/view_variables.css' + ) diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index f333825ab43..eaec3c8b652 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -22,9 +22,9 @@ var/requires_tech = FALSE //handles techweb-oriented surgeries, previously restricted to the /advanced subtype (You still need to add designs) var/replaced_by //type; doesn't show up if this type exists. Set to /datum/surgery if you want to hide a "base" surgery (useful for typing parents IE healing.dm just make sure to null it out again) /// Organ being directly manipulated, used for checking if the organ is still in the body after surgery has begun - var/organ_to_manipulate + var/organ_to_manipulate -/datum/surgery/New(surgery_target, surgery_location, surgery_bodypart) +/datum/surgery/New(atom/surgery_target, surgery_location, surgery_bodypart) ..() if(!surgery_target) return @@ -39,6 +39,8 @@ operated_wound = operated_bodypart.get_wound_type(targetable_wound) operated_wound.attached_surgery = src + SEND_SIGNAL(surgery_target, COMSIG_MOB_SURGERY_STARTED, src, surgery_location, surgery_bodypart) + /datum/surgery/Destroy() if(operated_wound) operated_wound.attached_surgery = null diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm index 5ada71ccb30..8b9e41f8585 100644 --- a/code/modules/surgery/tools.dm +++ b/code/modules/surgery/tools.dm @@ -230,7 +230,7 @@ /obj/item/surgical_drapes/Initialize(mapload) . = ..() - AddElement(/datum/element/surgery_initiator) + AddComponent(/datum/component/surgery_initiator) /obj/item/surgical_processor //allows medical cyborgs to scan and initiate advanced surgeries diff --git a/tgstation.dme b/tgstation.dme index 5555f2b41f9..957db2a7d41 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -207,6 +207,7 @@ #include "code\__DEFINES\dcs\signals\signals_hydroponic.dm" #include "code\__DEFINES\dcs\signals\signals_janitor.dm" #include "code\__DEFINES\dcs\signals\signals_light_eater.dm" +#include "code\__DEFINES\dcs\signals\signals_medical.dm" #include "code\__DEFINES\dcs\signals\signals_mind.dm" #include "code\__DEFINES\dcs\signals\signals_mod.dm" #include "code\__DEFINES\dcs\signals\signals_mood.dm" @@ -757,6 +758,7 @@ #include "code\datums\components\strong_pull.dm" #include "code\datums\components\subtype_picker.dm" #include "code\datums\components\summoning.dm" +#include "code\datums\components\surgery_initiator.dm" #include "code\datums\components\swabbing.dm" #include "code\datums\components\swarming.dm" #include "code\datums\components\tackle.dm" @@ -942,7 +944,6 @@ #include "code\datums\elements\spooky.dm" #include "code\datums\elements\squish.dm" #include "code\datums\elements\strippable.dm" -#include "code\datums\elements\surgery_initiator.dm" #include "code\datums\elements\swabbable.dm" #include "code\datums\elements\tenacious.dm" #include "code\datums\elements\tool_flash.dm" @@ -2123,7 +2124,46 @@ #include "code\modules\asset_cache\asset_cache_client.dm" #include "code\modules\asset_cache\asset_cache_item.dm" #include "code\modules\asset_cache\asset_list.dm" -#include "code\modules\asset_cache\asset_list_items.dm" +#include "code\modules\asset_cache\assets\achievements.dm" +#include "code\modules\asset_cache\assets\adventure.dm" +#include "code\modules\asset_cache\assets\arcade.dm" +#include "code\modules\asset_cache\assets\body_zones.dm" +#include "code\modules\asset_cache\assets\chat.dm" +#include "code\modules\asset_cache\assets\circuits.dm" +#include "code\modules\asset_cache\assets\common.dm" +#include "code\modules\asset_cache\assets\condiments.dm" +#include "code\modules\asset_cache\assets\contracts.dm" +#include "code\modules\asset_cache\assets\fish.dm" +#include "code\modules\asset_cache\assets\fontawesome.dm" +#include "code\modules\asset_cache\assets\genetics.dm" +#include "code\modules\asset_cache\assets\headers.dm" +#include "code\modules\asset_cache\assets\inventory.dm" +#include "code\modules\asset_cache\assets\irv.dm" +#include "code\modules\asset_cache\assets\jquery.dm" +#include "code\modules\asset_cache\assets\language.dm" +#include "code\modules\asset_cache\assets\lobby.dm" +#include "code\modules\asset_cache\assets\mafia.dm" +#include "code\modules\asset_cache\assets\moods.dm" +#include "code\modules\asset_cache\assets\notes.dm" +#include "code\modules\asset_cache\assets\orbit.dm" +#include "code\modules\asset_cache\assets\paper.dm" +#include "code\modules\asset_cache\assets\patches.dm" +#include "code\modules\asset_cache\assets\pda.dm" +#include "code\modules\asset_cache\assets\permissions.dm" +#include "code\modules\asset_cache\assets\pills.dm" +#include "code\modules\asset_cache\assets\pipes.dm" +#include "code\modules\asset_cache\assets\portraits.dm" +#include "code\modules\asset_cache\assets\radar.dm" +#include "code\modules\asset_cache\assets\research_designs.dm" +#include "code\modules\asset_cache\assets\safe.dm" +#include "code\modules\asset_cache\assets\sheetmaterials.dm" +#include "code\modules\asset_cache\assets\supplypods.dm" +#include "code\modules\asset_cache\assets\tgfont.dm" +#include "code\modules\asset_cache\assets\tgui.dm" +#include "code\modules\asset_cache\assets\tutorial_advisors.dm" +#include "code\modules\asset_cache\assets\uplink.dm" +#include "code\modules\asset_cache\assets\vending.dm" +#include "code\modules\asset_cache\assets\vv.dm" #include "code\modules\asset_cache\transports\asset_transport.dm" #include "code\modules\asset_cache\transports\webroot_transport.dm" #include "code\modules\atmospherics\environmental\LINDA_fire.dm" diff --git a/tgui/packages/tgui/components/BodyZoneSelector.tsx b/tgui/packages/tgui/components/BodyZoneSelector.tsx new file mode 100644 index 00000000000..6e3d2ecbd8b --- /dev/null +++ b/tgui/packages/tgui/components/BodyZoneSelector.tsx @@ -0,0 +1,150 @@ +import { Component, createRef } from "inferno"; +import { resolveAsset } from "../assets"; +import { Box } from "./Box"; + +export enum BodyZone { + Head = "head", + Chest = "chest", + LeftArm = "l_arm", + RightArm = "r_arm", + LeftLeg = "l_leg", + RightLeg = "r_leg", + Eyes = "eyes", + Mouth = "mouth", + Groin = "groin", +} + +const bodyZonePixelToZone: (x: number, y: number) => (BodyZone | null) + = (x, y) => { + // TypeScript translation of /atom/movable/screen/zone_sel/proc/get_zone_at + if (y < 1) { + return null; + } else if (y < 10) { + if (x > 10 && x < 15) { + return BodyZone.RightLeg; + } else if (x > 17 && x < 22) { + return BodyZone.LeftLeg; + } + } else if (y < 13) { + if (x > 8 && x < 11) { + return BodyZone.RightArm; + } else if (x > 12 && x < 20) { + return BodyZone.Groin; + } else if (x > 21 && x < 24) { + return BodyZone.LeftArm; + } + } else if (y < 22) { + if (x > 8 && x < 11) { + return BodyZone.RightArm; + } else if (x > 12 && x < 20) { + return BodyZone.Chest; + } else if (x > 21 && x < 24) { + return BodyZone.LeftArm; + } + } else if (y < 30 && (x > 12 && x < 20)) { + if (y > 23 && y < 24 && (x > 15 && x < 17)) { + return BodyZone.Mouth; + } else if (y > 25 && y < 27 && (x > 14 && x < 18)) { + return BodyZone.Eyes; + } else { + return BodyZone.Head; + } + } + + return null; + }; + +type BodyZoneSelectorProps = { + onClick?: (zone: BodyZone) => void, + scale?: number, + selectedZone: BodyZone | null, +} + +type BodyZoneSelectorState = { + hoverZone: BodyZone | null, +} + +export class BodyZoneSelector + extends Component +{ + ref = createRef(); + state: BodyZoneSelectorState = { + hoverZone: null, + } + + render() { + const { hoverZone } = this.state; + const { scale = 3, selectedZone } = this.props; + + return ( +
+ { + const onClick = this.props.onClick; + if (onClick && this.state.hoverZone) { + onClick(this.state.hoverZone); + } + }} + onMouseMove={(event) => { + if (!this.props.onClick) { + return; + } + + const rect = this.ref.current?.getBoundingClientRect(); + if (!rect) { + return; + } + + const x = event.clientX - rect.left; + const y = (32 * scale) - (event.clientY - rect.top); + + this.setState({ + hoverZone: bodyZonePixelToZone(x / scale, y / scale), + }); + }} + style={{ + "-ms-interpolation-mode": "nearest-neighbor", + "position": "absolute", + "width": `${32 * scale}px`, + "height": `${32 * scale}px`, + }} + /> + + {selectedZone && ( + + )} + + {hoverZone && (hoverZone !== selectedZone) && ( + + )} +
+ ); + } +} diff --git a/tgui/packages/tgui/interfaces/SurgeryInitiator.tsx b/tgui/packages/tgui/interfaces/SurgeryInitiator.tsx new file mode 100644 index 00000000000..00137c552eb --- /dev/null +++ b/tgui/packages/tgui/interfaces/SurgeryInitiator.tsx @@ -0,0 +1,172 @@ +import { sortBy } from "common/collections"; +import { KEY_DOWN, KEY_ENTER, KEY_UP } from "common/keycodes"; +import { BooleanLike } from "common/react"; +import { Component } from "inferno"; +import { useBackend } from "../backend"; +import { Button, KeyListener, Stack } from "../components"; +import { BodyZone, BodyZoneSelector } from "../components/BodyZoneSelector"; +import { Window } from "../layouts"; + +type Surgery = { + name: string, + blocked?: BooleanLike, +}; + +type SurgeryInitiatorData = { + selected_zone: BodyZone, + surgeries: Surgery[], + target_name: string, +}; + +const sortSurgeries + = sortBy((surgery: Surgery) => surgery.name); + +type SurgeryInitiatorInnerState = { + selectedSurgeryIndex: number, +}; + +class SurgeryInitiatorInner extends Component< + SurgeryInitiatorData, + SurgeryInitiatorInnerState +> { + state = { + selectedSurgeryIndex: 0, + } + + componentDidMount() { + this.updateSelectedSurgeryIndexState(); + } + + componentDidUpdate(prevProps: SurgeryInitiatorData) { + if (prevProps.selected_zone !== this.props.selected_zone) { + this.updateSelectedSurgeryIndexState(); + } + } + + updateSelectedSurgeryIndexState() { + this.setState({ + selectedSurgeryIndex: this.findSelectedSurgeryAfter(-1) || 0, + }); + } + + findSelectedSurgeryAfter(after: number): number | undefined { + const foundIndex + = this.props.surgeries.findIndex( + (surgery, index) => index > after && !surgery.blocked + ); + + return foundIndex === -1 ? undefined : foundIndex; + } + + findSelectedSurgeryBefore(before: number): number | undefined { + for (let index = before; index >= 0; index--) { + const surgery = this.props.surgeries[index]; + if (!surgery.blocked) { + return index; + } + } + + return undefined; + } + + render() { + const { act } = useBackend(this.context); + const { selected_zone, surgeries, target_name } = this.props; + + return ( + + + + + act("change_zone", { new_zone: zone })} + selectedZone={selected_zone} + /> + + + + + {surgeries.map((surgery, index) => ( + + ))} + + + + + { + const keyCode = event.code; + const surgery = surgeries[this.state.selectedSurgeryIndex]; + + switch (keyCode) { + case KEY_DOWN: + this.setState((state) => { + return { + selectedSurgeryIndex: + this.findSelectedSurgeryAfter( + state.selectedSurgeryIndex + ) || this.findSelectedSurgeryAfter(-1) || 0, + }; + }); + + break; + case KEY_UP: + this.setState((state) => { + return { + selectedSurgeryIndex: + this.findSelectedSurgeryBefore( + state.selectedSurgeryIndex - 1 + ) + ?? this.findSelectedSurgeryBefore( + this.props.surgeries.length - 1 + ) + ?? 0, + }; + }); + + break; + case KEY_ENTER: + if (surgery) { + act("start_surgery", { + surgery_name: surgery.name, + }); + } + + break; + } + }} + /> + + + ); + } +} + +export const SurgeryInitiator = (props, context) => { + const { data } = useBackend(context); + + return ( + + ); +};