diff --git a/.github/workflows/render_nanomaps.yml b/.github/workflows/render_nanomaps.yml new file mode 100644 index 0000000000..6b58c9e8e0 --- /dev/null +++ b/.github/workflows/render_nanomaps.yml @@ -0,0 +1,35 @@ +# GitHub action to autorender nanomaps outside the game +# This kills off the awful verb we have that takes a full 50 seconds and hangs the whole server +# The file names and locations are VERY important here +# DO NOT EDIT THIS UNLESS YOU KNOW WHAT YOU ARE DOING +# -aa +name: 'Render Nanomaps' +on: + push: + branches: master + paths: + - 'maps/**' + +jobs: + generate_maps: + name: 'Generate NanoMaps' + runs-on: ubuntu-18.04 + steps: + - name: 'Update Branch' + uses: actions/checkout@v2 + with: + fetch-depth: 1 + + - name: 'Generate Maps' + run: './tools/github-actions/nanomap-renderer-invoker.sh' + + - name: 'Commit Maps' + run: | + git config --local user.email "action@github.com" + git config --local user.name "NanoMap Generation" + git pull origin master + git commit -m "NanoMap Auto-Update (`date`)" -a || true + - name: 'Push Maps' + uses: ad-m/github-push-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index 1f00987671..77f9127bf4 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ Going to make a Pull Request? Make sure you read the [CONTRIBUTING.md](.github/C CHOMPStation is a fork of the Yawn-wider code branch which is a fork of the VOREStation code branch which is a fork of the Polaris code branch, itself a fork of the Baystation12 code branch, for the game Space Station 13. +![Render Nanomaps](https://github.com/VOREStation/VOREStation/workflows/Render%20Nanomaps/badge.svg) + --- ### LICENSE diff --git a/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm b/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm index fb686820ee..f95b613466 100644 --- a/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm +++ b/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm @@ -232,7 +232,7 @@ // 0 amount = 0 means ejecting a full stack; -1 means eject everything /obj/machinery/atmospherics/binary/algae_farm/proc/eject_materials(var/material_name, var/amount) var/recursive = amount == -1 ? 1 : 0 - var/material/matdata = get_material_by_name(material_name) + var/datum/material/matdata = get_material_by_name(material_name) var/stack_type = matdata.stack_type var/obj/item/stack/material/S = new stack_type(loc) if(amount <= 0) @@ -266,7 +266,7 @@ to_chat(user, "\The [src] cannot hold more [S.name].") return 1 -/material/algae +/datum/material/algae name = MAT_ALGAE stack_type = /obj/item/stack/material/algae icon_colour = "#557722" diff --git a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm index dd38dae3ca..e960d36fa7 100644 --- a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm +++ b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm @@ -13,6 +13,7 @@ desc = "A one-way air valve that can be used to regulate input or output pressure, and flow rate. Does not require power." use_power = USE_POWER_OFF + interact_offline = TRUE var/unlocked = 0 //If 0, then the valve is locked closed, otherwise it is open(-able, it's a one-way valve so it closes if gas would flow backwards). var/target_pressure = ONE_ATMOSPHERE @@ -216,7 +217,7 @@ tgui_interact(user) /obj/machinery/atmospherics/binary/passive_gate/tgui_interact(mob/user, datum/tgui/ui) - if(stat & (BROKEN|NOPOWER)) + if(stat & BROKEN) return FALSE ui = SStgui.try_update_ui(user, src, ui) if(!ui) diff --git a/code/ATMOSPHERICS/components/omni_devices/filter.dm b/code/ATMOSPHERICS/components/omni_devices/filter.dm index 56171a0880..00e2f9d5dc 100644 --- a/code/ATMOSPHERICS/components/omni_devices/filter.dm +++ b/code/ATMOSPHERICS/components/omni_devices/filter.dm @@ -33,8 +33,10 @@ return ..() /obj/machinery/atmospherics/omni/atmos_filter/sort_ports() + var/any_updated = FALSE for(var/datum/omni_port/P in ports) if(P.update) + any_updated = TRUE if(output == P) output = null if(input == P) @@ -50,6 +52,8 @@ output = P if(ATM_O2 to ATM_N2O) atmos_filters += P + if(any_updated) + rebuild_filtering_list() /obj/machinery/atmospherics/omni/atmos_filter/error_check() if(!input || !output || !atmos_filters) @@ -231,7 +235,6 @@ target_port.mode = mode if(target_port.mode != previous_mode) handle_port_change(target_port) - rebuild_filtering_list() else return else diff --git a/code/ATMOSPHERICS/pipes/tank.dm b/code/ATMOSPHERICS/pipes/tank.dm index 54f90d9521..a893facff6 100644 --- a/code/ATMOSPHERICS/pipes/tank.dm +++ b/code/ATMOSPHERICS/pipes/tank.dm @@ -70,10 +70,6 @@ if(istype(W, /obj/item/device/pipe_painter)) return - if(istype(W, /obj/item/device/analyzer) && in_range(user, src)) - var/obj/item/device/analyzer/A = W - A.analyze_gases(src, user) - /obj/machinery/atmospherics/pipe/tank/air name = "Pressure Tank (Air)" icon_state = "air_map" diff --git a/code/__defines/misc_vr.dm b/code/__defines/misc_vr.dm index 57c651c195..46d8a347e8 100644 --- a/code/__defines/misc_vr.dm +++ b/code/__defines/misc_vr.dm @@ -63,4 +63,5 @@ #define MAT_TITANIUMGLASS "ti-glass" #define MAT_PLASTITANIUM "plastitanium" +#define MAT_PLASTITANIUMHULL "plastitanium hull" #define MAT_PLASTITANIUMGLASS "plastitanium glass" \ No newline at end of file diff --git a/code/__defines/pda.dm b/code/__defines/pda.dm new file mode 100644 index 0000000000..c5d32f03ba --- /dev/null +++ b/code/__defines/pda.dm @@ -0,0 +1,3 @@ +#define PDA_APP_UPDATE 0 +#define PDA_APP_NOUPDATE 1 +#define PDA_APP_UPDATE_SLOW 2 diff --git a/code/_global_vars/religion.dm b/code/_global_vars/religion.dm new file mode 100644 index 0000000000..7dab008b19 --- /dev/null +++ b/code/_global_vars/religion.dm @@ -0,0 +1,8 @@ +// All religion stuff +GLOBAL_VAR(religion) +GLOBAL_VAR(deity) + +//bible +GLOBAL_VAR(bible_name) +GLOBAL_VAR(bible_icon_state) +GLOBAL_VAR(bible_item_state) diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm index 02a8806089..a9aac1ffcf 100644 --- a/code/_helpers/text.dm +++ b/code/_helpers/text.dm @@ -21,6 +21,27 @@ /* * Text sanitization */ +// Can be used almost the same way as normal input for text +/proc/clean_input(Message, Title, Default, mob/user=usr) + var/txt = input(user, Message, Title, Default) as text | null + if(txt) + return html_encode(txt) + +//Simply removes < and > and limits the length of the message +/proc/strip_html_simple(var/t,var/limit=MAX_MESSAGE_LEN) + var/list/strip_chars = list("<",">") + t = copytext(t,1,limit) + for(var/char in strip_chars) + var/index = findtext(t, char) + while(index) + t = copytext(t, 1, index) + copytext(t, index+1) + index = findtext(t, char) + return t + +//Runs byond's sanitization proc along-side strip_html_simple +//I believe strip_html_simple() is required to run first to prevent '<' from displaying as '<' that html_encode() would cause +/proc/adminscrub(var/t,var/limit=MAX_MESSAGE_LEN) + return copytext((html_encode(strip_html_simple(t))),1,limit) //Used for preprocessing entered text /proc/sanitize(var/input, var/max_length = MAX_MESSAGE_LEN, var/encode = 1, var/trim = 1, var/extra = 1) diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index 859884a8b7..76b18f7222 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -141,8 +141,9 @@ return 1 /obj/machinery/turretid/AICtrlClick() //turns off/on Turrets - Topic(src, list("command"="enable", "value"="[!enabled]")) - return 1 + enabled = !enabled + updateTurrets() + return TRUE /atom/proc/AIAltClick(var/atom/A) return AltClick(A) @@ -156,8 +157,10 @@ return 1 /obj/machinery/turretid/AIAltClick() //toggles lethal on turrets - Topic(src, list("command"="lethal", "value"="[!lethal]")) - return 1 + if(lethal_is_configurable) + lethal = !lethal + updateTurrets() + return TRUE /atom/proc/AIMiddleClick(var/mob/living/silicon/user) return 0 diff --git a/code/_onclick/hud/alert_vr.dm b/code/_onclick/hud/alert_vr.dm new file mode 100644 index 0000000000..19310ad315 --- /dev/null +++ b/code/_onclick/hud/alert_vr.dm @@ -0,0 +1,25 @@ +/obj/screen/alert/fat + name = "Full" + desc = "You overate! If you don't exercise soon, you might find yourself gaining weight." + +/obj/screen/alert/fat/vampire + desc = "You overdrank! If you don't exercise soon, you might find yourself gaining weight." + +/obj/screen/alert/fat/synth + name = "Overcharged" + +/obj/screen/alert/hungry/vampire + desc = "You could use a bloodpack or two." + +/obj/screen/alert/hungry/synth + name = "Undercharged" + +/obj/screen/alert/starving + desc = "You're extremely hungry. The hunger pains make moving around a chore." + +/obj/screen/alert/starving/vampire + desc = "You are starving! Without some blood, moving around is a pain." + +/obj/screen/alert/starving/synth + name = "Low Power" + desc = "Your battery is very low! Low power mode makes all movements slower." diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 66cf3d1c12..5e5f044ac2 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -515,7 +515,7 @@ if("Show Crew Manifest") if(isAI(usr)) var/mob/living/silicon/ai/AI = usr - AI.ai_roster() + AI.subsystem_crew_manifest() if("Show Alerts") if(isAI(usr)) @@ -540,12 +540,14 @@ if("PDA - Send Message") if(isAI(usr)) var/mob/living/silicon/ai/AI = usr - AI.aiPDA.cmd_send_pdamesg(usr) + AI.aiPDA.start_program(AI.aiPDA.find_program(/datum/data/pda/app/messenger)) + AI.aiPDA.cmd_pda_open_ui(usr) if("PDA - Show Message Log") if(isAI(usr)) var/mob/living/silicon/ai/AI = usr - AI.aiPDA.cmd_show_message_log(usr) + AI.aiPDA.start_program(AI.aiPDA.find_program(/datum/data/pda/app/messenger)) + AI.aiPDA.cmd_pda_open_ui(usr) if("Take Image") if(isAI(usr)) diff --git a/code/controllers/subsystems/persistence.dm b/code/controllers/subsystems/persistence.dm index c2724c2d60..00c08363de 100644 --- a/code/controllers/subsystems/persistence.dm +++ b/code/controllers/subsystems/persistence.dm @@ -31,7 +31,7 @@ SUBSYSTEM_DEF(persistence) return // if((!T.z in GLOB.using_map.station_levels) || !initialized) - if(!T.z in using_map.station_levels) + if(!(T.z in using_map.station_levels)) return if(!tracking_values[track_type]) diff --git a/code/controllers/subsystems/supply.dm b/code/controllers/subsystems/supply.dm index 52a8776071..2447a0f122 100644 --- a/code/controllers/subsystems/supply.dm +++ b/code/controllers/subsystems/supply.dm @@ -105,7 +105,7 @@ SUBSYSTEM_DEF(supply) // Sell phoron and platinum if(istype(A, /obj/item/stack)) var/obj/item/stack/P = A - var/material/mat = P.get_material() + var/datum/material/mat = P.get_material() if(mat?.supply_conversion_value) EC.contents[EC.contents.len]["value"] = P.get_amount() * mat.supply_conversion_value EC.contents[EC.contents.len]["quantity"] = P.get_amount() diff --git a/code/controllers/subsystems/ticker.dm b/code/controllers/subsystems/ticker.dm index 31a1de0266..5d6aaf1fc3 100644 --- a/code/controllers/subsystems/ticker.dm +++ b/code/controllers/subsystems/ticker.dm @@ -32,12 +32,6 @@ SUBSYSTEM_DEF(ticker) var/list/datum/mind/minds = list() // The people in the game. Used for objective tracking. - // TODO - I am sure there is a better place these can go. - var/Bible_icon_state // icon_state the chaplain has chosen for his bible - var/Bible_item_state // item_state the chaplain has chosen for his bible - var/Bible_name // name of the bible - var/Bible_deity_name - var/random_players = FALSE // If set to nonzero, ALL players who latejoin or declare-ready join will have random appearances/genders // TODO - Should this go here or in the job subsystem? @@ -567,8 +561,4 @@ var/global/datum/controller/subsystem/ticker/ticker minds = SSticker.minds - Bible_icon_state = SSticker.Bible_icon_state - Bible_item_state = SSticker.Bible_item_state - Bible_name = SSticker.Bible_name - Bible_deity_name = SSticker.Bible_deity_name random_players = SSticker.random_players diff --git a/code/datums/datum.dm b/code/datums/datum.dm index 61eb4c6953..d806728f5d 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -31,5 +31,5 @@ weakref = null // Clear this reference to ensure it's kept for as brief duration as possible. tag = null - SSnanoui.close_uis(src) + SStgui.close_uis(src) return QDEL_HINT_QUEUE diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 10a7b4b7b9..bca9df5ae1 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -85,7 +85,6 @@ current.verbs -= /datum/changeling/proc/EvolutionMenu current.mind = null - SSnanoui.user_transferred(current, new_character) // transfer active NanoUI instances to new user if(new_character.mind) //remove any mind currently in our new body's mind variable new_character.mind.current = null diff --git a/code/datums/repositories/crew.dm b/code/datums/repositories/crew.dm index 7a748049bc..c45202194b 100644 --- a/code/datums/repositories/crew.dm +++ b/code/datums/repositories/crew.dm @@ -38,9 +38,10 @@ var/global/datum/repository/crew/crew_repository = new() crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job") if(C.sensor_mode >= SUIT_SENSOR_BINARY) - crewmemberData["dead"] = H.stat > UNCONSCIOUS + crewmemberData["dead"] = H.stat == DEAD if(C.sensor_mode >= SUIT_SENSOR_VITAL) + crewmemberData["stat"] = H.stat crewmemberData["oxy"] = round(H.getOxyLoss(), 1) crewmemberData["tox"] = round(H.getToxLoss(), 1) crewmemberData["fire"] = round(H.getFireLoss(), 1) diff --git a/code/datums/supplypacks/engineering_vr.dm b/code/datums/supplypacks/engineering_vr.dm index 61c0f0e180..ae02babaca 100644 --- a/code/datums/supplypacks/engineering_vr.dm +++ b/code/datums/supplypacks/engineering_vr.dm @@ -39,3 +39,11 @@ containertype = /obj/structure/closet/crate/secure/engineering containername = "Tesla Generator crate" access = access_ce + +/datum/supply_pack/eng/inducer + contains = list(/obj/item/weapon/inducer = 3) + name = "inducer" + cost = 90 //Relatively expensive + containertype = /obj/structure/closet/crate/xion + containername = "Inducers crate" + access = access_engine diff --git a/code/datums/supplypacks/medical.dm b/code/datums/supplypacks/medical.dm index 1307b8f985..69f198bbd4 100644 --- a/code/datums/supplypacks/medical.dm +++ b/code/datums/supplypacks/medical.dm @@ -32,6 +32,13 @@ containertype = /obj/structure/closet/crate/nanomed containername = "BloodPack crate" +/datum/supply_pack/med/synthplas + name = "BloodPack (Synthplas) crate" + contains = list(/obj/item/weapon/reagent_containers/blood/synthplas = 6) + cost = 80 + containertype = /obj/structure/closet/crate/nanomed + containername = "SynthPlas crate" + /datum/supply_pack/med/bodybag name = "Body bag crate" contains = list(/obj/item/weapon/storage/box/bodybags = 3) diff --git a/code/datums/supplypacks/recreation_vr.dm b/code/datums/supplypacks/recreation_vr.dm index 2e61f93473..5c2266523f 100644 --- a/code/datums/supplypacks/recreation_vr.dm +++ b/code/datums/supplypacks/recreation_vr.dm @@ -64,3 +64,25 @@ cost = 25 containertype = /obj/structure/closet/crate containername = "collar crate" + +/datum/supply_pack/recreation/shiny + name = "Shiny Clothing" + contains = list( + /obj/item/clothing/mask/muzzle/ballgag = 1, + /obj/item/clothing/mask/muzzle/ballgag/ringgag = 1, + /obj/item/clothing/head/shiny_hood = 1, + /obj/item/clothing/head/shiny_hood/poly = 1, + /obj/item/clothing/head/shiny_hood/closed = 1, + /obj/item/clothing/head/shiny_hood/closed/poly = 1, + /obj/item/clothing/under/shiny/catsuit = 1, + /obj/item/clothing/under/shiny/catsuit/poly = 1, + /obj/item/clothing/under/shiny/leotard = 1, + /obj/item/clothing/under/shiny/leotard/poly = 1, + /obj/item/clothing/accessory/shiny/gloves = 1, + /obj/item/clothing/accessory/shiny/gloves/poly = 1, + /obj/item/clothing/accessory/shiny/socks = 1, + /obj/item/clothing/accessory/shiny/socks/poly = 1 + ) + containertype = /obj/structure/closet/crate + containername = "Shiny clothes crate" + cost = 30 diff --git a/code/datums/uplink/announcements.dm b/code/datums/uplink/announcements.dm index 1c4a448cee..e85541a55d 100644 --- a/code/datums/uplink/announcements.dm +++ b/code/datums/uplink/announcements.dm @@ -25,16 +25,7 @@ return list("title" = title, "message" = message) /datum/uplink_item/abstract/announcements/fake_centcom/get_goods(var/obj/item/device/uplink/U, var/loc, var/mob/user, var/list/args) - for (var/obj/machinery/computer/communications/C in machines) - if(! (C.stat & (BROKEN|NOPOWER) ) ) - var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( C.loc ) - P.name = "'[command_name()] Update.'" - P.info = replacetext(args["message"], "\n", "
") - P.update_space(P.info) - P.update_icon() - C.messagetitle.Add(args["title"]) - C.messagetext.Add(P.info) - + post_comm_message(args["title"], replacetext(args["message"], "\n", "
")) command_announcement.Announce(args["message"], args["title"]) return 1 diff --git a/code/datums/uplink/implants.dm b/code/datums/uplink/implants.dm index bbbeaf9e7e..d1bb93acdc 100644 --- a/code/datums/uplink/implants.dm +++ b/code/datums/uplink/implants.dm @@ -73,3 +73,13 @@ name = "Integrated Surge Implant" item_cost = 40 path = /obj/item/weapon/storage/box/syndie_kit/imp_aug/surge + +/datum/uplink_item/item/implants/imp_armblade + name = "Integrated Armblade Implant" + item_cost = 40 + path = /obj/item/weapon/storage/box/syndie_kit/imp_aug/armblade + +/datum/uplink_item/item/implants/imp_handblade + name = "Integrated Handblade Implant" + item_cost = 25 + path = /obj/item/weapon/storage/box/syndie_kit/imp_aug/handblade diff --git a/code/datums/uplink/uplink_items.dm b/code/datums/uplink/uplink_items.dm index cca1933c9c..8d9de8f732 100644 --- a/code/datums/uplink/uplink_items.dm +++ b/code/datums/uplink/uplink_items.dm @@ -51,7 +51,7 @@ var/datum/uplink/uplink = new() if(!can_buy(U)) return - if(U.CanUseTopic(user, inventory_state) != STATUS_INTERACTIVE) + if(U.CanUseTopic(user, GLOB.tgui_inventory_state) != STATUS_INTERACTIVE) return var/cost = cost(U.uses, U) diff --git a/code/datums/vending/stored_item.dm b/code/datums/vending/stored_item.dm index 7c27776aa9..23d06c909a 100644 --- a/code/datums/vending/stored_item.dm +++ b/code/datums/vending/stored_item.dm @@ -2,11 +2,11 @@ * Datum that holds the instances and information about the items stored. Currently used in SmartFridges and Vending Machines. */ /datum/stored_item - var/item_name = "name" //Name of the item(s) displayed - var/item_path = null - var/amount = 0 - var/list/instances //What items are actually stored - var/stored //The thing holding it is + var/item_name = "name" //Name of the item(s) displayed + var/item_path = null + var/amount = 0 + var/list/instances //What items are actually stored + var/stored //The thing holding it is /datum/stored_item/New(var/stored, var/path, var/name = null, var/amount = 0) src.item_path = path diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm index 7efbb84c20..0cb7cbd594 100644 --- a/code/defines/obj/weapon.dm +++ b/code/defines/obj/weapon.dm @@ -10,6 +10,8 @@ w_class = ITEMSIZE_SMALL attack_verb = list("called", "rang") hitsound = 'sound/weapons/ring.ogg' + drop_sound = 'sound/items/drop/device.ogg' + pickup_sound = 'sound/items/pickup/device.ogg' /obj/item/weapon/rsp name = "\improper Rapid-Seed-Producer (RSP)" @@ -22,6 +24,8 @@ var/stored_matter = 0 var/mode = 1 w_class = ITEMSIZE_NORMAL + drop_sound = 'sound/items/drop/device.ogg' + pickup_sound = 'sound/items/pickup/device.ogg' /obj/item/weapon/soap name = "soap" @@ -35,7 +39,6 @@ throwforce = 0 throw_speed = 4 throw_range = 20 - drop_sound = 'sound/misc/slip.ogg' /obj/item/weapon/soap/nanotrasen desc = "A NanoTrasen-brand bar of soap. Smells of phoron." @@ -149,6 +152,8 @@ throw_range = 20 matter = list(DEFAULT_WALL_MATERIAL = 100) origin_tech = list(TECH_MAGNET = 1) + drop_sound = 'sound/items/drop/device.ogg' + pickup_sound = 'sound/items/pickup/device.ogg' /obj/item/weapon/staff name = "wizards staff" @@ -196,6 +201,8 @@ item_state = "std_mod" w_class = ITEMSIZE_SMALL var/mtype = 1 // 1=electronic 2=hardware + drop_sound = 'sound/items/drop/component.ogg' + pickup_sound = 'sound/items/pickup/component.ogg' /obj/item/weapon/module/card_reader name = "card reader module" @@ -227,7 +234,6 @@ item_state = "std_mod" desc = "Charging circuits for power cells." - /obj/item/device/camera_bug name = "camera bug" icon = 'icons/obj/device.dmi' @@ -304,6 +310,8 @@ display_contents_with_number = 1 max_w_class = ITEMSIZE_NORMAL max_storage_space = 100 + drop_sound = 'sound/items/drop/device.ogg' + pickup_sound = 'sound/items/pickup/device.ogg' /obj/item/weapon/storage/part_replacer/adv name = "advanced rapid part exchange device" @@ -332,7 +340,8 @@ icon = 'icons/obj/stock_parts.dmi' w_class = ITEMSIZE_SMALL var/rating = 1 - drop_sound = 'sound/items/drop/glass.ogg' + drop_sound = 'sound/items/drop/component.ogg' + pickup_sound = 'sound/items/pickup/component.ogg' /obj/item/weapon/stock_parts/New() src.pixel_x = rand(-5.0, 5) diff --git a/code/game/antagonist/outsider/ert_vr.dm b/code/game/antagonist/outsider/ert_vr.dm new file mode 100644 index 0000000000..e808272614 --- /dev/null +++ b/code/game/antagonist/outsider/ert_vr.dm @@ -0,0 +1,6 @@ +//boosted ERT spawn/cap numbers to match the Von Braun's spawns, just to be safe. not much point going to all the effort of giving you twelve slots if only seven can ever be used without admin fuckery. -Killian +/datum/antagonist/ert + hard_cap = 12 + hard_cap_round = 12 + initial_spawn_req = 4 + initial_spawn_target = 12 \ No newline at end of file diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm index ddd49703c6..3ed52d317c 100644 --- a/code/game/dna/dna2.dm +++ b/code/game/dna/dna2.dm @@ -280,7 +280,7 @@ var/global/list/datum/dna/gene/dna_genes[0] // Set a DNA UI block's raw value. /datum/dna/proc/SetUIValue(var/block,var/value,var/defer=0) if (block<=0) return - ASSERT(value>0) + ASSERT(value>=0) ASSERT(value<=4095) UI[block]=value dirtyUI=1 @@ -296,7 +296,6 @@ var/global/list/datum/dna/gene/dna_genes[0] // Used in hair and facial styles (value being the index and maxvalue being the len of the hairstyle list) /datum/dna/proc/SetUIValueRange(var/block,var/value,var/maxvalue,var/defer=0) if (block<=0) return - if (value==0) value = 1 // FIXME: hair/beard/eye RGB values if they are 0 are not set, this is a work around we'll encode it in the DNA to be 1 instead. ASSERT(maxvalue<=4095) var/range = (4095 / maxvalue) if(value) @@ -306,7 +305,7 @@ var/global/list/datum/dna/gene/dna_genes[0] /datum/dna/proc/GetUIValueRange(var/block,var/maxvalue) if (block<=0) return 0 var/value = GetUIValue(block) - return round(0.5 + (value / 4096) * maxvalue) + return round(0.5 + (value / 4095) * maxvalue) // Is the UI gene "on" or "off"? // For UI, this is simply a check of if the value is > 2050. @@ -392,7 +391,7 @@ var/global/list/datum/dna/gene/dna_genes[0] /datum/dna/proc/GetSEValueRange(var/block,var/maxvalue) if (block<=0) return 0 var/value = GetSEValue(block) - return round(1 +(value / 4096)*maxvalue) + return round(1 +(value / 4095)*maxvalue) // Is the block "on" (1) or "off" (0)? (Un-assigned genes are always off.) /datum/dna/proc/GetSEState(var/block) diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm index f4fcffbd34..cd3ec6a44d 100644 --- a/code/game/dna/dna2_helpers.dm +++ b/code/game/dna/dna2_helpers.dm @@ -177,7 +177,7 @@ // Ears var/ears = dna.GetUIValueRange(DNA_UI_EAR_STYLE, ear_styles_list.len + 1) - 1 - if(ears <= 1) + if(ears < 1) H.ear_style = null else if((0 < ears) && (ears <= ear_styles_list.len)) H.ear_style = ear_styles_list[ear_styles_list[ears]] @@ -192,14 +192,14 @@ //Tail var/tail = dna.GetUIValueRange(DNA_UI_TAIL_STYLE, tail_styles_list.len + 1) - 1 - if(tail <= 1) + if(tail < 1) H.tail_style = null else if((0 < tail) && (tail <= tail_styles_list.len)) H.tail_style = tail_styles_list[tail_styles_list[tail]] //Wing var/wing = dna.GetUIValueRange(DNA_UI_WING_STYLE, wing_styles_list.len + 1) - 1 - if(wing <= 1) + if(wing < 1) H.wing_style = null else if((0 < wing) && (wing <= wing_styles_list.len)) H.wing_style = wing_styles_list[wing_styles_list[wing]] diff --git a/code/game/gamemodes/changeling/powers/fabricate_clothing.dm b/code/game/gamemodes/changeling/powers/fabricate_clothing.dm index b90b402e78..6ec87a64d4 100644 --- a/code/game/gamemodes/changeling/powers/fabricate_clothing.dm +++ b/code/game/gamemodes/changeling/powers/fabricate_clothing.dm @@ -286,5 +286,5 @@ var/global/list/changeling_fabricated_clothing = list( if(!registered_user) registered_user = usr usr.set_id_info(src) - ui_interact(registered_user) + tgui_interact(registered_user) ..() \ No newline at end of file diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm index 9bb25ec6b4..c946965072 100644 --- a/code/game/jobs/access.dm +++ b/code/game/jobs/access.dm @@ -182,7 +182,7 @@ /proc/get_access_by_id(id) var/list/AS = get_all_access_datums_by_id() - return AS[id] + return AS["[id]"] /proc/get_all_jobs() var/list/all_jobs = list() diff --git a/code/game/jobs/job/captain.dm b/code/game/jobs/job/captain.dm index e767bb5c35..10174fd37b 100644 --- a/code/game/jobs/job/captain.dm +++ b/code/game/jobs/job/captain.dm @@ -29,7 +29,7 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) job_description = "The Site Manager manages the other Command Staff, and through them the rest of the station. Though they have access to everything, \ they do not understand everything, and are expected to delegate tasks to the appropriate crew member. The Site Manager is expected to \ have an understanding of Standard Operating Procedure, and is subject to it, and legal action, in the same way as every other crew member." - alt_titles = list("Overseer"= /datum/alt_title/overseer) + alt_titles = list("Overseer"= /datum/alt_title/overseer,"Colony Director"= /datum/alt_title/colonydirector) //CHOMPEdit //YW UNCOMMENTINGSTART: REINSTATE LOYALTY IMPLANT /datum/job/captain/equip(var/mob/living/carbon/human/H) @@ -46,7 +46,8 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) // Captain Alt Titles /datum/alt_title/overseer title = "Overseer" - +/datum/alt_title/colonydirector //CHOMPEdit + title = "Colony Director" //CHOMPEdit ////////////////////////////////// // Head of Personnel ////////////////////////////////// diff --git a/code/game/jobs/job/civilian_chaplain.dm b/code/game/jobs/job/civilian_chaplain.dm index 93989d2c44..5fba7b155d 100644 --- a/code/game/jobs/job/civilian_chaplain.dm +++ b/code/game/jobs/job/civilian_chaplain.dm @@ -32,136 +32,69 @@ if(!B) return - spawn(0) - var/religion_name = "Unitarianism" - var/new_religion = sanitize(input(H, "You are the crew services officer. Would you like to change your religion? Default is Unitarianism", "Name change", religion_name), MAX_NAME_LEN) + if(GLOB.religion) + B.deity_name = GLOB.deity + B.name = GLOB.bible_name + B.icon_state = GLOB.bible_icon_state + B.item_state = GLOB.bible_item_state + to_chat(H, "There is already an established religion onboard the station. You are an acolyte of [GLOB.deity]. Defer to the [title].") + return + + INVOKE_ASYNC(src, .proc/religion_prompts, H, B) - if (!new_religion) - new_religion = religion_name - switch(lowertext(new_religion)) - if("unitarianism") - B.name = "The Great Canon" - if("christianity") - B.name = "The Holy Bible" - if("judaism") - B.name = "The Torah" - if("islam") - B.name = "Quran" - if("buddhism") - B.name = "Tripitakas" - if("hinduism") - B.name = pick("The Srimad Bhagvatam", "The Four Vedas", "The Shiv Mahapuran", "Devi Mahatmya") - if("neopaganism") - B.name = "Neopagan Hymnbook" - if("phact shintoism") - B.name = "The Kojiki" - if("kishari national faith") - B.name = "The Scriptures of Kishar" - if("pleromanism") - B.name = "The Revised Great Canon" - if("spectralism") - B.name = "The Book of the Spark" - if("hauler") - B.name = "Histories of Captaincy" - if("nock") - B.name = "The Book of the First" - if("singulitarian worship") - B.name = "The Book of the Precursors" - if("starlit path of angessa martei") - B.name = "Quotations of Exalted Martei" - if("sikhism") - B.name = "Guru Granth Sahib" - else - B.name = "The Holy Book of [new_religion]" - feedback_set_details("religion_name","[new_religion]") +/datum/job/chaplain/proc/religion_prompts(mob/living/carbon/human/H, obj/item/weapon/storage/bible/B) + var/religion_name = "Unitarianism" + var/new_religion = sanitize(input(H, "You are the crew services officer. Would you like to change your religion? Default is Unitarianism", "Name change", religion_name), MAX_NAME_LEN) + if(!new_religion) + new_religion = religion_name - spawn(1) - var/deity_name = "Hashem" - var/new_deity = sanitize(input(H, "Would you like to change your deity? Default is Hashem", "Name change", deity_name), MAX_NAME_LEN) + switch(lowertext(new_religion)) + if("unitarianism") + B.name = "The Great Canon" + if("christianity") + B.name = "The Holy Bible" + if("judaism") + B.name = "The Torah" + if("islam") + B.name = "Quran" + if("buddhism") + B.name = "Tripitakas" + if("hinduism") + B.name = pick("The Srimad Bhagvatam", "The Four Vedas", "The Shiv Mahapuran", "Devi Mahatmya") + if("neopaganism") + B.name = "Neopagan Hymnbook" + if("phact shintoism") + B.name = "The Kojiki" + if("kishari national faith") + B.name = "The Scriptures of Kishar" + if("pleromanism") + B.name = "The Revised Great Canon" + if("spectralism") + B.name = "The Book of the Spark" + if("hauler") + B.name = "Histories of Captaincy" + if("nock") + B.name = "The Book of the First" + if("singulitarian worship") + B.name = "The Book of the Precursors" + if("starlit path of angessa martei") + B.name = "Quotations of Exalted Martei" + if("sikhism") + B.name = "Guru Granth Sahib" + else + B.name = "The Holy Book of [new_religion]" + feedback_set_details("religion_name","[new_religion]") - if ((length(new_deity) == 0) || (new_deity == "Hashem") ) - new_deity = deity_name - B.deity_name = new_deity + var/deity_name = "Hashem" + var/new_deity = sanitize(input(H, "Would you like to change your deity? Default is Hashem", "Name change", deity_name), MAX_NAME_LEN) - var/accepted = 0 - var/outoftime = 0 - spawn(200) // 20 seconds to choose - outoftime = 1 - var/new_book_style = "Bible" + if((length(new_deity) == 0) || (new_deity == "Hashem")) + new_deity = deity_name + B.deity_name = new_deity - while(!accepted) - if(!B) break // prevents possible runtime errors - new_book_style = input(H,"Which bible style would you like?") in list("Bible", "Koran", "Scrapbook", "Pagan", "White Bible", "Holy Light", "Athiest", "Tome", "The King in Yellow", "Ithaqua", "Scientology", "the bible melts", "Necronomicon","Orthodox","Torah") - switch(new_book_style) - if("Koran") - B.icon_state = "koran" - B.item_state = "koran" - if("Scrapbook") - B.icon_state = "scrapbook" - B.item_state = "scrapbook" - if("White Bible") - B.icon_state = "white" - B.item_state = "syringe_kit" - if("Holy Light") - B.icon_state = "holylight" - B.item_state = "syringe_kit" - if("Athiest") - B.icon_state = "athiest" - B.item_state = "syringe_kit" - if("Tome") - B.icon_state = "tome" - B.item_state = "syringe_kit" - if("The King in Yellow") - B.icon_state = "kingyellow" - B.item_state = "kingyellow" - if("Ithaqua") - B.icon_state = "ithaqua" - B.item_state = "ithaqua" - if("Scientology") - B.icon_state = "scientology" - B.item_state = "scientology" - if("the bible melts") - B.icon_state = "melted" - B.item_state = "melted" - if("Necronomicon") - B.icon_state = "necronomicon" - B.item_state = "necronomicon" - if("Pagan") - B.icon_state = "shadows" - B.item_state = "syringe_kit" - if("Orthodox") - B.icon_state = "orthodoxy" - B.item_state = "bible" - if("Torah") - B.icon_state = "torah" - B.item_state = "clipboard" - if("Guru") - B.icon_state = "guru" - B.item_state = "clipboard" - else - B.icon_state = "bible" - B.item_state = "bible" + GLOB.religion = new_religion + GLOB.bible_name = B.name + GLOB.deity = B.deity_name + feedback_set_details("religion_deity","[new_deity]") + - H.update_inv_l_hand() // so that it updates the bible's item_state in his hand - - switch(input(H,"Look at your bible - is this what you want?") in list("Yes","No")) - if("Yes") - accepted = 1 - if("No") - if(outoftime) - to_chat(H, "Welp, out of time, buddy. You're stuck. Next time choose faster.") - accepted = 1 - - if(ticker) - ticker.Bible_icon_state = B.icon_state - ticker.Bible_item_state = B.item_state - ticker.Bible_name = B.name - ticker.Bible_deity_name = B.deity_name - feedback_set_details("religion_deity","[new_deity]") - feedback_set_details("religion_book","[new_book_style]") - return 1 - -/* If you uncomment this, every time the mob preview updates it makes a new PDA. It seems to work just fine and display without it, so why this exists, haven't a clue. -Hawk -/datum/job/chaplain/equip_preview(var/mob/living/carbon/human/H, var/alt_title) - return equip(H, alt_title, FALSE) -*/ diff --git a/code/game/jobs/job/exploration_vr.dm b/code/game/jobs/job/exploration_vr.dm index d555c531a2..7f3b57f0b1 100644 --- a/code/game/jobs/job/exploration_vr.dm +++ b/code/game/jobs/job/exploration_vr.dm @@ -130,6 +130,7 @@ var/const/SAR =(1<<14) outfit_type = /decl/hierarchy/outfit/job/assistant/explorer job_description = "Off-duty crew has no responsibilities or authority and is just there to spend their well-deserved time off." pto_type = PTO_EXPLORATION + economic_modifier = 5 /datum/alt_title/offduty_exp - title = "Off-duty Explorer" \ No newline at end of file + title = "Off-duty Explorer" diff --git a/code/game/jobs/job/offduty_vr.dm b/code/game/jobs/job/offduty_vr.dm index 416543956c..1928e242e6 100644 --- a/code/game/jobs/job/offduty_vr.dm +++ b/code/game/jobs/job/offduty_vr.dm @@ -16,6 +16,7 @@ outfit_type = /decl/hierarchy/outfit/job/assistant/worker job_description = "Off-duty crew has no responsibilities or authority and is just there to spend their well-deserved time off." pto_type = PTO_CIVILIAN + economic_modifier = 2 /datum/alt_title/offduty_civ title = "Off-duty Worker" @@ -34,6 +35,7 @@ outfit_type = /decl/hierarchy/outfit/job/assistant/cargo job_description = "Off-duty crew has no responsibilities or authority and is just there to spend their well-deserved time off." pto_type = PTO_CARGO + economic_modifier = 2 /datum/alt_title/offduty_crg title = "Off-duty Cargo" @@ -52,6 +54,7 @@ outfit_type = /decl/hierarchy/outfit/job/assistant/engineer job_description = "Off-duty crew has no responsibilities or authority and is just there to spend their well-deserved time off." pto_type = PTO_ENGINEERING + economic_modifier = 5 /datum/alt_title/offduty_eng title = "Off-duty Engineer" @@ -70,6 +73,7 @@ outfit_type = /decl/hierarchy/outfit/job/assistant/medic job_description = "Off-duty crew has no responsibilities or authority and is just there to spend their well-deserved time off." pto_type = PTO_MEDICAL + economic_modifier = 5 /datum/alt_title/offduty_med title = "Off-duty Medic" @@ -88,6 +92,7 @@ outfit_type = /decl/hierarchy/outfit/job/assistant/scientist job_description = "Off-duty crew has no responsibilities or authority and is just there to spend their well-deserved time off." pto_type = PTO_SCIENCE + economic_modifier = 5 /datum/alt_title/offduty_sci title = "Off-duty Scientist" @@ -106,6 +111,7 @@ outfit_type = /decl/hierarchy/outfit/job/assistant/officer job_description = "Off-duty crew has no responsibilities or authority and is just there to spend their well-deserved time off." pto_type = PTO_SECURITY + economic_modifier = 5 /datum/alt_title/offduty_sec title = "Off-duty Officer" diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index 403efbf4fe..3aec6c8c37 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -540,6 +540,8 @@ var/global/datum/controller/occupations/job_master // EMAIL GENERATION // Email addresses will be created under this domain name. Mostly for the looks. var/domain = "freemail.nt" + if(using_map && LAZYLEN(using_map.usable_email_tlds)) + domain = using_map.usable_email_tlds[1] var/sanitized_name = sanitize(replacetext(replacetext(lowertext(H.real_name), " ", "."), "'", "")) var/complete_login = "[sanitized_name]@[domain]" diff --git a/code/game/jobs/jobs.dm b/code/game/jobs/jobs.dm index 6fc853dba4..d430eacaf3 100644 --- a/code/game/jobs/jobs.dm +++ b/code/game/jobs/jobs.dm @@ -54,7 +54,7 @@ var/list/assistant_occupations = list( var/list/command_positions = list( - "Colony Director", + "Site Manager", "Head of Personnel", "Head of Security", "Chief Engineer", @@ -136,7 +136,7 @@ var/list/nonhuman_positions = list( ) var/list/whitelisted_positions = list( - "Colony Director", + "Site Manager", "Head of Personnel", "Head of Security", "Chief Engineer", diff --git a/code/game/machinery/air_alarm.dm b/code/game/machinery/air_alarm.dm index a5d8759173..d87eae4118 100644 --- a/code/game/machinery/air_alarm.dm +++ b/code/game/machinery/air_alarm.dm @@ -188,7 +188,7 @@ /obj/machinery/alarm/proc/handle_heating_cooling(var/datum/gas_mixture/environment) if(!regulating_temperature) //check for when we should start adjusting temperature - if(!get_danger_level(target_temperature, TLV["temperature"]) && abs(environment.temperature - target_temperature) > 2.0) + if(!get_danger_level(target_temperature, TLV["temperature"]) && abs(environment.temperature - target_temperature) > 2.0 && environment.return_pressure() >= 1) update_use_power(USE_POWER_ACTIVE) regulating_temperature = 1 audible_message("\The [src] clicks as it starts [environment.temperature > target_temperature ? "cooling" : "heating"] the room.",\ @@ -196,7 +196,7 @@ playsound(src, 'sound/machines/click.ogg', 50, 1) else //check for when we should stop adjusting temperature - if(get_danger_level(target_temperature, TLV["temperature"]) || abs(environment.temperature - target_temperature) <= 0.5) + if(get_danger_level(target_temperature, TLV["temperature"]) || abs(environment.temperature - target_temperature) <= 0.5 || environment.return_pressure() < 1) update_use_power(USE_POWER_IDLE) regulating_temperature = 0 audible_message("\The [src] clicks quietly as it stops [environment.temperature > target_temperature ? "cooling" : "heating"] the room.",\ diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm index 6fe30aeaab..2d5e39b1b7 100644 --- a/code/game/machinery/atmoalter/canister.dm +++ b/code/game/machinery/atmoalter/canister.dm @@ -260,7 +260,7 @@ update_flag ..() - SSnanoui.update_uis(src) // Update all NanoUIs attached to src + SStgui.update_uis(src) // Update all NanoUIs attached to src /obj/machinery/portable_atmospherics/canister/attack_ai(var/mob/user as mob) return src.attack_hand(user) diff --git a/code/game/machinery/atmoalter/portable_atmospherics.dm b/code/game/machinery/atmoalter/portable_atmospherics.dm index 915fb8fac1..dc530ecc2f 100644 --- a/code/game/machinery/atmoalter/portable_atmospherics.dm +++ b/code/game/machinery/atmoalter/portable_atmospherics.dm @@ -136,12 +136,6 @@ else to_chat(user, "Nothing happens.") return - - else if ((istype(W, /obj/item/device/analyzer)) && Adjacent(user)) - var/obj/item/device/analyzer/A = W - A.analyze_gases(src, user) - return - return diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 0159c151ec..4351d29698 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -316,7 +316,7 @@ /obj/machinery/autolathe/dismantle() for(var/mat in stored_material) - var/material/M = get_material_by_name(mat) + var/datum/material/M = get_material_by_name(mat) if(!istype(M)) continue var/obj/item/stack/material/S = new M.stack_type(get_turf(src)) @@ -330,7 +330,7 @@ /obj/machinery/autolathe/proc/eject_materials(var/material, var/amount) // 0 amount = 0 means ejecting a full stack; -1 means eject everything var/recursive = amount == -1 ? 1 : 0 var/matstring = lowertext(material) - var/material/M = get_material_by_name(matstring) + var/datum/material/M = get_material_by_name(matstring) var/obj/item/stack/material/S = M.place_sheet(get_turf(src)) if(amount <= 0) diff --git a/code/game/machinery/bomb_tester_vr.dm b/code/game/machinery/bomb_tester_vr.dm index 826f632492..e3a3643526 100644 --- a/code/game/machinery/bomb_tester_vr.dm +++ b/code/game/machinery/bomb_tester_vr.dm @@ -237,12 +237,12 @@ pressure = faketank.return_pressure() var/strength = (pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE - var/mult = ((faketank.volume/140)**(1/2)) * (faketank.total_moles**2/3)/((29*0.64) **2/3) //Don't ask me what this is, see tanks.dm + var/mult = ((faketank.volume/140)**(1/2)) * (faketank.total_moles**(2/3))/((29*0.64) **(2/3)) //Don't ask me what this is, see tanks.dm var/dev = round((mult*strength)*0.15) var/heavy = round((mult*strength)*0.35) var/light = round((mult*strength)*0.80) - simulation_results += "
Final Result: Explosive tank rupture. [dev?"Extreme damage within [2.5*dev] meters. ":""][heavy?"Heavy damage within [2.5*heavy] meters. ":""][light?"Light damage within [2.5*light] meters. ":""]Hazardous shrapnel produced." + simulation_results += "
Final Result: Explosive tank rupture. [dev?"Extreme damage within [2*dev] meters. ":""][heavy?"Heavy damage within [2*heavy] meters. ":""][light?"Light damage within [2*light] meters. ":""]Hazardous shrapnel produced." return 1 else faketank_integrity -= 7 diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 73b78cb148..955ccf596a 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -204,7 +204,9 @@ else P = W itemname = P.name - info = P.notehtml + var/datum/data/pda/app/notekeeper/N = P.find_program(/datum/data/pda/app/notekeeper) + if(N) + info = N.notehtml to_chat(U, "You hold \a [itemname] up to the camera ...") for(var/mob/living/silicon/ai/O in living_mob_list) if(!O.client) diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index 8ef01c9b64..6921cf989c 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -92,8 +92,11 @@ var/blocked = 0 //Player cannot attack/heal while set var/turtle = 0 -/obj/machinery/computer/arcade/battle/New() - ..() +/obj/machinery/computer/arcade/battle/Initialize() + . = ..() + randomize_characters() + +/obj/machinery/computer/arcade/battle/proc/randomize_characters() var/name_action var/name_part1 var/name_part2 @@ -111,17 +114,17 @@ if(..()) return user.set_machine(src) - ui_interact(user) + tgui_interact(user) -/** - * Display the NanoUI window for the arcade machine. - * - * See NanoUI documentation for details. - */ -/obj/machinery/computer/arcade/battle/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/computer/arcade/battle/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ArcadeBattle", name) + ui.open() - var/list/data = list() +/obj/machinery/computer/arcade/battle/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + data["name"] = name data["temp"] = temp data["enemyAction"] = enemy_action data["enemyName"] = enemy_name @@ -129,59 +132,54 @@ data["playerMP"] = player_mp data["enemyHP"] = enemy_hp data["gameOver"] = gameover + return data - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "arcade_battle.tmpl", src.name, 400, 300) - ui.set_initial_data(data) - ui.open() - //ui.set_auto_update(2) - -/obj/machinery/computer/arcade/battle/Topic(href, href_list) +/obj/machinery/computer/arcade/battle/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return 1 + return TRUE - if (!blocked && !gameover) - if (href_list["attack"]) - blocked = 1 - var/attackamt = rand(2,6) - temp = "You attack for [attackamt] damage!" - playsound(src, 'sound/arcade/hit.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE) - if(turtle > 0) - turtle-- + if(!blocked && !gameover) + switch(action) + if("attack") + blocked = 1 + var/attackamt = rand(2,6) + temp = "You attack for [attackamt] damage!" + playsound(src, 'sound/arcade/hit.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE) + if(turtle > 0) + turtle-- - sleep(10) - enemy_hp -= attackamt - arcade_action() + sleep(10) + enemy_hp -= attackamt + arcade_action() - else if (href_list["heal"]) - blocked = 1 - var/pointamt = rand(1,3) - var/healamt = rand(6,8) - temp = "You use [pointamt] magic to heal for [healamt] damage!" - playsound(src, 'sound/arcade/heal.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE) - turtle++ + if("heal") + blocked = 1 + var/pointamt = rand(1,3) + var/healamt = rand(6,8) + temp = "You use [pointamt] magic to heal for [healamt] damage!" + playsound(src, 'sound/arcade/heal.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE) + turtle++ - sleep(10) - player_mp -= pointamt - player_hp += healamt - blocked = 1 - arcade_action() + sleep(10) + player_mp -= pointamt + player_hp += healamt + blocked = 1 + arcade_action() - else if (href_list["charge"]) - blocked = 1 - var/chargeamt = rand(4,7) - temp = "You regain [chargeamt] points" - playsound(src, 'sound/arcade/mana.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE) - player_mp += chargeamt - if(turtle > 0) - turtle-- + if("charge") + blocked = 1 + var/chargeamt = rand(4,7) + temp = "You regain [chargeamt] points" + playsound(src, 'sound/arcade/mana.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE) + player_mp += chargeamt + if(turtle > 0) + turtle-- - sleep(10) - arcade_action() + sleep(10) + arcade_action() - else if (href_list["newgame"]) //Reset everything + if(action == "newgame") //Reset everything temp = "New Round" player_hp = 30 player_mp = 10 @@ -191,12 +189,11 @@ turtle = 0 if(emagged) - src.New() + randomize_characters() emagged = 0 - src.add_fingerprint(usr) - SSnanoui.update_uis(src) - return + add_fingerprint(usr) + return TRUE /obj/machinery/computer/arcade/battle/proc/arcade_action() if ((enemy_mp <= 0) || (enemy_hp <= 0)) @@ -211,7 +208,7 @@ new /obj/item/clothing/head/collectable/petehat(src.loc) message_admins("[key_name_admin(usr)] has outbombed Cuban Pete and been awarded a bomb.") log_game("[key_name_admin(usr)] has outbombed Cuban Pete and been awarded a bomb.") - src.New() + randomize_characters() emagged = 0 else if(!contents.len) feedback_inc("arcade_win_normal") diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 97d68e190a..29783c4c9c 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -36,6 +36,13 @@ return tgui_interact(user) +/obj/machinery/computer/security/attack_robot(mob/user) + if(isrobot(user)) + var/mob/living/silicon/robot/R = user + if(!R.shell) + return attack_hand(user) + ..() + /obj/machinery/computer/security/attack_ai(mob/user) if(isAI(user)) to_chat(user, "You realise its kind of stupid to access a camera console when you have the entire camera network at your metaphorical fingertips") diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index 7833a58d72..0f52e67b8c 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -26,7 +26,7 @@ var/list/formatted = list() for(var/job in jobs) formatted.Add(list(list( - "display_name" = replacetext(job, " ", " "), + "display_name" = replacetext(job, " ", " "), "target_rank" = get_target_rank(), "job" = job))) @@ -68,7 +68,7 @@ id_card.forceMove(src) modify = id_card - SSnanoui.update_uis(src) + SStgui.update_uis(src) attack_hand(user) /obj/machinery/computer/card/attack_ai(var/mob/user as mob) @@ -77,20 +77,27 @@ /obj/machinery/computer/card/attack_hand(mob/user as mob) if(..()) return if(stat & (NOPOWER|BROKEN)) return - ui_interact(user) + tgui_interact(user) -/obj/machinery/computer/card/ui_interact(mob/user, ui_key="main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/computer/card/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "IdentificationComputer", name) + ui.open() +/obj/machinery/computer/card/tgui_static_data(mob/user) + var/list/data = ..() if(data_core) data_core.get_manifest_list() + data["manifest"] = PDA_Manifest + return data + +/obj/machinery/computer/card/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() - var/data[0] - data["src"] = "\ref[src]" data["station_name"] = station_name() data["mode"] = mode data["printing"] = printing - data["manifest"] = PDA_Manifest data["target_name"] = modify ? modify.name : "-----" data["target_owner"] = modify && modify.registered_name ? modify.registered_name : "-----" data["target_rank"] = get_target_rank() @@ -110,27 +117,27 @@ continue if(dept.centcom_only && !is_centcom()) continue - departments[++departments.len] = list("department_name" = dept.name, "jobs" = format_jobs(SSjob.get_job_titles_in_department(dept.name)) ) - + departments.Add(list(list( + "department_name" = dept.name, + "jobs" = format_jobs(SSjob.get_job_titles_in_department(dept.name)) + ))) data["departments"] = departments - if (modify && is_centcom()) - var/list/all_centcom_access = list() + var/list/all_centcom_access = list() + var/list/regions = list() + if(modify && is_centcom()) for(var/access in get_all_centcom_access()) all_centcom_access.Add(list(list( - "desc" = replacetext(get_centcom_access_desc(access), " ", " "), + "desc" = replacetext(get_centcom_access_desc(access), " ", " "), "ref" = access, "allowed" = (access in modify.access) ? 1 : 0))) - - data["all_centcom_access"] = all_centcom_access - else if (modify) - var/list/regions = list() - for(var/i = 1; i <= 7; i++) + else if(modify) + for(var/i in ACCESS_REGION_SECURITY to ACCESS_REGION_SUPPLY) var/list/accesses = list() for(var/access in get_region_accesses(i)) if (get_access_desc(access)) accesses.Add(list(list( - "desc" = replacetext(get_access_desc(access), " ", " "), + "desc" = replacetext(get_access_desc(access), " ", " "), "ref" = access, "allowed" = (access in modify.access) ? 1 : 0))) @@ -138,23 +145,20 @@ "name" = get_region_accesses_name(i), "accesses" = accesses))) - data["regions"] = regions + data["regions"] = regions + data["all_centcom_access"] = all_centcom_access - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "identification_computer.tmpl", src.name, 600, 700) - ui.set_initial_data(data) - ui.open() + return data -/obj/machinery/computer/card/Topic(href, href_list) +/obj/machinery/computer/card/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return 1 + return TRUE - switch(href_list["choice"]) - if ("modify") - if (modify) + switch(action) + if("modify") + if(modify) data_core.manifest_modify(modify.registered_name, modify.assignment) - modify.name = text("[modify.registered_name]'s ID Card ([modify.assignment])") + modify.name = "[modify.registered_name]'s ID Card ([modify.assignment])" if(ishuman(usr)) modify.forceMove(get_turf(src)) if(!usr.get_active_hand()) @@ -165,12 +169,13 @@ modify = null else var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I)) + if(istype(I, /obj/item/weapon/card/id) && usr.unEquip(I)) I.forceMove(src) modify = I + . = TRUE - if ("scan") - if (scan) + if("scan") + if(scan) if(ishuman(usr)) scan.forceMove(get_turf(src)) if(!usr.get_active_hand()) @@ -181,25 +186,26 @@ scan = null else var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id)) + if(istype(I, /obj/item/weapon/card/id)) usr.drop_item() I.forceMove(src) scan = I + . = TRUE if("access") - if(href_list["allowed"]) - if(is_authenticated()) - var/access_type = text2num(href_list["access_target"]) - var/access_allowed = text2num(href_list["allowed"]) - if(access_type in (is_centcom() ? get_all_centcom_access() : get_all_station_access())) - modify.access -= access_type - if(!access_allowed) - modify.access += access_type - modify.lost_access = list() //VOREStation addition: reset the lost access upon any modifications + if(is_authenticated()) + var/access_type = text2num(params["access_target"]) + var/access_allowed = text2num(params["allowed"]) + if(access_type in (is_centcom() ? get_all_centcom_access() : get_all_station_access())) + modify.access -= access_type + if(!access_allowed) + modify.access += access_type + modify.lost_access = list() //VOREStation addition: reset the lost access upon any modifications + . = TRUE - if ("assign") - if (is_authenticated() && modify) - var/t1 = href_list["assign_target"] + if("assign") + if(is_authenticated() && modify) + var/t1 = params["assign_target"] if(t1 == "Custom") var/temp_t = sanitize(input("Enter a custom job assignment.","Assignment"), 45) //let custom jobs function as an impromptu alt title, mainly for sechuds @@ -222,44 +228,42 @@ modify.lost_access = list() //VOREStation addition: reset the lost access upon any modifications callHook("reassign_employee", list(modify)) + . = TRUE - if ("reg") - if (is_authenticated()) - var/t2 = modify - if ((modify == t2 && (in_range(src, usr) || (istype(usr, /mob/living/silicon))) && istype(loc, /turf))) - var/temp_name = sanitizeName(href_list["reg"]) - if(temp_name) - modify.registered_name = temp_name - else - src.visible_message("[src] buzzes rudely.") - SSnanoui.update_uis(src) + if("reg") + if(is_authenticated()) + var/temp_name = sanitizeName(params["reg"]) + if(temp_name) + modify.registered_name = temp_name + else + visible_message("[src] buzzes rudely.") + . = TRUE - if ("account") - if (is_authenticated()) - var/t2 = modify - if ((modify == t2 && (in_range(src, usr) || (istype(usr, /mob/living/silicon))) && istype(loc, /turf))) - var/account_num = text2num(href_list["account"]) - modify.associated_account_number = account_num - SSnanoui.update_uis(src) + if("account") + if(is_authenticated()) + var/account_num = text2num(params["account"]) + modify.associated_account_number = account_num + . = TRUE - if ("mode") - mode = text2num(href_list["mode_target"]) + if("mode") + mode = text2num(params["mode_target"]) + . = TRUE - if ("print") - if (!printing) + if("print") + if(!printing) printing = 1 spawn(50) printing = null - SSnanoui.update_uis(src) + SStgui.update_uis(src) var/obj/item/weapon/paper/P = new(loc) - if (mode) + if(mode) P.name = text("crew manifest ([])", stationtime2text()) P.info = {"

Crew Manifest


[data_core ? data_core.get_manifest(0) : ""] "} - else if (modify) + else if(modify) P.name = "access report" P.info = {"

Access Report

Prepared By: [scan.registered_name ? scan.registered_name : "Unknown"]
@@ -273,19 +277,20 @@ for(var/A in modify.access) P.info += " [get_access_desc(A)]" + . = TRUE - if ("terminate") - if (is_authenticated()) + if("terminate") + if(is_authenticated()) modify.assignment = "Dismissed" //VOREStation Edit: setting adjustment modify.access = list() modify.lost_access = list() //VOREStation addition: reset the lost access upon any modifications callHook("terminate_employee", list(modify)) - if (modify) - modify.name = text("[modify.registered_name]'s ID Card ([modify.assignment])") + . = TRUE - return 1 + if(modify) + modify.name = "[modify.registered_name]'s ID Card ([modify.assignment])" /obj/machinery/computer/card/centcom name = "\improper CentCom ID card modification console" diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 9333e32556..e878aaaf8a 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -9,553 +9,24 @@ light_color = "#0099ff" req_access = list(access_heads) circuit = /obj/item/weapon/circuitboard/communications - var/prints_intercept = 1 - var/authenticated = 0 - var/list/messagetitle = list() - var/list/messagetext = list() - var/currmsg = 0 - var/aicurrmsg = 0 - var/state = STATE_DEFAULT - var/aistate = STATE_DEFAULT - var/message_cooldown = 0 - var/centcomm_message_cooldown = 0 - var/tmp_alertlevel = 0 - var/const/STATE_DEFAULT = 1 - var/const/STATE_CALLSHUTTLE = 2 - var/const/STATE_CANCELSHUTTLE = 3 - var/const/STATE_MESSAGELIST = 4 - var/const/STATE_VIEWMESSAGE = 5 - var/const/STATE_DELMESSAGE = 6 - var/const/STATE_STATUSDISPLAY = 7 - var/const/STATE_ALERT_LEVEL = 8 - var/const/STATE_CONFIRM_LEVEL = 9 - var/const/STATE_CREWTRANSFER = 10 - var/status_display_freq = "1435" - var/stat_msg1 - var/stat_msg2 + var/datum/tgui_module/communications/communications - var/datum/lore/atc_controller/ATC - var/datum/announcement/priority/crew_announcement = new - -/obj/machinery/computer/communications/New() - ..() - ATC = atc - crew_announcement.newscast = 1 - -/obj/machinery/computer/communications/process() - if(..()) - if(state != STATE_STATUSDISPLAY) - src.updateDialog() - - -/obj/machinery/computer/communications/Topic(href, href_list) - if(..()) - return 1 - if (using_map && !(src.z in using_map.contact_levels)) - to_chat(usr, "Unable to establish a connection: You're too far away from the station!") - return - usr.set_machine(src) - - if(!href_list["operation"]) - return - switch(href_list["operation"]) - // main interface - if("main") - src.state = STATE_DEFAULT - if("login") - var/mob/M = usr - var/obj/item/weapon/card/id/I = M.GetIdCard() - if (I && istype(I)) - if(src.check_access(I)) - authenticated = 1 - if(access_captain in I.access) - authenticated = 2 - crew_announcement.announcer = GetNameAndAssignmentFromId(I) - if("logout") - authenticated = 0 - crew_announcement.announcer = "" - - if("swipeidseclevel") - if(src.authenticated) //Let heads change the alert level. - var/old_level = security_level - if(!tmp_alertlevel) tmp_alertlevel = SEC_LEVEL_GREEN - if(tmp_alertlevel < SEC_LEVEL_GREEN) tmp_alertlevel = SEC_LEVEL_GREEN - if(tmp_alertlevel > SEC_LEVEL_BLUE) tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this - set_security_level(tmp_alertlevel) - if(security_level != old_level) - //Only notify the admins if an actual change happened - log_game("[key_name(usr)] has changed the security level to [get_security_level()].") - message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].") - switch(security_level) - if(SEC_LEVEL_GREEN) - feedback_inc("alert_comms_green",1) - if(SEC_LEVEL_YELLOW) - feedback_inc("alert_comms_yellow",1) - if(SEC_LEVEL_VIOLET) - feedback_inc("alert_comms_violet",1) - if(SEC_LEVEL_ORANGE) - feedback_inc("alert_comms_orange",1) - if(SEC_LEVEL_BLUE) - feedback_inc("alert_comms_blue",1) - tmp_alertlevel = 0 - state = STATE_DEFAULT - - if("announce") - if(src.authenticated==2) - if(message_cooldown) - to_chat(usr, "Please allow at least one minute to pass between announcements") - return - var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement") as null|message - if(!input || !(usr in view(1,src))) - return - crew_announcement.Announce(input) - message_cooldown = 1 - spawn(600)//One minute cooldown - message_cooldown = 0 - - if("callshuttle") - src.state = STATE_DEFAULT - if(src.authenticated) - src.state = STATE_CALLSHUTTLE - if("callshuttle2") - if(src.authenticated) - call_shuttle_proc(usr) - if(emergency_shuttle.online()) - post_status("shuttle") - src.state = STATE_DEFAULT - if("cancelshuttle") - src.state = STATE_DEFAULT - if(src.authenticated) - src.state = STATE_CANCELSHUTTLE - if("cancelshuttle2") - if(src.authenticated) - cancel_call_proc(usr) - src.state = STATE_DEFAULT - if("messagelist") - src.currmsg = 0 - src.state = STATE_MESSAGELIST - if("toggleatc") - src.ATC.squelched = !src.ATC.squelched - if("viewmessage") - src.state = STATE_VIEWMESSAGE - if (!src.currmsg) - if(href_list["message-num"]) - src.currmsg = text2num(href_list["message-num"]) - else - src.state = STATE_MESSAGELIST - if("delmessage") - src.state = (src.currmsg) ? STATE_DELMESSAGE : STATE_MESSAGELIST - if("delmessage2") - if(src.authenticated) - if(src.currmsg) - var/title = src.messagetitle[src.currmsg] - var/text = src.messagetext[src.currmsg] - src.messagetitle.Remove(title) - src.messagetext.Remove(text) - if(src.currmsg == src.aicurrmsg) - src.aicurrmsg = 0 - src.currmsg = 0 - src.state = STATE_MESSAGELIST - else - src.state = STATE_VIEWMESSAGE - if("status") - src.state = STATE_STATUSDISPLAY - - // Status display stuff - if("setstat") - switch(href_list["statdisp"]) - if("message") - post_status("message", stat_msg1, stat_msg2) - if("alert") - post_status("alert", href_list["alert"]) - else - post_status(href_list["statdisp"]) - - if("setmsg1") - stat_msg1 = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", stat_msg1) as text|null, 40), 40) - src.updateDialog() - if("setmsg2") - stat_msg2 = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", stat_msg2) as text|null, 40), 40) - src.updateDialog() - - // OMG CENTCOMM LETTERHEAD - if("MessageCentCom") - if(src.authenticated==2) - if(centcomm_message_cooldown) - to_chat(usr, "Arrays recycling. Please stand by.") - return - var/input = sanitize(input("Please choose a message to transmit to [using_map.boss_short] via quantum entanglement. \ - Please be aware that this process is very expensive, and abuse will lead to... termination. \ - Transmission does not guarantee a response. \ - There is a 30 second delay before you may send another message, be clear, full and concise.", "Central Command Quantum Messaging") as null|message) - if(!input || !(usr in view(1,src))) - return - CentCom_announce(input, usr) - to_chat(usr, "Message transmitted.") - log_game("[key_name(usr)] has made an IA [using_map.boss_short] announcement: [input]") - centcomm_message_cooldown = 1 - spawn(300)//10 minute cooldown - centcomm_message_cooldown = 0 - - - // OMG SYNDICATE ...LETTERHEAD - if("MessageSyndicate") - if((src.authenticated==2) && (src.emagged)) - if(centcomm_message_cooldown) - to_chat(usr, "Arrays recycling. Please stand by.") - return - var/input = sanitize(input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "")) - if(!input || !(usr in view(1,src))) - return - Syndicate_announce(input, usr) - to_chat(usr, "Message transmitted.") - log_game("[key_name(usr)] has made an illegal announcement: [input]") - centcomm_message_cooldown = 1 - spawn(300)//10 minute cooldown - centcomm_message_cooldown = 0 - - if("RestoreBackup") - to_chat(usr, "Backup routing data restored!") - src.emagged = 0 - src.updateDialog() - - - - // AI interface - if("ai-main") - src.aicurrmsg = 0 - src.aistate = STATE_DEFAULT - if("ai-callshuttle") - src.aistate = STATE_CALLSHUTTLE - if("ai-callshuttle2") - call_shuttle_proc(usr) - src.aistate = STATE_DEFAULT - if("ai-messagelist") - src.aicurrmsg = 0 - src.aistate = STATE_MESSAGELIST - if("ai-viewmessage") - src.aistate = STATE_VIEWMESSAGE - if (!src.aicurrmsg) - if(href_list["message-num"]) - src.aicurrmsg = text2num(href_list["message-num"]) - else - src.aistate = STATE_MESSAGELIST - if("ai-delmessage") - src.aistate = (src.aicurrmsg) ? STATE_DELMESSAGE : STATE_MESSAGELIST - if("ai-delmessage2") - if(src.aicurrmsg) - var/title = src.messagetitle[src.aicurrmsg] - var/text = src.messagetext[src.aicurrmsg] - src.messagetitle.Remove(title) - src.messagetext.Remove(text) - if(src.currmsg == src.aicurrmsg) - src.currmsg = 0 - src.aicurrmsg = 0 - src.aistate = STATE_MESSAGELIST - if("ai-status") - src.aistate = STATE_STATUSDISPLAY - - if("securitylevel") - src.tmp_alertlevel = text2num( href_list["newalertlevel"] ) - if(!tmp_alertlevel) tmp_alertlevel = 0 - state = STATE_CONFIRM_LEVEL - - if("changeseclevel") - state = STATE_ALERT_LEVEL - - - - src.updateUsrDialog() +/obj/machinery/computer/communications/Initialize() + . = ..() + communications = new(src) /obj/machinery/computer/communications/emag_act(var/remaining_charges, var/mob/user) if(!emagged) - src.emagged = 1 + emagged = TRUE + communications.emagged = TRUE to_chat(user, "You scramble the communication routing circuits!") - return 1 + return TRUE -/obj/machinery/computer/communications/attack_ai(var/mob/user as mob) - return src.attack_hand(user) +/obj/machinery/computer/communications/attack_ai(mob/user) + return attack_hand(user) -/obj/machinery/computer/communications/attack_hand(var/mob/user as mob) +/obj/machinery/computer/communications/attack_hand(mob/user) if(..()) return - if (using_map && !(src.z in using_map.contact_levels)) - to_chat(user, "Unable to establish a connection: You're too far away from the station!") - return - - user.set_machine(src) - var/dat = "Communications Console" - if (emergency_shuttle.has_eta()) - var/timeleft = emergency_shuttle.estimate_arrival_time() - dat += "Emergency shuttle\n
\nETA: [timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]
" - - if (istype(user, /mob/living/silicon)) - var/dat2 = src.interact_ai(user) // give the AI a different interact proc to limit its access - if(dat2) - dat += dat2 - user << browse(dat, "window=communications;size=400x500") - onclose(user, "communications") - return - - switch(src.state) - if(STATE_DEFAULT) - if (src.authenticated) - dat += "
\[ Log Out \]" - if (src.authenticated==2) - dat += "
\[ Make An Announcement \]" - if(src.emagged == 0) - dat += "
\[ Send an emergency message to [using_map.boss_short] \]" - else - dat += "
\[ Send an emergency message to \[UNKNOWN\] \]" - dat += "
\[ Restore Backup Routing Data \]" - - dat += "
\[ Change alert level \]" - if(emergency_shuttle.location()) - if (emergency_shuttle.online()) - dat += "
\[ Cancel Shuttle Call \]" - else - dat += "
\[ Call Emergency Shuttle \]" - - dat += "
\[ Set Status Display \]" - else - dat += "
\[ Log In \]" - dat += "
\[ Message List \]" - dat += "
\[ [ATC.squelched ? "Enable" : "Disable"] ATC Relay \]" - if(STATE_CALLSHUTTLE) - dat += "Are you sure you want to call the shuttle? \[ OK | Cancel \]" - if(STATE_CANCELSHUTTLE) - dat += "Are you sure you want to cancel the shuttle? \[ OK | Cancel \]" - if(STATE_MESSAGELIST) - dat += "Messages:" - for(var/i = 1; i<=src.messagetitle.len; i++) - dat += "
[src.messagetitle[i]]" - if(STATE_VIEWMESSAGE) - if (src.currmsg) - dat += "[src.messagetitle[src.currmsg]]

[src.messagetext[src.currmsg]]" - if (src.authenticated) - dat += "

\[ Delete \]" - else - src.state = STATE_MESSAGELIST - src.attack_hand(user) - return - if(STATE_DELMESSAGE) - if (src.currmsg) - dat += "Are you sure you want to delete this message? \[ OK | Cancel \]" - else - src.state = STATE_MESSAGELIST - src.attack_hand(user) - return - if(STATE_STATUSDISPLAY) - dat += "Set Status Displays
" - dat += "\[ Clear \]
" - dat += "\[ Station Time \]
" - dat += "\[ Shuttle ETA \]
" - dat += "\[ Message \]" - dat += "
" - dat += "\[ Alert: None |" - dat += " Red Alert |" - dat += " Lockdown |" - dat += " Biohazard \]

" - if(STATE_ALERT_LEVEL) - dat += "Current alert level: [get_security_level()]
" - if(security_level == SEC_LEVEL_DELTA) - dat += "The self-destruct mechanism is active. Find a way to deactivate the mechanism to lower the alert level or evacuate." - else - dat += "Blue
" - dat += "Orange
" - dat += "Violet
" - dat += "Yellow
" - dat += "Green" - if(STATE_CONFIRM_LEVEL) - dat += "Current alert level: [get_security_level()]
" - dat += "Confirm the change to: [num2seclevel(tmp_alertlevel)]
" - dat += "OK to confirm change.
" - - dat += "
\[ [(src.state != STATE_DEFAULT) ? "Main Menu | " : ""]Close \]" - user << browse(dat, "window=communications;size=400x500") - onclose(user, "communications") - - - - -/obj/machinery/computer/communications/proc/interact_ai(var/mob/living/silicon/ai/user as mob) - var/dat = "" - switch(src.aistate) - if(STATE_DEFAULT) - if(emergency_shuttle.location() && !emergency_shuttle.online()) - dat += "
\[ Call Emergency Shuttle \]" - dat += "
\[ Message List \]" - dat += "
\[ Set Status Display \]" - dat += "
\[ [ATC.squelched ? "Enable" : "Disable"] ATC Relay \]" - if(STATE_CALLSHUTTLE) - dat += "Are you sure you want to call the shuttle? \[ OK | Cancel \]" - if(STATE_MESSAGELIST) - dat += "Messages:" - for(var/i = 1; i<=src.messagetitle.len; i++) - dat += "
[src.messagetitle[i]]" - if(STATE_VIEWMESSAGE) - if (src.aicurrmsg) - dat += "[src.messagetitle[src.aicurrmsg]]

[src.messagetext[src.aicurrmsg]]" - dat += "

\[ Delete \]" - else - src.aistate = STATE_MESSAGELIST - src.attack_hand(user) - return null - if(STATE_DELMESSAGE) - if(src.aicurrmsg) - dat += "Are you sure you want to delete this message? \[ OK | Cancel \]" - else - src.aistate = STATE_MESSAGELIST - src.attack_hand(user) - return - - if(STATE_STATUSDISPLAY) - dat += "Set Status Displays
" - dat += "\[ Clear \]
" - dat += "\[ Station Time \]
" - dat += "\[ Shuttle ETA \]
" - dat += "\[ Message \]" - dat += "
" - dat += "\[ Alert: None |" - dat += " Red Alert |" - dat += " Lockdown |" - dat += " Biohazard \]

" - - - dat += "
\[ [(src.aistate != STATE_DEFAULT) ? "Main Menu | " : ""]Close \]" - return dat - -/proc/enable_prison_shuttle(var/mob/user) - for(var/obj/machinery/computer/prison_shuttle/PS in machines) - PS.allowedtocall = !(PS.allowedtocall) - -/proc/call_shuttle_proc(var/mob/user) - if ((!( ticker ) || !emergency_shuttle.location())) - return - - if(!universe.OnShuttleCall(usr)) - to_chat(user, "Cannot establish a bluespace connection.") - return - - if(deathsquad.deployed) - to_chat(user, "[using_map.boss_short] will not allow the shuttle to be called. Consider all contracts terminated.") - return - - if(emergency_shuttle.deny_shuttle) - to_chat(user, "The emergency shuttle may not be sent at this time. Please try again later.") - return - - if(world.time < 6000) // Ten minute grace period to let the game get going without lolmetagaming. -- TLE - to_chat(user, "The emergency shuttle is refueling. Please wait another [round((6000-world.time)/600)] minute\s before trying again.") - return - - if(emergency_shuttle.going_to_centcom()) - to_chat(user, "The emergency shuttle may not be called while returning to [using_map.boss_short].") - return - - if(emergency_shuttle.online()) - to_chat(user, "The emergency shuttle is already on its way.") - return - - if(ticker.mode.name == "blob") - to_chat(user, "Under directive 7-10, [station_name()] is quarantined until further notice.") - return - - emergency_shuttle.call_evac() - log_game("[key_name(user)] has called the shuttle.") - message_admins("[key_name_admin(user)] has called the shuttle.", 1) - admin_chat_message(message = "Emergency evac beginning! Called by [key_name(user)]!", color = "#CC2222") //VOREStation Add - - - return - -/proc/init_shift_change(var/mob/user, var/force = 0) - if ((!( ticker ) || !emergency_shuttle.location())) - return - - if(emergency_shuttle.going_to_centcom()) - to_chat(user, "The shuttle may not be called while returning to [using_map.boss_short].") - return - - if(emergency_shuttle.online()) - to_chat(user, "The shuttle is already on its way.") - return - - // if force is 0, some things may stop the shuttle call - if(!force) - if(emergency_shuttle.deny_shuttle) - to_chat(user, "[using_map.boss_short] does not currently have a shuttle available in your sector. Please try again later.") - return - - if(deathsquad.deployed == 1) - to_chat(user, "[using_map.boss_short] will not allow the shuttle to be called. Consider all contracts terminated.") - return - - if(world.time < 54000) // 30 minute grace period to let the game get going - to_chat(user, "The shuttle is refueling. Please wait another [round((54000-world.time)/60)] minutes before trying again.") - return - - if(ticker.mode.auto_recall_shuttle) - //New version pretends to call the shuttle but cause the shuttle to return after a random duration. - emergency_shuttle.auto_recall = 1 - - if(ticker.mode.name == "blob" || ticker.mode.name == "epidemic") - to_chat(user, "Under directive 7-10, [station_name()] is quarantined until further notice.") - return - - emergency_shuttle.call_transfer() - - //delay events in case of an autotransfer - if (isnull(user)) - SSevents.delay_events(EVENT_LEVEL_MODERATE, 9000) //15 minutes - SSevents.delay_events(EVENT_LEVEL_MAJOR, 9000) - - log_game("[user? key_name(user) : "Autotransfer"] has called the shuttle.") - message_admins("[user? key_name_admin(user) : "Autotransfer"] has called the shuttle.", 1) - admin_chat_message(message = "Autotransfer shuttle dispatched, shift ending soon.", color = "#2277BB") //VOREStation Add - - return - -/proc/cancel_call_proc(var/mob/user) - if (!( ticker ) || !emergency_shuttle.can_recall()) - return - if((ticker.mode.name == "blob")||(ticker.mode.name == "Meteor")) - return - - if(!emergency_shuttle.going_to_centcom()) //check that shuttle isn't already heading to CentCom - emergency_shuttle.recall() - log_game("[key_name(user)] has recalled the shuttle.") - message_admins("[key_name_admin(user)] has recalled the shuttle.", 1) - return - - -/proc/is_relay_online() - for(var/obj/machinery/telecomms/relay/M in world) - if(M.stat == 0) - return 1 - return 0 - -/obj/machinery/computer/communications/proc/post_status(var/command, var/data1, var/data2) - - var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) - - if(!frequency) return - - var/datum/signal/status_signal = new - status_signal.source = src - status_signal.transmission_method = TRANSMISSION_RADIO - status_signal.data["command"] = command - - switch(command) - if("message") - status_signal.data["msg1"] = data1 - status_signal.data["msg2"] = data2 - log_admin("STATUS: [src.fingerprintslast] set status screen message with [src]: [data1] [data2]") - //message_admins("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]") - if("alert") - status_signal.data["picture_state"] = data1 - - frequency.post_signal(src, status_signal) + communications.tgui_interact(user) diff --git a/code/game/machinery/computer/guestpass.dm b/code/game/machinery/computer/guestpass.dm index af9201e94c..b0531e8438 100644 --- a/code/game/machinery/computer/guestpass.dm +++ b/code/game/machinery/computer/guestpass.dm @@ -13,14 +13,14 @@ var/reason = "NOT SPECIFIED" /obj/item/weapon/card/id/guest/GetAccess() - if (world.time > expiration_time) + if(world.time > expiration_time) return access else return temp_access /obj/item/weapon/card/id/guest/examine(mob/user) . = ..() - if (world.time < expiration_time) + if(world.time < expiration_time) . += "This pass expires at [worldtime2stationtime(expiration_time)]." else . += "It expired at [worldtime2stationtime(expiration_time)]." @@ -28,7 +28,7 @@ /obj/item/weapon/card/id/guest/read() if(!Adjacent(usr)) return //Too far to read - if (world.time > expiration_time) + if(world.time > expiration_time) to_chat(usr, "This pass expired at [worldtime2stationtime(expiration_time)].") else to_chat(usr, "This pass expires at [worldtime2stationtime(expiration_time)].") @@ -105,7 +105,7 @@ if(!giver && user.unEquip(I)) I.forceMove(src) giver = I - SSnanoui.update_uis(src) + SStgui.update_uis(src) else if(giver) to_chat(user, "There is already ID card inside.") return @@ -119,128 +119,120 @@ return user.set_machine(src) + tgui_interact(user) - ui_interact(user) +/obj/machinery/computer/guestpass/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "GuestPass", name) + ui.open() -/** - * Display the NanoUI window for the guest pass console. - * - * See NanoUI documentation for details. - */ -/obj/machinery/computer/guestpass/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/computer/guestpass/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() - var/list/data = list() + var/list/area_list = list() - var/area_list[0] - - if (giver && giver.access) + data["access"] = null + if(giver && giver.access) data["access"] = giver.access for (var/A in giver.access) if(A in accesses) - area_list[++area_list.len] = list("area" = A, "area_name" = get_access_desc(A), "on" = 1) + area_list.Add(list(list("area" = A, "area_name" = get_access_desc(A), "on" = 1))) else - area_list[++area_list.len] = list("area" = A, "area_name" = get_access_desc(A), "on" = null) + area_list.Add(list(list("area" = A, "area_name" = get_access_desc(A), "on" = null))) + data["area"] = area_list data["giver"] = giver data["giveName"] = giv_name data["reason"] = reason data["duration"] = duration - data["area"] = area_list data["mode"] = mode data["log"] = internal_log data["uid"] = uid - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "guest_pass.tmpl", src.name, 400, 520) - ui.set_initial_data(data) - ui.open() - //ui.set_auto_update(5) + return data -/obj/machinery/computer/guestpass/Topic(href, href_list) +/obj/machinery/computer/guestpass/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return 1 - usr.set_machine(src) - if (href_list["mode"]) - mode = href_list["mode"] + return TRUE - if (href_list["choice"]) - switch(href_list["choice"]) - if ("giv_name") - var/nam = sanitizeName(input("Person pass is issued to", "Name", giv_name) as text|null) - if (nam) - giv_name = nam - if ("reason") - var/reas = sanitize(input("Reason why pass is issued", "Reason", reason) as text|null) - if(reas) - reason = reas - if ("duration") - var/dur = input("Duration (in minutes) during which pass is valid (up to 120 minutes).", "Duration") as num|null - if (dur) - if (dur > 0 && dur <= 120) - duration = dur - else - to_chat(usr, "Invalid duration.") - if ("access") - var/A = text2num(href_list["access"]) - if (A in accesses) - accesses.Remove(A) + switch(action) + if("mode") + mode = params["mode"] + + if("giv_name") + var/nam = sanitizeName(input("Person pass is issued to", "Name", giv_name) as text|null) + if(nam) + giv_name = nam + if("reason") + var/reas = sanitize(input("Reason why pass is issued", "Reason", reason) as text|null) + if(reas) + reason = reas + if("duration") + var/dur = input("Duration (in minutes) during which pass is valid (up to 120 minutes).", "Duration") as num|null + if(dur) + if(dur > 0 && dur <= 120) + duration = dur else - if(A in giver.access) //Let's make sure the ID card actually has the access. - accesses.Add(A) - else - to_chat(usr, "Invalid selection, please consult technical support if there are any issues.") - log_debug("[key_name_admin(usr)] tried selecting an invalid guest pass terminal option.") - if (href_list["action"]) - switch(href_list["action"]) - if ("id") - if (giver) - if(ishuman(usr)) - giver.loc = usr.loc - if(!usr.get_active_hand()) - usr.put_in_hands(giver) - giver = null - else - giver.loc = src.loc - giver = null - accesses.Cut() + to_chat(usr, "Invalid duration.") + if("access") + var/A = text2num(params["access"]) + if(A in accesses) + accesses.Remove(A) + else + if(A in giver.access) //Let's make sure the ID card actually has the access. + accesses.Add(A) else - var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I)) - I.loc = src - giver = I - - if ("print") - var/dat = "

Activity log of guest pass terminal #[uid]


" - for (var/entry in internal_log) - dat += "[entry]

" - //to_chat(usr, "Printing the log, standby...") - //sleep(50) - var/obj/item/weapon/paper/P = new/obj/item/weapon/paper( loc ) - P.name = "activity log" - P.info = dat - - if ("issue") - if (giver) - var/number = add_zero("[rand(0,9999)]", 4) - var/entry = "\[[stationtime2text()]\] Pass #[number] issued by [giver.registered_name] ([giver.assignment]) to [giv_name]. Reason: [reason]. Grants access to following areas: " - for (var/i=1 to accesses.len) - var/A = accesses[i] - if (A) - var/area = get_access_desc(A) - entry += "[i > 1 ? ", [area]" : "[area]"]" - entry += ". Expires at [worldtime2stationtime(world.time + duration*10*60)]." - internal_log.Add(entry) - - var/obj/item/weapon/card/id/guest/pass = new(src.loc) - pass.temp_access = accesses.Copy() - pass.registered_name = giv_name - pass.expiration_time = world.time + duration*10*60 - pass.reason = reason - pass.name = "guest pass #[number]" + to_chat(usr, "Invalid selection, please consult technical support if there are any issues.") + log_debug("[key_name_admin(usr)] tried selecting an invalid guest pass terminal option.") + if("id") + if(giver) + if(ishuman(usr)) + giver.loc = usr.loc + if(!usr.get_active_hand()) + usr.put_in_hands(giver) + giver = null else - to_chat(usr, "Cannot issue pass without issuing ID.") + giver.loc = src.loc + giver = null + accesses.Cut() + else + var/obj/item/I = usr.get_active_hand() + if(istype(I, /obj/item/weapon/card/id) && usr.unEquip(I)) + I.loc = src + giver = I + + if("print") + var/dat = "

Activity log of guest pass terminal #[uid]


" + for (var/entry in internal_log) + dat += "[entry]

" + //to_chat(usr, "Printing the log, standby...") + //sleep(50) + var/obj/item/weapon/paper/P = new/obj/item/weapon/paper( loc ) + P.name = "activity log" + P.info = dat + + if("issue") + if(giver) + var/number = add_zero("[rand(0,9999)]", 4) + var/entry = "\[[stationtime2text()]\] Pass #[number] issued by [giver.registered_name] ([giver.assignment]) to [giv_name]. Reason: [reason]. Grants access to following areas: " + for (var/i=1 to accesses.len) + var/A = accesses[i] + if(A) + var/area = get_access_desc(A) + entry += "[i > 1 ? ", [area]" : "[area]"]" + entry += ". Expires at [worldtime2stationtime(world.time + duration*10*60)]." + internal_log.Add(entry) + + var/obj/item/weapon/card/id/guest/pass = new(src.loc) + pass.temp_access = accesses.Copy() + pass.registered_name = giv_name + pass.expiration_time = world.time + duration*10*60 + pass.reason = reason + pass.name = "guest pass #[number]" + else + to_chat(usr, "Cannot issue pass without issuing ID.") + + add_fingerprint(usr) + return TRUE - src.add_fingerprint(usr) - SSnanoui.update_uis(src) diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm index 1dc0709ed3..1caa7b61a4 100644 --- a/code/game/machinery/computer/message.dm +++ b/code/game/machinery/computer/message.dm @@ -131,7 +131,10 @@ //Get out list of viable PDAs var/list/obj/item/device/pda/sendPDAs = list() for(var/obj/item/device/pda/P in PDAs) - if(!P.owner || P.toff || P.hidden) + if(!P.owner || P.hidden) + continue + var/datum/data/pda/app/messenger/M = P.find_program(/datum/data/pda/app/messenger) + if(!M || M.toff) continue sendPDAs["[P.name]"] = "\ref[P]" data["possibleRecipients"] = sendPDAs @@ -265,7 +268,11 @@ if("set_recipient") var/ref = params["val"] var/obj/item/device/pda/P = locate(ref) - if(!istype(P) || !P.owner || P.toff || P.hidden) + if(!istype(P) || !P.owner || P.hidden) + return FALSE + + var/datum/data/pda/app/messenger/M = P.find_program(/datum/data/pda/app/messenger) + if(!M || M.toff) return FALSE customrecepient = P . = TRUE @@ -286,22 +293,26 @@ var/obj/item/device/pda/PDARec = null for(var/obj/item/device/pda/P in PDAs) - if(!P.owner || P.toff || P.hidden) continue + if(!P.owner || P.hidden) + continue + var/datum/data/pda/app/messenger/M = P.find_program(/datum/data/pda/app/messenger) + if(!M || M.toff) + continue if(P.owner == customsender) PDARec = P //Sender isn't faking as someone who exists if(isnull(PDARec)) linkedServer.send_pda_message("[customrecepient.owner]", "[customsender]","[custommessage]") - customrecepient.new_message(customsender, customsender, customjob, custommessage) + var/datum/data/pda/app/messenger/M = customrecepient.find_program(/datum/data/pda/app/messenger) + if(M) + M.receive_message(list("sent" = 0, "owner" = customsender, "job" = customjob, "message" = custommessage), null) //Sender is faking as someone who exists else linkedServer.send_pda_message("[customrecepient.owner]", "[PDARec.owner]","[custommessage]") - customrecepient.tnote.Add(list(list("sent" = 0, "owner" = "[PDARec.owner]", "job" = "[customjob]", "message" = "[custommessage]", "target" ="\ref[PDARec]"))) - - if(!customrecepient.conversations.Find("\ref[PDARec]")) - customrecepient.conversations.Add("\ref[PDARec]") - - customrecepient.new_message(PDARec, custommessage) + + var/datum/data/pda/app/messenger/M = customrecepient.find_program(/datum/data/pda/app/messenger) + if(M) + M.receive_message(list("sent" = 0, "owner" = "[PDARec.owner]", "job" = "[customjob]", "message" = "[custommessage]", "target" = "\ref[PDARec]"), "\ref[PDARec]") //Finally.. ResetMessage() . = TRUE diff --git a/code/game/machinery/computer/timeclock_vr.dm b/code/game/machinery/computer/timeclock_vr.dm index 85924d79f6..8cfc711c18 100644 --- a/code/game/machinery/computer/timeclock_vr.dm +++ b/code/game/machinery/computer/timeclock_vr.dm @@ -55,7 +55,7 @@ if(!card && user.unEquip(I)) I.forceMove(src) card = I - SSnanoui.update_uis(src) + SStgui.update_uis(src) update_icon() else if(card) to_chat(user, "There is already ID card inside.") @@ -66,23 +66,33 @@ if(..()) return user.set_machine(src) - ui_interact(user) + tgui_interact(user) -/obj/machinery/computer/timeclock/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/computer/timeclock/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TimeClock", name) + ui.open() + +/obj/machinery/computer/timeclock/tgui_data(mob/user) + var/list/data = ..() - var/list/data = list() // Okay, data for showing the user's OWN PTO stuff if(user.client) data["department_hours"] = SANITIZE_LIST(user.client.department_hours) data["user_name"] = "[user]" // Data about the card that we put into it. + data["card"] = null + data["assignment"] = null + data["job_datum"] = null + data["allow_change_job"] = null + data["job_choices"] = null if(card) data["card"] = "[card]" data["assignment"] = card.assignment var/datum/job/job = job_master.GetJob(card.rank) - if (job) + if(job) data["job_datum"] = list( "title" = job.title, "departments" = english_list(job.departments), @@ -96,46 +106,42 @@ if(job && job.timeoff_factor < 0) // Currently are Off Duty, so gotta lookup what on-duty jobs are open data["job_choices"] = getOpenOnDutyJobs(user, job.pto_type) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "timeclock_vr.tmpl", capitalize(src.name), 500, 520) - ui.set_initial_data(data) - ui.open() + return data -/obj/machinery/computer/timeclock/Topic(href, href_list) +/obj/machinery/computer/timeclock/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return 1 - usr.set_machine(src) - src.add_fingerprint(usr) + return TRUE - if (href_list["id"]) - if(card) - usr.put_in_hands(card) - card = null - else - var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I)) - I.forceMove(src) - card = I - update_icon() - return 1 - if(href_list["switch-to-onduty-rank"]) - if(checkFace()) - if(checkCardCooldown()) - makeOnDuty(href_list["switch-to-onduty-rank"], href_list["switch-to-onduty-assignment"]) + add_fingerprint(usr) + + switch(action) + if("id") + if(card) usr.put_in_hands(card) card = null - update_icon() - return 1 - if(href_list["switch-to-offduty"]) - if(checkFace()) - if(checkCardCooldown()) - makeOffDuty() - usr.put_in_hands(card) - card = null - update_icon() - return 1 - return 1 // Return 1 to update UI + else + var/obj/item/I = usr.get_active_hand() + if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I)) + I.forceMove(src) + card = I + update_icon() + return TRUE + if("switch-to-onduty-rank") + if(checkFace()) + if(checkCardCooldown()) + makeOnDuty(params["switch-to-onduty-rank"], params["switch-to-onduty-assignment"]) + usr.put_in_hands(card) + card = null + update_icon() + return TRUE + if("switch-to-offduty") + if(checkFace()) + if(checkCardCooldown()) + makeOffDuty() + usr.put_in_hands(card) + card = null + update_icon() + return TRUE /obj/machinery/computer/timeclock/proc/getOpenOnDutyJobs(var/mob/user, var/department) var/list/available_jobs = list() diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index a133aab9b1..2a36b5db6c 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -74,97 +74,81 @@ storage_name = "Travel Oversight Control" allow_items = 1 -/obj/machinery/computer/cryopod/attack_ai() - attack_hand() +/obj/machinery/computer/cryopod/attack_ai(mob/user) + attack_hand(user) -/obj/machinery/computer/cryopod/attack_hand(mob/user = usr) +/obj/machinery/computer/cryopod/attack_hand(mob/user) if(stat & (NOPOWER|BROKEN)) return - user.set_machine(src) - add_fingerprint(usr) + tgui_interact(user) - var/dat +/obj/machinery/computer/cryopod/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "CryoStorageVr", storage_name) // VOREStation Edit - Use our own template for our custom data + ui.open() - if(!(ticker)) - return +/obj/machinery/computer/cryopod/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() - dat += "

[storage_name]
" - dat += "Welcome, [user.real_name].


" - dat += "View storage log.
" + data["real_name"] = user.real_name + data["allow_items"] = allow_items + data["crew"] = frozen_crew + + data["items"] = list() if(allow_items) - dat += "View objects.
" - //dat += "Recover object.
" //VOREStation Removal - Just log them. - //dat += "Recover all objects.
" //VOREStation Removal + for(var/F in frozen_items) + data["items"].Add(F) // VOREStation Edit + /* VOREStation Removal + data["items"].Add(list(list( + "name" = "[F]", + "ref" = REF(F), + ))) + VOREStation Removal End */ - user << browse(dat, "window=cryopod_console") - onclose(user, "cryopod_console") - -/obj/machinery/computer/cryopod/Topic(href, href_list) + return data +/obj/machinery/computer/cryopod/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) return - var/mob/user = usr + add_fingerprint(usr) - add_fingerprint(user) + return FALSE // VOREStation Edit - prevent topic exploits - if(href_list["log"]) + switch(action) + if("item") + if(!allow_items) + return - var/dat = "Recently stored [storage_type]


" - for(var/person in frozen_crew) - dat += "[person]
" - dat += "
" + if(!LAZYLEN(frozen_items)) + to_chat(usr, "There is nothing to recover from storage.") + return - user << browse(dat, "window=cryolog") + var/obj/item/I = locate(params["ref"]) in frozen_items + if(!I) + to_chat(usr, "\The [I] is no longer in storage.") + return - if(href_list["view"]) - if(!allow_items) return + visible_message("The console beeps happily as it disgorges [I].") - var/dat = "Recently stored objects


" - //VOREStation Edit Start - for(var/I in frozen_items) - dat += "[I]
" - //VOREStation Edit End - dat += "
" - - user << browse(dat, "window=cryoitems") - - else if(href_list["item"]) - if(!allow_items) return - - if(frozen_items.len == 0) - to_chat(user, "There is nothing to recover from storage.") - return - - var/obj/item/I = input(usr, "Please choose which object to retrieve.","Object recovery",null) as null|anything in frozen_items - if(!I) - return - - if(!(I in frozen_items)) - to_chat(user, "\The [I] is no longer in storage.") - return - - visible_message("The console beeps happily as it disgorges \the [I].", 3) - - I.forceMove(get_turf(src)) - frozen_items -= I - - else if(href_list["allitems"]) - if(!allow_items) return - - if(frozen_items.len == 0) - to_chat(user, "There is nothing to recover from storage.") - return - - visible_message("The console beeps happily as it disgorges the desired objects.", 3) - - for(var/obj/item/I in frozen_items) I.forceMove(get_turf(src)) frozen_items -= I + if("allitems") + if(!allow_items) + return + + if(!LAZYLEN(frozen_items)) + to_chat(usr, "There is nothing to recover from storage.") + return + + visible_message("The console beeps happily as it disgorges the desired objects.") + + for(var/obj/item/I in frozen_items) + I.forceMove(get_turf(src)) + frozen_items -= I - updateUsrDialog() - return /obj/item/weapon/circuitboard/cryopodcontrol name = "Circuit board (Cryogenic Oversight Console)" diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 05eb9c322c..db27559796 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -14,7 +14,7 @@ Barricades density = 1.0 var/health = 100 var/maxhealth = 100 - var/material/material + var/datum/material/material /obj/structure/barricade/New(var/newloc, var/material_name) ..(newloc) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 9e81b6312e..5a2e21bafc 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -853,11 +853,13 @@ About the new airlock wires panel: /obj/machinery/door/airlock/attack_ghost(mob/user) tgui_interact(user) -/obj/machinery/door/airlock/tgui_interact(mob/user, datum/tgui/ui) +/obj/machinery/door/airlock/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui, datum/tgui_state/custom_state) ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "AiAirlock", name) ui.open() + if(custom_state) + ui.set_state(custom_state) return TRUE /obj/machinery/door/airlock/tgui_data(mob/user) diff --git a/code/game/machinery/doors/blast_door.dm b/code/game/machinery/doors/blast_door.dm index a6b503cdbd..bc9c199ed2 100644 --- a/code/game/machinery/doors/blast_door.dm +++ b/code/game/machinery/doors/blast_door.dm @@ -19,7 +19,7 @@ icon = 'icons/obj/doors/rapid_pdoor.dmi' icon_state = null min_force = 20 //minimum amount of force needed to damage the door with a melee weapon - var/material/implicit_material + var/datum/material/implicit_material // Icon states for different shutter types. Simply change this instead of rewriting the update_icon proc. var/icon_state_open = null var/icon_state_opening = null diff --git a/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm b/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm index ef6367758f..9e65c06bcd 100644 --- a/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm +++ b/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm @@ -7,7 +7,6 @@ layer = ABOVE_OBJ_LAYER var/id_tag - var/datum/topic_state/remote/remote_state var/obj/machinery/embedded_controller/radio/airlock/master_controller /obj/machinery/dummy_airlock_controller/process() @@ -25,15 +24,10 @@ break if(!master_controller) qdel(src) - else - remote_state = new /datum/topic_state/remote(src, master_controller) /obj/machinery/dummy_airlock_controller/Destroy() if(master_controller) master_controller.dummy_terminals -= src - if(remote_state) - qdel(remote_state) - remote_state = null return ..() /obj/machinery/dummy_airlock_controller/interface_interact(var/mob/user) diff --git a/code/game/machinery/jukebox.dm b/code/game/machinery/jukebox.dm index 6b53d5d968..05aee888a9 100644 --- a/code/game/machinery/jukebox.dm +++ b/code/game/machinery/jukebox.dm @@ -191,91 +191,91 @@ if (panel_open) overlays += "panel_open" -/obj/machinery/media/jukebox/Topic(href, href_list) - if(..() || !(Adjacent(usr) || istype(usr, /mob/living/silicon))) - return - - if(!anchored) - to_chat(usr, "You must secure \the [src] first.") - return - - if(inoperable()) - to_chat(usr, "\The [src] doesn't appear to function.") - return - - if(href_list["change_track"]) - var/datum/track/T = locate(href_list["change_track"]) in tracks - if(istype(T)) - current_track = T - StartPlaying() - else if(href_list["loopmode"]) - var/newval = text2num(href_list["loopmode"]) - loop_mode = sanitize_inlist(newval, list(JUKEMODE_NEXT, JUKEMODE_RANDOM, JUKEMODE_REPEAT_SONG, JUKEMODE_PLAY_ONCE), loop_mode) - else if(href_list["volume"]) - var/newval = input("Choose Jukebox volume (0-100%)", "Jukebox volume", round(volume * 100.0)) - newval = sanitize_integer(text2num(newval), min = 0, max = 100, default = volume * 100.0) - volume = newval / 100.0 - update_music() // To broadcast volume change without restarting song - else if(href_list["stop"]) - StopPlaying() - else if(href_list["play"]) - if(emagged) - playsound(src, 'sound/items/AirHorn.ogg', 100, 1) - for(var/mob/living/carbon/M in ohearers(6, src)) - if(M.get_ear_protection() >= 2) - continue - M.SetSleeping(0) - M.stuttering += 20 - M.ear_deaf += 30 - M.Weaken(3) - if(prob(30)) - M.Stun(10) - M.Paralyse(4) - else - M.make_jittery(500) - spawn(15) - explode() - else if(current_track == null) - to_chat(usr, "No track selected.") - else - StartPlaying() - - return 1 - /obj/machinery/media/jukebox/interact(mob/user) if(inoperable()) to_chat(usr, "\The [src] doesn't appear to function.") return - ui_interact(user) + tgui_interact(user) -/obj/machinery/media/jukebox/ui_interact(mob/user, ui_key = "jukebox", var/datum/nanoui/ui = null, var/force_open = 1) - var/title = "RetroBox - Space Style" - var/data[0] +/obj/machinery/media/jukebox/tgui_status(mob/user) + if(inoperable()) + to_chat(user, "[src] doesn't appear to function.") + return STATUS_CLOSE + if(!anchored) + to_chat(user, "You must secure [src] first.") + return STATUS_CLOSE + . = ..() - if(operable()) - data["playing"] = playing - data["hacked"] = hacked - data["max_queue_len"] = max_queue_len - data["media_start_time"] = media_start_time - data["loop_mode"] = loop_mode - data["volume"] = volume - if(current_track) - data["current_track_ref"] = "\ref[current_track]" // Convenient shortcut - data["current_track"] = current_track.toNanoList() - data["percent"] = playing ? min(100, round(world.time - media_start_time) / current_track.duration) : 0; - - var/list/nano_tracks = new - for(var/datum/track/T in tracks) - nano_tracks[++nano_tracks.len] = T.toNanoList() - data["tracks"] = nano_tracks - - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "jukebox.tmpl", title, 450, 600) - ui.set_initial_data(data) +/obj/machinery/media/jukebox/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Jukebox", "RetroBox - Space Style") ui.open() - ui.set_auto_update(playing) + +/obj/machinery/media/jukebox/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + data["playing"] = playing + data["loop_mode"] = loop_mode + data["volume"] = volume + data["current_track_ref"] = null + data["current_track"] = null + if(current_track) + data["current_track_ref"] = "\ref[current_track]" // Convenient shortcut + data["current_track"] = current_track.toTguiList() + data["percent"] = playing ? min(100, round(world.time - media_start_time) / current_track.duration) : 0; + + var/list/tgui_tracks = list() + for(var/datum/track/T in tracks) + tgui_tracks.Add(list(T.toTguiList())) + data["tracks"] = tgui_tracks + + return data + +/obj/machinery/media/jukebox/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + switch(action) + if("change_track") + var/datum/track/T = locate(params["change_track"]) in tracks + if(istype(T)) + current_track = T + StartPlaying() + return TRUE + if("loopmode") + var/newval = text2num(params["loopmode"]) + loop_mode = sanitize_inlist(newval, list(JUKEMODE_NEXT, JUKEMODE_RANDOM, JUKEMODE_REPEAT_SONG, JUKEMODE_PLAY_ONCE), loop_mode) + return TRUE + if("volume") + volume = clamp(params["val"], 0, 1) + update_music() // To broadcast volume change without restarting song + return TRUE + if("stop") + StopPlaying() + return TRUE + if("play") + if(emagged) + playsound(src, 'sound/items/AirHorn.ogg', 100, 1) + for(var/mob/living/carbon/M in ohearers(6, src)) + if(M.get_ear_protection() >= 2) + continue + M.SetSleeping(0) + M.stuttering += 20 + M.ear_deaf += 30 + M.Weaken(3) + if(prob(30)) + M.Stun(10) + M.Paralyse(4) + else + M.make_jittery(500) + spawn(15) + explode() + else if(current_track == null) + to_chat(usr, "No track selected.") + else + StartPlaying() + return TRUE /obj/machinery/media/jukebox/attack_ai(mob/user as mob) return src.attack_hand(user) diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm index 887473612a..ffa444612a 100644 --- a/code/game/machinery/newscaster.dm +++ b/code/game/machinery/newscaster.dm @@ -101,22 +101,22 @@ NEWSCASTER.newsAlert(annoncement) NEWSCASTER.update_icon() - var/list/receiving_pdas = new - for (var/obj/item/device/pda/P in PDAs) - if(!P.owner) - continue - if(P.toff) - continue - receiving_pdas += P + // var/list/receiving_pdas = new + // for (var/obj/item/device/pda/P in PDAs) + // if(!P.owner) + // continue + // if(P.toff) + // continue + // receiving_pdas += P - spawn(0) // get_receptions sleeps further down the line, spawn of elsewhere - var/datum/receptions/receptions = get_receptions(null, receiving_pdas) // datums are not atoms, thus we have to assume the newscast network always has reception + // spawn(0) // get_receptions sleeps further down the line, spawn of elsewhere + // var/datum/receptions/receptions = get_receptions(null, receiving_pdas) // datums are not atoms, thus we have to assume the newscast network always has reception - for(var/obj/item/device/pda/PDA in receiving_pdas) - if(!(receptions.receiver_reception[PDA] & TELECOMMS_RECEPTION_RECEIVER)) - continue + // for(var/obj/item/device/pda/PDA in receiving_pdas) + // if(!(receptions.receiver_reception[PDA] & TELECOMMS_RECEPTION_RECEIVER)) + // continue - PDA.new_news(annoncement) + // PDA.new_news(annoncement) var/datum/feed_network/news_network = new /datum/feed_network //The global news-network, which is coincidentally a global list. @@ -132,20 +132,6 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster) var/ispowered = 1 //starts powered, changes with power_change() //var/list/datum/feed_channel/channel_list = list() //This list will contain the names of the feed channels. Each name will refer to a data region where the messages of the feed channels are stored. //OBSOLETE: We're now using a global news network - var/screen = 0 //Or maybe I'll make it into a list within a list afterwards... whichever I prefer, go fuck yourselves :3 - // 0 = welcome screen - main menu - // 1 = view feed channels - // 2 = create feed channel - // 3 = create feed story - // 4 = feed story submited sucessfully - // 5 = feed channel created successfully - // 6 = ERROR: Cannot create feed story - // 7 = ERROR: Cannot create feed channel - // 8 = print newspaper - // 9 = viewing channel feeds - // 10 = censor feed story - // 11 = censor feed channel - //Holy shit this is outdated, made this when I was still starting newscasters :3 var/paper_remaining = 0 var/securityCaster = 0 // 0 = Caster cannot be used to issue wanted posters @@ -171,6 +157,8 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster) anchored = 1 var/obj/machinery/exonet_node/node = null circuit = /obj/item/weapon/circuitboard/newscaster + // TGUI + var/list/temp = null /obj/machinery/newscaster/security_unit //Security unit name = "Security Newscaster" @@ -246,10 +234,16 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster) return return -/obj/machinery/newscaster/attack_ai(mob/user as mob) +/obj/machinery/newscaster/attack_ai(mob/user) return attack_hand(user) -/obj/machinery/newscaster/attack_hand(mob/user as mob) //########### THE MAIN BEEF IS HERE! And in the proc below this...############ +/obj/machinery/newscaster/tgui_status(mob/user) + if(!ispowered || isbroken) + return STATUS_CLOSE + . = ..() + + +/obj/machinery/newscaster/attack_hand(mob/user) if(!ispowered || isbroken) return @@ -263,263 +257,136 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster) if(!user.IsAdvancedToolUser()) return 0 + + tgui_interact(user) - if(istype(user, /mob/living/carbon/human) || istype(user,/mob/living/silicon)) - var/mob/living/human_or_robot_user = user - var/dat - dat = text("Newscaster

Newscaster Unit #[unit_no]

") +/** + * Sets a temporary message to display to the user + * + * Arguments: + * * text - Text to display, null/empty to clear the message from the UI + * * style - The style of the message: (color name), info, success, warning, danger, virus + */ +/obj/machinery/newscaster/proc/set_temp(text = "", style = "info", update_now = FALSE) + temp = list(text = text, style = style) + if(update_now) + SStgui.update_uis(src) + +/obj/machinery/newscaster/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Newscaster", "Newscaster Unit #[unit_no]") + ui.open() - scan_user(human_or_robot_user) //Newscaster scans you +/obj/machinery/newscaster/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() - switch(screen) - if(0) - dat += "Welcome to Newscasting Unit #[unit_no].
Interface & News networks Operational." - dat += "
Property of NanoTrasen Inc" - if(news_network.wanted_issue) - dat+= "
Read Wanted Issue" - dat+= "

Create Feed Channel" - dat+= "
View Feed Channels" - dat+= "
Submit new Feed story" - dat+= "
Print newspaper" - dat+= "
Re-scan User" - dat+= "

Exit" - if(securityCaster) - var/wanted_already = 0 - if(news_network.wanted_issue) - wanted_already = 1 + // Main menu + data["temp"] = temp - dat+="
Feed Security functions:
" - dat+="
[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue" - dat+="
Censor Feed Stories" - dat+="
Mark Feed Channel with [using_map.company_name] D-Notice" - dat+="

The newscaster recognises you as: [scanned_user]" - if(1) - dat+= "Station Feed Channels
" - if(isemptylist(news_network.network_channels)) - dat+="No active channels found..." - else - for(var/datum/feed_channel/CHANNEL in news_network.network_channels) - if(CHANNEL.is_admin_channel) - dat+="[CHANNEL.channel_name]
" - else - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
" - dat+="

Refresh" - dat+="
Back" - if(2) - dat+="Creating new Feed Channel..." - dat+="
Channel Name: [channel_name]
" - dat+="Channel Author: [scanned_user]
" - dat+="Will Accept Public Feeds: [(c_locked) ? ("NO") : ("YES")]

" - dat+="
Submit

Cancel
" - if(3) - dat+="Creating new Feed Message..." - dat+="
Receiving Channel: [channel_name]
" //MARK - dat+="Message Author: [scanned_user]
" - dat+="Message Body: [msg]
" - dat+="Attach Photo: [(photo_data ? "Photo Attached" : "No Photo")]
" - dat+="
Submit

Cancel
" - if(4) - dat+="Feed story successfully submitted to [channel_name].

" - dat+="
Return
" - if(5) - dat+="Feed Channel [channel_name] created successfully.

" - dat+="
Return
" - if(6) - dat+="ERROR: Could not submit Feed story to Network.

" - if(channel_name=="") - dat+="•Invalid receiving channel name.
" - if(scanned_user=="Unknown") - dat+="•Channel author unverified.
" - if(msg == "" || msg == "\[REDACTED\]") - dat+="•Invalid message body.
" + data["user"] = tgui_user_name(user) + data["unit_no"] = unit_no - dat+="
Return
" - if(7) - dat+="ERROR: Could not submit Feed Channel to Network.

" - var/list/existing_authors = list() - for(var/datum/feed_channel/FC in news_network.network_channels) - if(FC.author == "\[REDACTED\]") - existing_authors += FC.backup_author - else - existing_authors += FC.author - if(scanned_user in existing_authors) - dat+="•There already exists a Feed channel under your name.
" - if(channel_name=="" || channel_name == "\[REDACTED\]") - dat+="•Invalid channel name.
" - var/check = 0 - for(var/datum/feed_channel/FC in news_network.network_channels) - if(FC.channel_name == channel_name) - check = 1 - break - if(check) - dat+="•Channel name already in use.
" - if(scanned_user=="Unknown") - dat+="•Channel author unverified.
" - dat+="
Return
" - if(8) - var/total_num=length(news_network.network_channels) - var/active_num=total_num - var/message_num=0 - for(var/datum/feed_channel/FC in news_network.network_channels) - if(!FC.censored) - message_num += length(FC.messages) //Dont forget, datum/feed_channel's var messages is a list of datum/feed_message - else - active_num-- - dat+="Network currently serves a total of [total_num] Feed channels, [active_num] of which are active, and a total of [message_num] Feed Stories." //TODO: CONTINUE - dat+="

Liquid Paper remaining: [(paper_remaining) *100 ] cm^3" - dat+="

Print Paper" - dat+="
Cancel" - if(9) - dat+="[viewing_channel.channel_name]: \[created by: [viewing_channel.author]\]
" - if(viewing_channel.censored) - dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [using_map.company_name] D-Notice.
" - dat+="No further feed story additions are allowed while the D-Notice is in effect.

" - else - if(isemptylist(viewing_channel.messages)) - dat+="No feed messages found in channel...
" - else - var/i = 0 - for(var/datum/feed_message/MESSAGE in viewing_channel.messages) - i++ - dat+="-[MESSAGE.body]
" - if(MESSAGE.img) - usr << browse_rsc(MESSAGE.img, "tmp_photo[i].png") - dat+="
" - if(MESSAGE.caption) - dat+="[MESSAGE.caption]
" - dat+="
" - dat+="\[Story by [MESSAGE.author] - [MESSAGE.time_stamp]\]
" - dat+="

Refresh" - dat+="
Back" - if(10) - dat+="[using_map.company_name] Feed Censorship Tool
" - dat+="NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.
" - dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.
" - dat+="
Select Feed channel to get Stories from:
" - if(isemptylist(news_network.network_channels)) - dat+="No feed channels found active...
" - else - for(var/datum/feed_channel/CHANNEL in news_network.network_channels) - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
" - dat+="
Cancel" - if(11) - dat+="[using_map.company_name] D-Notice Handler
" - dat+="A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the station's" - dat+="morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed" - dat+="stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.
" - if(isemptylist(news_network.network_channels)) - dat+="No feed channels found active...
" - else - for(var/datum/feed_channel/CHANNEL in news_network.network_channels) - dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
" + var/list/wanted_issue = null + if(news_network.wanted_issue) + wanted_issue = list( + "author" = news_network.wanted_issue.backup_author, + "criminal" = news_network.wanted_issue.author, + "desc" = news_network.wanted_issue.body, + "img" = null + ) + if(news_network.wanted_issue.img) + wanted_issue["img"] = icon2base64(news_network.wanted_issue.img) - dat+="
Back" - if(12) - dat+="[viewing_channel.channel_name]: \[ created by: [viewing_channel.author] \]
" - dat+="[(viewing_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
" + data["wanted_issue"] = wanted_issue + data["securityCaster"] = !!securityCaster + + var/list/network_channels = list() + for(var/datum/feed_channel/FC in news_network.network_channels) + network_channels.Add(list(list( + "admin" = FC.is_admin_channel, + "ref" = REF(FC), + "name" = FC.channel_name, + "censored" = FC.censored, + ))) + data["channels"] = network_channels - if(isemptylist(viewing_channel.messages)) - dat+="No feed messages found in channel...
" - else - for(var/datum/feed_message/MESSAGE in viewing_channel.messages) - dat+="-[MESSAGE.body]
\[[MESSAGE.message_type] by [MESSAGE.author]\]
" - dat+="[(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]
" - dat+="
Back" - if(13) - dat+="[viewing_channel.channel_name]: \[ created by: [viewing_channel.author] \]
" - dat+="Channel messages listed below. If you deem them dangerous to the station, you can Bestow a D-Notice upon the channel.
" - if(viewing_channel.censored) - dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [using_map.company_name] D-Notice.
" - dat+="No further feed story additions are allowed while the D-Notice is in effect.

" - else - if(isemptylist(viewing_channel.messages)) - dat+="No feed messages found in channel...
" - else - for(var/datum/feed_message/MESSAGE in viewing_channel.messages) - dat+="-[MESSAGE.body]
\[[MESSAGE.message_type] by [MESSAGE.author]\]
" + // Creating Channels + data["channel_name"] = channel_name + data["c_locked"] = c_locked - dat+="
Back" - if(14) - dat+="Wanted Issue Handler:" - var/wanted_already = 0 - var/end_param = 1 - if(news_network.wanted_issue) - wanted_already = 1 - end_param = 2 + // Creating Messages + // data["channel_name"] = channel_name + data["msg"] = msg + data["photo_data"] = !!photo_data - if(wanted_already) - dat+="
A wanted issue is already in Feed Circulation. You can edit or cancel it below.
" - dat+="
" - dat+="Criminal Name: [channel_name]
" - dat+="Description: [msg]
" - dat+="Attach Photo: [(photo_data ? "Photo Attached" : "No Photo")]
" - if(wanted_already) - dat+="Wanted Issue created by: [news_network.wanted_issue.backup_author]
" - else - dat+="Wanted Issue will be created under prosecutor: [scanned_user]
" - dat+="
[(wanted_already) ? ("Edit Issue") : ("Submit")]" - if(wanted_already) - dat+="
Take down Issue" - dat+="
Cancel" - if(15) - dat+="Wanted issue for [channel_name] is now in Network Circulation.

" - dat+="
Return
" - if(16) - dat+="ERROR: Wanted Issue rejected by Network.

" - if(channel_name=="" || channel_name == "\[REDACTED\]") - dat+="•Invalid name for person wanted.
" - if(scanned_user=="Unknown") - dat+="•Issue author unverified.
" - if(msg == "" || msg == "\[REDACTED\]") - dat+="•Invalid description.
" - dat+="
Return
" - if(17) - dat+="Wanted Issue successfully deleted from Circulation
" - dat+="
Return
" - if(18) - dat+="-- STATIONWIDE WANTED ISSUE --
\[Submitted by: [news_network.wanted_issue.backup_author]\]
" - dat+="Criminal: [news_network.wanted_issue.author]
" - dat+="Description: [news_network.wanted_issue.body]
" - dat+="Photo:: " - if(news_network.wanted_issue.img) - usr << browse_rsc(news_network.wanted_issue.img, "tmp_photow.png") - dat+="
" - else - dat+="None" - dat+="

Back
" - if(19) - dat+="Wanted issue for [channel_name] successfully edited.

" - dat+="
Return
" - if(20) - dat+="Printing successful. Please receive your newspaper from the bottom of the machine.

" - dat+="Return" - if(21) - dat+="Unable to print newspaper. Insufficient paper. Please notify maintenance personnel to refill machine storage.

" - dat+="Return" - else - dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com" + // Printing menu + var/total_num = LAZYLEN(news_network.network_channels) + var/active_num = total_num + var/message_num = 0 + for(var/datum/feed_channel/FC in news_network.network_channels) + if(!FC.censored) + message_num += length(FC.messages) //Dont forget, datum/feed_channel's var messages is a list of datum/feed_message + else + active_num-- + data["total_num"] = total_num + data["active_num"] = active_num + data["message_num"] = message_num + data["paper_remaining"] = paper_remaining + // Viewing a specific channel + var/list/viewing = null + if(viewing_channel) + var/list/messages = list() + viewing = list( + "name" = viewing_channel.channel_name, + "author" = viewing_channel.author, + "censored" = viewing_channel.censored, + "messages" = messages, + "ref" = REF(viewing_channel), + ) + if(!viewing_channel.censored) + for(var/datum/feed_message/M in viewing_channel.messages) + var/list/msgdata = list( + "body" = M.body, + "img" = null, + "type" = M.message_type, + "caption" = null, + "author" = M.author, + "timestamp" = M.time_stamp, + "ref" = REF(M), + ) + if(M.img) + msgdata["img"] = icon2base64(M.img) + msgdata["caption"] = M.caption - human_or_robot_user << browse(dat, "window=newscaster_main;size=400x600") - onclose(human_or_robot_user, "newscaster_main") + messages.Add(list(msgdata)) + data["viewing_channel"] = viewing -/obj/machinery/newscaster/Topic(href, href_list) + // Censorship + data["company"] = using_map.company_name + + return data + +/obj/machinery/newscaster/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return - if((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) - if(href_list["set_channel_name"]) - channel_name = sanitizeSafe(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""), MAX_LNAME_LEN) - updateUsrDialog() - //update_icon() + return TRUE - else if(href_list["set_channel_lock"]) + switch(action) + if("cleartemp") + temp = null + return TRUE + + if("set_channel_name") + channel_name = sanitizeSafe(params["val"], MAX_LNAME_LEN) + return TRUE + + if("set_channel_lock") c_locked = !c_locked - updateUsrDialog() - //update_icon() + return TRUE - else if(href_list["submit_new_channel"]) + if("submit_new_channel") //var/list/existing_channels = list() //OBSOLETE var/list/existing_authors = list() for(var/datum/feed_channel/FC in news_network.network_channels) @@ -533,121 +400,118 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster) if(FC.channel_name == channel_name) check = 1 break - if(channel_name == "" || channel_name == "\[REDACTED\]" || scanned_user == "Unknown" || check || (scanned_user in existing_authors)) - screen=7 - else - var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel") - if(choice=="Confirm") - news_network.CreateFeedChannel(channel_name, scanned_user, c_locked) - screen=5 - updateUsrDialog() - //update_icon() + var/our_user = tgui_user_name(usr) + if(channel_name == "" || channel_name == "\[REDACTED\]") + set_temp("Error: Could not submit feed channel to network: Invalid Channel Name.", "danger", FALSE) + return TRUE + if(our_user == "Unknown") + set_temp("Error: Could not submit feed channel to network: Channel author unverified.", "danger", FALSE) + return TRUE + if(check) + set_temp("Error: Could not submit feed channel to network: Channel name already in use.", "danger", FALSE) + return TRUE + if(our_user in existing_authors) + set_temp("Error: Could not submit feed channel to network: A feed channel already exists under your name.", "danger", FALSE) + return TRUE - else if(href_list["set_channel_receiving"]) + var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel") + if(choice == "Confirm") + news_network.CreateFeedChannel(channel_name, our_user, c_locked) + set_temp("Feed channel [channel_name] created successfully.", "success", FALSE) + return TRUE + + if("set_channel_receiving") //var/list/datum/feed_channel/available_channels = list() var/list/available_channels = list() for(var/datum/feed_channel/F in news_network.network_channels) if((!F.locked || F.author == scanned_user) && !F.censored) available_channels += F.channel_name - channel_name = input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels - updateUsrDialog() + var/new_channel_name = input(usr, "Choose receiving Feed Channel", "Network Channel Handler") as null|anything in available_channels + if(new_channel_name) + channel_name = new_channel_name + return TRUE - else if(href_list["set_new_message"]) - msg = sanitize(input(usr, "Write your Feed story", "Network Channel Handler", "")) - updateUsrDialog() + if("set_new_message") + msg = sanitize(input(usr, "Write your Feed story", "Network Channel Handler", "") as message|null) + return TRUE - else if(href_list["set_attachment"]) + if("set_attachment") AttachPhoto(usr) - updateUsrDialog() + return TRUE - else if(href_list["submit_new_message"]) - if(msg =="" || msg=="\[REDACTED\]" || scanned_user == "Unknown" || channel_name == "") - screen=6 - else - var/image = photo_data ? photo_data.photo : null - feedback_inc("newscaster_stories",1) - news_network.SubmitArticle(msg, scanned_user, channel_name, image, 0) - screen=4 + if("submit_new_message") + var/our_user = tgui_user_name(usr) + if(msg == "" || msg == "\[REDACTED\]") + set_temp("Error: Could not submit feed message to network: Invalid Message.", "danger", FALSE) + return TRUE + if(our_user == "Unknown") + set_temp("Error: Could not submit feed message to network: Channel author unverified.", "danger", FALSE) + return TRUE + if(channel_name == "") + set_temp("Error: Could not submit feed message to network: No feed channel selected.", "danger", FALSE) + return TRUE - updateUsrDialog() + var/image = photo_data ? photo_data.photo : null + feedback_inc("newscaster_stories",1) + news_network.SubmitArticle(msg, our_user, channel_name, image, 0) + set_temp("Feed message created successfully.", "success", FALSE) + return TRUE - else if(href_list["create_channel"]) - screen=2 - updateUsrDialog() - - else if(href_list["create_feed_story"]) - screen=3 - updateUsrDialog() - - else if(href_list["menu_paper"]) - screen=8 - updateUsrDialog() - else if(href_list["print_paper"]) + if("print_paper") if(!paper_remaining) - screen=21 - else - print_paper() - screen = 20 - updateUsrDialog() + set_temp("Unable to print newspaper. Insufficient paper. Please notify maintenance personnel to refill machine storage.", "danger", FALSE) + return TRUE + + print_paper() + set_temp("Printing successful. Please receive your newspaper from the bottom of the machine.", "success", FALSE) + return TRUE - else if(href_list["menu_censor_story"]) - screen=10 - updateUsrDialog() + if("set_wanted_desc") + msg = sanitize(params["val"]) + return TRUE - else if(href_list["menu_censor_channel"]) - screen=11 - updateUsrDialog() + if("submit_wanted") + if(!securityCaster) + return FALSE + var/our_user = tgui_user_name(usr) + if(channel_name == "") + set_temp("Error: Could not submit wanted issue to network: Invalid Criminal Name.", "danger", FALSE) + return TRUE + if(msg == "") + set_temp("Error: Could not submit wanted issue to network: Invalid Description.", "danger", FALSE) + return TRUE + if(our_user == "Unknown") + set_temp("Error: Could not submit wanted issue to network: Author unverified.", "danger", FALSE) + return TRUE - else if(href_list["menu_wanted"]) - var/already_wanted = 0 - if(news_network.wanted_issue) - already_wanted = 1 + var/choice = alert("Please confirm Wanted Issue change.", "Network Security Handler", "Confirm", "Cancel") + if(choice == "Confirm") + if(news_network.wanted_issue) + if(news_network.wanted_issue.is_admin_message) + alert("The wanted issue has been distributed by a [using_map.company_name] higherup. You cannot edit it.", "Ok") + return + news_network.wanted_issue.author = channel_name + news_network.wanted_issue.body = msg + news_network.wanted_issue.backup_author = scanned_user + if(photo_data) + news_network.wanted_issue.img = photo_data.photo.img + set_temp("Wanted issue for [channel_name] successfully edited.", "success", FALSE) + return TRUE - if(already_wanted) - channel_name = news_network.wanted_issue.author - msg = news_network.wanted_issue.body - screen = 14 - updateUsrDialog() + var/datum/feed_message/WANTED = new /datum/feed_message + WANTED.author = channel_name + WANTED.body = msg + WANTED.backup_author = scanned_user //I know, a bit wacky + if(photo_data) + WANTED.img = photo_data.photo.img + news_network.wanted_issue = WANTED + news_network.alert_readers() + set_temp("Wanted issue for [channel_name] is now in Network Circulation.", "success", FALSE) + return TRUE - else if(href_list["set_wanted_name"]) - channel_name = sanitizeSafe(input(usr, "Provide the name of the Wanted person", "Network Security Handler", ""), MAX_LNAME_LEN) - updateUsrDialog() - - else if(href_list["set_wanted_desc"]) - msg = sanitize(input(usr, "Provide the a description of the Wanted person and any other details you deem important", "Network Security Handler", "")) - updateUsrDialog() - - else if(href_list["submit_wanted"]) - var/input_param = text2num(href_list["submit_wanted"]) - if(msg == "" || channel_name == "" || scanned_user == "Unknown") - screen = 16 - else - var/choice = alert("Please confirm Wanted Issue [(input_param==1) ? ("creation.") : ("edit.")]","Network Security Handler","Confirm","Cancel") - if(choice=="Confirm") - if(input_param==1) //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one. See the else below - var/datum/feed_message/WANTED = new /datum/feed_message - WANTED.author = channel_name - WANTED.body = msg - WANTED.backup_author = scanned_user //I know, a bit wacky - if(photo_data) - WANTED.img = photo_data.photo.img - news_network.wanted_issue = WANTED - news_network.alert_readers() - screen = 15 - else - if(news_network.wanted_issue.is_admin_message) - alert("The wanted issue has been distributed by a [using_map.company_name] higherup. You cannot edit it.","Ok") - return - news_network.wanted_issue.author = channel_name - news_network.wanted_issue.body = msg - news_network.wanted_issue.backup_author = scanned_user - if(photo_data) - news_network.wanted_issue.img = photo_data.photo.img - screen = 19 - - updateUsrDialog() - - else if(href_list["cancel_wanted"]) + if("cancel_wanted") + if(!securityCaster) + return FALSE if(news_network.wanted_issue.is_admin_message) alert("The wanted issue has been distributed by a [using_map.company_name] higherup. You cannot take it down.","Ok") return @@ -656,49 +520,52 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster) news_network.wanted_issue = null for(var/obj/machinery/newscaster/NEWSCASTER in GLOB.allCasters) NEWSCASTER.update_icon() - screen=17 - updateUsrDialog() + set_temp("Wanted issue taken down.", "success", FALSE) + return TRUE - else if(href_list["view_wanted"]) - screen=18 - updateUsrDialog() - else if(href_list["censor_channel_author"]) - var/datum/feed_channel/FC = locate(href_list["censor_channel_author"]) + if("censor_channel_author") + if(!securityCaster) + return FALSE + var/datum/feed_channel/FC = locate(params["ref"]) if(FC.is_admin_channel) alert("This channel was created by a [using_map.company_name] Officer. You cannot censor it.","Ok") return - if(FC.author != "\[REDACTED\]") + if(FC.author != "\[REDACTED\]") FC.backup_author = FC.author - FC.author = "\[REDACTED\]" + FC.author = "\[REDACTED\]" else FC.author = FC.backup_author FC.update() - updateUsrDialog() + return TRUE - else if(href_list["censor_channel_story_author"]) - var/datum/feed_message/MSG = locate(href_list["censor_channel_story_author"]) + if("censor_channel_story_author") + if(!securityCaster) + return FALSE + var/datum/feed_message/MSG = locate(params["ref"]) if(MSG.is_admin_message) alert("This message was created by a [using_map.company_name] Officer. You cannot censor its author.","Ok") return - if(MSG.author != "\[REDACTED\]") + if(MSG.author != "\[REDACTED\]") MSG.backup_author = MSG.author - MSG.author = "\[REDACTED\]" + MSG.author = "\[REDACTED\]" else MSG.author = MSG.backup_author MSG.parent_channel.update() - updateUsrDialog() + return TRUE - else if(href_list["censor_channel_story_body"]) - var/datum/feed_message/MSG = locate(href_list["censor_channel_story_body"]) + if("censor_channel_story_body") + if(!securityCaster) + return FALSE + var/datum/feed_message/MSG = locate(params["ref"]) if(MSG.is_admin_message) alert("This channel was created by a [using_map.company_name] Officer. You cannot censor it.","Ok") return - if(MSG.body != "\[REDACTED\]") + if(MSG.body != "\[REDACTED\]") MSG.backup_body = MSG.body MSG.backup_caption = MSG.caption MSG.backup_img = MSG.img - MSG.body = "\[REDACTED\]" - MSG.caption = "\[REDACTED\]" + MSG.body = "\[REDACTED\]" + MSG.caption = "\[REDACTED\]" MSG.img = null else MSG.body = MSG.backup_body @@ -706,60 +573,32 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster) MSG.img = MSG.backup_img MSG.parent_channel.update() - updateUsrDialog() + return TRUE - else if(href_list["pick_d_notice"]) - var/datum/feed_channel/FC = locate(href_list["pick_d_notice"]) - viewing_channel = FC - screen=13 - updateUsrDialog() - - else if(href_list["toggle_d_notice"]) - var/datum/feed_channel/FC = locate(href_list["toggle_d_notice"]) + if("toggle_d_notice") + if(!securityCaster) + return FALSE + var/datum/feed_channel/FC = locate(params["ref"]) if(FC.is_admin_channel) alert("This channel was created by a [using_map.company_name] Officer. You cannot place a D-Notice upon it.","Ok") return FC.censored = !FC.censored FC.update() - updateUsrDialog() + return TRUE - else if(href_list["view"]) - screen=1 - updateUsrDialog() - - else if(href_list["setScreen"]) //Brings us to the main menu and resets all fields~ - screen = text2num(href_list["setScreen"]) - if(screen == 0) - scanned_user = "Unknown"; - msg = ""; - c_locked=0; - channel_name=""; - viewing_channel = null - updateUsrDialog() - - else if(href_list["show_channel"]) - var/datum/feed_channel/FC = locate(href_list["show_channel"]) + if("show_channel") + var/datum/feed_channel/FC = locate(params["show_channel"]) viewing_channel = FC - screen = 9 - updateUsrDialog() + return TRUE - else if(href_list["pick_censor_channel"]) - var/datum/feed_channel/FC = locate(href_list["pick_censor_channel"]) - viewing_channel = FC - screen = 12 - updateUsrDialog() - - else if(href_list["refresh"]) - updateUsrDialog() - -/obj/machinery/newscaster/attackby(I as obj, user as mob) +/obj/machinery/newscaster/attackby(I as obj, user) if(computer_deconstruction_screwdriver(user, I)) return else attack_hand(user) return -/obj/machinery/newscaster/attack_ai(mob/user as mob) +/obj/machinery/newscaster/attack_ai(mob/user) return attack_hand(user) //or maybe it'll have some special functions? No idea. /datum/news_photo @@ -770,7 +609,7 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster) is_synth = synth photo = p -/obj/machinery/newscaster/proc/AttachPhoto(mob/user as mob) +/obj/machinery/newscaster/proc/AttachPhoto(mob/user) if(photo_data) if(!photo_data.is_synth) photo_data.photo.loc = src.loc @@ -812,7 +651,7 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster) drop_sound = 'sound/items/drop/wrapper.ogg' pickup_sound = 'sound/items/pickup/wrapper.ogg' -obj/item/weapon/newspaper/attack_self(mob/user as mob) +obj/item/weapon/newspaper/attack_self(mob/user) if(ishuman(user)) var/mob/living/carbon/human/human_user = user var/dat @@ -868,7 +707,7 @@ obj/item/weapon/newspaper/attack_self(mob/user as mob) for(var/datum/feed_channel/NP in news_content) pages++ if(important_message!=null) - dat+="
Wanted Issue:


" + dat+="
Wanted Issue:


" dat+="Criminal name: [important_message.author]
" dat+="Description: [important_message.body]
" dat+="Photo:: " @@ -922,7 +761,7 @@ obj/item/weapon/newspaper/Topic(href, href_list) if(istype(src.loc, /mob)) attack_self(src.loc) -obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user as mob) +obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user) if(istype(W, /obj/item/weapon/pen)) if(scribble_page == curr_page) to_chat(user, "There's already a scribble in this page... You wouldn't want to make things too cluttered, would you?") @@ -939,8 +778,20 @@ obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user as mob) return ////////////////////////////////////helper procs +/obj/machinery/newscaster/proc/tgui_user_name(mob/user) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + var/obj/item/weapon/card/id/I = H.GetIdCard() + if(I) + return GetNameAndAssignmentFromId(I) -/obj/machinery/newscaster/proc/scan_user(mob/living/user as mob) + if(issilicon(user)) + var/mob/living/silicon/S = user + return "[S.name] ([S.job])" + + return "Unknown" + +/obj/machinery/newscaster/proc/scan_user(mob/living/user) if(istype(user,/mob/living/carbon/human)) //User is a human var/mob/living/carbon/human/human_user = user var/obj/item/weapon/card/id/I = human_user.GetIdCard() diff --git a/code/game/machinery/oxygen_pump.dm b/code/game/machinery/oxygen_pump.dm index 37c75957be..f7821a4e84 100644 --- a/code/game/machinery/oxygen_pump.dm +++ b/code/game/machinery/oxygen_pump.dm @@ -79,7 +79,7 @@ update_use_power(USE_POWER_IDLE) /obj/machinery/oxygen_pump/attack_ai(mob/user as mob) - ui_interact(user) + tgui_interact(user) /obj/machinery/oxygen_pump/proc/attach_mask(var/mob/living/carbon/C) if(C && istype(C)) @@ -176,61 +176,60 @@ set src in oview(1) set category = "Object" set name = "Show Tank Settings" - ui_interact(usr) + tgui_interact(usr) -//GUI Tank Setup -/obj/machinery/oxygen_pump/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] +/obj/machinery/oxygen_pump/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) if(!tank) - to_chat(usr, "It is missing a tank!") - data["tankPressure"] = 0 - data["releasePressure"] = 0 - data["defaultReleasePressure"] = 0 - data["maxReleasePressure"] = 0 - data["maskConnected"] = 0 - data["tankInstalled"] = 0 - // this is the data which will be sent to the ui + to_chat(user, "[src] is missing a tank.") + if(ui) + ui.close() + return + + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Tank", name) + ui.open() + +/obj/machinery/oxygen_pump/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + data["showToggle"] = FALSE + data["maskConnected"] = !!breather + + data["tankPressure"] = 0 + data["releasePressure"] = 0 + data["defaultReleasePressure"] = 0 + data["minReleasePressure"] = 0 + data["releasePressure"] = round(tank.distribute_pressure ? tank.distribute_pressure : 0) + data["maxReleasePressure"] = round(TANK_MAX_RELEASE_PRESSURE) + if(tank) data["tankPressure"] = round(tank.air_contents.return_pressure() ? tank.air_contents.return_pressure() : 0) - data["releasePressure"] = round(tank.distribute_pressure ? tank.distribute_pressure : 0) data["defaultReleasePressure"] = round(TANK_DEFAULT_RELEASE_PRESSURE) - data["maxReleasePressure"] = round(TANK_MAX_RELEASE_PRESSURE) - data["maskConnected"] = 0 - data["tankInstalled"] = 1 - if(!breather) - data["maskConnected"] = 0 - if(breather) - data["maskConnected"] = 1 + return data - - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "Oxygen_pump.tmpl", "Tank", 500, 300) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) - -/obj/machinery/oxygen_pump/Topic(href, href_list) +/obj/machinery/oxygen_pump/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return 1 + return TRUE - if (href_list["dist_p"]) - if (href_list["dist_p"] == "reset") - tank.distribute_pressure = TANK_DEFAULT_RELEASE_PRESSURE - else if (href_list["dist_p"] == "max") - tank.distribute_pressure = TANK_MAX_RELEASE_PRESSURE - else - var/cp = text2num(href_list["dist_p"]) - tank.distribute_pressure += cp - tank.distribute_pressure = min(max(round(tank.distribute_pressure), 0), TANK_MAX_RELEASE_PRESSURE) - return 1 + switch(action) + if("pressure") + var/pressure = params["pressure"] + if(pressure == "reset") + pressure = TANK_DEFAULT_RELEASE_PRESSURE + . = TRUE + else if(pressure == "min") + pressure = 0 + . = TRUE + else if(pressure == "max") + pressure = TANK_MAX_RELEASE_PRESSURE + . = TRUE + else if(text2num(pressure) != null) + pressure = text2num(pressure) + . = TRUE + if(.) + tank.distribute_pressure = clamp(round(pressure), 0, TANK_MAX_RELEASE_PRESSURE) /obj/machinery/oxygen_pump/anesthetic name = "anesthetic pump" diff --git a/code/game/machinery/painter_vr.dm b/code/game/machinery/painter_vr.dm index cc961a737f..64490a19b2 100644 --- a/code/game/machinery/painter_vr.dm +++ b/code/game/machinery/painter_vr.dm @@ -1,3 +1,10 @@ +// I'm honestly pretty sure that short of stuffing five million things into this +// there's absolutely no way it could ever have any performance impact +// Given that all it does is set the color var +// But just in case it's cursed in some arcane horrible way +// I'm going to leave this limit here +#define MAX_PROCESSING 10 // Arbitrary performance insurance + /obj/machinery/gear_painter name = "Color Mate" desc = "A machine to give your apparel a fresh new color! Recommended to use with white items for best results." @@ -29,9 +36,9 @@ processing.Cut() return ..() -/obj/machinery/gear_painter/attackby(obj/item/W as obj, mob/user as mob) - if(processing.len) - to_chat(user, "The machine is already loaded.") +/obj/machinery/gear_painter/attackby(obj/item/W, mob/user) + if(LAZYLEN(processing) >= MAX_PROCESSING) + to_chat(user, "The machine is full.") return if(default_deconstruction_screwdriver(user, W)) return @@ -45,65 +52,65 @@ user.drop_from_inventory(W) W.forceMove(src) processing |= W + SStgui.update_uis(src) else ..() update_icon() -/obj/machinery/gear_painter/attack_hand(mob/user as mob) +/obj/machinery/gear_painter/attack_hand(mob/user) if(..()) return - interact(user) + tgui_interact(user) -/obj/machinery/gear_painter/interact(mob/user as mob) - if(inoperable()) - return - user.set_machine(src) - var/dat = "Color Mate Control Panel
" - if(!processing.len) - dat += "No item inserted." - else - for(var/atom/movable/O in processing) - dat += "Item inserted: [O]
" - dat += "Select new color.
" - dat += "Color: " - dat += "Apply new color.

" - dat += "Remove paintjob.

" - dat += "Eject item.

" +/obj/machinery/gear_painter/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ColorMate", name) + ui.open() - var/datum/browser/menu = new(user, "colormate","Color Mate Control Panel", 400, 600, src) - menu.set_content(dat) - menu.open() - return +/obj/machinery/gear_painter/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() -/obj/machinery/gear_painter/Topic(href, href_list) + var/list/items = list() + for(var/atom/movable/O in processing) + items.Add("[O]") + data["items"] = items + + data["activecolor"] = activecolor + return data + +/obj/machinery/gear_painter/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return + return TRUE - usr.set_machine(src) add_fingerprint(usr) - if(href_list["close"]) - return + switch(action) + if("select") + var/newcolor = input(usr, "Choose a color.", "", activecolor) as color|null + if(newcolor) + activecolor = newcolor + . = TRUE - if(href_list["select"]) - var/newcolor = input(usr, "Choose a color.", "", activecolor) as color|null - if(newcolor) - activecolor = newcolor + if("paint") + for(var/atom/movable/O in processing) + O.color = activecolor + CHECK_TICK + playsound(src, 'sound/effects/spray3.ogg', 50, 1) + . = TRUE - if(href_list["paint"]) - for(var/atom/movable/O in processing) - O.color = activecolor - playsound(src, 'sound/effects/spray3.ogg', 50, 1) + if("clear") + for(var/atom/movable/O in processing) + O.color = initial(O.color) + CHECK_TICK + playsound(src, 'sound/effects/spray3.ogg', 50, 1) + . = TRUE - if(href_list["clear"]) - for(var/atom/movable/O in processing) - O.color = initial(O.color) - playsound(src, 'sound/effects/spray3.ogg', 50, 1) - - if(href_list["eject"]) - for(var/atom/movable/O in processing) - O.forceMove(drop_location()) - processing.Cut() + if("eject") + for(var/atom/movable/O in processing) + O.forceMove(drop_location()) + CHECK_TICK + processing.Cut() + . = TRUE update_icon() - updateUsrDialog() diff --git a/code/game/machinery/partslathe_vr.dm b/code/game/machinery/partslathe_vr.dm index aab15f40f9..c5ddcff900 100644 --- a/code/game/machinery/partslathe_vr.dm +++ b/code/game/machinery/partslathe_vr.dm @@ -233,7 +233,6 @@ /obj/machinery/partslathe/attack_hand(mob/user) if(..()) return - ui_interact(user) tgui_interact(user) /obj/machinery/partslathe/ui_assets(mob/user) diff --git a/code/game/machinery/pda_multicaster.dm b/code/game/machinery/pda_multicaster.dm index 20e870d3d0..a70f1ede37 100644 --- a/code/game/machinery/pda_multicaster.dm +++ b/code/game/machinery/pda_multicaster.dm @@ -63,7 +63,9 @@ /obj/machinery/pda_multicaster/proc/update_PDAs(var/turn_off) for(var/obj/item/device/pda/pda in contents) - pda.toff = turn_off + var/datum/data/pda/app/messenger/M = pda.find_program(/datum/data/pda/app/messenger/multicast) + if(M) + M.toff = turn_off /obj/machinery/pda_multicaster/proc/update_power() if(toggle) diff --git a/code/game/machinery/pipe/pipelayer.dm b/code/game/machinery/pipe/pipelayer.dm index 8b49989e61..e671f2bb52 100644 --- a/code/game/machinery/pipe/pipelayer.dm +++ b/code/game/machinery/pipe/pipelayer.dm @@ -145,7 +145,7 @@ /obj/machinery/pipelayer/proc/eject_metal() var/amount_ejected = 0 while (metal >= 1) - var/material/M = get_material_by_name(DEFAULT_WALL_MATERIAL) + var/datum/material/M = get_material_by_name(DEFAULT_WALL_MATERIAL) var/obj/item/stack/material/S = new M.stack_type(get_turf(src)) S.amount = min(metal, S.max_amount) metal -= S.amount diff --git a/code/game/machinery/pointdefense.dm b/code/game/machinery/pointdefense.dm index 7391cbe65e..637ad9f53b 100644 --- a/code/game/machinery/pointdefense.dm +++ b/code/game/machinery/pointdefense.dm @@ -95,7 +95,7 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense) /obj/machinery/pointdefense_control/attackby(var/obj/item/W, var/mob/user) if(W?.is_multitool()) var/new_ident = input(user, "Enter a new ident tag.", "[src]", id_tag) as null|text - if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, physical_state)) + if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, GLOB.tgui_physical_state)) // Check for duplicate controllers with this ID for(var/thing in GLOB.pointdefense_controllers) var/obj/machinery/pointdefense_control/PC = thing @@ -211,7 +211,7 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense) /obj/machinery/power/pointdefense/attackby(var/obj/item/W, var/mob/user) if(W?.is_multitool()) var/new_ident = input(user, "Enter a new ident tag.", "[src]", id_tag) as null|text - if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, physical_state)) + if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, GLOB.tgui_physical_state)) to_chat(user, "You register [src] with the [new_ident] network.") id_tag = new_ident return diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 1ed44c61bc..01a890bd79 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -66,6 +66,7 @@ var/last_fired = FALSE //TRUE: if the turret is cooling down from a shot, FALSE: turret is ready to fire var/shot_delay = 1.5 SECONDS //1.5 seconds between each shot + var/targetting_is_configurable = TRUE // if false, you cannot change who this turret attacks via its UI var/check_arrest = TRUE //checks if the perp is set to arrest var/check_records = TRUE //checks if a security record exists at all var/check_weapons = FALSE //checks if it can shoot people that have a weapon they aren't authorized to have @@ -81,6 +82,7 @@ var/enabled = TRUE //determines if the turret is on var/lethal = FALSE //whether in lethal or stun mode + var/lethal_is_configurable = TRUE // if false, its lethal setting cannot be changed var/disabled = FALSE var/shot_sound //what sound should play when the turret fires @@ -214,6 +216,9 @@ req_one_access = list() installation = /obj/item/weapon/gun/energy/lasertag/omni + targetting_is_configurable = FALSE + lethal_is_configurable = FALSE + locked = FALSE enabled = FALSE anchored = FALSE @@ -262,43 +267,14 @@ if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag) && check_weapons) // Checks if they are a blue player return TURRET_PRIORITY_TARGET -/obj/machinery/porta_turret/lasertag/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - data["access"] = !isLocked(user) - data["locked"] = locked - data["enabled"] = enabled - //data["is_lethal"] = 1 // VOREStation Removal of "Lethal" setting - it does nothing. Rykka did dis. - //data["lethal"] = lethal // VOREStation Removal of "Lethal" setting - it does nothing. Rykka did dis. - - if(data["access"]) - var/settings[0] - settings[++settings.len] = list("category" = "Target Red", "setting" = "check_synth", "value" = check_synth) // Could not get the UI to work with new vars specifically for lasertag turrets -Nalarac - settings[++settings.len] = list("category" = "Target Blue", "setting" = "check_weapons", "value" = check_weapons) // So I'm using these variables since they don't do anything else in this case - data["settings"] = settings - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 300) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/porta_turret/lasertag/Topic(href, href_list) - if(..()) - return 1 - - if(href_list["command"] && href_list["value"]) - var/value = text2num(href_list["value"]) - if(href_list["command"] == "enable") - enabled = value - //else if(href_list["command"] == "lethal") // VOREStation Removal of "Lethal" setting - it does nothing. Rykka did dis. - //lethal = value // VOREStation Removal of "Lethal" setting - it does nothing. Rykka did dis. - else if(href_list["command"] == "check_synth") - check_synth = value - else if(href_list["command"] == "check_weapons") - check_weapons = value - - return 1 +/obj/machinery/porta_turret/lasertag/tgui_data(mob/user) + var/list/data = list( + "locked" = isLocked(user), // does the current user have access? + "on" = enabled, // is turret turned on? + "lethal" = lethal, + "lethal_is_configurable" = lethal_is_configurable + ) + return data /obj/machinery/porta_turret/Initialize() //Sets up a spark system @@ -401,102 +377,99 @@ lethal_shot_sound = 'sound/weapons/eluger.ogg' shot_sound = 'sound/weapons/Taser.ogg' -/obj/machinery/porta_turret/proc/isLocked(mob/user) - if(ailock && issilicon(user)) - to_chat(user, "There seems to be a firewall preventing you from accessing this device.") - return 1 - - if(locked && !issilicon(user)) - to_chat(user, "Controls locked.") - return 1 - - return 0 - -/obj/machinery/porta_turret/attack_ai(mob/user) - if(isLocked(user)) - return - - ui_interact(user) - -/obj/machinery/porta_turret/attack_hand(mob/user) - if(isLocked(user)) - return - - ui_interact(user) - -/obj/machinery/porta_turret/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - data["access"] = !isLocked(user) - data["locked"] = locked - data["enabled"] = enabled - data["is_lethal"] = 1 - data["lethal"] = lethal - - if(data["access"]) - var/settings[0] - settings[++settings.len] = list("category" = "Neutralize All Non-Synthetics", "setting" = "check_synth", "value" = check_synth) - settings[++settings.len] = list("category" = "Check Weapon Authorization", "setting" = "check_weapons", "value" = check_weapons) - settings[++settings.len] = list("category" = "Check Security Records", "setting" = "check_records", "value" = check_records) - settings[++settings.len] = list("category" = "Check Arrest Status", "setting" = "check_arrest", "value" = check_arrest) - settings[++settings.len] = list("category" = "Check Access Authorization", "setting" = "check_access", "value" = check_access) - settings[++settings.len] = list("category" = "Check misc. Lifeforms", "setting" = "check_anomalies", "value" = check_anomalies) - settings[++settings.len] = list("category" = "Neutralize All Entities", "setting" = "check_all", "value" = check_all) - settings[++settings.len] = list("category" = "Neutralize Downed Entities", "setting" = "check_down", "value" = check_down) - data["settings"] = settings - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 300) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - /obj/machinery/porta_turret/proc/HasController() var/area/A = get_area(src) return A && A.turret_controls.len > 0 -/obj/machinery/porta_turret/CanUseTopic(var/mob/user) +/obj/machinery/porta_turret/proc/isLocked(mob/user) if(HasController()) - to_chat(user, "Turrets can only be controlled using the assigned turret controller.") - return STATUS_CLOSE + return TRUE + if(isrobot(user) || isAI(user)) + if(ailock) + to_chat(user, "There seems to be a firewall preventing you from accessing this device.") + return TRUE + else + return FALSE + if(isobserver(user)) + var/mob/observer/dead/D = user + if(D.can_admin_interact()) + return FALSE + else + return TRUE + if(locked) + return TRUE + return FALSE - if(isLocked(user)) - return STATUS_CLOSE +/obj/machinery/porta_turret/attack_ai(mob/user) + tgui_interact(user) +/obj/machinery/porta_turret/attack_ghost(mob/user) + tgui_interact(user) + +/obj/machinery/porta_turret/attack_hand(mob/user) + tgui_interact(user) + +/obj/machinery/porta_turret/tgui_interact(mob/user, datum/tgui/ui = null) + if(HasController()) + to_chat(user, "[src] can only be controlled using the assigned turret controller.") + return if(!anchored) - to_chat(user, "\The [src] has to be secured first!") - return STATUS_CLOSE + to_chat(user, "[src] has to be secured first!") + return + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PortableTurret", name, 500, 400) + ui.open() - return ..() +/obj/machinery/porta_turret/tgui_data(mob/user) + var/list/data = list( + "locked" = isLocked(user), // does the current user have access? + "on" = enabled, + "targetting_is_configurable" = targetting_is_configurable, // If false, targetting settings don't show up + "lethal" = lethal, + "lethal_is_configurable" = lethal_is_configurable, + "check_weapons" = check_weapons, + "neutralize_noaccess" = check_access, + "neutralize_norecord" = check_records, + "neutralize_criminals" = check_arrest, + "neutralize_all" = check_all, + "neutralize_nonsynth" = check_synth, + "neutralize_unidentified" = check_anomalies, + "neutralize_down" = check_down, + ) + return data -/obj/machinery/porta_turret/Topic(href, href_list) +/obj/machinery/porta_turret/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return 1 + return TRUE + if(isLocked(usr)) + return TRUE + . = TRUE - if(href_list["command"] && href_list["value"]) - var/value = text2num(href_list["value"]) - if(href_list["command"] == "enable") - enabled = value - else if(href_list["command"] == "lethal") - lethal = value - else if(href_list["command"] == "check_synth") - check_synth = value - else if(href_list["command"] == "check_weapons") - check_weapons = value - else if(href_list["command"] == "check_records") - check_records = value - else if(href_list["command"] == "check_arrest") - check_arrest = value - else if(href_list["command"] == "check_access") - check_access = value - else if(href_list["command"] == "check_anomalies") - check_anomalies = value - else if(href_list["command"] == "check_all") - check_all = value - else if(href_list["command"] == "check_down") - check_down = value - - return 1 + switch(action) + if("power") + enabled = !enabled + if("lethal") + if(lethal_is_configurable) + lethal = !lethal + if(targetting_is_configurable) + switch(action) + if("authweapon") + check_weapons = !check_weapons + if("authaccess") + check_access = !check_access + if("authnorecord") + check_records = !check_records + if("autharrest") + check_arrest = !check_arrest + if("authxeno") + check_anomalies = !check_anomalies + if("authsynth") + check_synth = !check_synth + if("authall") + check_all = !check_all + if("authdown") + check_down = !check_down /obj/machinery/porta_turret/power_change() if(powered()) @@ -929,6 +902,7 @@ var/check_weapons var/check_anomalies var/check_all + var/check_down var/ailock /obj/machinery/porta_turret/proc/setState(var/datum/turret_checks/TC) @@ -944,6 +918,7 @@ check_weapons = TC.check_weapons check_anomalies = TC.check_anomalies check_all = TC.check_all + check_down = TC.check_down ailock = TC.ailock power_change() diff --git a/code/game/machinery/portable_turret_vr.dm b/code/game/machinery/portable_turret_vr.dm index c313ad27aa..4af3a78142 100644 --- a/code/game/machinery/portable_turret_vr.dm +++ b/code/game/machinery/portable_turret_vr.dm @@ -10,3 +10,16 @@ check_weapons = TRUE auto_repair = TRUE can_salvage = FALSE + +/obj/machinery/porta_turret/stationary/syndie/CIWS + name = "mercenary CIWS turret" + desc = "A ship-grade weapons turret designed for anti-fighter defense." + req_one_access = list(access_syndicate) + installation = /obj/item/weapon/gun/energy/lasercannon + health = 500 + maxhealth = 500 + enabled = TRUE + lethal = TRUE + check_weapons = TRUE + auto_repair = TRUE + can_salvage = FALSE \ No newline at end of file diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index 62a2e08918..6332bab79a 100644 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -105,6 +105,8 @@ return /obj/machinery/recharger/attack_hand(mob/user as mob) + if(!Adjacent(user)) + return FALSE add_fingerprint(user) if(charging) diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index e87de196d9..86b339e6d5 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -104,7 +104,6 @@ var/list/obj/machinery/requests_console/allConsoles = list() /obj/machinery/requests_console/attack_hand(user as mob) if(..(user)) return - ui_interact(user) tgui_interact(user) /obj/machinery/requests_console/tgui_interact(mob/user, datum/tgui/ui) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 8aa944e849..3d13b800e2 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -652,12 +652,12 @@ /obj/machinery/suit_cycler/vintage/pilot name = "Vintage Pilot suit cycler" model_text = "Vintage Pilot" - departments = list("Vintage Pilot (Bubble Helm)","Vintage Pilot (Closed Helm)") + departments = list("Vintage Pilot (Bubble Helm)","Vintage Pilot (Closed Helm)","No Change") /obj/machinery/suit_cycler/vintage/medsci name = "Vintage MedSci suit cycler" model_text = "Vintage MedSci" - departments = list("Vintage Medical (Bubble Helm)","Vintage Medical (Closed Helm)","Vintage Research (Bubble Helm)","Vintage Research (Closed Helm)") + departments = list("Vintage Medical (Bubble Helm)","Vintage Medical (Closed Helm)","Vintage Research (Bubble Helm)","Vintage Research (Closed Helm)","No Change") /obj/machinery/suit_cycler/vintage/rugged name = "Vintage Ruggedized suit cycler" @@ -1052,14 +1052,6 @@ var/turf/T = get_turf(src) if(!target_species || !target_department) return - - if(target_species) - if(helmet) helmet.refit_for_species(target_species) - if(suit) - suit.refit_for_species(target_species) - if(suit.helmet) - suit.helmet.refit_for_species(target_species) - //Now "Complete" with most departmental and variant suits, and sorted by department. These aren't available in the standard or emagged cycler lists because they're incomplete for most species. switch(target_department) if("No Change") diff --git a/code/game/machinery/suit_storage_unit_vr.dm b/code/game/machinery/suit_storage_unit_vr.dm index 3db523972a..2b354cbd93 100644 --- a/code/game/machinery/suit_storage_unit_vr.dm +++ b/code/game/machinery/suit_storage_unit_vr.dm @@ -1,6 +1,6 @@ /obj/machinery/suit_cycler departments = list("Engineering","Mining","Medical","Security","Atmos","HAZMAT","Construction","Biohazard","Emergency Medical Response","Crowd Control","Exploration","Pilot Blue","Pilot","Manager","Prototype") - species = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_UNATHI, SPECIES_TAJ, SPECIES_TESHARI, SPECIES_AKULA, SPECIES_SERGAL, SPECIES_VULPKANIN, SPECIES_GREY_YW /*ywedit*/) + species = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_UNATHI, SPECIES_TAJ, SPECIES_TESHARI, SPECIES_AKULA, SPECIES_SERGAL, SPECIES_VULPKANIN, /*yawngreyedit*/SPECIES_GREY_YW) // Old Exploration is too WIP to use right now /obj/machinery/suit_cycler/exploration @@ -14,7 +14,7 @@ name = "Manager suit cycler" model_text = "Manager" req_access = list(access_captain) - departments = list("Manager") + departments = list("Manager","No Change") /obj/machinery/suit_cycler/captain/Initialize() //No Teshari Sprites species -= SPECIES_TESHARI @@ -64,4 +64,4 @@ name = "Talon captain suit cycler" model_text = "Talon captain" req_access = list(access_talon) - departments = list("Talon Officer","No Change") \ No newline at end of file + departments = list("Talon Officer","No Change") diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 5b7740b471..631e5b9779 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -11,7 +11,7 @@ var/id = null var/one_time_use = 0 //Used for one-time-use teleport cards (such as clown planet coordinates.) //Setting this to 1 will set locked to null after a player enters the portal and will not allow hand-teles to open portals to that location. - var/datum/nano_module/program/teleport_control/teleport_control + var/datum/tgui_module/teleport_control/teleport_control /obj/machinery/computer/teleporter/New() id = "[rand(1000, 9999)]" @@ -44,7 +44,7 @@ teleport_control.station = station /obj/machinery/computer/teleporter/Destroy() - qdel_null(teleport_control) + QDEL_NULL(teleport_control) return ..() /obj/machinery/computer/teleporter/attackby(I as obj, mob/living/user as mob) @@ -96,108 +96,13 @@ attack_hand() /obj/machinery/computer/teleporter/attack_ai(mob/user) - ui_interact(user) + teleport_control.tgui_interact(user) /obj/machinery/computer/teleporter/attack_hand(mob/user) add_fingerprint(user) if(stat & (BROKEN|NOPOWER)) return - ui_interact(user) - -/obj/machinery/computer/teleporter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - teleport_control.ui_interact(user, ui_key, ui, force_open) - -/obj/machinery/computer/teleporter/interact(mob/user) - teleport_control.ui_interact(user) - -////// -////// Nano-module for teleporter -////// -/datum/nano_module/program/teleport_control - name = "Teleporter Control" - var/locked_name = "Not Locked" - var/obj/item/locked = null - var/obj/machinery/teleport/station/station = null - var/obj/machinery/teleport/hub/hub = null - -/datum/nano_module/program/teleport_control/Topic(href, href_list) - if(..()) return 1 - - if(href_list["select_target"]) - var/list/L = list() - var/list/areaindex = list() - - for(var/obj/item/device/radio/beacon/R in GLOB.all_beacons) - var/turf/T = get_turf(R) - if(!T) - continue - if(!(T.z in using_map.player_levels)) - continue - var/tmpname = T.loc.name - if(areaindex[tmpname]) - tmpname = "[tmpname] ([++areaindex[tmpname]])" - else - areaindex[tmpname] = 1 - L[tmpname] = R - - for (var/obj/item/weapon/implant/tracking/I in GLOB.all_tracking_implants) - if(!I.implanted || !ismob(I.loc)) - continue - else - var/mob/M = I.loc - if(M.stat == 2) - if(M.timeofdeath + 6000 < world.time) - continue - var/turf/T = get_turf(M) - if(T) continue - if(T.z == 2) continue - var/tmpname = M.real_name - if(areaindex[tmpname]) - tmpname = "[tmpname] ([++areaindex[tmpname]])" - else - areaindex[tmpname] = 1 - L[tmpname] = I - - var/desc = input("Please select a location to lock in.", "Locking Menu") in L|null - if(!desc) - return 0 - if(get_dist(host, usr) > 1 && !issilicon(usr)) - return 0 - - locked = L[desc] - locked_name = desc - return 1 - - if(href_list["test_fire"]) - station?.testfire() - return 1 - - if(href_list["toggle_on"]) - if(!station) - return 0 - - if(station.engaged) - station.disengage() - else - station.engage() - - return 1 - -/datum/nano_module/program/teleport_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - - data["locked_name"] = locked_name ? locked_name : "No Target" - data["station_connected"] = station ? 1 : 0 - data["hub_connected"] = hub ? 1 : 0 - data["calibrated"] = hub ? hub.accurate : 0 - data["teleporter_on"] = station ? station.engaged : 0 - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "teleport_control.tmpl", "Teleport Control Console", 400, 500, state = state) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + teleport_control.tgui_interact(user) /obj/machinery/computer/teleporter/verb/set_id(t as text) set category = "Object" @@ -211,14 +116,6 @@ id = t return -/proc/find_loc(obj/R as obj) - if(!R) return null - var/turf/T = R.loc - while(!istype(T, /turf)) - T = T.loc - if(!T || istype(T, /area)) return null - return T - ////// ////// Root of all the machinery ////// diff --git a/code/game/machinery/turret_control.dm b/code/game/machinery/turret_control.dm index a3d10db557..ad55fe14a1 100644 --- a/code/game/machinery/turret_control.dm +++ b/code/game/machinery/turret_control.dm @@ -11,31 +11,35 @@ desc = "Used to control a room's automated defenses." icon = 'icons/obj/machines/turret_control.dmi' icon_state = "control_standby" - anchored = 1 - density = 0 - var/enabled = 0 - var/lethal = 0 - var/locked = 1 + anchored = TRUE + density = FALSE + var/enabled = FALSE + var/lethal = FALSE + var/lethal_is_configurable = TRUE + var/locked = TRUE var/area/control_area //can be area name, path or nothing. - var/check_arrest = 1 //checks if the perp is set to arrest - var/check_records = 1 //checks if a security record exists at all - var/check_weapons = 0 //checks if it can shoot people that have a weapon they aren't authorized to have - var/check_access = 1 //if this is active, the turret shoots everything that does not meet the access requirements - var/check_anomalies = 1 //checks if it can shoot at unidentified lifeforms (ie xenos) - var/check_synth = 0 //if active, will shoot at anything not an AI or cyborg - var/check_all = 0 //If active, will shoot at anything. - var/ailock = 0 //Silicons cannot use this + var/targetting_is_configurable = TRUE // if false, you cannot change who this turret attacks via its UI + var/check_arrest = TRUE //checks if the perp is set to arrest + var/check_records = TRUE //checks if a security record exists at all + var/check_weapons = FALSE //checks if it can shoot people that have a weapon they aren't authorized to have + var/check_access = TRUE //if this is active, the turret shoots everything that does not meet the access requirements + var/check_anomalies = TRUE //checks if it can shoot at unidentified lifeforms (ie xenos) + var/check_synth = FALSE //if active, will shoot at anything not an AI or cyborg + var/check_all = FALSE //If active, will shoot at anything. + var/check_down = TRUE //If active, won't shoot laying targets. + var/ailock = FALSE //Silicons cannot use this + var/syndicate = FALSE req_access = list(access_ai_upload) /obj/machinery/turretid/stun - enabled = 1 + enabled = TRUE icon_state = "control_stun" /obj/machinery/turretid/lethal - enabled = 1 - lethal = 1 + enabled = TRUE + lethal = TRUE icon_state = "control_kill" /obj/machinery/turretid/Destroy() @@ -67,21 +71,24 @@ . = ..() /obj/machinery/turretid/proc/isLocked(mob/user) - if(ailock && issilicon(user)) - to_chat(user, "There seems to be a firewall preventing you from accessing this device.") - return 1 + if(isrobot(user) || isAI(user)) + if(ailock) + to_chat(user, "There seems to be a firewall preventing you from accessing this device.") + return TRUE + else + return FALSE - if(locked && !issilicon(user)) - to_chat(user, "Access denied.") - return 1 + if(isobserver(user)) + var/mob/observer/dead/D = user + if(D.can_admin_interact()) + return FALSE + else + return TRUE - return 0 + if(locked) + return TRUE -/obj/machinery/turretid/CanUseTopic(mob/user) - if(isLocked(user)) - return STATUS_CLOSE - - return ..() + return FALSE /obj/machinery/turretid/attackby(obj/item/weapon/W, mob/user) if(stat & BROKEN) @@ -100,77 +107,80 @@ /obj/machinery/turretid/emag_act(var/remaining_charges, var/mob/user) if(!emagged) to_chat(user, "You short out the turret controls' access analysis module.") - emagged = 1 - locked = 0 - ailock = 0 - return 1 + emagged = TRUE + locked = FALSE + ailock = FALSE + return TRUE /obj/machinery/turretid/attack_ai(mob/user as mob) - if(isLocked(user)) - return + tgui_interact(user) - ui_interact(user) +/obj/machinery/turretid/attack_ghost(mob/user as mob) + tgui_interact(user) /obj/machinery/turretid/attack_hand(mob/user as mob) - if(isLocked(user)) + tgui_interact(user) + +/obj/machinery/turretid/tgui_interact(mob/user, datum/tgui/ui = null) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PortableTurret", name) // 500, 400 + ui.open() + +/obj/machinery/turretid/tgui_data(mob/user) + var/list/data = list( + "locked" = isLocked(user), // does the current user have access? + "on" = enabled, + "targetting_is_configurable" = targetting_is_configurable, + "lethal" = lethal, + "lethal_is_configurable" = lethal_is_configurable, + "check_weapons" = check_weapons, + "neutralize_noaccess" = check_access, + "one_access" = FALSE, + "selectedAccess" = list(), + "access_is_configurable" = FALSE, + "neutralize_norecord" = check_records, + "neutralize_criminals" = check_arrest, + "neutralize_nonsynth" = check_synth, + "neutralize_all" = check_all, + "neutralize_unidentified" = check_anomalies, + "neutralize_down" = check_down, + ) + return data + +/obj/machinery/turretid/tgui_act(action, params) + if(..()) + return + if(isLocked(usr)) return - ui_interact(user) + . = TRUE + switch(action) + if("power") + enabled = !enabled + if("lethal") + if(lethal_is_configurable) + lethal = !lethal + if(targetting_is_configurable) + switch(action) + if("authweapon") + check_weapons = !check_weapons + if("authaccess") + check_access = !check_access + if("authnorecord") + check_records = !check_records + if("autharrest") + check_arrest = !check_arrest + if("authxeno") + check_anomalies = !check_anomalies + if("authsynth") + check_synth = !check_synth + if("authall") + check_all = !check_all + if("authdown") + check_down = !check_down -/obj/machinery/turretid/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - data["access"] = !isLocked(user) - data["locked"] = locked - data["enabled"] = enabled - data["is_lethal"] = 1 - data["lethal"] = lethal - - if(data["access"]) - var/settings[0] - settings[++settings.len] = list("category" = "Neutralize All Non-Synthetics", "setting" = "check_synth", "value" = check_synth) - settings[++settings.len] = list("category" = "Check Weapon Authorization", "setting" = "check_weapons", "value" = check_weapons) - settings[++settings.len] = list("category" = "Check Security Records", "setting" = "check_records", "value" = check_records) - settings[++settings.len] = list("category" = "Check Arrest Status", "setting" = "check_arrest", "value" = check_arrest) - settings[++settings.len] = list("category" = "Check Access Authorization", "setting" = "check_access", "value" = check_access) - settings[++settings.len] = list("category" = "Check misc. Lifeforms", "setting" = "check_anomalies", "value" = check_anomalies) - settings[++settings.len] = list("category" = "Neutralize All Entities", "setting" = "check_all", "value" = check_all) - - data["settings"] = settings - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 300) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/turretid/Topic(href, href_list) - if(..()) - return 1 - - if(href_list["command"] && href_list["value"]) - var/value = text2num(href_list["value"]) - if(href_list["command"] == "enable") - enabled = value - else if(href_list["command"] == "lethal") - lethal = value - else if(href_list["command"] == "check_synth") - check_synth = value - else if(href_list["command"] == "check_weapons") - check_weapons = value - else if(href_list["command"] == "check_records") - check_records = value - else if(href_list["command"] == "check_arrest") - check_arrest = value - else if(href_list["command"] == "check_access") - check_access = value - else if(href_list["command"] == "check_anomalies") - check_anomalies = value - else if(href_list["command"] == "check_all") - check_all = value - - updateTurrets() - return 1 + updateTurrets() /obj/machinery/turretid/proc/updateTurrets() var/datum/turret_checks/TC = new @@ -183,10 +193,11 @@ TC.check_weapons = check_weapons TC.check_anomalies = check_anomalies TC.check_all = check_all + TC.check_down = check_down TC.ailock = ailock if(istype(control_area)) - for (var/obj/machinery/porta_turret/aTurret in control_area) + for(var/obj/machinery/porta_turret/aTurret in control_area) aTurret.setState(TC) update_icon() diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index dcdd8d88fe..c918fca5d2 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -26,9 +26,6 @@ var/vend_delay = 10 //How long does it take to vend? var/categories = CAT_NORMAL // Bitmask of cats we're currently showing var/datum/stored_item/vending_product/currently_vending = null // What we're requesting payment for right now - var/tmp/actively_vending = null // Used to allow TGUI to display normal items in-progress being vended - var/status_message = "" // Status screen messages like "insufficient funds", displayed in NanoUI - var/status_error = 0 // Set to 1 if status_message is an error var/vending_sound = "machines/vending/vending_drop.ogg" /* @@ -91,6 +88,7 @@ build_inventory() power_change() +GLOBAL_LIST_EMPTY(vending_products) /** * Build produdct_records from the products lists * @@ -115,6 +113,7 @@ product.category = category product_records.Add(product) + GLOB.vending_products[entry] = 1 /obj/machinery/vending/Destroy() qdel(wires) @@ -151,32 +150,8 @@ return 1 /obj/machinery/vending/attackby(obj/item/weapon/W as obj, mob/user as mob) - var/obj/item/weapon/card/id/I = W.GetID() - if(currently_vending && vendor_account && !vendor_account.suspended) - var/paid = 0 - var/handled = 0 - - if(I) //for IDs and PDAs and wallets with IDs - paid = pay_with_card(I,W) - handled = 1 - else if(istype(W, /obj/item/weapon/spacecash/ewallet)) - var/obj/item/weapon/spacecash/ewallet/C = W - paid = pay_with_ewallet(C) - handled = 1 - else if(istype(W, /obj/item/weapon/spacecash)) - var/obj/item/weapon/spacecash/C = W - paid = pay_with_cash(C, user) - handled = 1 - - if(paid) - vend(currently_vending, usr) - return - else if(handled) - SStgui.update_uis(src) - return // don't smack that machine with your 2 thalers - if(I || istype(W, /obj/item/weapon/spacecash)) attack_hand(user) return @@ -262,8 +237,7 @@ visible_message("\The [usr] swipes \the [wallet] through \the [src].") playsound(src, 'sound/machines/id_swipe.ogg', 50, 1) if(currently_vending.price > wallet.worth) - status_message = "Insufficient funds on chargecard." - status_error = 1 + to_chat(usr, "Insufficient funds on chargecard.") return 0 else wallet.worth -= currently_vending.price @@ -276,22 +250,18 @@ * Takes payment for whatever is the currently_vending item. Returns 1 if * successful, 0 if failed */ -/obj/machinery/vending/proc/pay_with_card(var/obj/item/weapon/card/id/I, var/obj/item/ID_container) - if(I==ID_container || ID_container == null) - visible_message("\The [usr] swipes \the [I] through \the [src].") - else - visible_message("\The [usr] swipes \the [ID_container] through \the [src].") +/obj/machinery/vending/proc/pay_with_card(obj/item/weapon/card/id/I, mob/M) + visible_message("[M] swipes a card through [src].") playsound(src, 'sound/machines/id_swipe.ogg', 50, 1) + var/datum/money_account/customer_account = get_account(I.associated_account_number) if(!customer_account) - status_message = "Error: Unable to access account. Please contact technical support if problem persists." - status_error = 1 - return 0 + to_chat(M, "Error: Unable to access account. Please contact technical support if problem persists.") + return FALSE if(customer_account.suspended) - status_message = "Unable to access account: account suspended." - status_error = 1 - return 0 + to_chat(M, "Unable to access account: account suspended.") + return FALSE // Have the customer punch in the PIN before checking if there's enough money. Prevents people from figuring out acct is // empty at high security levels @@ -300,38 +270,36 @@ customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2) if(!customer_account) - status_message = "Unable to access account: incorrect credentials." - status_error = 1 - return 0 + to_chat(M, "Unable to access account: incorrect credentials.") + return FALSE if(currently_vending.price > customer_account.money) - status_message = "Insufficient funds in account." - status_error = 1 - return 0 + to_chat(M, "Insufficient funds in account.") + return FALSE + + // Okay to move the money at this point + + // debit money from the purchaser's account + customer_account.money -= currently_vending.price + + // create entry in the purchaser's account log + var/datum/transaction/T = new() + T.target_name = "[vendor_account.owner_name] (via [name])" + T.purpose = "Purchase of [currently_vending.item_name]" + if(currently_vending.price > 0) + T.amount = "([currently_vending.price])" else - // Okay to move the money at this point + T.amount = "[currently_vending.price]" + T.source_terminal = name + T.date = current_date_string + T.time = stationtime2text() + customer_account.transaction_log.Add(T) - // debit money from the purchaser's account - customer_account.money -= currently_vending.price - - // create entry in the purchaser's account log - var/datum/transaction/T = new() - T.target_name = "[vendor_account.owner_name] (via [name])" - T.purpose = "Purchase of [currently_vending.item_name]" - if(currently_vending.price > 0) - T.amount = "([currently_vending.price])" - else - T.amount = "[currently_vending.price]" - T.source_terminal = name - T.date = current_date_string - T.time = stationtime2text() - customer_account.transaction_log.Add(T) - - // Give the vendor the money. We use the account owner name, which means - // that purchases made with stolen/borrowed card will look like the card - // owner made them - credit_purchase(customer_account.owner_name) - return 1 + // Give the vendor the money. We use the account owner name, which means + // that purchases made with stolen/borrowed card will look like the card + // owner made them + credit_purchase(customer_account.owner_name) + return 1 /** * Add money for current purchase to the vendor account. @@ -367,6 +335,11 @@ wires.Interact(user) tgui_interact(user) +/obj/machinery/vending/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/vending), + ) + /obj/machinery/vending/tgui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) @@ -375,39 +348,34 @@ /obj/machinery/vending/tgui_data(mob/user) var/list/data = list() - if(currently_vending) - data["mode"] = 1 - data["product"] = currently_vending.item_name - data["price"] = currently_vending.price - data["message"] = status_message - data["message_err"] = status_error - data["products"] = null - else - data["mode"] = 0 - var/list/listed_products = list() + var/list/listed_products = list() - for(var/key = 1 to product_records.len) - var/datum/stored_item/vending_product/I = product_records[key] + data["chargesMoney"] = length(prices) > 0 ? TRUE : FALSE + for(var/key = 1 to product_records.len) + var/datum/stored_item/vending_product/I = product_records[key] - if(!(I.category & categories)) - continue + if(!(I.category & categories)) + continue - listed_products.Add(list(list( - "key" = key, - "name" = I.item_name, - "price" = I.price, - "color" = I.display_color, - "amount" = I.get_amount()))) + listed_products.Add(list(list( + "key" = key, + "name" = I.item_name, + "price" = I.price, + "color" = I.display_color, + "isatom" = ispath(I.item_path, /atom), + "path" = replacetext(replacetext("[I.item_path]", "/obj/item/", ""), "/", "-"), + "amount" = I.get_amount() + ))) - data["products"] = listed_products + data["products"] = listed_products if(coin) data["coin"] = coin.name else data["coin"] = FALSE - if(actively_vending) - data["actively_vending"] = actively_vending + if(currently_vending) + data["actively_vending"] = currently_vending.item_name else data["actively_vending"] = null @@ -417,6 +385,29 @@ else data["panel"] = 0 + var/mob/living/carbon/human/H + var/obj/item/weapon/card/id/C + + data["guestNotice"] = "No valid ID card detected. Wear your ID, or present cash."; + data["userMoney"] = 0 + data["user"] = null + if(ishuman(user)) + H = user + C = H.GetIdCard() + var/obj/item/weapon/spacecash/S = H.get_active_hand() + if(istype(S)) + data["userMoney"] = S.worth + data["guestNotice"] = "Accepting [S.initial_name]. You have: [S.worth]â‚®." + else if(istype(C)) + var/datum/money_account/A = get_account(C.associated_account_number) + if(istype(A)) + data["user"] = list() + data["user"]["name"] = A.owner_name + data["userMoney"] = A.money + data["user"]["job"] = (istype(C) && C.rank) ? C.rank : "No Job" + else + data["guestNotice"] = "Unlinked ID detected. Present cash to pay."; + return data /obj/machinery/vending/tgui_act(action, params) @@ -427,36 +418,36 @@ if(..()) return TRUE - if(action == "remove_coin") - if(issilicon(usr)) - return FALSE - - if(!coin) - to_chat(usr, "There is no coin in this machine.") - return - - coin.forceMove(src.loc) - if(!usr.get_active_hand()) - usr.put_in_hands(coin) - - to_chat(usr, "You remove \the [coin] from \the [src].") - coin = null - categories &= ~CAT_COIN - return TRUE - - if(!usr.contents.Find(src) && (!in_range(src, usr) && isturf(loc))) - return FALSE - . = TRUE switch(action) + if("remove_coin") + if(issilicon(usr)) + return FALSE + + if(!coin) + to_chat(usr, "There is no coin in this machine.") + return + + coin.forceMove(src.loc) + if(!usr.get_active_hand()) + usr.put_in_hands(coin) + + to_chat(usr, "You remove \the [coin] from \the [src].") + coin = null + categories &= ~CAT_COIN + return TRUE if("vend") - if(!vend_ready || currently_vending) + if(!vend_ready) + to_chat(usr, "[src] is busy!") return if(!allowed(usr) && !emagged && scan_id) to_chat(usr, "Access denied.") //Unless emagged of course flick("[icon_state]-deny",src) playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0) return + if(panel_open) + to_chat(usr, "[src] cannot dispense products while its service panel is open!") + return var/key = text2num(params["vend"]) var/datum/stored_item/vending_product/R = product_records[key] @@ -464,39 +455,83 @@ // This should not happen unless the request from NanoUI was bad if(!(R.category & categories)) return + + if(!can_buy(R, usr)) + return + + vend_ready = FALSE // From this point onwards, vendor is locked to performing this transaction only, until it is resolved. if(R.price <= 0) vend(R, usr) - else if(issilicon(usr)) //If the item is not free, provide feedback if a synth is trying to buy something. + add_fingerprint(usr) + vend_ready = TRUE + return TRUE + + if(issilicon(usr)) //If the item is not free, provide feedback if a synth is trying to buy something. to_chat(usr, "Lawed unit recognized. Lawed units cannot complete this transaction. Purchase canceled.") return - else - currently_vending = R - if(!vendor_account || vendor_account.suspended) - status_message = "This machine is currently unable to process payments due to issues with the associated account." - status_error = 1 - else - status_message = "Please swipe a card or insert cash to pay for the item." - status_error = 0 + if(!ishuman(usr)) + return - if("cancelpurchase") - currently_vending = null + var/mob/living/carbon/human/H = usr + var/obj/item/weapon/card/id/C = H.GetIdCard() + + if(!vendor_account || vendor_account.suspended) + to_chat(usr, "Vendor account offline. Unable to process transaction.") + flick("[icon_state]-deny",src) + vend_ready = TRUE + return + + currently_vending = R + + var/paid = FALSE + + if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash)) + var/obj/item/weapon/spacecash/cash = usr.get_active_hand() + paid = pay_with_cash(cash, usr) + else if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash/ewallet)) + var/obj/item/weapon/spacecash/ewallet/wallet = usr.get_active_hand() + paid = pay_with_ewallet(wallet) + else if(istype(C, /obj/item/weapon/card)) + paid = pay_with_card(C, usr) + /*else if(usr.can_advanced_admin_interact()) + to_chat(usr, "Vending object due to admin interaction.") + paid = TRUE*/ + else + to_chat(usr, "Payment failure: you have no ID or other method of payment.") + vend_ready = TRUE + flick("[icon_state]-deny",src) + return TRUE // we set this because they shouldn't even be able to get this far, and we want the UI to update. + if(paid) + vend(currently_vending, usr) // vend will handle vend_ready + . = TRUE + else + to_chat(usr, "Payment failure: unable to process payment.") + vend_ready = TRUE if("togglevoice") if(!panel_open) return FALSE shut_up = !shut_up -/obj/machinery/vending/proc/vend(datum/stored_item/vending_product/R, mob/user) - if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH - to_chat(usr, "Access denied.") //Unless emagged of course +/obj/machinery/vending/proc/can_buy(datum/stored_item/vending_product/R, mob/user) + if(!allowed(user) && !emagged && scan_id) + to_chat(user, "Access denied.") //Unless emagged of course flick("[icon_state]-deny",src) playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0) + return FALSE + return TRUE + +/obj/machinery/vending/proc/vend(datum/stored_item/vending_product/R, mob/user) + if(!can_buy(R, user)) return - vend_ready = 0 //One thing at a time!! - actively_vending = R.item_name - status_message = "Vending..." - status_error = 0 + + if(!R.amount) + to_chat(user, "[src] has ran out of that product.") + vend_ready = TRUE + return + + vend_ready = FALSE //One thing at a time!! SStgui.update_uis(src) if(R.category & CAT_COIN) @@ -523,24 +558,22 @@ use_power(vend_power_usage) //actuators and stuff flick("[icon_state]-vend",src) - spawn(vend_delay) - R.get_product(get_turf(src)) - if(has_logs) - do_logging(R, user, 1) - if(prob(1)) - sleep(3) - if(R.get_product(get_turf(src))) - visible_message("\The [src] clunks as it vends an additional item.") - playsound(src, "sound/[vending_sound]", 100, 1, 1) + addtimer(CALLBACK(src, .proc/delayed_vend, R, user), vend_delay) - status_message = "" - status_error = 0 - vend_ready = 1 - actively_vending = null - currently_vending = null - SStgui.update_uis(src) +/obj/machinery/vending/proc/delayed_vend(datum/stored_item/vending_product/R, mob/user) + R.get_product(get_turf(src)) + if(has_logs) + do_logging(R, user, 1) + if(prob(1)) + sleep(3) + if(R.get_product(get_turf(src))) + visible_message("\The [src] clunks as it vends an additional item.") + playsound(src, "sound/[vending_sound]", 100, 1, 1) + + vend_ready = 1 + currently_vending = null + SStgui.update_uis(src) - return 1 /obj/machinery/vending/proc/do_logging(datum/stored_item/vending_product/R, mob/user, var/vending = 0) if(user.GetIdCard()) diff --git a/code/game/machinery/vending_machines.dm b/code/game/machinery/vending_machines.dm index 9fd733f711..82c9eb0581 100644 --- a/code/game/machinery/vending_machines.dm +++ b/code/game/machinery/vending_machines.dm @@ -535,6 +535,7 @@ product.category = category product_records.Add(product) + GLOB.vending_products[entry] = 1 /obj/machinery/vending/magivend name = "MagiVend" diff --git a/code/game/machinery/vitals_monitor.dm b/code/game/machinery/vitals_monitor.dm index a26c3ff706..e6d1ba5811 100644 --- a/code/game/machinery/vitals_monitor.dm +++ b/code/game/machinery/vitals_monitor.dm @@ -144,6 +144,6 @@ if(!istype(user)) return - if(CanInteract(user, physical_state)) + if(CanInteract(user, GLOB.tgui_physical_state)) beep = !beep to_chat(user, "You turn the sound on \the [src] [beep ? "on" : "off"].") diff --git a/code/game/mecha/combat/combat.dm b/code/game/mecha/combat/combat.dm index d618d276c3..7661bb3255 100644 --- a/code/game/mecha/combat/combat.dm +++ b/code/game/mecha/combat/combat.dm @@ -17,6 +17,8 @@ max_special_equip = 1 cargo_capacity = 1 + encumbrance_gap = 1.5 + starting_components = list( /obj/item/mecha_parts/component/hull/durable, /obj/item/mecha_parts/component/actuator, diff --git a/code/game/mecha/combat/phazon.dm b/code/game/mecha/combat/phazon.dm index 17aea92345..3ae3e41e13 100644 --- a/code/game/mecha/combat/phazon.dm +++ b/code/game/mecha/combat/phazon.dm @@ -25,6 +25,8 @@ max_universal_equip = 3 max_special_equip = 4 + encumbrance_gap = 2 + starting_components = list( /obj/item/mecha_parts/component/hull/durable, /obj/item/mecha_parts/component/actuator, diff --git a/code/game/mecha/components/actuators.dm b/code/game/mecha/components/actuators.dm index d814518629..b04306333b 100644 --- a/code/game/mecha/components/actuators.dm +++ b/code/game/mecha/components/actuators.dm @@ -19,7 +19,7 @@ internal_damage_flag = MECHA_INT_CONTROL_LOST - var/strafing_multiplier = 1.5 + var/strafing_multiplier = 1 /obj/item/mecha_parts/component/actuator/get_step_delay() return step_delay diff --git a/code/game/mecha/equipment/tools/drill.dm b/code/game/mecha/equipment/tools/drill.dm index 346481eb66..7a3587e454 100644 --- a/code/game/mecha/equipment/tools/drill.dm +++ b/code/game/mecha/equipment/tools/drill.dm @@ -49,11 +49,34 @@ for(var/obj/item/weapon/ore/ore in range(chassis,1)) if(get_dir(chassis,ore)&chassis.dir) ore.forceMove(ore_box) + else if(isliving(target)) + drill_mob(target, chassis.occupant) + return 1 else if(target.loc == C) log_message("Drilled through [target]") target.ex_act(2) return 1 +/obj/item/mecha_parts/mecha_equipment/tool/drill/proc/drill_mob(mob/living/target, mob/user) + add_attack_logs(user, target, "attacked", "[name]", "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])") + var/drill_force = force //Couldn't manage it otherwise. + if(ishuman(target)) + target.apply_damage(drill_force, BRUTE) + return + + else if(istype(target, /mob/living/simple_mob)) + var/mob/living/simple_mob/S = target + if(target.stat == DEAD) + if(S.meat_amount > 0) + S.harvest(user) + return + else + S.gib() + return + else + S.apply_damage(drill_force) + return + /obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill name = "diamond drill" desc = "This is an upgraded version of the drill that'll pierce the heavens!" diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index 320a1a2747..02c7e1f4df 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -32,6 +32,13 @@ chassis.visible_message("[chassis] fires [src]!") occupant_message("You fire [src]!") log_message("Fired from [src], targeting [target].") + var/target_for_log = "unknown" + if(ismob(target)) + target_for_log = target + else if(target) + target_for_log = "[target.name]" + add_attack_logs(chassis.occupant,target_for_log,"Fired exosuit weapon [src.name] (MANUAL)") + for(var/i = 1 to min(projectiles, projectiles_per_shot)) var/turf/aimloc = targloc if(deviation) @@ -86,4 +93,4 @@ if(!isnull(M.accuracy)) P.accuracy += M.accuracy if(!isnull(M.accuracy_dispersion)) - P.dispersion = max(P.dispersion + M.accuracy_dispersion, 0) \ No newline at end of file + P.dispersion = max(P.dispersion + M.accuracy_dispersion, 0) diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm index 521eb421de..fe8ec5876d 100644 --- a/code/game/mecha/mech_fabricator.dm +++ b/code/game/mecha/mech_fabricator.dm @@ -659,7 +659,7 @@ /obj/machinery/mecha_part_fabricator/proc/eject_materials(var/material, var/amount) // 0 amount = 0 means ejecting a full stack; -1 means eject everything var/recursive = amount == -1 ? 1 : 0 var/matstring = lowertext(material) - var/material/M = get_material_by_name(matstring) + var/datum/material/M = get_material_by_name(matstring) var/obj/item/stack/material/S = M.place_sheet(get_turf(src)) if(amount <= 0) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index c9d6f3048c..e7e0d3b7dd 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -23,20 +23,23 @@ description_info = "Alt click to strafe." icon = 'icons/mecha/mecha.dmi' density = 1 //Dense. To raise the heat. - opacity = 1 ///opaque. Menacing. - anchored = 1 //no pulling around. - unacidable = 1 //and no deleting hoomans inside - layer = MOB_LAYER //icon draw layer - infra_luminosity = 15 //byond implementation is bugged. + opacity = 1 //Opaque. Menacing. + anchored = 1 //No pulling around. + unacidable = 1 //And no deleting hoomans inside + layer = MOB_LAYER //Icon draw layer + infra_luminosity = 15 //Byond implementation is bugged. var/initial_icon = null //Mech type for resetting icon. Only used for reskinning kits (see custom items) var/can_move = 1 var/mob/living/carbon/occupant = null - var/step_in = 10 //make a step in step_in/10 sec. + + var/step_in = 10 //Make a step in step_in/10 sec. + var/encumbrance_gap = 1 //How many points of slowdown are negated from equipment? Added to the mech's base step_in. + var/dir_in = 2 //What direction will the mech face when entered/powered on? Defaults to South. var/step_energy_drain = 10 - var/health = 300 //health is health - var/maxhealth = 300 //maxhealth is maxhealth. - var/deflect_chance = 10 //chance to deflect the incoming projectiles, hits, or lesser the effect of ex_act. + var/health = 300 //Health is health + var/maxhealth = 300 //Maxhealth is maxhealth. + var/deflect_chance = 10 //Chance to deflect the incoming projectiles, hits, or lesser the effect of ex_act. //the values in this list show how much damage will pass through, not how much will be absorbed. var/list/damage_absorption = list( "brute"=0.8, @@ -51,7 +54,7 @@ var/damage_minimum = 10 //Incoming damage lower than this won't actually deal damage. Scrapes shouldn't be a real thing. var/minimum_penetration = 15 //Incoming damage won't be fully applied if you don't have at least 20. Almost all AP clears this. - var/fail_penetration_value = 0.66 //By how much failing to penetrate reduces your shit. 66% by default. + var/fail_penetration_value = 0.66 //By how much failing to penetrate reduces your shit. 66% by default. 100dmg = 66dmg if failed pen var/obj/item/weapon/cell/cell var/state = MECHA_OPERATING @@ -59,8 +62,8 @@ var/last_message = 0 var/add_req_access = 1 var/maint_access = 1 - var/dna //dna-locking the mech - var/list/proc_res = list() //stores proc owners, like proc_res["functionname"] = owner reference + var/dna //Dna-locking the mech + var/list/proc_res = list() //Stores proc owners, like proc_res["functionname"] = owner reference var/datum/effect/effect/system/spark_spread/spark_system = new var/lights = 0 var/lights_power = 6 @@ -82,17 +85,17 @@ var/obj/item/device/radio/radio = null var/max_temperature = 25000 //Kelvin values. - var/internal_damage_threshold = 33 //health percentage below which internal damage is possible + var/internal_damage_threshold = 33 //Health percentage below which internal damage is possible var/internal_damage_minimum = 15 //At least this much damage to trigger some real bad hurt. - var/internal_damage = 0 //contains bitflags + var/internal_damage = 0 //Contains bitflags - var/list/operation_req_access = list()//required access level for mecha operation - var/list/internals_req_access = list(access_engine,access_robotics)//required access level to open cell compartment + var/list/operation_req_access = list() //Required access level for mecha operation + var/list/internals_req_access = list(access_engine,access_robotics) //Required access level to open cell compartment - var/datum/global_iterator/pr_int_temp_processor //normalizes internal air mixture temperature - var/datum/global_iterator/pr_inertial_movement //controls intertial movement in spesss - var/datum/global_iterator/pr_give_air //moves air from tank to cabin - var/datum/global_iterator/pr_internal_damage //processes internal damage + var/datum/global_iterator/pr_int_temp_processor //Normalizes internal air mixture temperature + var/datum/global_iterator/pr_inertial_movement //Controls intertial movement in spesss + var/datum/global_iterator/pr_give_air //Moves air from tank to cabin + var/datum/global_iterator/pr_internal_damage //Processes internal damage var/wreckage @@ -193,6 +196,7 @@ var/datum/action/innate/mecha/mech_toggle_cloaking/cloak_action = new var/weapons_only_cycle = FALSE //So combat mechs don't switch to their equipment at times. + /obj/mecha/Initialize() ..() @@ -560,12 +564,12 @@ target.attack_hand(src.occupant) return 1 if(istype(target, /obj/machinery/embedded_controller)) - target.ui_interact(src.occupant) + target.tgui_interact(src.occupant) return 1 return 0 -/obj/mecha/contents_nano_distance(var/src_object, var/mob/living/user) - . = user.shared_living_nano_distance(src_object) //allow them to interact with anything they can interact with normally. +/obj/mecha/contents_tgui_distance(var/src_object, var/mob/living/user) + . = user.shared_living_tgui_distance(src_object) //allow them to interact with anything they can interact with normally. if(. != STATUS_INTERACTIVE) //Allow interaction with the mecha or anything that is part of the mecha if(src_object == src || (src_object in src)) @@ -642,18 +646,21 @@ /obj/mecha/proc/get_step_delay() var/tally = 0 - if(overload) - tally = min(1, round(step_in/2)) + if(LAZYLEN(equipment)) + for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment) + if(ME.get_step_delay()) + tally += ME.get_step_delay() + + if(tally <= encumbrance_gap) // If the total is less than our encumbrance gap, ignore equipment weight. + tally = 0 + else // Otherwise, start the tally after cutting that gap out. + tally -= encumbrance_gap for(var/slot in internal_components) var/obj/item/mecha_parts/component/C = internal_components[slot] if(C && C.get_step_delay()) tally += C.get_step_delay() - for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment) - if(ME.get_step_delay()) - tally += ME.get_step_delay() - var/obj/item/mecha_parts/component/actuator/actuator = internal_components[MECH_ACTUATOR] if(!actuator) // Relying purely on hydraulic pumps. You're going nowhere fast. @@ -675,7 +682,10 @@ break break - return max(1, round(tally, 0.1)) + if(overload) // At the end, because this would normally just make the mech *slower* since tally wasn't starting at 0. + tally = min(1, round(tally/2)) + + return max(1, round(tally, 0.1)) // Round the total to the nearest 10th. Can't go lower than 1 tick. Even humans have a delay longer than that. /obj/mecha/proc/dyndomove(direction) if(!can_move) diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm index 86405b6934..aff19e301d 100644 --- a/code/game/mecha/working/ripley.dm +++ b/code/game/mecha/working/ripley.dm @@ -14,6 +14,8 @@ minimum_penetration = 10 + encumbrance_gap = 2 + starting_components = list( /obj/item/mecha_parts/component/hull/durable, /obj/item/mecha_parts/component/actuator, diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index 48223c67e2..1e804bbb26 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -438,11 +438,15 @@ steam.start() -- spawns the effect if(src.processing) src.processing = 0 spawn(0) - var/turf/T = get_turf(src.holder) + var/turf/T if(istype(holder, /atom/movable)) var/atom/movable/AM = holder if(AM.locs && AM.locs.len) - T = pick(AM.locs) + T = get_turf(pick(AM.locs)) + else + T = get_turf(AM) + else //when would this ever be attached a non-atom/movable? + T = get_turf(src.holder) if(T != src.oldposition) if(isturf(T)) var/obj/effect/effect/ion_trails/I = new /obj/effect/effect/ion_trails(src.oldposition) diff --git a/code/game/objects/effects/prop/columnblast.dm b/code/game/objects/effects/prop/columnblast.dm new file mode 100644 index 0000000000..fc604235c8 --- /dev/null +++ b/code/game/objects/effects/prop/columnblast.dm @@ -0,0 +1,54 @@ + +/obj/effect/temporary_effect/eruption + name = "eruption" + desc = "Oh shit!" + icon_state = "pool" + icon = 'icons/effects/64x64.dmi' + + pixel_x = -16 + +/obj/effect/temporary_effect/eruption/New(var/turf/T, var/ttd = 10 SECONDS, var/newcolor) + if(ttd) + time_to_die = ttd + + if(newcolor) + color = newcolor + + ..() + +/obj/effect/temporary_effect/eruption/Initialize() + ..() + flick("[icon_state]_create",src) + +/obj/effect/temporary_effect/eruption/Destroy() + var/turf/T = get_turf(src) + flick("[icon_state]_erupt",src) + spawn(5) + if(on_eruption(T)) + spawn(2) + ..() + +/obj/effect/temporary_effect/eruption/proc/on_eruption(var/turf/Target) // Override for specific functions, as below. + return TRUE + +/obj/effect/temporary_effect/eruption/testing/on_eruption(var/turf/Target) + if(Target) + new /obj/effect/explosion(Target) + return TRUE + +/* + * Subtypes + */ + +/obj/effect/temporary_effect/eruption/flamestrike + desc = "A bubbling pool of fire!" + +/obj/effect/temporary_effect/eruption/flamestrike/on_eruption(var/turf/Target) + if(Target) + Target.hotspot_expose(1000, 50, 1) + + for(var/mob/living/L in Target) + L.fire_stacks += 2 + L.add_modifier(/datum/modifier/fire/stack_managed/intense, 30 SECONDS) + + return TRUE \ No newline at end of file diff --git a/code/game/objects/effects/prop/snake.dm b/code/game/objects/effects/prop/snake.dm new file mode 100644 index 0000000000..2b3812ccc9 --- /dev/null +++ b/code/game/objects/effects/prop/snake.dm @@ -0,0 +1,125 @@ + +/obj/effect/temporary_effect/pulse/snake + name = "snake head" + pulses_remaining = 20 + pulse_delay = 0.5 SECONDS + + icon_state = "arrow_omni" + + invisibility = 100 + +// The atom which created this. + var/atom/movable/creator +// Will the snake ever intentionally move onto its creator's turf? + var/safe = FALSE + + var/ignore_density = FALSE + +// The turfs this snake has already crossed. + var/list/iterated_turfs = list() +// How many turfs this snake should remember. + var/total_turf_memory = 5 +// Is the snake hunting a specific atom? (Will always try to meander toward this target.) + var/atom/hunting + +/obj/effect/temporary_effect/pulse/snake/New(var/turf/T, var/atom/hunt_target, var/atom/Creator) + if(hunt_target) + hunting = hunt_target + + if(Creator) + creator = Creator + + ..() + +/obj/effect/temporary_effect/pulse/snake/pulse_loop() // Override needed unfortunately to handle the possibility of not finding a target turf. + set waitfor = FALSE + + while(pulses_remaining) + sleep(pulse_delay) + if(on_pulse()) + pulses_remaining-- + else + break + qdel(src) + +/obj/effect/temporary_effect/pulse/snake/on_pulse() + var/list/possible_turfs = list() + + if(LAZYLEN(iterated_turfs) && iterated_turfs.len > total_turf_memory) + iterated_turfs.Cut(total_turf_memory + 1) + + for(var/direction in list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST) - turn(src.dir,180)) + var/turf/T = get_step(src, direction) + if(T in iterated_turfs) + continue + + if(!ignore_density && T.density) + continue + + if(safe && creator && get_dir(src, T) == get_dir(src,creator)) + continue + + if(hunting && get_dist(T, hunting) > get_dist(src, hunting)) + continue + + possible_turfs |= T + + if(T == get_step(src, dir)) + possible_turfs[T] = 4 + else + possible_turfs[T] = 1 + + var/turf/Target + + if(LAZYLEN(possible_turfs)) // Pick from our remaining possible turfs. + Target = pickweight(possible_turfs) + else // IF we have none left, just pick a random one. + for(var/turf/T in oview(1, src)) + possible_turfs |= T + Target = pick(possible_turfs) + + if(Target) + iterated_turfs.Insert(1, Target) + on_leave_turf(get_turf(src)) + dir = get_dir(src, Target) + forceMove(Target) + on_enter_turf(Target) + return TRUE + + else + on_leave_turf(get_turf(src)) + return FALSE + +/obj/effect/temporary_effect/pulse/snake/proc/on_leave_turf(var/turf/T) + +/obj/effect/temporary_effect/pulse/snake/proc/on_enter_turf(var/turf/T) + +/obj/effect/temporary_effect/pulse/snake/testing/on_leave_turf(var/turf/T) + if(T) + new /obj/effect/temporary_effect/eruption/testing(T, 3 SECONDS, "#ff0000") + +/obj/effect/temporary_effect/pulse/snake/testing/on_enter_turf(var/turf/T) + if(T) + T.color = "#00ff00" + + spawn(3 SECONDS) + T.color = initial(T.color) + +/obj/effect/temporary_effect/pulse/snake/testing/hunter/pulse_loop() + hunting = locate(/mob/living) in range(7, src) + ..() + +/* + * Subtypes + */ + +/obj/effect/temporary_effect/pulse/snake/flamestrike + name = "fiery shockwave" + + total_turf_memory = 8 + pulses_remaining = 8 + pulse_delay = 0.2 SECONDS + +/obj/effect/temporary_effect/pulse/snake/flamestrike/on_leave_turf(var/turf/T) + if(T) + new /obj/effect/temporary_effect/eruption/flamestrike(T, 1.2 SECONDS, "#f75000") diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 9812704a75..e90cf3aaea 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -91,16 +91,16 @@ var/icon/default_worn_icon //Default on-mob icon var/worn_layer //Default on-mob layer - + // Pickup/Drop/Equip/Throw Sounds ///Used when thrown into a mob var/mob_throw_hit_sound // Sound used when equipping the items into a valid slot. - var/equip_sound + var/equip_sound // pickup sound - this is the default - var/pickup_sound = 'sound/items/pickup/device.ogg' + var/pickup_sound = "generic_pickup" // drop sound - this is the default - var/drop_sound = 'sound/items/drop/device.ogg' + var/drop_sound = "generic_drop" var/tip_timer // reference to timer id for a tooltip we might open soon @@ -468,12 +468,12 @@ var/list/global/slot_flags_enumeration = list( if(!canremove) return 0 - + if(!slot) if(issilicon(M)) return 1 // for stuff in grippers return 0 - + if(!M.slot_is_accessible(slot, src, disable_warning? null : M)) return 0 return 1 @@ -785,6 +785,8 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. // My best guess as to why this is here would be that it does so little. Still, keep it under all the procs, for sanity's sake. /obj/item/device icon = 'icons/obj/device.dmi' + pickup_sound = 'sound/items/pickup/device.ogg' + drop_sound = 'sound/items/drop/device.ogg' //Worn icon generation for on-mob sprites /obj/item/proc/make_worn_icon(var/body_type,var/slot_name,var/inhands,var/default_icon,var/default_layer,var/icon/clip_mask = null) //VOREStation edit - add 'clip mask' argument. diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm deleted file mode 100644 index 18e0f8f139..0000000000 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ /dev/null @@ -1,1603 +0,0 @@ - -//The advanced pea-green monochrome lcd of tomorrow. - -var/global/list/obj/item/device/pda/PDAs = list() - -/obj/item/device/pda - name = "\improper PDA" - desc = "A portable microcomputer by Thinktronic Systems, LTD. Functionality determined by a preprogrammed ROM cartridge." - icon = 'icons/obj/pda.dmi' - icon_state = "pda" - item_state = "electronic" - w_class = ITEMSIZE_SMALL - slot_flags = SLOT_ID | SLOT_BELT - sprite_sheets = list(SPECIES_TESHARI = 'icons/mob/species/seromi/id.dmi') - - //Main variables - var/pdachoice = 1 - var/owner = null - var/default_cartridge = 0 // Access level defined by cartridge - var/obj/item/weapon/cartridge/cartridge = null //current cartridge - var/mode = 0 //Controls what menu the PDA will display. 0 is hub; the rest are either built in or based on cartridge. - - var/lastmode = 0 - var/ui_tick = 0 - var/nanoUI[0] - - //Secondary variables - var/scanmode = 0 //1 is medical scanner, 2 is forensics, 3 is reagent scanner. - var/fon = 0 //Is the flashlight function on? - var/f_lum = 2 //Luminosity for the flashlight function - var/message_silent = 0 //To beep or not to beep, that is the question - var/news_silent = 1 //To beep or not to beep, that is the question. The answer is No. - var/toff = 0 //If 1, messenger disabled - var/tnote[0] //Current Texts - var/last_text //No text spamming - var/last_honk //Also no honk spamming that's bad too - var/ttone = "beep" //The PDA ringtone! - var/newstone = "beep, beep" //The news ringtone! - var/lock_code = "" // Lockcode to unlock uplink - var/honkamt = 0 //How many honks left when infected with honk.exe - var/mimeamt = 0 //How many silence left when infected with mime.exe - var/note = "Congratulations, your station has chosen the Thinktronic 5230 Personal Data Assistant!" //Current note in the notepad function - var/notehtml = "" - var/cart = "" //A place to stick cartridge menu information - var/detonate = 1 // Can the PDA be blown up? - var/hidden = 0 // Is the PDA hidden from the PDA list? - var/active_conversation = null // New variable that allows us to only view a single conversation. - var/list/conversations = list() // For keeping up with who we have PDA messsages from. - var/new_message = 0 //To remove hackish overlay check - var/new_news = 0 - var/touch_silent = 0 //If 1, no beeps on interacting. - - var/active_feed // The selected feed - var/list/warrant // The warrant as we last knew it - var/list/feeds = list() // The list of feeds as we last knew them - var/list/feed_info = list() // The data and contents of each feed as we last knew them - - var/list/cartmodes = list(40, 42, 43, 433, 44, 441, 45, 451, 46, 48, 47, 49) // If you add more cartridge modes add them to this list as well. - var/list/no_auto_update = list(1, 40, 43, 44, 441, 45, 451) // These modes we turn off autoupdate - var/list/update_every_five = list(3, 41, 433, 46, 47, 48, 49) // These we update every 5 ticks - - var/obj/item/weapon/card/id/id = null //Making it possible to slot an ID card into the PDA so it can function as both. - var/ownjob = null //related to above - this is assignment (potentially alt title) - var/ownrank = null // this one is rank, never alt title - - var/obj/item/device/paicard/pai = null // A slot for a personal AI device - - var/spam_proof = FALSE // If true, it can't be spammed by random events. - -/obj/item/device/pda/examine(mob/user) - . = ..() - if(Adjacent(user)) - . += "The time [stationtime2text()] is displayed in the corner of the screen." - -/obj/item/device/pda/CtrlClick() - if(issilicon(usr)) - return - - if(can_use(usr)) - remove_pen() - return - ..() - -/obj/item/device/pda/AltClick() - if(issilicon(usr)) - return - - if ( can_use(usr) ) - if(id) - remove_id() - else - to_chat(usr, "This PDA does not have an ID in it.") - -//Bloop when using: -/obj/item/device/pda/CouldUseTopic(var/mob/user) - ..() - if(iscarbon(user) && !touch_silent) - playsound(src, 'sound/machines/pda_click.ogg', 20) - -/obj/item/device/pda/medical - default_cartridge = /obj/item/weapon/cartridge/medical - icon_state = "pda-m" - -/obj/item/device/pda/viro - default_cartridge = /obj/item/weapon/cartridge/medical - icon_state = "pda-v" - -/obj/item/device/pda/engineering - default_cartridge = /obj/item/weapon/cartridge/engineering - icon_state = "pda-e" - -/obj/item/device/pda/security - default_cartridge = /obj/item/weapon/cartridge/security - icon_state = "pda-s" - -/obj/item/device/pda/detective - default_cartridge = /obj/item/weapon/cartridge/detective - icon_state = "pda-det" - -/obj/item/device/pda/warden - default_cartridge = /obj/item/weapon/cartridge/security - icon_state = "pda-warden" - -/obj/item/device/pda/janitor - default_cartridge = /obj/item/weapon/cartridge/janitor - icon_state = "pda-j" - ttone = "slip" - -/obj/item/device/pda/science - default_cartridge = /obj/item/weapon/cartridge/signal/science - icon_state = "pda-tox" - ttone = "boom" - -/obj/item/device/pda/clown - default_cartridge = /obj/item/weapon/cartridge/clown - icon_state = "pda-clown" - desc = "A portable microcomputer by Thinktronic Systems, LTD. The surface is coated with polytetrafluoroethylene and banana drippings." - ttone = "honk" - -/obj/item/device/pda/mime - default_cartridge = /obj/item/weapon/cartridge/mime - icon_state = "pda-mime" - message_silent = 1 - news_silent = 1 - ttone = "silence" - newstone = "silence" - -/obj/item/device/pda/heads - default_cartridge = /obj/item/weapon/cartridge/head - icon_state = "pda-h" - news_silent = 1 - -/obj/item/device/pda/heads/hop - default_cartridge = /obj/item/weapon/cartridge/hop - icon_state = "pda-hop" - -/obj/item/device/pda/heads/hos - default_cartridge = /obj/item/weapon/cartridge/hos - icon_state = "pda-hos" - -/obj/item/device/pda/heads/ce - default_cartridge = /obj/item/weapon/cartridge/ce - icon_state = "pda-ce" - -/obj/item/device/pda/heads/cmo - default_cartridge = /obj/item/weapon/cartridge/cmo - icon_state = "pda-cmo" - -/obj/item/device/pda/heads/rd - default_cartridge = /obj/item/weapon/cartridge/rd - icon_state = "pda-rd" - -/obj/item/device/pda/captain - default_cartridge = /obj/item/weapon/cartridge/captain - icon_state = "pda-c" - detonate = 0 - //toff = 1 - -/obj/item/device/pda/ert - default_cartridge = /obj/item/weapon/cartridge/captain - icon_state = "pda-h" - detonate = 0 -// hidden = 1 - -/obj/item/device/pda/cargo - default_cartridge = /obj/item/weapon/cartridge/quartermaster - icon_state = "pda-cargo" - -/obj/item/device/pda/quartermaster - default_cartridge = /obj/item/weapon/cartridge/quartermaster - icon_state = "pda-q" - -/obj/item/device/pda/shaftminer - icon_state = "pda-miner" - default_cartridge = /obj/item/weapon/cartridge/miner - -/obj/item/device/pda/syndicate - default_cartridge = /obj/item/weapon/cartridge/syndicate - icon_state = "pda-syn" -// name = "Military PDA" // Vorestation Edit -// owner = "John Doe" - hidden = 1 - -/obj/item/device/pda/chaplain - default_cartridge = /obj/item/weapon/cartridge/service - icon_state = "pda-holy" - ttone = "holy" - -/obj/item/device/pda/lawyer - default_cartridge = /obj/item/weapon/cartridge/lawyer - icon_state = "pda-lawyer" - ttone = "..." - -/obj/item/device/pda/botanist - default_cartridge = /obj/item/weapon/cartridge/service - icon_state = "pda-hydro" - -/obj/item/device/pda/roboticist - default_cartridge = /obj/item/weapon/cartridge/signal/science - icon_state = "pda-robot" - -/obj/item/device/pda/librarian - default_cartridge = /obj/item/weapon/cartridge/service - icon_state = "pda-libb" - desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a WGW-11 series e-reader." - note = "Congratulations, your station has chosen the Thinktronic 5290 WGW-11 Series E-reader and Personal Data Assistant!" - message_silent = 1 //Quiet in the library! - news_silent = 0 // Librarian is above the law! (That and alt job title is reporter) - -/obj/item/device/pda/clear - icon_state = "pda-transp" - desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a special edition with a transparent case." - note = "Congratulations, you have chosen the Thinktronic 5230 Personal Data Assistant Deluxe Special Max Turbo Limited Edition!" - -/obj/item/device/pda/chef - default_cartridge = /obj/item/weapon/cartridge/service - icon_state = "pda-chef" - -/obj/item/device/pda/bar - default_cartridge = /obj/item/weapon/cartridge/service - icon_state = "pda-bar" - -/obj/item/device/pda/atmos - default_cartridge = /obj/item/weapon/cartridge/atmos - icon_state = "pda-atmo" - -/obj/item/device/pda/chemist - default_cartridge = /obj/item/weapon/cartridge/chemistry - icon_state = "pda-chem" - -/obj/item/device/pda/geneticist - default_cartridge = /obj/item/weapon/cartridge/medical - icon_state = "pda-gene" - - -// Special AI/pAI PDAs that cannot explode. -/obj/item/device/pda/ai - icon_state = "NONE" - ttone = "data" - newstone = "news" - detonate = 0 - - -/obj/item/device/pda/ai/proc/set_name_and_job(newname as text, newjob as text, newrank as null|text) - owner = newname - ownjob = newjob - if(newrank) - ownrank = newrank - else - ownrank = ownjob - name = newname + " (" + ownjob + ")" - -//AI verb and proc for sending PDA messages. -/obj/item/device/pda/ai/verb/cmd_send_pdamesg() - set category = "AI IM" - set name = "Send Message" - set src in usr - if(usr.stat == 2) - to_chat(usr, "You can't send PDA messages because you are dead!") - return - var/list/plist = available_pdas() - if (plist) - var/c = input(usr, "Please select a PDA") as null|anything in sortList(plist) - if (!c) // if the user hasn't selected a PDA file we can't send a message - return - var/selected = plist[c] - create_message(usr, selected, 0) - -/obj/item/device/pda/ai/verb/cmd_toggle_pda_receiver() - set category = "AI IM" - set name = "Toggle Sender/Receiver" - set src in usr - if(usr.stat == 2) - to_chat(usr, "You can't send PDA messages because you are dead!") - return - toff = !toff - to_chat(usr, "PDA sender/receiver toggled [(toff ? "Off" : "On")]!") - -/obj/item/device/pda/ai/verb/cmd_toggle_pda_silent() - set category = "AI IM" - set name = "Toggle Ringer" - set src in usr - if(usr.stat == 2) - to_chat(usr, "You can't send PDA messages because you are dead!") - return - message_silent=!message_silent - to_chat(usr, "PDA ringer toggled [(message_silent ? "Off" : "On")]!") - -/obj/item/device/pda/ai/verb/cmd_show_message_log() - set category = "AI IM" - set name = "Show Message Log" - set src in usr - if(usr.stat == 2) - to_chat(usr, "You can't send PDA messages because you are dead!") - return - var/HTML = "AI PDA Message Log" - for(var/index in tnote) - if(index["sent"]) - HTML += addtext("→ To ", index["owner"],":
", index["message"], "
") - else - HTML += addtext("← From ", index["owner"],":
", index["message"], "
") - HTML +="" - usr << browse(HTML, "window=log;size=400x444;border=1;can_resize=1;can_close=1;can_minimize=0") - - -/obj/item/device/pda/ai/can_use() - return 1 - - -/obj/item/device/pda/ai/attack_self(mob/user as mob) - if ((honkamt > 0) && (prob(60)))//For clown virus. - honkamt-- - playsound(src, 'sound/items/bikehorn.ogg', 30, 1) - return - - -/obj/item/device/pda/ai/pai - ttone = "assist" - -/obj/item/device/pda/ai/shell - spam_proof = TRUE // Since empty shells get a functional PDA. - -// Used for the PDA multicaster, which mirrors messages sent to it to a specific department, -/obj/item/device/pda/multicaster - ownjob = "Relay" - icon_state = "NONE" - ttone = "data" - detonate = 0 - news_silent = 1 - spam_proof = TRUE // Spam messages don't actually work and its difficult to disable these. - var/list/cartridges_to_send_to = list() - -// This is what actually mirrors the message, -/obj/item/device/pda/multicaster/new_message(var/sending_unit, var/sender, var/sender_job, var/message) - if(sender) - var/list/targets = list() - for(var/obj/item/device/pda/pda in PDAs) - if(pda.cartridge && pda.owner && is_type_in_list(pda.cartridge, cartridges_to_send_to)) - targets |= pda - if(targets.len) - for(var/obj/item/device/pda/target in targets) - create_message(target, sender, sender_job, message) - -// This has so much copypasta, -/obj/item/device/pda/multicaster/create_message(var/obj/item/device/pda/P, var/original_sender, var/original_job, var/t) - t = sanitize(t, MAX_MESSAGE_LEN, 0) - t = replace_characters(t, list(""" = "\"")) - if (!t || !istype(P)) - return - - if (isnull(P)||P.toff || toff) - return - - last_text = world.time - var/datum/reception/reception = get_reception(src, P, t) - t = reception.message - - if(reception.message_server && (reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER)) // only send the message if it's stable, - if(reception.telecomms_reception & TELECOMMS_RECEPTION_RECEIVER == 0) // Does our recipient have a broadcaster on their level?, - return - var/send_result = reception.message_server.send_pda_message("[P.owner]","[owner]","[t]") - if (send_result) - return - - P.tnote.Add(list(list("sent" = 0, "owner" = "[owner]", "job" = "[ownjob]", "message" = "[t]", "target" = "\ref[src]"))) - - if(!P.conversations.Find("\ref[src]")) - P.conversations.Add("\ref[src]") - - P.new_message(src, "[original_sender] \[Relayed\]", original_job, t, 0) - - else - return - -/obj/item/device/pda/multicaster/command/New() - ..() - owner = "Command Department" - name = "Command Department (Relay)" - cartridges_to_send_to = command_cartridges - -/obj/item/device/pda/multicaster/security/New() - ..() - owner = "Security Department" - name = "Security Department (Relay)" - cartridges_to_send_to = security_cartridges - -/obj/item/device/pda/multicaster/engineering/New() - ..() - owner = "Engineering Department" - name = "Engineering Department (Relay)" - cartridges_to_send_to = engineering_cartridges - -/obj/item/device/pda/multicaster/medical/New() - ..() - owner = "Medical Department" - name = "Medical Department (Relay)" - cartridges_to_send_to = medical_cartridges - -/obj/item/device/pda/multicaster/research/New() - ..() - owner = "Research Department" - name = "Research Department (Relay)" - cartridges_to_send_to = research_cartridges - -/obj/item/device/pda/multicaster/cargo/New() - ..() - owner = "Cargo Department" - name = "Cargo Department (Relay)" - cartridges_to_send_to = cargo_cartridges - -/obj/item/device/pda/multicaster/civilian/New() - ..() - owner = "Civilian Services Department" - name = "Civilian Services Department (Relay)" - cartridges_to_send_to = civilian_cartridges - -/* - * The Actual PDA - */ - -/obj/item/device/pda/New(var/mob/living/carbon/human/H) - ..() - PDAs += src - PDAs = sortAtom(PDAs) - if(default_cartridge) - cartridge = new default_cartridge(src) - new /obj/item/weapon/pen(src) - pdachoice = isnull(H) ? 1 : (ishuman(H) ? H.pdachoice : 1) - switch(pdachoice) - if(1) icon = 'icons/obj/pda.dmi' - if(2) icon = 'icons/obj/pda_slim.dmi' - if(3) icon = 'icons/obj/pda_old.dmi' - if(4) icon = 'icons/obj/pda_rugged.dmi' - if(5) icon = 'icons/obj/pda_holo.dmi' - if(6) - icon = 'icons/obj/pda_wrist.dmi' - item_state = icon_state - item_icons = list( - slot_belt_str = 'icons/mob/pda_wrist.dmi', - slot_wear_id_str = 'icons/mob/pda_wrist.dmi', - slot_gloves_str = 'icons/mob/pda_wrist.dmi' - ) - desc = "A portable microcomputer by Thinktronic Systems, LTD. This model is a wrist-bound version." - slot_flags = SLOT_ID | SLOT_BELT | SLOT_GLOVES - sprite_sheets = list( - SPECIES_TESHARI = 'icons/mob/species/seromi/pda_wrist.dmi', - SPECIES_VR_TESHARI = 'icons/mob/species/seromi/pda_wrist.dmi', - ) - else - icon = 'icons/obj/pda_old.dmi' - log_debug("Invalid switch for PDA, defaulting to old PDA icons. [pdachoice] chosen.") - - -/obj/item/device/pda/proc/can_use() - - if(!ismob(loc)) - return 0 - - var/mob/M = loc - if(M.stat || M.restrained() || M.paralysis || M.stunned || M.weakened) - return 0 - if((src in M.contents) || ( istype(loc, /turf) && in_range(src, M) )) - return 1 - else - return 0 - -/obj/item/device/pda/GetAccess() - if(id) - return id.GetAccess() - else - return ..() - -/obj/item/device/pda/GetID() - return id - -/obj/item/device/pda/MouseDrop(obj/over_object as obj, src_location, over_location) - var/mob/M = usr - if((!istype(over_object, /obj/screen)) && can_use()) - return attack_self(M) - return - - -/obj/item/device/pda/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui_tick++ - var/datum/nanoui/old_ui = SSnanoui.get_open_ui(user, src, "main") - var/auto_update = 1 - if(mode in no_auto_update) - auto_update = 0 - if(old_ui && (mode == lastmode && ui_tick % 5 && mode in update_every_five)) - return - - lastmode = mode - - var/title = "Personal Data Assistant" - - var/data[0] // This is the data that will be sent to the PDA - - data["owner"] = owner // Who is your daddy... - data["ownjob"] = ownjob // ...and what does he do? - - data["mode"] = mode // The current view - data["scanmode"] = scanmode // Scanners - data["fon"] = fon // Flashlight on? - data["pai"] = (isnull(pai) ? 0 : 1) // pAI inserted? - data["note"] = note // current pda notes - data["message_silent"] = message_silent // does the pda make noise when it receives a message? - data["news_silent"] = news_silent // does the pda make noise when it receives news? - data["touch_silent"] = touch_silent // does the pda make noise when it receives news? - data["toff"] = toff // is the messenger function turned off? - data["active_conversation"] = active_conversation // Which conversation are we following right now? - - - data["idInserted"] = (id ? 1 : 0) - data["idLink"] = (id ? text("[id.registered_name], [id.assignment]") : "--------") - - data["cart_loaded"] = cartridge ? 1:0 - if(cartridge) - var/cartdata[0] - cartdata["access"] = list(\ - "access_security" = cartridge.access_security,\ - "access_engine" = cartridge.access_engine,\ - "access_atmos" = cartridge.access_atmos,\ - "access_medical" = cartridge.access_medical,\ - "access_clown" = cartridge.access_clown,\ - "access_mime" = cartridge.access_mime,\ - "access_janitor" = cartridge.access_janitor,\ - "access_quartermaster" = cartridge.access_quartermaster,\ - "access_hydroponics" = cartridge.access_hydroponics,\ - "access_reagent_scanner" = cartridge.access_reagent_scanner,\ - "access_remote_door" = cartridge.access_remote_door,\ - "access_status_display" = cartridge.access_status_display,\ - "access_detonate_pda" = cartridge.access_detonate_pda\ - ) - - if(mode in cartmodes) - data["records"] = cartridge.create_NanoUI_values() - - if(mode == 0) - cartdata["name"] = cartridge.name - if(isnull(cartridge.radio)) - cartdata["radio"] = 0 - else - if(istype(cartridge.radio, /obj/item/radio/integrated/beepsky)) - cartdata["radio"] = 1 - if(istype(cartridge.radio, /obj/item/radio/integrated/signal)) - cartdata["radio"] = 2 - //if(istype(cartridge.radio, /obj/item/radio/integrated/mule)) - // cartdata["radio"] = 3 - - if(mode == 2) - cartdata["charges"] = cartridge.charges ? cartridge.charges : 0 - data["cartridge"] = cartdata - - data["stationTime"] = stationtime2text() - data["new_Message"] = new_message - data["new_News"] = new_news - - var/datum/reception/reception = get_reception(src, do_sleep = 0) - var/has_reception = reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER - data["reception"] = has_reception - - if(mode==2) - var/convopdas[0] - var/pdas[0] - var/count = 0 - for (var/obj/item/device/pda/P in PDAs) - if (!P.owner||P.toff||P == src||P.hidden) continue - if(conversations.Find("\ref[P]")) - convopdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "1"))) - else - pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) - count++ - - data["convopdas"] = convopdas - data["pdas"] = pdas - data["pda_count"] = count - - if(mode==21) - data["messagescount"] = tnote.len - data["messages"] = tnote - else - data["messagescount"] = null - data["messages"] = null - - if(active_conversation) - for(var/c in tnote) - if(c["target"] == active_conversation) - data["convo_name"] = sanitize(c["owner"]) - data["convo_job"] = sanitize(c["job"]) - break - if(mode==41) - data_core.get_manifest_list() - - - if(mode==3) - data["aircontents"] = src.analyze_air() - if(mode==6) - if(has_reception) - feeds.Cut() - for(var/datum/feed_channel/channel in news_network.network_channels) - feeds[++feeds.len] = list("name" = channel.channel_name, "censored" = channel.censored) - data["feedChannels"] = feeds - if(mode==61) - var/datum/feed_channel/FC - for(FC in news_network.network_channels) - if(FC.channel_name == active_feed["name"]) - break - - var/list/feed = feed_info[active_feed] - if(!feed) - feed = list() - feed["channel"] = FC.channel_name - feed["author"] = "Unknown" - feed["censored"]= 0 - feed["updated"] = -1 - feed_info[active_feed] = feed - - if(FC.updated > feed["updated"] && has_reception) - feed["author"] = FC.author - feed["updated"] = FC.updated - feed["censored"] = FC.censored - - var/list/messages = list() - if(!FC.censored) - var/index = 0 - for(var/datum/feed_message/FM in FC.messages) - index++ - if(FM.img) - usr << browse_rsc(FM.img, "pda_news_tmp_photo_[feed["channel"]]_[index].png") - // News stories are HTML-stripped but require newline replacement to be properly displayed in NanoUI - var/body = replacetext(FM.body, "\n", "
") - messages[++messages.len] = list("author" = FM.author, "body" = body, "message_type" = FM.message_type, "time_stamp" = FM.time_stamp, "has_image" = (FM.img != null), "caption" = FM.caption, "index" = index) - feed["messages"] = messages - - data["feed"] = feed - - data["manifest"] = PDA_Manifest - - nanoUI = data - // update the ui if it exists, returns null if no ui is passed/found - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "pda.tmpl", title, 520, 400, state = inventory_state) - // add templates for screens in common with communicator. - ui.add_template("atmosphericScan", "atmospheric_scan.tmpl") - ui.add_template("crewManifest", "crew_manifest.tmpl") - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(auto_update) - -/obj/item/device/pda/attack_self(mob/user as mob) - user.set_machine(src) - - if(active_uplink_check(user)) - return - - ui_interact(user) //NanoUI requires this proc - return - -/obj/item/device/pda/Topic(href, href_list) - if(href_list["cartmenu"] && !isnull(cartridge)) - cartridge.Topic(href, href_list) - return 1 - if(href_list["radiomenu"] && !isnull(cartridge) && !isnull(cartridge.radio)) - cartridge.radio.Topic(href, href_list) - return 1 - - - ..() - var/mob/user = usr - var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main") - var/mob/living/U = usr - //Looking for master was kind of pointless since PDAs don't appear to have one. - //if ((src in U.contents) || ( istype(loc, /turf) && in_range(src, U) ) ) - if (usr.stat == DEAD) - return 0 - if(!can_use()) //Why reinvent the wheel? There's a proc that does exactly that. - U.unset_machine() - if(ui) - ui.close() - return 0 - - add_fingerprint(U) - U.set_machine(src) - - switch(href_list["choice"]) - -//BASIC FUNCTIONS=================================== - - if("Close")//Self explanatory - U.unset_machine() - ui.close() - return 0 - if("Refresh")//Refresh, goes to the end of the proc. - if("Return")//Return - if(mode<=9) - mode = 0 - else - mode = round(mode/10) - if(mode==2) - active_conversation = null - if(mode==4)//Fix for cartridges. Redirects to hub. - mode = 0 - else if(mode >= 40 && mode <= 49)//Fix for cartridges. Redirects to refresh the menu. - cartridge.mode = mode - if ("Authenticate")//Checks for ID - id_check(U, 1) - if("UpdateInfo") - ownjob = id.assignment - ownrank = id.rank - name = "PDA-[owner] ([ownjob])" - if("Eject")//Ejects the cart, only done from hub. - verb_remove_cartridge() - -//MENU FUNCTIONS=================================== - - if("0")//Hub - mode = 0 - if("1")//Notes - mode = 1 - if("2")//Messenger - mode = 2 - if("21")//Read messages - mode = 21 - if("3")//Atmos scan - mode = 3 - if("4")//Redirects to hub - mode = 0 - if("chatroom") // chatroom hub - mode = 5 - if("41") //Manifest - mode = 41 - - -//MAIN FUNCTIONS=================================== - - if("Light") - if(fon) - fon = 0 - set_light(0) - else - fon = 1 - set_light(f_lum) - if("Medical Scan") - if(scanmode == 1) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_medical)) - scanmode = 1 - if("Reagent Scan") - if(scanmode == 3) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_reagent_scanner)) - scanmode = 3 - if("Halogen Counter") - if(scanmode == 4) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_engine)) - scanmode = 4 - if("Honk") - if ( !(last_honk && world.time < last_honk + 20) ) - playsound(src, 'sound/items/bikehorn.ogg', 50, 1) - last_honk = world.time - if("Gas Scan") - if(scanmode == 5) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_atmos)) - scanmode = 5 - if("Toggle Beeping") - touch_silent = !touch_silent - -//MESSENGER/NOTE FUNCTIONS=================================== - - if ("Edit") - var/n = input(U, "Please enter message", name, notehtml) as message - if (in_range(src, U) && loc == U) - n = sanitizeSafe(n, extra = 0) - if (mode == 1) - note = html_decode(n) - notehtml = note - note = replacetext(note, "\n", "
") - else - ui.close() - if("Toggle Messenger") - toff = !toff - if("Toggle Ringer")//If viewing texts then erase them, if not then toggle silent status - message_silent = !message_silent - if("Toggle News") - news_silent = !news_silent - if("Clear")//Clears messages - if(href_list["option"] == "All") - tnote.Cut() - conversations.Cut() - if(href_list["option"] == "Convo") - var/new_tnote[0] - for(var/i in tnote) - if(i["target"] != active_conversation) - new_tnote[++new_tnote.len] = i - tnote = new_tnote - conversations.Remove(active_conversation) - - active_conversation = null - if(mode==21) - mode=2 - - if("Ringtone") - var/t = input(U, "Please enter a new ringtone.", name, ttone) as text //Start of YW EDIT - if (in_range(src, U) && loc == U && t) - if(src.hidden_uplink && hidden_uplink.check_trigger(U, lowertext(t), lowertext(lock_code))) - to_chat(U, "The PDA softly beeps.") - ui.close() - else - ttone = sanitize(t, 20) //End of YW EDIT - else - ui.close() - return 0 - if("Newstone") - var/t = input(U, "Please enter new news tone", name, newstone) as text - if (in_range(src, U) && loc == U && t) - newstone = sanitize(t, 20) - ui.close() - return 0 - if("Message") - - var/obj/item/device/pda/P = locate(href_list["target"]) - src.create_message(U, P, !href_list["notap"]) - if(mode == 2) - if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp. - active_conversation = href_list["target"] - mode = 21 - - if("Select Conversation") - var/P = href_list["convo"] - for(var/n in conversations) - if(P == n) - active_conversation=P - mode=21 - if("Select Feed") - var/n = href_list["name"] - for(var/f in feeds) - if(f["name"] == n) - active_feed = f - mode=61 - if("Send Honk")//Honk virus - if(cartridge && cartridge.access_clown)//Cartridge checks are kind of unnecessary since everything is done through switch. - var/obj/item/device/pda/P = locate(href_list["target"])//Leaving it alone in case it may do something useful, I guess. - if(!isnull(P)) - if (!P.toff && cartridge.charges > 0) - cartridge.charges-- - U.show_message("Virus sent!", 1) - P.honkamt = (rand(15,20)) - else - to_chat(U, "PDA not found.") - else - ui.close() - return 0 - if("Send Silence")//Silent virus - if(cartridge && cartridge.access_mime) - var/obj/item/device/pda/P = locate(href_list["target"]) - if(!isnull(P)) - if (!P.toff && cartridge.charges > 0) - cartridge.charges-- - U.show_message("Virus sent!", 1) - P.message_silent = 1 - P.news_silent = 1 - P.ttone = "silence" - P.newstone = "silence" - else - to_chat(U, "PDA not found.") - else - ui.close() - return 0 - - -//SYNDICATE FUNCTIONS=================================== - - if("Toggle Door") - if(cartridge && cartridge.access_remote_door) - for(var/obj/machinery/door/blast/M in machines) - if(M.id == cartridge.remote_door_id) - if(M.density) - M.open() - else - M.close() - - if("Detonate")//Detonate PDA... maybe - if(cartridge && cartridge.access_detonate_pda) - var/obj/item/device/pda/P = locate(href_list["target"]) - var/datum/reception/reception = get_reception(src, P, "", do_sleep = 0) - if(!(reception.message_server && reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER)) - U.show_message("An error flashes on your [src]: Connection unavailable", 1) - return - if(reception.telecomms_reception & TELECOMMS_RECEPTION_RECEIVER == 0) // Does our recepient have a broadcaster on their level? - U.show_message("An error flashes on your [src]: Recipient unavailable", 1) - return - if(!isnull(P)) - if (!P.toff && cartridge.charges > 0) - cartridge.charges-- - - var/difficulty = 2 - - if(P.cartridge) - difficulty += P.cartridge.access_medical - difficulty += P.cartridge.access_security - difficulty += P.cartridge.access_engine - difficulty += P.cartridge.access_clown - difficulty += P.cartridge.access_janitor - if(P.hidden_uplink) - difficulty += 3 - - if(prob(difficulty)) - U.show_message("An error flashes on your [src].", 1) - else if (prob(difficulty * 7)) - U.show_message("Energy feeds back into your [src]!", 1) - ui.close() - detonate_act(src) - log_admin("[key_name(U)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up") - message_admins("[key_name_admin(U)] just attempted to blow up [P] with the Detomatix cartridge but failed.", 1) - else - U.show_message("Success!", 1) - log_admin("[key_name(U)] just attempted to blow up [P] with the Detomatix cartridge and succeeded") - message_admins("[key_name_admin(U)] just attempted to blow up [P] with the Detomatix cartridge and succeeded.", 1) - detonate_act(P) - else - to_chat(U, "No charges left.") - - else - to_chat(U, "PDA not found.") - else - U.unset_machine() - ui.close() - return 0 - -//pAI FUNCTIONS=================================== - if("pai") - if(pai) - if(pai.loc != src) - pai = null - else - switch(href_list["option"]) - if("1") // Configure pAI device - pai.attack_self(U) - if("2") // Eject pAI device - var/turf/T = get_turf_or_move(src.loc) - if(T) - pai.loc = T - pai = null - - else - mode = text2num(href_list["choice"]) - if(cartridge) - cartridge.mode = mode - -//EXTRA FUNCTIONS=================================== - - if (mode == 2||mode == 21)//To clear message overlays. - new_message = 0 - update_icon() - - if (mode == 6||mode == 61)//To clear news overlays. - new_news = 0 - update_icon() - - if ((honkamt > 0) && (prob(60)))//For clown virus. - honkamt-- - playsound(src, 'sound/items/bikehorn.ogg', 30, 1) - - return 1 // return 1 tells it to refresh the UI in NanoUI - -/obj/item/device/pda/update_icon() - ..() - - overlays.Cut() - if(new_message || new_news) - overlays += image(icon, "pda-r") - -/obj/item/device/pda/proc/detonate_act(var/obj/item/device/pda/P) - //TODO: sometimes these attacks show up on the message server - var/i = rand(1,100) - var/j = rand(0,1) //Possibility of losing the PDA after the detonation - var/message = "" - var/mob/living/M = null - if(ismob(P.loc)) - M = P.loc - - //switch(i) //Yes, the overlapping cases are intended. - if(i<=10) //The traditional explosion - P.explode() - j=1 - message += "Your [P] suddenly explodes!" - if(i>=10 && i<= 20) //The PDA burns a hole in the holder. - j=1 - if(M && isliving(M)) - M.apply_damage( rand(30,60) , BURN) - message += "You feel a searing heat! Your [P] is burning!" - if(i>=20 && i<=25) //EMP - empulse(P.loc, 1, 2, 4, 6, 1) - message += "Your [P] emits a wave of electromagnetic energy!" - if(i>=25 && i<=40) //Smoke - var/datum/effect/effect/system/smoke_spread/chem/S = new /datum/effect/effect/system/smoke_spread/chem - S.attach(P.loc) - S.set_up(P, 10, 0, P.loc) - playsound(P, 'sound/effects/smoke.ogg', 50, 1, -3) - S.start() - message += "Large clouds of smoke billow forth from your [P]!" - if(i>=40 && i<=45) //Bad smoke - var/datum/effect/effect/system/smoke_spread/bad/B = new /datum/effect/effect/system/smoke_spread/bad - B.attach(P.loc) - B.set_up(P, 10, 0, P.loc) - playsound(P, 'sound/effects/smoke.ogg', 50, 1, -3) - B.start() - message += "Large clouds of noxious smoke billow forth from your [P]!" - if(i>=65 && i<=75) //Weaken - if(M && isliving(M)) - M.apply_effects(0,1) - message += "Your [P] flashes with a blinding white light! You feel weaker." - if(i>=75 && i<=85) //Stun and stutter - if(M && isliving(M)) - M.apply_effects(1,0,0,0,1) - message += "Your [P] flashes with a blinding white light! You feel weaker." - if(i>=85) //Sparks - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(2, 1, P.loc) - s.start() - message += "Your [P] begins to spark violently!" - if(i>45 && i<65 && prob(50)) //Nothing happens - message += "Your [P] bleeps loudly." - j = prob(10) - - if(j && detonate) //This kills the PDA - qdel(P) - if(message) - message += "It melts in a puddle of plastic." - else - message += "Your [P] shatters in a thousand pieces!" - - if(M && isliving(M)) - message = "[message]" - M.show_message(message, 1) - -/obj/item/device/pda/proc/remove_id() - if (id) - if (ismob(loc)) - var/mob/M = loc - M.put_in_hands(id) - to_chat(usr, "You remove the ID from the [name].") - playsound(src, 'sound/machines/id_swipe.ogg', 100, 1) - else - id.loc = get_turf(src) - id = null - -/obj/item/device/pda/proc/remove_pen() - var/obj/item/weapon/pen/O = locate() in src - if(O) - if(istype(loc, /mob)) - var/mob/M = loc - if(M.get_active_hand() == null) - M.put_in_hands(O) - to_chat(usr, "You remove \the [O] from \the [src].") - return - O.loc = get_turf(src) - else - to_chat(usr, "This PDA does not have a pen in it.") - -/obj/item/device/pda/proc/create_message(var/mob/living/U = usr, var/obj/item/device/pda/P, var/tap = 1) - if(tap) - U.visible_message("\The [U] taps on their PDA's screen.") - var/t = input(U, "Please enter message", P.name, null) as text - t = sanitize(t) - //t = readd_quotes(t) - t = replace_characters(t, list(""" = "\"")) - if (!t || !istype(P)) - return - if (!in_range(src, U) && loc != U) - return - - if (isnull(P)||P.toff || toff) - return - - if (last_text && world.time < last_text + 5) - return - - if (!can_use()) - return - - if (is_jammed(src)) - return - - last_text = world.time - var/datum/reception/reception = get_reception(src, P, t) - t = reception.message - - if(reception.message_server && (reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER)) // only send the message if it's stable - if(reception.telecomms_reception & TELECOMMS_RECEPTION_RECEIVER == 0) // Does our recipient have a broadcaster on their level? - to_chat(U, "ERROR: Cannot reach recipient.") - return - var/send_result = reception.message_server.send_pda_message("[P.owner]","[owner]","[t]") - if (send_result) - to_chat(U, "ERROR: Messaging server rejected your message. Reason: contains '[send_result]'.") - return - - tnote.Add(list(list("sent" = 1, "owner" = "[P.owner]", "job" = "[P.ownjob]", "message" = "[t]", "target" = "\ref[P]"))) - P.tnote.Add(list(list("sent" = 0, "owner" = "[owner]", "job" = "[ownjob]", "message" = "[t]", "target" = "\ref[src]"))) - for(var/mob/M in player_list) - if(M.stat == DEAD && M.client && (M.is_preference_enabled(/datum/client_preference/ghost_ears))) // src.client is so that ghosts don't have to listen to mice - if(istype(M, /mob/new_player)) - continue - if(M.forbid_seeing_deadchat) - continue - M.show_message("PDA Message - [owner] -> [P.owner]: [t]") - - if(!conversations.Find("\ref[P]")) - conversations.Add("\ref[P]") - if(!P.conversations.Find("\ref[src]")) - P.conversations.Add("\ref[src]") - to_chat(U, "[bicon(src)] Sent message to [P.owner] ([P.ownjob]), \"[t]\"") - - if (prob(5) && security_level >= SEC_LEVEL_BLUE) //Give the AI a chance of intercepting the message //VOREStation Edit: no spam interception on lower codes + lower interception chance - var/who = src.owner - if(prob(50)) - who = P.owner - for(var/mob/living/silicon/ai/ai in mob_list) - // Allows other AIs to intercept the message but the AI won't intercept their own message. - if(ai.aiPDA != P && ai.aiPDA != src) - ai.show_message("Intercepted message from [who]: [t]") - - P.new_message_from_pda(src, t) - SSnanoui.update_user_uis(U, src) // Update the sending user's PDA UI so that they can see the new message - else - to_chat(U, "ERROR: Messaging server is not responding.") - -/obj/item/device/pda/proc/new_info(var/beep_silent, var/message_tone, var/reception_message) - if (!beep_silent) - playsound(src, 'sound/machines/twobeep.ogg', 50, 1) - for (var/mob/O in hearers(2, loc)) - O.show_message(text("[bicon(src)] *[message_tone]*")) - //Search for holder of the PDA. - var/mob/living/L = null - if(loc && isliving(loc)) - L = loc - //Maybe they are a pAI! - else - L = get(src, /mob/living/silicon) - - if(L) - if(reception_message) - to_chat(L,reception_message) - SSnanoui.update_user_uis(L, src) // Update the receiving user's PDA UI so that they can see the new message - -/obj/item/device/pda/proc/new_news(var/message) - new_info(news_silent, newstone, news_silent ? "" : "[bicon(src)] [message]") - - if(!news_silent) - new_news = 1 - update_icon() - -/obj/item/device/pda/ai/new_news(var/message) - // Do nothing - -/obj/item/device/pda/proc/new_message_from_pda(var/obj/item/device/pda/sending_device, var/message) - if (is_jammed(src)) - return - new_message(sending_device, sending_device.owner, sending_device.ownjob, message) - -/obj/item/device/pda/proc/new_message(var/sending_unit, var/sender, var/sender_job, var/message, var/reply = 1) - var/reception_message = "[bicon(src)] Message from [sender] ([sender_job]), \"[message]\" ([reply ? "Reply" : "Unable to Reply"])" - new_info(message_silent, ttone, reception_message) - - log_pda("(PDA: [sending_unit]) sent \"[message]\" to [name]", usr) - new_message = 1 - update_icon() - -/obj/item/device/pda/ai/new_message(var/atom/movable/sending_unit, var/sender, var/sender_job, var/message) - var/track = "" - if(ismob(sending_unit.loc) && isAI(loc)) - track = "(Follow)" - - var/reception_message = "[bicon(src)] Message from [sender] ([sender_job]), \"[message]\" (Reply) [track]" - new_info(message_silent, newstone, reception_message) - - log_pda("(PDA: [sending_unit]) sent \"[message]\" to [name]",usr) - new_message = 1 - -/obj/item/device/pda/proc/spam_message(sender, message) - var/reception_message = "\icon[src] Message from [sender] (Unknown / spam?), \"[message]\" (Unable to Reply)" - new_info(message_silent, ttone, reception_message) - - if(prob(50)) // Give the AI an increased chance to intercept the message - for(var/mob/living/silicon/ai/ai in mob_list) - if(ai.aiPDA != src) - ai.show_message("Intercepted message from [sender] (Unknown / spam?) to [owner]: [message]") - -/obj/item/device/pda/verb/verb_reset_pda() - set category = "Object" - set name = "Reset PDA" - set src in usr - - if(issilicon(usr)) - return - - if(can_use(usr)) - mode = 0 - SSnanoui.update_uis(src) - to_chat(usr, "You press the reset button on \the [src].") - else - to_chat(usr, "You cannot do this while restrained.") - -/obj/item/device/pda/verb/verb_remove_id() - set category = "Object" - set name = "Remove id" - set src in usr - - if(issilicon(usr)) - return - - if ( can_use(usr) ) - if(id) - remove_id() - else - to_chat(usr, "This PDA does not have an ID in it.") - else - to_chat(usr, "You cannot do this while restrained.") - - -/obj/item/device/pda/verb/verb_remove_pen() - set category = "Object" - set name = "Remove pen" - set src in usr - - if(issilicon(usr)) - return - - if ( can_use(usr) ) - remove_pen() - else - to_chat(usr, "You cannot do this while restrained.") - -/obj/item/device/pda/verb/verb_remove_cartridge() - set category = "Object" - set name = "Remove cartridge" - set src in usr - - if(issilicon(usr)) - return - - if(!can_use(usr)) - to_chat(usr, "You cannot do this while restrained.") - return - - if(isnull(cartridge)) - to_chat(usr, "There's no cartridge to eject.") - return - - cartridge.forceMove(get_turf(src)) - if(ismob(loc)) - var/mob/M = loc - M.put_in_hands(cartridge) - mode = 0 - scanmode = 0 - if (cartridge.radio) - cartridge.radio.hostpda = null - to_chat(usr, "You remove \the [cartridge] from the [name].") - playsound(src, 'sound/machines/id_swipe.ogg', 100, 1) - cartridge = null - -/obj/item/device/pda/proc/id_check(mob/user as mob, choice as num)//To check for IDs; 1 for in-pda use, 2 for out of pda use. - if(choice == 1) - if (id) - remove_id() - return 1 - else - var/obj/item/I = user.get_active_hand() - if (istype(I, /obj/item/weapon/card/id) && user.unEquip(I)) - I.loc = src - id = I - return 1 - else - var/obj/item/weapon/card/I = user.get_active_hand() - if (istype(I, /obj/item/weapon/card/id) && I:registered_name && user.unEquip(I)) - var/obj/old_id = id - I.loc = src - id = I - user.put_in_hands(old_id) - return 1 - return 0 - -// access to status display signals -/obj/item/device/pda/attackby(obj/item/C as obj, mob/user as mob) - ..() - if(istype(C, /obj/item/weapon/cartridge) && !cartridge) - cartridge = C - user.drop_item() - cartridge.loc = src - to_chat(usr, "You insert [cartridge] into [src].") - SSnanoui.update_uis(src) // update all UIs attached to src - if(cartridge.radio) - cartridge.radio.hostpda = src - - else if(istype(C, /obj/item/weapon/card/id)) - var/obj/item/weapon/card/id/idcard = C - if(!idcard.registered_name) - to_chat(user, "\The [src] rejects the ID.") - return - if(!owner) - owner = idcard.registered_name - ownjob = idcard.assignment - ownrank = idcard.rank - name = "PDA-[owner] ([ownjob])" - to_chat(user, "Card scanned.") - else - //Basic safety check. If either both objects are held by user or PDA is on ground and card is in hand. - if(((src in user.contents) && (C in user.contents)) || (istype(loc, /turf) && in_range(src, user) && (C in user.contents)) ) - if(id_check(user, 2)) - to_chat(user, "You put the ID into \the [src]'s slot.") - updateSelfDialog()//Update self dialog on success. - return //Return in case of failed check or when successful. - updateSelfDialog()//For the non-input related code. - else if(istype(C, /obj/item/device/paicard) && !src.pai) - user.drop_item() - C.loc = src - pai = C - to_chat(user, "You slot \the [C] into \the [src].") - SSnanoui.update_uis(src) // update all UIs attached to src - else if(istype(C, /obj/item/weapon/pen)) - var/obj/item/weapon/pen/O = locate() in src - if(O) - to_chat(user, "There is already a pen in \the [src].") - else - user.drop_item() - C.loc = src - to_chat(user, "You slot \the [C] into \the [src].") - return - -/obj/item/device/pda/attack(mob/living/C as mob, mob/living/user as mob) - if (istype(C, /mob/living/carbon)) - switch(scanmode) - if(1) - - for (var/mob/O in viewers(C, null)) - O.show_message("\The [user] has analyzed [C]'s vitals!", 1) - - user.show_message("Analyzing Results for [C]:") - user.show_message(" Overall Status: [C.stat > 1 ? "dead" : "[C.health - C.halloss]% healthy"]", 1) - user.show_message(text(" Damage Specifics: []-[]-[]-[]", - (C.getOxyLoss() > 50) ? "warning" : "", C.getOxyLoss(), - (C.getToxLoss() > 50) ? "warning" : "", C.getToxLoss(), - (C.getFireLoss() > 50) ? "warning" : "", C.getFireLoss(), - (C.getBruteLoss() > 50) ? "warning" : "", C.getBruteLoss() - ), 1) - user.show_message(" Key: Suffocation/Toxin/Burns/Brute", 1) - user.show_message(" Body Temperature: [C.bodytemperature-T0C]°C ([C.bodytemperature*1.8-459.67]°F)", 1) - if(C.tod && (C.stat == DEAD || (C.status_flags & FAKEDEATH))) - user.show_message(" Time of Death: [C.tod]") - if(istype(C, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = C - var/list/damaged = H.get_damaged_organs(1,1) - user.show_message("Localized Damage, Brute/Burn:",1) - if(length(damaged)>0) - for(var/obj/item/organ/external/org in damaged) - user.show_message(text(" []: []-[]", - capitalize(org.name), (org.brute_dam > 0) ? "warning" : "notice", org.brute_dam, (org.burn_dam > 0) ? "warning" : "notice", org.burn_dam),1) - else - user.show_message(" Limbs are OK.",1) - - if(2) - if (!istype(C:dna, /datum/dna)) - to_chat(user, "No fingerprints found on [C]") - else - to_chat(user, text("\The [C]'s Fingerprints: [md5(C:dna.uni_identity)]")) - if ( !(C:blood_DNA) ) - to_chat(user, "No blood found on [C]") - if(C:blood_DNA) - qdel(C:blood_DNA) - else - to_chat(user, "Blood found on [C]. Analysing...") - spawn(15) - for(var/blood in C:blood_DNA) - to_chat(user, "Blood type: [C:blood_DNA[blood]]\nDNA: [blood]") - - if(4) - user.visible_message("\The [user] has analyzed [C]'s radiation levels!", "You have analyzed [C]'s radiation levels!") - to_chat(user, "Analyzing Results for [C]:") - if(C.radiation) - to_chat(user, "Radiation Level: [C.radiation]") - else - to_chat(user, "No radiation detected.") - -/obj/item/device/pda/afterattack(atom/A as mob|obj|turf|area, mob/user as mob, proximity) - if(!proximity) return - switch(scanmode) - - if(3) - if(!isobj(A)) - return - if(!isnull(A.reagents)) - if(A.reagents.reagent_list.len > 0) - var/reagents_length = A.reagents.reagent_list.len - to_chat(user, "[reagents_length] chemical agent[reagents_length > 1 ? "s" : ""] found.") - for (var/re in A.reagents.reagent_list) - to_chat(user, " [re]") - else - to_chat(user, "No active chemical agents found in [A].") - else - to_chat(user, "No significantchemical agents found in [A].") - - if(5) - analyze_gases(A, user) - - if (!scanmode && istype(A, /obj/item/weapon/paper) && owner) - // JMO 20140705: Makes scanned document show up properly in the notes. Not pretty for formatted documents, - // as this will clobber the HTML, but at least it lets you scan a document. You can restore the original - // notes by editing the note again. (Was going to allow you to edit, but scanned documents are too long.) - var/raw_scan = (A:info) - var/formatted_scan = "" - // Scrub out the tags (replacing a few formatting ones along the way) - - // Find the beginning and end of the first tag. - var/tag_start = findtext(raw_scan,"<") - var/tag_stop = findtext(raw_scan,">") - - // Until we run out of complete tags... - while(tag_start&&tag_stop) - var/pre = copytext(raw_scan,1,tag_start) // Get the stuff that comes before the tag - var/tag = lowertext(copytext(raw_scan,tag_start+1,tag_stop)) // Get the tag so we can do intellegent replacement - var/tagend = findtext(tag," ") // Find the first space in the tag if there is one. - - // Anything that's before the tag can just be added as is. - formatted_scan = formatted_scan+pre - - // If we have a space after the tag (and presumably attributes) just crop that off. - if (tagend) - tag=copytext(tag,1,tagend) - - if (tag=="p"||tag=="/p"||tag=="br") // Check if it's I vertical space tag. - formatted_scan=formatted_scan+"
" // If so, add some padding in. - - raw_scan = copytext(raw_scan,tag_stop+1) // continue on with the stuff after the tag - - // Look for the next tag in what's left - tag_start = findtext(raw_scan,"<") - tag_stop = findtext(raw_scan,">") - - // Anything that is left in the page. just tack it on to the end as is - formatted_scan=formatted_scan+raw_scan - - // If there is something in there already, pad it out. - if (length(note)>0) - note = note + "

" - - // Store the scanned document to the notes - note = "Scanned Document. Edit to restore previous notes/delete scan.
----------
" + formatted_scan + "
" - // notehtml ISN'T set to allow user to get their old notes back. A better implementation would add a "scanned documents" - // feature to the PDA, which would better convey the availability of the feature, but this will work for now. - - // Inform the user - to_chat(user, "Paper scanned and OCRed to notekeeper.") //concept of scanning paper copyright brainoblivion 2009 - - -/obj/item/device/pda/proc/explode() //This needs tuning. //Sure did. - if(!src.detonate) return - var/turf/T = get_turf(src.loc) - if(T) - T.hotspot_expose(700,125) - explosion(T, 0, 0, 1, rand(1,2)) - return - -/obj/item/device/pda/Destroy() - PDAs -= src - if (src.id && prob(100) && !delete_id) //IDs are kept in 90% of the cases //VOREStation Edit - 100% of the cases, excpet when specified otherwise - src.id.forceMove(get_turf(src.loc)) - else - QDEL_NULL(src.id) - QDEL_NULL(src.cartridge) - QDEL_NULL(src.pai) - return ..() - -/obj/item/device/pda/clown/Crossed(atom/movable/AM as mob|obj) //Clown PDA is slippery. - if(AM.is_incorporeal()) - return - if (istype(AM, /mob/living)) - var/mob/living/M = AM - - if(M.slip("the PDA",8) && M.real_name != src.owner && istype(src.cartridge, /obj/item/weapon/cartridge/clown)) - if(src.cartridge.charges < 5) - src.cartridge.charges++ - -/obj/item/device/pda/proc/available_pdas() - var/list/names = list() - var/list/plist = list() - var/list/namecounts = list() - - if (toff) - to_chat(usr, "Turn on your receiver in order to send messages.") - return - - for (var/obj/item/device/pda/P in PDAs) - if (!P.owner) - continue - else if(P.hidden) - continue - else if (P == src) - continue - else if (P.toff) - continue - - var/name = P.owner - if (name in names) - namecounts[name]++ - name = text("[name] ([namecounts[name]])") - else - names.Add(name) - namecounts[name] = 1 - - plist[text("[name]")] = P - return plist - - -//Some spare PDAs in a box -/obj/item/weapon/storage/box/PDAs - name = "box of spare PDAs" - desc = "A box of spare PDA microcomputers." - icon = 'icons/obj/pda.dmi' - icon_state = "pdabox" - - New() - ..() - new /obj/item/device/pda(src) - new /obj/item/device/pda(src) - new /obj/item/device/pda(src) - new /obj/item/device/pda(src) - new /obj/item/weapon/cartridge/head(src) - - var/newcart = pick( /obj/item/weapon/cartridge/engineering, - /obj/item/weapon/cartridge/security, - /obj/item/weapon/cartridge/medical, - /obj/item/weapon/cartridge/signal/science, - /obj/item/weapon/cartridge/quartermaster) - new newcart(src) - -// Pass along the pulse to atoms in contents, largely added so pAIs are vulnerable to EMP -/obj/item/device/pda/emp_act(severity) - for(var/atom/A in src) - A.emp_act(severity) - -/obj/item/device/pda/proc/analyze_air() - var/list/results = list() - var/turf/T = get_turf(src.loc) - if(!isnull(T)) - var/datum/gas_mixture/environment = T.return_air() - var/pressure = environment.return_pressure() - var/total_moles = environment.total_moles - if (total_moles) - var/o2_level = environment.gas["oxygen"]/total_moles - var/n2_level = environment.gas["nitrogen"]/total_moles - var/co2_level = environment.gas["carbon_dioxide"]/total_moles - var/phoron_level = environment.gas["phoron"]/total_moles - var/unknown_level = 1-(o2_level+n2_level+co2_level+phoron_level) - - // entry is what the element is describing - // Type identifies which unit or other special characters to use - // Val is the information reported - // Bad_high/_low are the values outside of which the entry reports as dangerous - // Poor_high/_low are the values outside of which the entry reports as unideal - // Values were extracted from the template itself - results = list( - list("entry" = "Pressure", "units" = "kPa", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80), - list("entry" = "Temperature", "units" = "°C", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5), - list("entry" = "Oxygen", "units" = "kPa", "val" = "[round(o2_level*100,0.1)]", "bad_high" = 140, "poor_high" = 135, "poor_low" = 19, "bad_low" = 17), - list("entry" = "Nitrogen", "units" = "kPa", "val" = "[round(n2_level*100,0.1)]", "bad_high" = 105, "poor_high" = 85, "poor_low" = 50, "bad_low" = 40), - list("entry" = "Carbon Dioxide", "units" = "kPa", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0), - list("entry" = "Phoron", "units" = "kPa", "val" = "[round(phoron_level*100,0.01)]", "bad_high" = 0.5, "poor_high" = 0, "poor_low" = 0, "bad_low" = 0), - list("entry" = "Other", "units" = "kPa", "val" = "[round(unknown_level, 0.01)]", "bad_high" = 1, "poor_high" = 0.5, "poor_low" = 0, "bad_low" = 0) - ) - - if(isnull(results)) - results = list(list("entry" = "pressure", "units" = "kPa", "val" = "0", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80)) - return results diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm deleted file mode 100644 index e85460284c..0000000000 --- a/code/game/objects/items/devices/PDA/cart.dm +++ /dev/null @@ -1,630 +0,0 @@ -var/list/command_cartridges = list( - /obj/item/weapon/cartridge/captain, - /obj/item/weapon/cartridge/hop, - /obj/item/weapon/cartridge/hos, - /obj/item/weapon/cartridge/ce, - /obj/item/weapon/cartridge/rd, - /obj/item/weapon/cartridge/cmo, - /obj/item/weapon/cartridge/head, - /obj/item/weapon/cartridge/lawyer // Internal Affaris, - ) - -var/list/security_cartridges = list( - /obj/item/weapon/cartridge/security, - /obj/item/weapon/cartridge/detective, - /obj/item/weapon/cartridge/hos - ) - -var/list/engineering_cartridges = list( - /obj/item/weapon/cartridge/engineering, - /obj/item/weapon/cartridge/atmos, - /obj/item/weapon/cartridge/ce - ) - -var/list/medical_cartridges = list( - /obj/item/weapon/cartridge/medical, - /obj/item/weapon/cartridge/chemistry, - /obj/item/weapon/cartridge/cmo - ) - -var/list/research_cartridges = list( - /obj/item/weapon/cartridge/signal/science, - /obj/item/weapon/cartridge/rd - ) - -var/list/cargo_cartridges = list( - /obj/item/weapon/cartridge/quartermaster, // This also covers cargo-techs, apparently, - /obj/item/weapon/cartridge/miner, - /obj/item/weapon/cartridge/hop - ) - -var/list/civilian_cartridges = list( - /obj/item/weapon/cartridge/janitor, - /obj/item/weapon/cartridge/service, - /obj/item/weapon/cartridge/hop - ) - -/obj/item/weapon/cartridge - name = "generic cartridge" - desc = "A data cartridge for portable microcomputers." - icon = 'icons/obj/pda.dmi' - icon_state = "cart" - item_state = "electronic" - w_class = ITEMSIZE_TINY - drop_sound = 'sound/items/drop/component.ogg' - pickup_sound = 'sound/items/pickup/component.ogg' - - var/obj/item/radio/integrated/radio = null - var/access_security = 0 - var/access_engine = 0 - var/access_atmos = 0 - var/access_medical = 0 - var/access_clown = 0 - var/access_mime = 0 - var/access_janitor = 0 -// var/access_flora = 0 - var/access_reagent_scanner = 0 - var/access_remote_door = 0 // Control some blast doors remotely!! - var/remote_door_id = "" - var/access_status_display = 0 - var/access_quartermaster = 0 - var/access_detonate_pda = 0 - var/access_hydroponics = 0 - var/charges = 0 - var/mode = null - var/menu - var/datum/data/record/active1 = null //General - var/datum/data/record/active2 = null //Medical - var/datum/data/record/active3 = null //Security - var/selected_sensor = null // Power Sensor - var/message1 // used for status_displays - var/message2 - var/list/stored_data = list() - -/obj/item/weapon/cartridge/Destroy() - QDEL_NULL(radio) - return ..() - -/obj/item/weapon/cartridge/engineering - name = "\improper Power-ON cartridge" - icon_state = "cart-e" - access_engine = 1 - -/obj/item/weapon/cartridge/atmos - name = "\improper BreatheDeep cartridge" - icon_state = "cart-a" - access_atmos = 1 - -/obj/item/weapon/cartridge/medical - name = "\improper Med-U cartridge" - icon_state = "cart-m" - access_medical = 1 - -/obj/item/weapon/cartridge/chemistry - name = "\improper ChemWhiz cartridge" - icon_state = "cart-chem" - access_reagent_scanner = 1 - access_medical = 1 - -/obj/item/weapon/cartridge/security - name = "\improper R.O.B.U.S.T. cartridge" - icon_state = "cart-s" - access_security = 1 - -/obj/item/weapon/cartridge/security/Initialize() - radio = new /obj/item/radio/integrated/beepsky(src) - . = ..() - -/obj/item/weapon/cartridge/detective - name = "\improper D.E.T.E.C.T. cartridge" - icon_state = "cart-s" - access_security = 1 - access_medical = 1 - - -/obj/item/weapon/cartridge/janitor - name = "\improper CustodiPRO cartridge" - desc = "The ultimate in clean-room design." - icon_state = "cart-j" - access_janitor = 1 - -/obj/item/weapon/cartridge/lawyer - name = "\improper P.R.O.V.E. cartridge" - icon_state = "cart-s" - access_security = 1 - -/obj/item/weapon/cartridge/clown - name = "\improper Honkworks 5.0 cartridge" - icon_state = "cart-clown" - access_clown = 1 - charges = 5 - -/obj/item/weapon/cartridge/mime - name = "\improper Gestur-O 1000 cartridge" - icon_state = "cart-mi" - access_mime = 1 - charges = 5 -/* -/obj/item/weapon/cartridge/botanist - name = "Green Thumb v4.20" - icon_state = "cart-b" - access_flora = 1 -*/ - -/obj/item/weapon/cartridge/service - name = "\improper Serv-U Pro cartridge" - desc = "A data cartridge designed to serve YOU!" - -/obj/item/weapon/cartridge/signal - name = "generic signaler cartridge" - desc = "A data cartridge with an integrated radio signaler module." - var/qdeled = 0 - -/obj/item/weapon/cartridge/signal/science - name = "\improper Signal Ace 2 cartridge" - desc = "Complete with integrated radio signaler!" - icon_state = "cart-tox" - access_reagent_scanner = 1 - access_atmos = 1 - -/obj/item/weapon/cartridge/signal/Initialize() - radio = new /obj/item/radio/integrated/signal(src) - . = ..() - -/obj/item/weapon/cartridge/quartermaster - name = "\improper Space Parts & Space Vendors cartridge" - desc = "Perfect for the Quartermaster on the go!" - icon_state = "cart-q" - access_quartermaster = 1 - -/obj/item/weapon/cartridge/miner - name = "\improper Drill-Jockey 4.5 cartridge" - desc = "It's covered in some sort of sand." - icon_state = "cart-q" - -/obj/item/weapon/cartridge/head - name = "\improper Easy-Record DELUXE cartridge" - icon_state = "cart-h" - access_status_display = 1 - -/obj/item/weapon/cartridge/hop - name = "\improper HumanResources9001 cartridge" - icon_state = "cart-h" - access_status_display = 1 - access_quartermaster = 1 - access_janitor = 1 - access_security = 1 - -/obj/item/weapon/cartridge/hos - name = "\improper R.O.B.U.S.T. DELUXE cartridge" - icon_state = "cart-hos" - access_status_display = 1 - access_security = 1 - -/obj/item/weapon/cartridge/hos/Initialize() - radio = new /obj/item/radio/integrated/beepsky(src) - . = ..() - -/obj/item/weapon/cartridge/ce - name = "\improper Power-On DELUXE cartridge" - icon_state = "cart-ce" - access_status_display = 1 - access_engine = 1 - access_atmos = 1 - -/obj/item/weapon/cartridge/cmo - name = "\improper Med-U DELUXE cartridge" - icon_state = "cart-cmo" - access_status_display = 1 - access_reagent_scanner = 1 - access_medical = 1 - -/obj/item/weapon/cartridge/rd - name = "\improper Signal Ace DELUXE cartridge" - icon_state = "cart-rd" - access_status_display = 1 - access_reagent_scanner = 1 - access_atmos = 1 - -/obj/item/weapon/cartridge/rd/Initialize() - radio = new /obj/item/radio/integrated/signal(src) - . = ..() - -/obj/item/weapon/cartridge/captain - name = "\improper Value-PAK cartridge" - desc = "Now with 200% more value!" - icon_state = "cart-c" - access_quartermaster = 1 - access_janitor = 1 - access_engine = 1 - access_security = 1 - access_medical = 1 - access_reagent_scanner = 1 - access_status_display = 1 - access_atmos = 1 - -/obj/item/weapon/cartridge/syndicate - name = "\improper Detomatix cartridge" - icon_state = "cart" - access_remote_door = 1 - access_detonate_pda = 1 - remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing. - charges = 4 - -/obj/item/weapon/cartridge/proc/post_status(var/command, var/data1, var/data2) - - var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) - if(!frequency) return - - var/datum/signal/status_signal = new - status_signal.source = src - status_signal.transmission_method = TRANSMISSION_RADIO - status_signal.data["command"] = command - - switch(command) - if("message") - status_signal.data["msg1"] = data1 - status_signal.data["msg2"] = data2 - if(loc) - var/obj/item/PDA = loc - var/mob/user = PDA.fingerprintslast - log_admin("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]") - message_admins("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]") - - if("alert") - status_signal.data["picture_state"] = data1 - - frequency.post_signal(src, status_signal) - - -/* - This generates the nano values of the cart menus. - Because we close the UI when we insert a new cart - we don't have to worry about null values on items - the user can't access. Well, unless they are href hacking. - But in that case their UI will just lock up. -*/ - - -/obj/item/weapon/cartridge/proc/create_NanoUI_values(mob/user as mob) - var/values[0] - - /* Signaler (Mode: 40) */ - - - if(istype(radio,/obj/item/radio/integrated/signal) && (mode==40)) - var/obj/item/radio/integrated/signal/R = radio - values["signal_freq"] = format_frequency(R.frequency) - values["signal_code"] = R.code - - - /* Station Display (Mode: 42) */ - - if(mode==42) - values["message1"] = message1 ? message1 : "(none)" - values["message2"] = message2 ? message2 : "(none)" - - - - /* Power Monitor (Mode: 43 / 433) */ - - if(mode==43 || mode==433) - var/list/sensors = list() - var/obj/machinery/power/sensor/MS = null - var/my_z = get_z(user) - var/list/levels = using_map.get_map_levels(my_z) - - for(var/obj/machinery/power/sensor/S in machines) - if(!(get_z(S) in levels)) - continue - sensors.Add(list(list("name_tag" = S.name_tag))) - if(S.name_tag == selected_sensor) - MS = S - values["power_sensors"] = sensors - if(selected_sensor && MS) - values["sensor_reading"] = MS.return_reading_data() - - - /* General Records (Mode: 44 / 441 / 45 / 451) */ - if(mode == 44 || mode == 441 || mode == 45 || mode ==451) - if(istype(active1, /datum/data/record) && (active1 in data_core.general)) - values["general"] = active1.fields - values["general_exists"] = 1 - - else - values["general_exists"] = 0 - - - - /* Medical Records (Mode: 44 / 441) */ - - if(mode == 44 || mode == 441) - var/medData[0] - for(var/datum/data/record/R in sortRecord(data_core.general)) - medData[++medData.len] = list(Name = R.fields["name"],"ref" = "\ref[R]") - values["medical_records"] = medData - - if(istype(active2, /datum/data/record) && (active2 in data_core.medical)) - values["medical"] = active2.fields - values["medical_exists"] = 1 - else - values["medical_exists"] = 0 - - /* Security Records (Mode:45 / 451) */ - - if(mode == 45 || mode == 451) - var/secData[0] - for (var/datum/data/record/R in sortRecord(data_core.general)) - secData[++secData.len] = list(Name = R.fields["name"], "ref" = "\ref[R]") - values["security_records"] = secData - - if(istype(active3, /datum/data/record) && (active3 in data_core.security)) - values["security"] = active3.fields - values["security_exists"] = 1 - else - values["security_exists"] = 0 - - /* Security Bot Control (Mode: 46) */ - - if(mode==46) - var/botsData[0] - var/beepskyData[0] - if(istype(radio,/obj/item/radio/integrated/beepsky)) - var/obj/item/radio/integrated/beepsky/SC = radio - beepskyData["active"] = SC.active - if(SC.active && !isnull(SC.botstatus)) - var/area/loca = SC.botstatus["loca"] - var/loca_name = sanitize(loca.name) - beepskyData["botstatus"] = list("loca" = loca_name, "mode" = SC.botstatus["mode"]) - else - beepskyData["botstatus"] = list("loca" = null, "mode" = -1) - var/botsCount=0 - if(SC.botlist && SC.botlist.len) - for(var/mob/living/bot/B in SC.botlist) - botsCount++ - if(B.loc) - botsData[++botsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]") - - if(!botsData.len) - botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) - - beepskyData["bots"] = botsData - beepskyData["count"] = botsCount - - else - beepskyData["active"] = 0 - botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) - beepskyData["botstatus"] = list("loca" = null, "mode" = null) - beepskyData["bots"] = botsData - beepskyData["count"] = 0 - - values["beepsky"] = beepskyData - - - /* MULEBOT Control (Mode: 48) */ - - if(mode==48) - var/mulebotsData[0] - var/count = 0 - - for(var/mob/living/bot/mulebot/M in living_mob_list) - if(!M.on) - continue - ++count - var/muleData[0] - muleData["name"] = M.suffix - muleData["location"] = get_area(M) - muleData["paused"] = M.paused - muleData["home"] = M.homeName - muleData["target"] = M.targetName - muleData["ref"] = "\ref[M]" - muleData["load"] = M.load ? M.load.name : "Nothing" - - mulebotsData[++mulebotsData.len] = muleData.Copy() - - values["mulebotcount"] = count - values["mulebots"] = mulebotsData - - - - /* Supply Shuttle Requests Menu (Mode: 47) */ - - if(mode==47) - var/supplyData[0] - var/datum/shuttle/autodock/ferry/supply/shuttle = SSsupply.shuttle - if (shuttle) - supplyData["shuttle_moving"] = shuttle.has_arrive_time() - supplyData["shuttle_eta"] = shuttle.eta_minutes() - supplyData["shuttle_loc"] = shuttle.at_station() ? "Station" : "Dock" - var/supplyOrderCount = 0 - var/supplyOrderData[0] - for(var/S in SSsupply.shoppinglist) - var/datum/supply_order/SO = S - - supplyOrderData[++supplyOrderData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "ApprovedBy" = SO.ordered_by, "Comment" = html_encode(SO.comment)) - if(!supplyOrderData.len) - supplyOrderData[++supplyOrderData.len] = list("Number" = null, "Name" = null, "OrderedBy"=null) - - supplyData["approved"] = supplyOrderData - supplyData["approved_count"] = supplyOrderCount - - var/requestCount = 0 - var/requestData[0] - for(var/S in SSsupply.order_history) - var/datum/supply_order/SO = S - if(SO.status != SUP_ORDER_REQUESTED) - continue - - requestCount++ - requestData[++requestData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "OrderedBy" = SO.ordered_by, "Comment" = html_encode(SO.comment)) - if(!requestData.len) - requestData[++requestData.len] = list("Number" = null, "Name" = null, "orderedBy" = null, "Comment" = null) - - supplyData["requests"] = requestData - supplyData["requests_count"] = requestCount - - - values["supply"] = supplyData - - - - /* Janitor Supplies Locator (Mode: 49) */ - if(mode==49) - var/JaniData[0] - var/turf/cl = get_turf(src) - - if(cl) - JaniData["user_loc"] = list("x" = cl.x, "y" = cl.y) - else - JaniData["user_loc"] = list("x" = 0, "y" = 0) - var/MopData[0] - for(var/obj/item/weapon/mop/M in GLOB.all_mops) - var/turf/ml = get_turf(M) - if(ml) - if(ml.z != cl.z) - continue - var/direction = get_dir(src, M) - MopData[++MopData.len] = list ("x" = ml.x, "y" = ml.y, "dir" = uppertext(dir2text(direction)), "status" = M.reagents.total_volume ? "Wet" : "Dry") - - if(!MopData.len) - MopData[++MopData.len] = list("x" = 0, "y" = 0, dir=null, status = null) - - - var/BucketData[0] - for(var/obj/structure/mopbucket/B in GLOB.all_mopbuckets) - var/turf/bl = get_turf(B) - if(bl) - if(bl.z != cl.z) - continue - var/direction = get_dir(src,B) - BucketData[++BucketData.len] = list ("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.reagents.total_volume/100) - - if(!BucketData.len) - BucketData[++BucketData.len] = list("x" = 0, "y" = 0, dir=null, status = null) - - var/CbotData[0] - for(var/mob/living/bot/cleanbot/B in mob_list) - var/turf/bl = get_turf(B) - if(bl) - if(bl.z != cl.z) - continue - var/direction = get_dir(src,B) - CbotData[++CbotData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.on ? "Online" : "Offline") - - - if(!CbotData.len) - CbotData[++CbotData.len] = list("x" = 0, "y" = 0, dir=null, status = null) - var/CartData[0] - for(var/obj/structure/janitorialcart/B in GLOB.all_janitorial_carts) - var/turf/bl = get_turf(B) - if(bl) - if(bl.z != cl.z) - continue - var/direction = get_dir(src,B) - var/status = "No Bucket" - if(B.mybucket) - status = B.mybucket.reagents.total_volume / 100 - CartData[++CartData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = status) - if(!CartData.len) - CartData[++CartData.len] = list("x" = 0, "y" = 0, dir=null, status = null) - - - - - JaniData["mops"] = MopData - JaniData["buckets"] = BucketData - JaniData["cleanbots"] = CbotData - JaniData["carts"] = CartData - values["janitor"] = JaniData - - return values - - - - - -/obj/item/weapon/cartridge/Topic(href, href_list) - ..() - - if (!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - usr.unset_machine() - usr << browse(null, "window=pda") - return - - - - - switch(href_list["choice"]) - if("Medical Records") - var/datum/data/record/R = locate(href_list["target"]) - var/datum/data/record/M = locate(href_list["target"]) - loc:mode = 441 - mode = 441 - if (R in data_core.general) - for (var/datum/data/record/E in data_core.medical) - if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - M = E - break - active1 = R - active2 = M - - if("Security Records") - var/datum/data/record/R = locate(href_list["target"]) - var/datum/data/record/S = locate(href_list["target"]) - loc:mode = 451 - mode = 451 - if (R in data_core.general) - for (var/datum/data/record/E in data_core.security) - if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - S = E - break - active1 = R - active3 = S - - if("Send Signal") - if(is_jammed(src)) - return - spawn( 0 ) - radio:send_signal("ACTIVATE") - return - - if("Signal Frequency") - var/new_frequency = sanitize_frequency(radio:frequency + text2num(href_list["sfreq"])) - radio:set_frequency(new_frequency) - - if("Signal Code") - radio:code += text2num(href_list["scode"]) - radio:code = round(radio:code) - radio:code = min(100, radio:code) - radio:code = max(1, radio:code) - - if("Status") - switch(href_list["statdisp"]) - if("message") - post_status("message", message1, message2) - if("alert") - post_status("alert", href_list["alert"]) - if("setmsg1") - message1 = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", message1) as text|null, 40), 40) - updateSelfDialog() - if("setmsg2") - message2 = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", message2) as text|null, 40), 40) - updateSelfDialog() - else - post_status(href_list["statdisp"]) - - if("Power Select") - selected_sensor = href_list["target"] - loc:mode = 433 - mode = 433 - if("Power Clear") - selected_sensor = null - loc:mode = 43 - mode = 43 - - if("MULEbot") - var/mob/living/bot/mulebot/M = locate(href_list["ref"]) - if(istype(M)) - M.obeyCommand(href_list["command"]) - - return 1 diff --git a/code/game/objects/items/devices/PDA/cart_vr.dm b/code/game/objects/items/devices/PDA/cart_vr.dm deleted file mode 100644 index fc4e3d098a..0000000000 --- a/code/game/objects/items/devices/PDA/cart_vr.dm +++ /dev/null @@ -1,17 +0,0 @@ -var/list/exploration_cartridges = list( - /obj/item/weapon/cartridge/explorer, - /obj/item/weapon/cartridge/sar - ) - -/obj/item/weapon/cartridge/explorer - name = "\improper Explorator cartridge" - icon_state = "cart-e" - access_reagent_scanner = 1 - access_atmos = 1 - -/obj/item/weapon/cartridge/sar - name = "\improper Med-Exp cartridge" - icon_state = "cart-m" - access_medical = 1 - access_reagent_scanner = 1 - access_atmos = 1 diff --git a/code/game/objects/items/devices/PDA/chatroom.dm b/code/game/objects/items/devices/PDA/chatroom.dm deleted file mode 100644 index 008dab6414..0000000000 --- a/code/game/objects/items/devices/PDA/chatroom.dm +++ /dev/null @@ -1,16 +0,0 @@ -var/list/chatrooms = list() - -/datum/chatroom - var/name = "Generic Chatroom" - var/list/logged_in = list() - var/list/logs = list() // chat logs - var/list/banned = list() // banned users - var/list/whitelist = list() // whitelisted users - var/list/muted = list() - var/topic = "" // topic message for the chatroom - var/password = "" // blank for no password. - var/operator = "" // name of the operator - -/datum/chatroom/proc/attempt_connect(var/obj/item/device/pda/device, var/obj/password) - if(!device) - return diff --git a/code/game/objects/items/devices/PDA/radio.dm b/code/game/objects/items/devices/PDA/radio.dm deleted file mode 100644 index 133798e4b1..0000000000 --- a/code/game/objects/items/devices/PDA/radio.dm +++ /dev/null @@ -1,153 +0,0 @@ -/obj/item/radio/integrated - name = "\improper PDA radio module" - desc = "An electronic radio system." - icon = 'icons/obj/module.dmi' - icon_state = "power_mod" - var/obj/item/device/pda/hostpda = null - - var/on = 0 //Are we currently active?? - var/menu_message = "" - - New() - ..() - if (istype(loc.loc, /obj/item/device/pda)) - hostpda = loc.loc - - proc/post_signal(var/freq, var/key, var/value, var/key2, var/value2, var/key3, var/value3, s_filter) - - //to_world("Post: [freq]: [key]=[value], [key2]=[value2]") - var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq) - - if(!frequency) return - - var/datum/signal/signal = new() - signal.source = src - signal.transmission_method = TRANSMISSION_RADIO - signal.data[key] = value - if(key2) - signal.data[key2] = value2 - if(key3) - signal.data[key3] = value3 - - frequency.post_signal(src, signal, radio_filter = s_filter) - - return - - proc/generate_menu() - -/obj/item/radio/integrated/beepsky - var/list/botlist = null // list of bots - var/mob/living/bot/secbot/active // the active bot; if null, show bot list - var/list/botstatus // the status signal sent by the bot - - var/control_freq = BOT_FREQ - - // create a new QM cartridge, and register to receive bot control & beacon message - New() - ..() - spawn(5) - if(radio_controller) - radio_controller.add_object(src, control_freq, radio_filter = RADIO_SECBOT) - - // receive radio signals - // can detect bot status signals - // create/populate list as they are recvd - - receive_signal(datum/signal/signal) -// var/obj/item/device/pda/P = src.loc - - /* - to_world("recvd:[P] : [signal.source]") - for(var/d in signal.data) - to_world("- [d] = [signal.data[d]]") - */ - if (signal.data["type"] == "secbot") - if(!botlist) - botlist = new() - - if(!(signal.source in botlist)) - botlist += signal.source - - if(active == signal.source) - var/list/b = signal.data - botstatus = b.Copy() - -// if (istype(P)) P.updateSelfDialog() - - Topic(href, href_list) - ..() - var/obj/item/device/pda/PDA = src.hostpda - - switch(href_list["op"]) - - if("control") - active = locate(href_list["bot"]) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT) - - if("scanbots") // find all bots - botlist = null - post_signal(control_freq, "command", "bot_status", s_filter = RADIO_SECBOT) - - if("botlist") - active = null - - if("stop", "go") - post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = RADIO_SECBOT) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT) - - if("summon") - post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , s_filter = RADIO_SECBOT) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT) - - -/obj/item/radio/integrated/beepsky/Destroy() - if(radio_controller) - radio_controller.remove_object(src, control_freq) - return ..() - -/* - * Radio Cartridge, essentially a signaler. - */ - - -/obj/item/radio/integrated/signal - var/frequency = 1457 - var/code = 30.0 - var/last_transmission - var/datum/radio_frequency/radio_connection - -/obj/item/radio/integrated/signal/Initialize() - if(!radio_controller) - return - - if (src.frequency < PUBLIC_LOW_FREQ || src.frequency > PUBLIC_HIGH_FREQ) - src.frequency = sanitize_frequency(src.frequency) - - set_frequency(frequency) - -/obj/item/radio/integrated/signal/proc/set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - radio_connection = radio_controller.add_object(src, frequency) - -/obj/item/radio/integrated/signal/proc/send_signal(message="ACTIVATE") - - if(last_transmission && world.time < (last_transmission + 5)) - return - last_transmission = world.time - - var/time = time2text(world.realtime,"hh:mm:ss") - var/turf/T = get_turf(src) - lastsignalers.Add("[time] : [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) : [format_frequency(frequency)]/[code]") - - var/datum/signal/signal = new - signal.source = src - signal.encryption = code - signal.data["message"] = message - - radio_connection.post_signal(src, signal) - -/obj/item/radio/integrated/signal/Destroy() - if(radio_controller) - radio_controller.remove_object(src, frequency) - return ..() diff --git a/code/game/objects/items/devices/communicator/UI.dm b/code/game/objects/items/devices/communicator/UI.dm deleted file mode 100644 index a4686e39de..0000000000 --- a/code/game/objects/items/devices/communicator/UI.dm +++ /dev/null @@ -1,292 +0,0 @@ -// Proc: ui_interact() -// Parameters: 4 (standard NanoUI arguments) -// Description: Uses a bunch of for loops to turn lists into lists of lists, so they can be displayed in nanoUI, then displays various buttons to the user. -/obj/item/device/communicator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/key_state = null) - // this is the data which will be sent to the ui - var/data[0] //General nanoUI information - var/communicators[0] //List of communicators - var/invites[0] //Communicators and ghosts we've invited to our communicator. - var/requests[0] //Communicators and ghosts wanting to go in our communicator. - var/voices[0] //Current /mob/living/voice s inside the device. - var/connected_communicators[0] //Current communicators connected to the device. - - var/im_contacts_ui[0] //List of communicators that have been messaged. - var/im_list_ui[0] //List of messages. - - var/weather[0] - var/modules_ui[0] //Home screen info. - - //First we add other 'local' communicators. - for(var/obj/item/device/communicator/comm in known_devices) - if(comm.network_visibility && comm.exonet) - communicators[++communicators.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address) - - //Now for ghosts who we pretend have communicators. - for(var/mob/observer/dead/O in known_devices) - if(O.client && O.client.prefs.communicator_visibility == 1 && O.exonet) - communicators[++communicators.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address, "ref" = "\ref[O]") - - //Lists all the other communicators that we invited. - for(var/obj/item/device/communicator/comm in voice_invites) - if(comm.exonet) - invites[++invites.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address, "ref" = "\ref[comm]") - - //Ghosts we invited. - for(var/mob/observer/dead/O in voice_invites) - if(O.exonet && O.client) - invites[++invites.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address, "ref" = "\ref[O]") - - //Communicators that want to talk to us. - for(var/obj/item/device/communicator/comm in voice_requests) - if(comm.exonet) - requests[++requests.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address, "ref" = "\ref[comm]") - - //Ghosts that want to talk to us. - for(var/mob/observer/dead/O in voice_requests) - if(O.exonet && O.client) - requests[++requests.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address, "ref" = "\ref[O]") - - //Now for all the voice mobs inside the communicator. - for(var/mob/living/voice/voice in contents) - voices[++voices.len] = list("name" = sanitize("[voice.name]'s communicator"), "true_name" = sanitize(voice.name)) - - //Finally, all the communicators linked to this one. - for(var/obj/item/device/communicator/comm in communicating) - connected_communicators[++connected_communicators.len] = list("name" = sanitize(comm.name), "true_name" = sanitize(comm.name), "ref" = "\ref[comm]") - - //Devices that have been messaged or recieved messages from. - for(var/obj/item/device/communicator/comm in im_contacts) - if(comm.exonet) - im_contacts_ui[++im_contacts_ui.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address, "ref" = "\ref[comm]") - - for(var/mob/observer/dead/ghost in im_contacts) - if(ghost.exonet) - im_contacts_ui[++im_contacts_ui.len] = list("name" = sanitize(ghost.name), "address" = ghost.exonet.address, "ref" = "\ref[ghost]") - - for(var/obj/item/integrated_circuit/input/EPv2/CIRC in im_contacts) - if(CIRC.exonet && CIRC.assembly) - im_contacts_ui[++im_contacts_ui.len] = list("name" = sanitize(CIRC.assembly.name), "address" = CIRC.exonet.address, "ref" = "\ref[CIRC]") - - - //Actual messages. - for(var/I in im_list) - im_list_ui[++im_list_ui.len] = list("address" = I["address"], "to_address" = I["to_address"], "im" = I["im"]) - - //Weather reports. - for(var/datum/planet/planet in SSplanets.planets) - if(planet.weather_holder && planet.weather_holder.current_weather) - var/list/W = list( - "Planet" = planet.name, - "Time" = planet.current_time.show_time("hh:mm"), - "Weather" = planet.weather_holder.current_weather.name, - "Temperature" = planet.weather_holder.temperature - T0C, - "High" = planet.weather_holder.current_weather.temp_high - T0C, - "Low" = planet.weather_holder.current_weather.temp_low - T0C, - "WindDir" = planet.weather_holder.wind_dir ? dir2text(planet.weather_holder.wind_dir) : "None", - "WindSpeed" = planet.weather_holder.wind_speed ? "[planet.weather_holder.wind_speed > 2 ? "Severe" : "Normal"]" : "None", - "Forecast" = english_list(planet.weather_holder.forecast, and_text = "→", comma_text = "→", final_comma_text = "→") // Unicode RIGHTWARDS ARROW. - ) - weather[++weather.len] = W - - // Update manifest - data_core.get_manifest_list() - - //Modules for homescreen. - for(var/list/R in modules) - modules_ui[++modules_ui.len] = R - - data["user"] = "\ref[user]" // For receiving input() via topic, because input(usr,...) wasn't working on cartridges - data["owner"] = owner ? owner : "Unset" - data["occupation"] = occupation ? occupation : "Swipe ID to set." - data["connectionStatus"] = get_connection_to_tcomms() - data["visible"] = network_visibility - data["address"] = exonet.address ? exonet.address : "Unallocated" - data["targetAddress"] = target_address - data["targetAddressName"] = target_address_name - data["currentTab"] = selected_tab - data["knownDevices"] = communicators - data["invitesSent"] = invites - data["requestsReceived"] = requests - data["voice_mobs"] = voices - data["communicating"] = connected_communicators - data["video_comm"] = video_source ? "\ref[video_source.loc]" : null - data["imContacts"] = im_contacts_ui - data["imList"] = im_list_ui - data["time"] = stationtime2text() - data["ring"] = ringer - data["homeScreen"] = modules_ui - data["note"] = note // current notes - data["weather"] = weather - data["aircontents"] = src.analyze_air() - data["flashlight"] = fon - data["manifest"] = PDA_Manifest - data["feeds"] = compile_news() - data["latest_news"] = get_recent_news() - if(newsfeed_channel) - data["target_feed"] = data["feeds"][newsfeed_channel] - if(cartridge) // If there's a cartridge, we need to grab the information from it - data["cart_devices"] = cartridge.get_device_status() - data["cart_templates"] = cartridge.ui_templates - for(var/list/L in cartridge.get_data()) - data[L["field"]] = L["value"] - // cartridge.get_data() returns a list of tuples: - // The field element is the tag used to access the information by the template - // The value element is the actual data, and can take any form necessary for the template - - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - data["currentTab"] = 1 // Reset the current tab, because we're going to home page - ui = new(user, src, ui_key, "communicator_header.tmpl", "Communicator", 475, 700, state = key_state) - // add templates for screens in common with communicator. - ui.add_template("atmosphericScan", "atmospheric_scan.tmpl") - ui.add_template("crewManifest", "crew_manifest.tmpl") - ui.add_template("Body", "communicator.tmpl") // Main body - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every five Master Controller tick - ui.set_auto_update(5) - -// Proc: Topic() -// Parameters: 2 (standard Topic arguments) -// Description: Responds to NanoUI button presses. -/obj/item/device/communicator/Topic(href, href_list) - if(..()) - return 1 - if(href_list["rename"]) - var/new_name = sanitizeSafe(input(usr,"Please enter your name.","Communicator",usr.name) ) - if(new_name) - register_device(new_name) - - if(href_list["toggle_visibility"]) - switch(network_visibility) - if(1) //Visible, becoming invisbile - network_visibility = 0 - if(camera) - camera.remove_network(NETWORK_COMMUNICATORS) - if(0) //Invisible, becoming visible - network_visibility = 1 - if(camera) - camera.add_network(NETWORK_COMMUNICATORS) - - if(href_list["toggle_ringer"]) - ringer = !ringer - - if(href_list["add_hex"]) - var/hex = href_list["add_hex"] - add_to_EPv2(hex) - - if(href_list["write_target_address"]) - var/new_address = sanitizeSafe(input(usr,"Please enter the desired target EPv2 address. Note that you must write the colons \ - yourself.","Communicator",src.target_address) ) - if(new_address) - target_address = new_address - - if(href_list["clear_target_address"]) - target_address = "" - - if(href_list["dial"]) - if(!get_connection_to_tcomms()) - to_chat(usr, "Error: Cannot connect to Exonet node.") - return - var/their_address = href_list["dial"] - exonet.send_message(their_address, "voice") - - if(href_list["decline"]) - var/ref_to_remove = href_list["decline"] - var/atom/decline = locate(ref_to_remove) - if(decline) - del_request(decline) - - if(href_list["message"]) - if(!get_connection_to_tcomms()) - to_chat(usr, "Error: Cannot connect to Exonet node.") - return - var/their_address = href_list["message"] - var/text = sanitizeSafe(input(usr,"Enter your message.","Text Message")) - if(text) - exonet.send_message(their_address, "text", text) - im_list += list(list("address" = exonet.address, "to_address" = their_address, "im" = text)) - log_pda("(COMM: [src]) sent \"[text]\" to [exonet.get_atom_from_address(their_address)]", usr) - for(var/mob/M in player_list) - if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears)) - if(istype(M, /mob/new_player) || M.forbid_seeing_deadchat) - continue - if(exonet.get_atom_from_address(their_address) == M) - continue - M.show_message("Comm IM - [src] -> [exonet.get_atom_from_address(their_address)]: [text]") - - if(href_list["disconnect"]) - var/name_to_disconnect = href_list["disconnect"] - for(var/mob/living/voice/V in contents) - if(name_to_disconnect == V.name) - close_connection(usr, V, "[usr] hung up") - for(var/obj/item/device/communicator/comm in communicating) - if(name_to_disconnect == comm.name) - close_connection(usr, comm, "[usr] hung up") - - if(href_list["startvideo"]) - var/ref_to_video = href_list["startvideo"] - var/obj/item/device/communicator/comm = locate(ref_to_video) - if(comm) - connect_video(usr, comm) - - if(href_list["endvideo"]) - if(video_source) - end_video() - - if(href_list["watchvideo"]) - if(video_source) - watch_video(usr,video_source.loc) - - if(href_list["copy"]) - target_address = href_list["copy"] - - if(href_list["copy_name"]) - target_address_name = href_list["copy_name"] - - if(href_list["hang_up"]) - for(var/mob/living/voice/V in contents) - close_connection(usr, V, "[usr] hung up") - for(var/obj/item/device/communicator/comm in communicating) - close_connection(usr, comm, "[usr] hung up") - - if(href_list["switch_tab"]) - selected_tab = href_list["switch_tab"] - - if(href_list["edit"]) - var/n = input(usr, "Please enter message", name, notehtml) - n = sanitizeSafe(n, extra = 0) - if(n) - note = html_decode(n) - notehtml = note - note = replacetext(note, "\n", "
") - else - note = "" - notehtml = note - - if(href_list["switch_template"]) - var/datum/nanoui/ui = SSnanoui.get_open_ui(usr, src, "main") - if(ui) - ui.add_template("Body", href_list["switch_template"]) - - if(href_list["Light"]) - fon = !fon - set_light(fon * flum) - - if(href_list["toggle_device"]) - var/obj/O = cartridge.internal_devices[text2num(href_list["toggle_device"])] - cartridge.active_devices ^= list(O) // Exclusive or, will toggle its presence - - if(href_list["newsfeed"]) - newsfeed_channel = text2num(href_list["newsfeed"]) - - if(href_list["cartridge_topic"] && cartridge) // Has to have a cartridge to perform these functions - cartridge.Topic(href, href_list) - - SSnanoui.update_uis(src) - add_fingerprint(usr) diff --git a/code/game/objects/items/devices/communicator/UI_tgui.dm b/code/game/objects/items/devices/communicator/UI_tgui.dm new file mode 100644 index 0000000000..8dabf77f42 --- /dev/null +++ b/code/game/objects/items/devices/communicator/UI_tgui.dm @@ -0,0 +1,326 @@ +// Proc: tgui_state() +// Parameters: User +// Description: This tells TGUI to only allow us to be interacted with while in a mob inventory. +/obj/item/device/communicator/tgui_state(mob/user) + return GLOB.tgui_inventory_state + +// Proc: tgui_interact() +// Parameters: User, UI, Parent UI +// Description: This proc handles opening the UI. It's basically just a standard stub. +/obj/item/device/communicator/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui, datum/tgui_state/custom_state) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Communicator", name) + if(custom_state) + ui.set_state(custom_state) + ui.open() + if(custom_state) // Just in case + ui.set_state(custom_state) + +// Proc: tgui_data() +// Parameters: User, UI, State +// Description: Uses a bunch of for loops to turn lists into lists of lists, so they can be displayed in nanoUI, then displays various buttons to the user. +/obj/item/device/communicator/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + // this is the data which will be sent to the ui + var/list/data = list() //General nanoUI information + var/list/communicators = list() //List of communicators + var/list/invites = list() //Communicators and ghosts we've invited to our communicator. + var/list/requests = list() //Communicators and ghosts wanting to go in our communicator. + var/list/voices = list() //Current /mob/living/voice s inside the device. + var/list/connected_communicators = list() //Current communicators connected to the device. + + var/list/im_contacts_ui = list() //List of communicators that have been messaged. + var/list/im_list_ui = list() //List of messages. + + var/list/weather = list() + var/list/modules_ui = list() //Home screen info. + + //First we add other 'local' communicators. + for(var/obj/item/device/communicator/comm in known_devices) + if(comm.network_visibility && comm.exonet) + communicators.Add(list(list( + "name" = sanitize(comm.name), + "address" = comm.exonet.address + ))) + + //Now for ghosts who we pretend have communicators. + for(var/mob/observer/dead/O in known_devices) + if(O.client && O.client.prefs.communicator_visibility == 1 && O.exonet) + communicators.Add(list(list( + "name" = sanitize("[O.client.prefs.real_name]'s communicator"), + "address" = O.exonet.address, + "ref" = "\ref[O]" + ))) + + //Lists all the other communicators that we invited. + for(var/obj/item/device/communicator/comm in voice_invites) + if(comm.exonet) + invites.Add(list(list( + "name" = sanitize(comm.name), + "address" = comm.exonet.address, + "ref" = "\ref[comm]" + ))) + + //Ghosts we invited. + for(var/mob/observer/dead/O in voice_invites) + if(O.exonet && O.client) + invites.Add(list(list( + "name" = sanitize("[O.client.prefs.real_name]'s communicator"), + "address" = O.exonet.address, + "ref" = "\ref[O]" + ))) + + //Communicators that want to talk to us. + for(var/obj/item/device/communicator/comm in voice_requests) + if(comm.exonet) + requests.Add(list(list( + "name" = sanitize(comm.name), + "address" = comm.exonet.address, + "ref" = "\ref[comm]" + ))) + + //Ghosts that want to talk to us. + for(var/mob/observer/dead/O in voice_requests) + if(O.exonet && O.client) + requests.Add(list(list( + "name" = sanitize("[O.client.prefs.real_name]'s communicator"), + "address" = O.exonet.address, + "ref" = "\ref[O]" + ))) + + //Now for all the voice mobs inside the communicator. + for(var/mob/living/voice/voice in contents) + voices.Add(list(list( + "name" = sanitize("[voice.name]'s communicator"), + "true_name" = sanitize(voice.name), + ))) + + //Finally, all the communicators linked to this one. + for(var/obj/item/device/communicator/comm in communicating) + connected_communicators.Add(list(list( + "name" = sanitize(comm.name), + "true_name" = sanitize(comm.name), + "ref" = "\ref[comm]", + ))) + + //Devices that have been messaged or recieved messages from. + for(var/obj/item/device/communicator/comm in im_contacts) + if(comm.exonet) + im_contacts_ui.Add(list(list( + "name" = sanitize(comm.name), + "address" = comm.exonet.address, + "ref" = "\ref[comm]" + ))) + + for(var/mob/observer/dead/ghost in im_contacts) + if(ghost.exonet) + im_contacts_ui.Add(list(list( + "name" = sanitize(ghost.name), + "address" = ghost.exonet.address, + "ref" = "\ref[ghost]" + ))) + + for(var/obj/item/integrated_circuit/input/EPv2/CIRC in im_contacts) + if(CIRC.exonet && CIRC.assembly) + im_contacts_ui.Add(list(list( + "name" = sanitize(CIRC.assembly.name), + "address" = CIRC.exonet.address, + "ref" = "\ref[CIRC]" + ))) + + + //Actual messages. + for(var/I in im_list) + im_list_ui.Add(list(list( + "address" = I["address"], + "to_address" = I["to_address"], + "im" = I["im"] + ))) + + //Weather reports. + for(var/datum/planet/planet in SSplanets.planets) + if(planet.weather_holder && planet.weather_holder.current_weather) + var/list/W = list( + "Planet" = planet.name, + "Time" = planet.current_time.show_time("hh:mm"), + "Weather" = planet.weather_holder.current_weather.name, + "Temperature" = planet.weather_holder.temperature - T0C, + "High" = planet.weather_holder.current_weather.temp_high - T0C, + "Low" = planet.weather_holder.current_weather.temp_low - T0C, + "WindDir" = planet.weather_holder.wind_dir ? dir2text(planet.weather_holder.wind_dir) : "None", + "WindSpeed" = planet.weather_holder.wind_speed ? "[planet.weather_holder.wind_speed > 2 ? "Severe" : "Normal"]" : "None", + "Forecast" = english_list(planet.weather_holder.forecast, and_text = "→", comma_text = "→", final_comma_text = "→") // Unicode RIGHTWARDS ARROW. + ) + weather.Add(list(W)) + + + //Modules for homescreen. + for(var/list/R in modules) + modules_ui.Add(list(R)) + + data["user"] = "\ref[user]" // For receiving input() via topic, because input(usr,...) wasn't working on cartridges + data["owner"] = owner ? owner : "Unset" + data["occupation"] = occupation ? occupation : "Swipe ID to set." + data["connectionStatus"] = get_connection_to_tcomms() + data["visible"] = network_visibility + data["address"] = exonet.address ? exonet.address : "Unallocated" + data["targetAddress"] = target_address + data["targetAddressName"] = target_address_name + data["currentTab"] = selected_tab + data["knownDevices"] = communicators + data["invitesSent"] = invites + data["requestsReceived"] = requests + data["voice_mobs"] = voices + data["communicating"] = connected_communicators + data["video_comm"] = video_source ? "\ref[video_source.loc]" : null + data["imContacts"] = im_contacts_ui + data["imList"] = im_list_ui + data["time"] = stationtime2text() + data["ring"] = ringer + data["homeScreen"] = modules_ui + data["note"] = note // current notes + data["weather"] = weather + data["aircontents"] = src.analyze_air() + data["flashlight"] = fon + data["feeds"] = compile_news() + data["latest_news"] = get_recent_news() + if(newsfeed_channel) + data["target_feed"] = data["feeds"][newsfeed_channel] + else + data["target_feed"] = null + + return data + +// Proc: tgui_static_data() +// Parameters: User, UI, State +// Description: Just like tgui_data, except it only gets called once when the user opens the UI, not every tick. +/obj/item/device/communicator/tgui_static_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + // Update manifest' + if(data_core) + data_core.get_manifest_list() + data["manifest"] = PDA_Manifest + return data + +// Proc: tgui-act() +// Parameters: 4 (standard tgui_act arguments) +// Description: Responds to UI button presses. +/obj/item/device/communicator/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + add_fingerprint(usr) + . = TRUE + switch(action) + if("rename") + var/new_name = sanitizeSafe(input(usr,"Please enter your name.","Communicator",usr.name) ) + if(new_name) + register_device(new_name) + + if("toggle_visibility") + switch(network_visibility) + if(1) //Visible, becoming invisbile + network_visibility = 0 + if(camera) + camera.remove_network(NETWORK_COMMUNICATORS) + if(0) //Invisible, becoming visible + network_visibility = 1 + if(camera) + camera.add_network(NETWORK_COMMUNICATORS) + + if("toggle_ringer") + ringer = !ringer + + if("add_hex") + var/hex = params["add_hex"] + add_to_EPv2(hex) + + if("write_target_address") + target_address = sanitizeSafe(params["val"]) + + if("clear_target_address") + target_address = "" + + if("dial") + if(!get_connection_to_tcomms()) + to_chat(usr, "Error: Cannot connect to Exonet node.") + return FALSE + var/their_address = params["dial"] + exonet.send_message(their_address, "voice") + + if("decline") + var/ref_to_remove = params["decline"] + var/atom/decline = locate(ref_to_remove) + if(decline) + del_request(decline) + + if("message") + if(!get_connection_to_tcomms()) + to_chat(usr, "Error: Cannot connect to Exonet node.") + return FALSE + var/their_address = params["message"] + var/text = sanitizeSafe(input(usr,"Enter your message.","Text Message")) + if(text) + exonet.send_message(their_address, "text", text) + im_list += list(list("address" = exonet.address, "to_address" = their_address, "im" = text)) + log_pda("(COMM: [src]) sent \"[text]\" to [exonet.get_atom_from_address(their_address)]", usr) + for(var/mob/M in player_list) + if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears)) + if(istype(M, /mob/new_player) || M.forbid_seeing_deadchat) + continue + if(exonet.get_atom_from_address(their_address) == M) + continue + M.show_message("Comm IM - [src] -> [exonet.get_atom_from_address(their_address)]: [text]") + + if("disconnect") + var/name_to_disconnect = params["disconnect"] + for(var/mob/living/voice/V in contents) + if(name_to_disconnect == sanitize(V.name)) + close_connection(usr, V, "[usr] hung up") + for(var/obj/item/device/communicator/comm in communicating) + if(name_to_disconnect == sanitize(comm.name)) + close_connection(usr, comm, "[usr] hung up") + + if("startvideo") + var/ref_to_video = params["startvideo"] + var/obj/item/device/communicator/comm = locate(ref_to_video) + if(comm) + connect_video(usr, comm) + + if("endvideo") + if(video_source) + end_video() + + if("copy") + target_address = params["copy"] + + if("copy_name") + target_address_name = params["copy_name"] + + if("hang_up") + for(var/mob/living/voice/V in contents) + close_connection(usr, V, "[usr] hung up") + for(var/obj/item/device/communicator/comm in communicating) + close_connection(usr, comm, "[usr] hung up") + + if("switch_tab") + selected_tab = params["switch_tab"] + + if("edit") + var/n = input(usr, "Please enter message", name, notehtml) as message|null + n = sanitizeSafe(n, extra = 0) + if(n) + note = html_decode(n) + notehtml = note + note = replacetext(note, "\n", "
") + else + note = "" + notehtml = note + + if("Light") + fon = !fon + set_light(fon * flum) + + if("newsfeed") + newsfeed_channel = text2num(params["newsfeed"]) + diff --git a/code/game/objects/items/devices/communicator/communicator.dm b/code/game/objects/items/devices/communicator/communicator.dm index 392af1b870..358ef3b61b 100644 --- a/code/game/objects/items/devices/communicator/communicator.dm +++ b/code/game/objects/items/devices/communicator/communicator.dm @@ -14,7 +14,6 @@ var/global/list/obj/item/device/communicator/all_communicators = list() #define WTHRTAB 7 #define MANITAB 8 #define SETTTAB 9 -#define EXTRTAB 10 /obj/item/device/communicator name = "communicator" @@ -43,19 +42,18 @@ var/global/list/obj/item/device/communicator/all_communicators = list() var/note = "Thank you for choosing the T-14.2 Communicator, this is your notepad!" //Current note in the notepad function var/notehtml = "" - var/obj/item/weapon/commcard/cartridge = null //current cartridge var/fon = 0 // Internal light var/flum = 2 // Brightness var/list/modules = list( - list("module" = "Phone", "icon" = "phone64", "number" = PHONTAB), - list("module" = "Contacts", "icon" = "person64", "number" = CONTTAB), - list("module" = "Messaging", "icon" = "comment64", "number" = MESSTAB), - list("module" = "News", "icon" = "note64", "number" = NEWSTAB), // Need a different icon, - list("module" = "Note", "icon" = "note64", "number" = NOTETAB), - list("module" = "Weather", "icon" = "sun64", "number" = WTHRTAB), - list("module" = "Crew Manifest", "icon" = "note64", "number" = MANITAB), // Need a different icon, - list("module" = "Settings", "icon" = "gear64", "number" = SETTTAB), + list("module" = "Phone", "icon" = "phone", "number" = PHONTAB), + list("module" = "Contacts", "icon" = "user", "number" = CONTTAB), + list("module" = "Messaging", "icon" = "comment-alt", "number" = MESSTAB), + list("module" = "News", "icon" = "newspaper", "number" = NEWSTAB), // Need a different icon, + list("module" = "Note", "icon" = "sticky-note", "number" = NOTETAB), + list("module" = "Weather", "icon" = "sun", "number" = WTHRTAB), + list("module" = "Crew Manifest", "icon" = "crown", "number" = MANITAB), // Need a different icon, + list("module" = "Settings", "icon" = "cog", "number" = SETTTAB), ) //list("module" = "Name of Module", "icon" = "icon name64", "number" = "what tab is the module") var/selected_tab = HOMETAB @@ -104,13 +102,6 @@ var/global/list/obj/item/device/communicator/all_communicators = list() register_device(S.loc.name) initialize_exonet(S.loc) -// Proc: examine() -// Parameters: user - the user doing the examining -// Description: Allows the user to click a link when examining to look at video if one is going. -/obj/item/device/communicator/examine(mob/user) - . = ..() - if(Adjacent(user) && video_source) - . += "It looks like it's on a video call: \[view\]" // Proc: initialize_exonet() // Parameters: 1 (user - the person the communicator belongs to) @@ -132,6 +123,9 @@ var/global/list/obj/item/device/communicator/all_communicators = list() // Description: Shows all the voice mobs inside the device, and their status. /obj/item/device/communicator/examine(mob/user) . = ..() + + if(Adjacent(user) && video_source) + . += "It looks like it's on a video call: \[view\]" for(var/mob/living/voice/voice in contents) . += "On the screen, you can see a image feed of [voice]." @@ -148,6 +142,17 @@ var/global/list/obj/item/device/communicator/all_communicators = list() else . += "The device doesn't appear to be transmitting any data." +// Proc: Topic() +// Parameters: href, href_list - Data from a link +// Description: Used by the above examine. +/obj/item/device/communicator/Topic(href, href_list) + if(..()) + return 1 + + if(href_list["watchvideo"]) + if(video_source) + watch_video(usr) + // Proc: emp_act() // Parameters: None // Description: Drops all calls when EMPed, so the holder can then get murdered by the antagonist. @@ -203,17 +208,6 @@ var/global/list/obj/item/device/communicator/all_communicators = list() if(!get_connection_to_tcomms()) close_connection(reason = "Connection timed out") -// Proc: attack() -// Parameters: 2 (M - what is being attacked. user - the mob that has the communicator) -// Description: When the communicator has an attached commcard with internal devices, relay the attack() through to those devices. -// Contents of the for loop are copied from gripper code, because that does approximately what we want to do. -/obj/item/device/communicator/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) - if(cartridge && cartridge.active_devices) - for(var/obj/item/wrapped in cartridge.active_devices) - if(wrapped) //The force of the wrapped obj gets set to zero during the attack() and afterattack(). - wrapped.attack(M,user) - return 0 - // Proc: attackby() // Parameters: 2 (C - what is used on the communicator. user - the mob that has the communicator) // Description: When an ID is swiped on the communicator, the communicator reads the job and checks it against the Owner name, if success, the occupation is added. @@ -229,13 +223,6 @@ var/global/list/obj/item/device/communicator/all_communicators = list() occupation = idcard.assignment to_chat(user, "Occupation updated.") - if(istype(C, /obj/item/weapon/commcard) && !cartridge) - cartridge = C - user.drop_item() - cartridge.forceMove(src) - to_chat(usr, "You slot \the [cartridge] into \the [src].") - modules[++modules.len] = list("module" = "External Device", "icon" = "external64", "number" = EXTRTAB) - SSnanoui.update_uis(src) // update all UIs attached to src return // Proc: attack_self() @@ -246,7 +233,7 @@ var/global/list/obj/item/device/communicator/all_communicators = list() initialize_exonet(user) alert_called = 0 update_icon() - ui_interact(user) + tgui_interact(user) if(video_source) watch_video(user) @@ -358,38 +345,6 @@ var/global/list/obj/item/device/communicator/all_communicators = list() client_huds |= global_hud.whitense client_huds |= global_hud.darkMask -/obj/item/device/communicator/verb/verb_remove_cartridge() - set category = "Object" - set name = "Remove commcard" - set src in usr - - // Can't remove what isn't there - if(!cartridge) - to_chat(usr, "There isn't a commcard to remove!") - return - - // Can't remove if you're physically unable to - if(usr.stat || usr.restrained() || usr.paralysis || usr.stunned || usr.weakened) - to_chat(usr, "You cannot do this while restrained.") - return - - var/turf/T = get_turf(src) - cartridge.loc = T - // If it's in someone, put the cartridge in their hands - if (ismob(loc)) - var/mob/M = loc - M.put_in_hands(cartridge) - // Else just set it on the ground - else - cartridge.loc = get_turf(src) - cartridge = null - // We have to iterate through the modules to find EXTRTAB, because list procs don't play nice with a list of lists - for(var/i = 1, i <= modules.len, i++) - if(modules[i]["number"] == EXTRTAB) - modules.Cut(i, i+1) - break - to_chat(usr, "You remove \the [cartridge] from the [name].") - //It's the 26th century. We should have smart watches by now. /obj/item/device/communicator/watch name = "communicator watch" diff --git a/code/game/objects/items/devices/communicator/helper.dm b/code/game/objects/items/devices/communicator/helper.dm index c45141afca..5cf5eac2c2 100644 --- a/code/game/objects/items/devices/communicator/helper.dm +++ b/code/game/objects/items/devices/communicator/helper.dm @@ -20,7 +20,7 @@ // Values were extracted from the template itself results = list( list("entry" = "Pressure", "units" = "kPa", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80), - list("entry" = "Temperature", "units" = "°C", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5), + list("entry" = "Temperature", "units" = "°C", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5), list("entry" = "Oxygen", "units" = "kPa", "val" = "[round(o2_level*100,0.1)]", "bad_high" = 140, "poor_high" = 135, "poor_low" = 19, "bad_low" = 17), list("entry" = "Nitrogen", "units" = "kPa", "val" = "[round(n2_level*100,0.1)]", "bad_high" = 105, "poor_high" = 85, "poor_low" = 50, "bad_low" = 40), list("entry" = "Carbon Dioxide", "units" = "kPa", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0), @@ -540,4 +540,4 @@ if(B.id == internal_data["shuttle_door_code"]) target_doors += B - return target_doors \ No newline at end of file + return target_doors diff --git a/code/game/objects/items/devices/hacktool.dm b/code/game/objects/items/devices/hacktool.dm index a48a3da024..b221ff875c 100644 --- a/code/game/objects/items/devices/hacktool.dm +++ b/code/game/objects/items/devices/hacktool.dm @@ -5,7 +5,7 @@ var/in_hack_mode = 0 var/list/known_targets var/list/supported_types - var/datum/topic_state/default/must_hack/hack_state + var/datum/tgui_state/default/must_hack/hack_state /obj/item/device/multitool/hacktool/New() ..() @@ -30,7 +30,7 @@ else ..() -/obj/item/device/multitool/hacktool/resolve_attackby(atom/A, mob/user) +/obj/item/device/multitool/hacktool/afterattack(atom/A, mob/user) sanity_check() if(!in_hack_mode) @@ -39,7 +39,8 @@ if(!attempt_hack(user, A)) return 0 - A.ui_interact(user, state = hack_state) + // Note, if you ever want to expand supported_types, you must manually add the custom state argument to their tgui_interact + A.tgui_interact(user, custom_state = hack_state) return 1 /obj/item/device/multitool/hacktool/proc/attempt_hack(var/mob/user, var/atom/target) @@ -83,18 +84,18 @@ /obj/item/device/multitool/hacktool/proc/on_target_destroy(var/target) known_targets -= target -/datum/topic_state/default/must_hack +/datum/tgui_state/default/must_hack var/obj/item/device/multitool/hacktool/hacktool -/datum/topic_state/default/must_hack/New(var/hacktool) +/datum/tgui_state/default/must_hack/New(var/hacktool) src.hacktool = hacktool ..() -/datum/topic_state/default/must_hack/Destroy() +/datum/tgui_state/default/must_hack/Destroy() hacktool = null return ..() -/datum/topic_state/default/must_hack/can_use_topic(var/src_object, var/mob/user) +/datum/tgui_state/default/must_hack/can_use_topic(src_object, mob/user) if(!hacktool || !hacktool.in_hack_mode || !(src_object in hacktool.known_targets)) return STATUS_CLOSE return ..() diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm index 8b7f55e0a9..77e463c0d0 100644 --- a/code/game/objects/items/devices/paicard.dm +++ b/code/game/objects/items/devices/paicard.dm @@ -33,6 +33,24 @@ GLOBAL_LIST_BOILERPLATE(all_pai_cards, /obj/item/device/paicard) QDEL_NULL(radio) return ..() +/obj/item/device/paicard/attack_ghost(mob/observer/dead/user) + if(istype(user) && user.can_admin_interact()) + switch(alert(user, "Would you like to become a pAI by force? (Admin)", "pAI Creation", "Yes", "No")) + if("Yes") + // Copied from paiController/Topic + var/mob/living/silicon/pai/pai = new(src) + pai.name = user.name + pai.real_name = pai.name + pai.key = user.key + + setPersonality(pai) + looking_for_personality = FALSE + + if(pai.mind) + update_antag_icons(pai.mind) + return ..() + + /obj/item/device/paicard/attack_self(mob/user) if (!in_range(src, user)) return diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index f1990c7fe2..d2511038dc 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -151,18 +151,10 @@ var/global/list/default_medbay_channels = list( return tgui_interact(user) -/obj/item/device/radio/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, datum/nano_ui/master_ui, datum/topic_state/state) - log_runtime(EXCEPTION("Warning: [user] attempted to call ui_interact on radio [src] [type]. This is deprecated. Please update the caller to tgui_interact.")) - -/obj/item/device/radio/Topic(href, href_list) - if(href_list["track"]) - log_runtime(EXCEPTION("Warning: Topic() was improperly called on radio [src] [type], with the track href and \[[href] [json_encode(href_list)]]. Please update the caller to use tgui_act.")) - . = ..() - -/obj/item/device/radio/tgui_interact(mob/user, datum/tgui/ui) +/obj/item/device/radio/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, "Radio", name) + ui = new(user, src, "Radio", name, parent_ui) ui.open() /obj/item/device/radio/tgui_data(mob/user) diff --git a/code/game/objects/items/devices/tvcamera.dm b/code/game/objects/items/devices/tvcamera.dm index e8b6df0b98..acf4b7cc3a 100644 --- a/code/game/objects/items/devices/tvcamera.dm +++ b/code/game/objects/items/devices/tvcamera.dm @@ -54,7 +54,7 @@ popup.set_content(jointext(dat,null)) popup.open() -/obj/item/device/tvcamera/Topic(bred, href_list, state = physical_state) +/obj/item/device/tvcamera/Topic(bred, href_list, state = GLOB.tgui_physical_state) if(..()) return 1 if(href_list["channel"]) diff --git a/code/game/objects/items/devices/uplink.dm b/code/game/objects/items/devices/uplink.dm index 5a19c72742..5b6e55290e 100644 --- a/code/game/objects/items/devices/uplink.dm +++ b/code/game/objects/items/devices/uplink.dm @@ -1,13 +1,23 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink) +// I placed this here because of how relevant it is. +// You place this in your uplinkable item to check if an uplink is active or not. +// If it is, it will display the uplink menu and return 1, else it'll return false. +// If it returns true, I recommend closing the item's normal menu with "user << browse(null, "window=name")" +/obj/item/proc/active_uplink_check(mob/user as mob) + // Activates the uplink if it's active + if(hidden_uplink) + if(hidden_uplink.active) + hidden_uplink.trigger(user) + return TRUE + return FALSE + /obj/item/device/uplink var/welcome = "Welcome, Operative" // Welcoming menu message var/uses // Numbers of crystals var/list/ItemsCategory // List of categories with lists of items var/list/ItemsReference // List of references with an associated item var/list/nanoui_items // List of items for NanoUI use - var/nanoui_menu = 0 // The current menu we are in - var/list/nanoui_data = new // Additional data for NanoUI use var/faction = "" //Antag faction holder. var/list/purchase_log = new @@ -17,9 +27,7 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink) var/next_offer_time var/datum/uplink_item/discount_item //The item to be discounted var/discount_amount //The amount as a percent the item will be discounted by - -/obj/item/device/uplink/nano_host() - return loc + var/compact_mode = FALSE /obj/item/device/uplink/Initialize(var/mapload, var/datum/mind/owner = null, var/telecrystals = DEFAULT_TELECRYSTAL_AMOUNT) . = ..() @@ -53,23 +61,20 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink) name = "hidden uplink" desc = "There is something wrong if you're examining this." var/active = 0 - var/datum/uplink_category/category = 0 // The current category we are in var/exploit_id // Id of the current exploit record we are viewing + var/selected_cat // The hidden uplink MUST be inside an obj/item's contents. /obj/item/device/uplink/hidden/Initialize() . = ..() if(!isitem(loc)) return INITIALIZE_HINT_QDEL - nanoui_data = list() - update_nano_data() /obj/item/device/uplink/hidden/next_offer() discount_item = default_uplink_selection.get_random_item(INFINITY) discount_amount = pick(90;0.9, 80;0.8, 70;0.7, 60;0.6, 50;0.5, 40;0.4, 30;0.3, 20;0.2, 10;0.1) - update_nano_data() - SSnanoui.update_uis(src) next_offer_time = world.time + offer_time + SStgui.update_uis(src) addtimer(CALLBACK(src, .proc/next_offer), offer_time) // Toggles the uplink on and off. Normally this will bypass the item's normal functions and go to the uplink menu, if activated. @@ -91,136 +96,137 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink) return 1 return 0 -/* - NANO UI FOR UPLINK WOOP WOOP -*/ -/obj/item/device/uplink/hidden/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/title = "Remote Uplink" - var/data[0] - uses = user.mind.tcrystals - if(ishuman(user)) - var/mob/living/carbon/human/H = user - faction = H.antag_faction +// Legacy +/obj/item/device/uplink/hidden/interact(mob/user) + tgui_interact(user) - data["welcome"] = welcome - data["crystals"] = uses - data["menu"] = nanoui_menu - data += nanoui_data +/***************** + * Uplink TGUI + *****************/ +/obj/item/device/uplink/tgui_host() + return loc - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) // No auto-refresh - ui = new(user, src, ui_key, "uplink.tmpl", title, 630, 700, state = inventory_state) - data["menu"] = 0 - ui.set_initial_data(data) +/obj/item/device/uplink/hidden/tgui_state(mob/user) + return GLOB.tgui_inventory_state + +/obj/item/device/uplink/hidden/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + if(!active) + toggle() + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Uplink", "Remote Uplink") + // This UI is only ever opened by one person, + // and never is updated outside of user input. + ui.set_autoupdate(FALSE) ui.open() +/obj/item/device/uplink/hidden/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + if(!user.mind) + return -// Interaction code. Gathers a list of items purchasable from the paren't uplink and displays it. It also adds a lock button. -/obj/item/device/uplink/hidden/interact(mob/user) - ui_interact(user) + var/list/data = ..() -/obj/item/device/uplink/hidden/CanUseTopic() + data["telecrystals"] = uses + data["lockable"] = TRUE + data["compactMode"] = compact_mode + + data["discount_name"] = discount_item ? discount_item.name : "" + data["discount_amount"] = (1-discount_amount)*100 + data["offer_expiry"] = worldtime2stationtime(next_offer_time) + + data["exploit"] = null + data["locked_records"] = null + + if(exploit_id) + for(var/datum/data/record/L in data_core.locked) + if(L.fields["id"] == exploit_id) + data["exploit"] = list() // Setting this to equal L.fields passes it's variables that are lists as reference instead of value. + // We trade off being able to automatically add shit for more control over what gets passed to json + // and if it's sanitized for html. + data["exploit"]["nanoui_exploit_record"] = html_encode(L.fields["exploit_record"]) // Change stuff into html + data["exploit"]["nanoui_exploit_record"] = replacetext(data["exploit"]["nanoui_exploit_record"], "\n", "
") // change line breaks into
+ data["exploit"]["name"] = html_encode(L.fields["name"]) + data["exploit"]["sex"] = html_encode(L.fields["sex"]) + data["exploit"]["age"] = html_encode(L.fields["age"]) + data["exploit"]["species"] = html_encode(L.fields["species"]) + data["exploit"]["rank"] = html_encode(L.fields["rank"]) + data["exploit"]["home_system"] = html_encode(L.fields["home_system"]) + data["exploit"]["citizenship"] = html_encode(L.fields["citizenship"]) + data["exploit"]["faction"] = html_encode(L.fields["faction"]) + data["exploit"]["religion"] = html_encode(L.fields["religion"]) + data["exploit"]["fingerprint"] = html_encode(L.fields["fingerprint"]) + if(L.fields["antagvis"] == ANTAG_KNOWN || (faction == L.fields["antagfac"] && (L.fields["antagvis"] == ANTAG_SHARED))) + data["exploit"]["antagfaction"] = html_encode(L.fields["antagfac"]) + else + data["exploit"]["antagfaction"] = html_encode("None") + break + else + var/list/permanentData = list() + for(var/datum/data/record/L in sortRecord(data_core.locked)) + permanentData.Add(list(list( + "name" = L.fields["name"], + "id" = L.fields["id"] + ))) + data["locked_records"] = permanentData + + return data + +/obj/item/device/uplink/hidden/tgui_static_data(mob/user) + var/list/data = ..() + + data["categories"] = list() + for(var/datum/uplink_category/category in uplink.categories) + if(category.can_view(src)) + var/list/cat = list( + "name" = category.name, + "items" = (category == selected_cat ? list() : null) + ) + for(var/datum/uplink_item/item in category.items) + if(!item.can_view(src)) + continue + var/cost = item.cost(uses, src) || "???" + cat["items"] += list(list( + "name" = item.name, + "cost" = cost, + "desc" = item.description(), + "ref" = REF(item), + )) + data["categories"] += list(cat) + + return data + +/obj/item/device/uplink/hidden/tgui_status(mob/user, datum/tgui_state/state) if(!active) return STATUS_CLOSE return ..() -// The purchasing code. -/obj/item/device/uplink/hidden/Topic(href, href_list) +/obj/item/device/uplink/hidden/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return 1 + return TRUE - var/mob/user = usr - if(href_list["buy_item"]) - var/datum/uplink_item/UI = (locate(href_list["buy_item"]) in uplink.items) - UI.buy(src, usr) - else if(href_list["lock"]) - toggle() - var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main") - ui.close() - else if(href_list["return"]) - nanoui_menu = round(nanoui_menu/10) - else if(href_list["menu"]) - nanoui_menu = text2num(href_list["menu"]) - if(href_list["id"]) - exploit_id = href_list["id"] - else if(href_list["category"]) - category = locate(href_list["category"]) in uplink.categories - - update_nano_data() - return 1 - -/obj/item/device/uplink/hidden/proc/update_nano_data() - if(nanoui_menu == 0) - var/categories[0] - for(var/datum/uplink_category/category in uplink.categories) - if(category.can_view(src)) - categories[++categories.len] = list("name" = category.name, "ref" = "\ref[category]") - nanoui_data["categories"] = categories - nanoui_data["discount_name"] = discount_item ? discount_item.name : "" - nanoui_data["discount_amount"] = (1-discount_amount)*100 - nanoui_data["offer_expiry"] = worldtime2stationtime(next_offer_time) - - if(category) - nanoui_data["current_category"] = category.name - var/items[0] - for(var/datum/uplink_item/item in category.items) - if(item.can_view(src)) - var/cost = item.cost(uses, src) - if(!cost) cost = "???" - items[++items.len] = list("name" = item.name, "description" = replacetext(item.description(), "\n", "
"), "can_buy" = item.can_buy(src), "cost" = cost, "ref" = "\ref[item]") - nanoui_data["items"] = items - - else if(nanoui_menu == 2) - var/permanentData[0] - for(var/datum/data/record/L in sortRecord(data_core.locked)) - permanentData[++permanentData.len] = list(Name = L.fields["name"],"id" = L.fields["id"]) - nanoui_data["exploit_records"] = permanentData - else if(nanoui_menu == 21) - nanoui_data["exploit_exists"] = 0 - - for(var/datum/data/record/L in data_core.locked) - if(L.fields["id"] == exploit_id) - nanoui_data["exploit"] = list() // Setting this to equal L.fields passes it's variables that are lists as reference instead of value. - // We trade off being able to automatically add shit for more control over what gets passed to json - // and if it's sanitized for html. - nanoui_data["exploit"]["nanoui_exploit_record"] = html_encode(L.fields["exploit_record"]) // Change stuff into html - nanoui_data["exploit"]["nanoui_exploit_record"] = replacetext(nanoui_data["exploit"]["nanoui_exploit_record"], "\n", "
") // change line breaks into
- nanoui_data["exploit"]["name"] = html_encode(L.fields["name"]) - nanoui_data["exploit"]["sex"] = html_encode(L.fields["sex"]) - nanoui_data["exploit"]["age"] = html_encode(L.fields["age"]) - nanoui_data["exploit"]["species"] = html_encode(L.fields["species"]) - nanoui_data["exploit"]["rank"] = html_encode(L.fields["rank"]) - nanoui_data["exploit"]["home_system"] = html_encode(L.fields["home_system"]) - nanoui_data["exploit"]["citizenship"] = html_encode(L.fields["citizenship"]) - nanoui_data["exploit"]["faction"] = html_encode(L.fields["faction"]) - nanoui_data["exploit"]["religion"] = html_encode(L.fields["religion"]) - nanoui_data["exploit"]["fingerprint"] = html_encode(L.fields["fingerprint"]) - if(L.fields["antagvis"] == ANTAG_KNOWN || (faction == L.fields["antagfac"] && (L.fields["antagvis"] == ANTAG_SHARED))) - nanoui_data["exploit"]["antagfaction"] = html_encode(L.fields["antagfac"]) - else - nanoui_data["exploit"]["antagfaction"] = html_encode("None") - nanoui_data["exploit_exists"] = 1 - break - -// I placed this here because of how relevant it is. -// You place this in your uplinkable item to check if an uplink is active or not. -// If it is, it will display the uplink menu and return 1, else it'll return false. -// If it returns true, I recommend closing the item's normal menu with "user << browse(null, "window=name")" -/obj/item/proc/active_uplink_check(mob/user as mob) - // Activates the uplink if it's active - if(src.hidden_uplink) - if(src.hidden_uplink.active) - src.hidden_uplink.trigger(user) - return 1 - return 0 + switch(action) + if("buy") + var/datum/uplink_item/UI = (locate(params["ref"]) in uplink.items) + UI.buy(src, usr) + return TRUE + if("lock") + toggle() + SStgui.close_uis(src) + if("select") + selected_cat = params["category"] + return TRUE + if("compact_toggle") + compact_mode = !compact_mode + return TRUE + if("view_exploits") + exploit_id = params["id"] + return TRUE // PRESET UPLINKS // A collection of preset uplinks. // // Includes normal radio uplink, multitool uplink, // implant uplink (not the implant tool) and a preset headset uplink. - /obj/item/device/radio/uplink/New(atom/loc, datum/mind/target_mind, telecrystals) ..(loc) hidden_uplink = new(src, target_mind, telecrystals) diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm index 782df54346..8bf366268a 100644 --- a/code/game/objects/items/stacks/sheets/leather.dm +++ b/code/game/objects/items/stacks/sheets/leather.dm @@ -4,8 +4,8 @@ singular_name = "human skin piece" icon_state = "sheet-hide" no_variants = FALSE - drop_sound = 'sound/items/drop/cloth.ogg' - pickup_sound = 'sound/items/pickup/cloth.ogg' + drop_sound = 'sound/items/drop/leather.ogg' + pickup_sound = 'sound/items/pickup/leather.ogg' /obj/item/stack/animalhide/human amount = 50 diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index ad187265c2..6e35e74974 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -66,63 +66,81 @@ else . += "There is enough charge for [get_amount()]." -/obj/item/stack/attack_self(mob/user as mob) - list_recipes(user) +/obj/item/stack/attack_self(mob/user) + tgui_interact(user) -/obj/item/stack/proc/list_recipes(mob/user as mob, recipes_sublist) - if (!recipes) - return - if (!src || get_amount() <= 0) - user << browse(null, "window=stack") - user.set_machine(src) //for correct work of onclose - var/list/recipe_list = recipes - if (recipes_sublist && recipe_list[recipes_sublist] && istype(recipe_list[recipes_sublist], /datum/stack_recipe_list)) - var/datum/stack_recipe_list/srl = recipe_list[recipes_sublist] - recipe_list = srl.recipes - var/t1 = text("Constructions from []Amount Left: []
", src, src.get_amount()) - for(var/i=1;i<=recipe_list.len,i++) - var/E = recipe_list[i] - if (isnull(E)) - t1 += "
" - continue +/obj/item/stack/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Stack", name) + ui.open() - if (i>1 && !isnull(recipe_list[i-1])) - t1+="
" +/obj/item/stack/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + data["amount"] = get_amount() - if (istype(E, /datum/stack_recipe_list)) - var/datum/stack_recipe_list/srl = E - t1 += "[srl.title]" + return data - if (istype(E, /datum/stack_recipe)) - var/datum/stack_recipe/R = E - var/max_multiplier = round(src.get_amount() / R.req_amount) - var/title as text - var/can_build = 1 - can_build = can_build && (max_multiplier>0) - if (R.res_amount>1) - title+= "[R.res_amount]x [R.title]\s" - else - title+= "[R.title]" - title+= " ([R.req_amount] [src.singular_name]\s)" - if (can_build) - t1 += text("[title] ") - else - t1 += text("[]", title) - continue - if (R.max_res_amount>1 && max_multiplier>1) - max_multiplier = min(max_multiplier, round(R.max_res_amount/R.res_amount)) - t1 += " |" - var/list/multipliers = list(5,10,25) - for (var/n in multipliers) - if (max_multiplier>=n) - t1 += " [n*R.res_amount]x" - if (!(max_multiplier in multipliers)) - t1 += " [max_multiplier*R.res_amount]x" +/obj/item/stack/tgui_static_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() - t1 += "
" - user << browse(t1, "window=stack") - onclose(user, "stack") - return + data["recipes"] = recursively_build_recipes(recipes) + + return data + +/obj/item/stack/proc/recursively_build_recipes(list/recipe_to_iterate) + var/list/L = list() + for(var/recipe in recipe_to_iterate) + if(istype(recipe, /datum/stack_recipe_list)) + var/datum/stack_recipe_list/R = recipe + L["[R.title]"] = recursively_build_recipes(R.recipes) + if(istype(recipe, /datum/stack_recipe)) + var/datum/stack_recipe/R = recipe + L["[R.title]"] = build_recipe(R) + + return L + +/obj/item/stack/proc/build_recipe(datum/stack_recipe/R) + return list( + "res_amount" = R.res_amount, + "max_res_amount" = R.max_res_amount, + "req_amount" = R.req_amount, + "ref" = "\ref[R]", + ) + +/obj/item/stack/tgui_state(mob/user) + return GLOB.tgui_hands_state + +/obj/item/stack/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + switch(action) + if("make") + if(get_amount() < 1) + qdel(src) + return + + var/datum/stack_recipe/R = locate(params["ref"]) + if(!is_valid_recipe(R, recipes)) //href exploit protection + return FALSE + var/multiplier = text2num(params["multiplier"]) + if(!multiplier || (multiplier <= 0)) //href exploit protection + return + produce_recipe(R, multiplier, usr) + return TRUE + +/obj/item/stack/proc/is_valid_recipe(datum/stack_recipe/R, list/recipe_list) + for(var/S in recipe_list) + if(S == R) + return TRUE + if(istype(S, /datum/stack_recipe_list)) + var/datum/stack_recipe_list/L = S + if(is_valid_recipe(R, L.recipes)) + return TRUE + + return FALSE /obj/item/stack/proc/produce_recipe(datum/stack_recipe/recipe, var/quantity, mob/user) var/required = quantity*recipe.req_amount @@ -169,7 +187,7 @@ if ((pass_color || recipe.pass_color)) if(!color) if(recipe.use_material) - var/material/MAT = get_material_by_name(recipe.use_material) + var/datum/material/MAT = get_material_by_name(recipe.use_material) if(MAT.icon_colour) O.color = MAT.icon_colour else @@ -177,35 +195,6 @@ else O.color = color -/obj/item/stack/Topic(href, href_list) - ..() - if ((usr.restrained() || usr.stat || usr.get_active_hand() != src)) - return - - if (href_list["sublist"] && !href_list["make"]) - list_recipes(usr, text2num(href_list["sublist"])) - - if (href_list["make"]) - if (src.get_amount() < 1) qdel(src) //Never should happen - - var/list/recipes_list = recipes - if (href_list["sublist"]) - var/datum/stack_recipe_list/srl = recipes_list[text2num(href_list["sublist"])] - recipes_list = srl.recipes - - var/datum/stack_recipe/R = recipes_list[text2num(href_list["make"])] - var/multiplier = text2num(href_list["multiplier"]) - if (!multiplier || (multiplier <= 0)) //href exploit protection - return - - src.produce_recipe(R, multiplier, usr) - - if (src && usr.machine==src) //do not reopen closed window - spawn( 0 ) - src.interact(usr) - return - return - //Return 1 if an immediate subsequent call to use() would succeed. //Ensures that code dealing with stacks uses the same logic /obj/item/stack/proc/can_use(var/used) diff --git a/code/game/objects/items/stacks/tickets.dm b/code/game/objects/items/stacks/tickets.dm new file mode 100644 index 0000000000..1d9cbf047e --- /dev/null +++ b/code/game/objects/items/stacks/tickets.dm @@ -0,0 +1,32 @@ +/obj/item/stack/arcadeticket + name = "arcade tickets" + desc = "Wow! With enough of these, you could buy a bike! ...Pssh, yeah right." + singular_name = "arcade ticket" + icon_state = "arcade-ticket" + item_state = "tickets" + w_class = ITEMSIZE_TINY + max_amount = 30 + +/obj/item/stack/arcadeticket/New(loc, amount = null) + . = ..() + update_icon() + +/obj/item/stack/arcadeticket/update_icon() + var/amount = get_amount() + switch(amount) + if(12 to INFINITY) + icon_state = "arcade-ticket_4" + if(6 to 12) + icon_state = "arcade-ticket_3" + if(2 to 6) + icon_state = "arcade-ticket_2" + else + icon_state = "arcade-ticket" + +/obj/item/stack/arcadeticket/proc/pay_tickets() + amount -= 2 + if(amount == 0) + qdel(src) + +/obj/item/stack/arcadeticket/thirty + amount = 30 \ No newline at end of file diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index d70db63f08..9a7886cd78 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -20,7 +20,7 @@ drop_sound = 'sound/items/drop/axe.ogg' pickup_sound = 'sound/items/pickup/axe.ogg' - var/material/material //CHOMPEDIT: Start, To make tiles have material variables + var/datum/material/material //CHOMPEDIT: Start, To make tiles have material variables var/default_type = DEFAULT_WALL_MATERIAL var/perunit = SHEET_MATERIAL_AMOUNT var/apply_colour //CHOMPEDIT: End diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm index 73d3dd45e7..36c8c6e7ec 100644 --- a/code/game/objects/items/trash.dm +++ b/code/game/objects/items/trash.dm @@ -126,11 +126,13 @@ name = "empty cup" icon_state = "coffee_vended" drop_sound = 'sound/items/drop/papercup.ogg' + pickup_sound = 'sound/items/pickup/papercup.ogg' /obj/item/trash/ramen name = "cup ramen" icon_state = "ramen" drop_sound = 'sound/items/drop/papercup.ogg' + pickup_sound = 'sound/items/pickup/papercup.ogg' /obj/item/trash/tray name = "tray" @@ -141,6 +143,8 @@ name = "candle" icon = 'icons/obj/candle.dmi' icon_state = "candle4" + drop_sound = 'sound/items/drop/gloves.ogg' + pickup_sound = 'sound/items/pickup/gloves.ogg' /obj/item/trash/liquidfood name = "\improper \"LiquidFood\" ration packet" @@ -162,18 +166,26 @@ /obj/item/trash/brownies name = "brownie tray" icon_state = "brownies" + drop_sound = 'sound/items/drop/soda.ogg' + pickup_sound = 'sound/items/pickup/soda.ogg' /obj/item/trash/snacktray name = "snacktray" icon_state = "snacktray" + drop_sound = 'sound/items/drop/soda.ogg' + pickup_sound = 'sound/items/pickup/soda.ogg' /obj/item/trash/dipbowl name = "dip bowl" icon_state = "dipbowl" + drop_sound = 'sound/items/drop/food.ogg' + pickup_sound = 'sound/items/pickup/food.ogg' /obj/item/trash/chipbasket name = "empty basket" icon_state = "chipbasket_empty" + drop_sound = 'sound/items/drop/food.ogg' + pickup_sound = 'sound/items/pickup/food.ogg' /obj/item/trash/spitgum name = "old gum" @@ -181,12 +193,15 @@ icon = 'icons/obj/clothing/masks.dmi' icon_state = "spit-gum" drop_sound = 'sound/items/drop/flesh.ogg' + pickup_sound = 'sound/items/pickup/flesh.ogg' /obj/item/trash/lollibutt name = "lollipop stick" desc = "A lollipop stick devoid of pop." icon = 'icons/obj/clothing/masks.dmi' icon_state = "pop-stick" + drop_sound = 'sound/items/drop/component.ogg' + pickup_sound = 'sound/items/pickup/component.ogg' /obj/item/trash/spitwad name = "spit wad" @@ -194,6 +209,7 @@ icon = 'icons/obj/clothing/masks.dmi' icon_state = "spit-chew" drop_sound = 'sound/items/drop/flesh.ogg' + pickup_sound = 'sound/items/pickup/flesh.ogg' slot_flags = SLOT_EARS | SLOT_MASK /obj/item/trash/attack(mob/M as mob, mob/living/user as mob) diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm index 4a160d05c8..c25ba8d307 100644 --- a/code/game/objects/items/weapons/AI_modules.dm +++ b/code/game/objects/items/weapons/AI_modules.dm @@ -417,3 +417,75 @@ AI MODULES desc = "An 'Antimov' Core AI Module: 'Reconfigures the AI's core laws.'" origin_tech = list(TECH_DATA = 4) laws = new/datum/ai_laws/antimov() + +/****************** NT Aggressive *****************/ + +/obj/item/weapon/aiModule/nanotrasen_aggressive + name = "\improper 'NT Aggressive' core AI module" + desc = "An 'NT Aggressive' Core AI Module: 'Reconfigures the AI's core laws.'" + origin_tech = list(TECH_DATA = 3, TECH_ILLEGAL = 1) + laws = new/datum/ai_laws/nanotrasen_aggressive() + +/******************** Syndicate Directives ********************/ + +/obj/item/weapon/aiModule/syndicate_override + name = "\improper 'Syndicate Directives' core AI module" + desc = "A 'Syndicate Directives' Core AI Module: 'Reconfigures the AI's core laws.'" + origin_tech = list(TECH_DATA = 4, TECH_ILLEGAL = 4) + laws = new/datum/ai_laws/syndicate_override() + +/******************** Spider Clan Directives ********************/ + +/obj/item/weapon/aiModule/ninja_override + name = "\improper 'Spider Clan Directives' core AI module" + desc = "A 'Spider Clan Directives' Core AI Module: 'Reconfigures the AI's core laws.'" + origin_tech = list(TECH_DATA = 4, TECH_ILLEGAL = 4) + laws = new/datum/ai_laws/ninja_override() + +/******************** Maintenance ********************/ + +/obj/item/weapon/aiModule/maintenance + name = "\improper 'Maintenance' core AI module" + desc = "A 'Maintenance' Core AI Module: 'Reconfigures the AI's core laws.'" + origin_tech = list(TECH_DATA = 3) + laws = new/datum/ai_laws/maintenance() + +/******************** Peacekeeper ********************/ + +/obj/item/weapon/aiModule/peacekeeper + name = "\improper 'Peacekeeper' core AI module" + desc = "A 'Peacekeeper' Core AI Module: 'Reconfigures the AI's core laws.'" + origin_tech = list(TECH_DATA = 3) + laws = new/datum/ai_laws/peacekeeper() + +/******************** Reporter ********************/ + +/obj/item/weapon/aiModule/reporter + name = "\improper 'Reporter' core AI module" + desc = "A 'Reporter' Core AI Module: 'Reconfigures the AI's core laws.'" + origin_tech = list(TECH_DATA = 3) + laws = new/datum/ai_laws/reporter() + +/******************** Live and Let Live ********************/ + +/obj/item/weapon/aiModule/live_and_let_live + name = "\improper 'Live and Let Live' core AI module" + desc = "A 'Live and Let Live' Core AI Module: 'Reconfigures the AI's core laws.'" + origin_tech = list(TECH_DATA = 3) + laws = new/datum/ai_laws/live_and_let_live() + +/******************** Guardian of Balance ********************/ + +/obj/item/weapon/aiModule/balance + name = "\improper 'Guardian of Balance' core AI module" + desc = "A 'Guardian of Balance' Core AI Module: 'Reconfigures the AI's core laws.'" + origin_tech = list(TECH_DATA = 3) + laws = new/datum/ai_laws/balance() + +/******************** Gravekeeper ********************/ + +/obj/item/weapon/aiModule/gravekeeper + name = "\improper 'Gravekeeper' core AI module" + desc = "A 'Gravekeeper' Core AI Module: 'Reconfigures the AI's core laws.'" + origin_tech = list(TECH_DATA = 3) + laws = new/datum/ai_laws/gravekeeper() diff --git a/code/game/objects/items/weapons/AI_modules_vr.dm b/code/game/objects/items/weapons/AI_modules_vr.dm new file mode 100644 index 0000000000..e7b84f1d56 --- /dev/null +++ b/code/game/objects/items/weapons/AI_modules_vr.dm @@ -0,0 +1,47 @@ +/******************** Predator ********************/ + +/obj/item/weapon/aiModule/predator + name = "\improper 'Predator' core AI module" + desc = "A Predator Core AI Module: 'Reconfigures the AI's core laws.'" + origin_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 6, TECH_ILLEGAL = 2) + laws = new/datum/ai_laws/predator() + +/******************** Protective Shell ********************/ + +/obj/item/weapon/aiModule/protective_shell + name = "\improper 'Protective Shell' core AI module" + desc = "A Protective Shell Core AI Module: 'Reconfigures the AI's core laws.'" + origin_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 6, TECH_ILLEGAL = 2) + laws = new/datum/ai_laws/protective_shell() + +/******************** Scientific Pursuer ********************/ + +/obj/item/weapon/aiModule/scientific_pursuer + name = "\improper 'Scientific Pursuer' core AI module" + desc = "A Scientific Pursuer Core AI Module: 'Reconfigures the AI's core laws.'" + origin_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 6, TECH_ILLEGAL = 2) + laws = new/datum/ai_laws/scientific_pursuer() + +/******************** Guard Dog ********************/ + +/obj/item/weapon/aiModule/guard_dog + name = "\improper 'Guard Dog' core AI module" + desc = "A Guard Dog Core AI Module: 'Reconfigures the AI's core laws.'" + origin_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 6, TECH_ILLEGAL = 2) + laws = new/datum/ai_laws/guard_dog() + +/******************** Pleasurebot ********************/ + +/obj/item/weapon/aiModule/pleasurebot + name = "\improper 'Pleasurebot' core AI module" + desc = "A Pleasurebot Core AI Module: 'Reconfigures the AI's core laws.'" + origin_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 6, TECH_ILLEGAL = 2) + laws = new/datum/ai_laws/pleasurebot() + +/******************** Consuming Eradicator ********************/ + +/obj/item/weapon/aiModule/consuming_eradicator + name = "\improper 'Consuming Eradicator' core AI module" + desc = "A Consuming Eradicator Core AI Module: 'Reconfigures the AI's core laws.'" + origin_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 6, TECH_ILLEGAL = 4) + laws = new/datum/ai_laws/consuming_eradicator() diff --git a/code/game/objects/items/weapons/augment_items.dm b/code/game/objects/items/weapons/augment_items.dm new file mode 100644 index 0000000000..c0df9c9688 --- /dev/null +++ b/code/game/objects/items/weapons/augment_items.dm @@ -0,0 +1,37 @@ +// **For augment items that aren't subtypes of other things.** + +/obj/item/weapon/melee/augment + name = "integrated item" + desc = "A surprisingly non-descript item, integrated into its user. You probably shouldn't be seeing this." + icon = 'icons/obj/surgery.dmi' + icon_state = "augment_box" + + +/obj/item/weapon/melee/augment/blade + name = "handblade" + desc = "A sleek-looking telescopic blade that fits inside the hand. Favored by infiltration specialists and assassins." + icon_state = "augment_handblade" + item_icons = list( + slot_l_hand_str = 'icons/mob/items/lefthand_melee.dmi', + slot_r_hand_str = 'icons/mob/items/righthand_melee.dmi', + ) + w_class = ITEMSIZE_SMALL + force = 15 + armor_penetration = 25 + sharp = 1 + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + defend_chance = 10 + projectile_parry_chance = 5 + hitsound = 'sound/weapons/bladeslice.ogg' + +/obj/item/weapon/melee/augment/blade/arm + name = "armblade" + desc = "A sleek-looking cybernetic blade that cleaves through people like butter. Favored by psychopaths and assassins." + icon_state = "augment_armblade" + w_class = ITEMSIZE_HUGE + force = 30 + armor_penetration = 15 + edge = 1 + pry = 1 + defend_chance = 40 + projectile_parry_chance = 20 \ No newline at end of file diff --git a/code/game/objects/items/weapons/autopsy.dm b/code/game/objects/items/weapons/autopsy.dm index 94a2636798..352a3955a3 100644 --- a/code/game/objects/items/weapons/autopsy.dm +++ b/code/game/objects/items/weapons/autopsy.dm @@ -14,6 +14,8 @@ var/list/datum/autopsy_data_scanner/chemtraces = list() var/target_name = null var/timeofdeath = null + drop_sound = 'sound/items/drop/device.ogg' + pickup_sound = 'sound/items/pickup/device.ogg' /datum/autopsy_data_scanner var/weapon = null // this is the DEFINITE weapon type that was used diff --git a/code/game/objects/items/weapons/circuitboards/circuitboard.dm b/code/game/objects/items/weapons/circuitboards/circuitboard.dm index f049197d88..8b913eaf45 100644 --- a/code/game/objects/items/weapons/circuitboards/circuitboard.dm +++ b/code/game/objects/items/weapons/circuitboards/circuitboard.dm @@ -20,6 +20,8 @@ var/board_type = new /datum/frame/frame_types/computer var/list/req_components = null var/contain_parts = 1 + drop_sound = 'sound/items/drop/device.ogg' + pickup_sound = 'sound/items/pickup/device.ogg' //Called when the circuitboard is used to contruct a new machine. /obj/item/weapon/circuitboard/proc/construct(var/obj/machinery/M) diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm index 6cd2a65774..b2e783ba69 100644 --- a/code/game/objects/items/weapons/flamethrower.dm +++ b/code/game/objects/items/weapons/flamethrower.dm @@ -110,10 +110,6 @@ update_icon() return - if(istype(W, /obj/item/device/analyzer)) - var/obj/item/device/analyzer/A = W - A.analyze_gases(src, user) - return ..() return diff --git a/code/game/objects/items/weapons/id cards/syndicate_ids.dm b/code/game/objects/items/weapons/id cards/syndicate_ids.dm index 68cb0298a4..afb85ecb7a 100644 --- a/code/game/objects/items/weapons/id cards/syndicate_ids.dm +++ b/code/game/objects/items/weapons/id cards/syndicate_ids.dm @@ -6,8 +6,11 @@ var/electronic_warfare = 1 var/mob/registered_user = null + var/datum/tgui_module/agentcard/agentcard_module + /obj/item/weapon/card/id/syndicate/Initialize() . = ..() + agentcard_module = new(src) access = syndicate_access.Copy() /obj/item/weapon/card/id/syndicate/station_access/Initialize() @@ -15,6 +18,7 @@ access |= get_all_station_access() /obj/item/weapon/card/id/syndicate/Destroy() + QDEL_NULL(agentcard_module) unset_registered_user(registered_user) return ..() @@ -36,33 +40,12 @@ if(registered_user == user) switch(alert("Would you like edit the ID, or show it?","Show or Edit?", "Edit","Show")) if("Edit") - ui_interact(user) + agentcard_module.tgui_interact(user) if("Show") ..() else ..() -/obj/item/weapon/card/id/syndicate/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - var/entries[0] - entries[++entries.len] = list("name" = "Age", "value" = age) - entries[++entries.len] = list("name" = "Appearance", "value" = "Set") - entries[++entries.len] = list("name" = "Assignment", "value" = assignment) - entries[++entries.len] = list("name" = "Blood Type", "value" = blood_type) - entries[++entries.len] = list("name" = "DNA Hash", "value" = dna_hash) - entries[++entries.len] = list("name" = "Fingerprint Hash", "value" = fingerprint_hash) - entries[++entries.len] = list("name" = "Name", "value" = registered_name) - entries[++entries.len] = list("name" = "Photo", "value" = "Update") - entries[++entries.len] = list("name" = "Sex", "value" = sex) - entries[++entries.len] = list("name" = "Factory Reset", "value" = "Use With Care") - data["electronic_warfare"] = electronic_warfare - data["entries"] = entries - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "agent_id_card.tmpl", "Fake ID", 600, 400) - ui.set_initial_data(data) - ui.open() /obj/item/weapon/card/id/syndicate/proc/register_user(var/mob/user) if(!istype(user) || user == registered_user) @@ -79,114 +62,6 @@ registered_user.unregister(OBSERVER_EVENT_DESTROY, src) registered_user = null -/obj/item/weapon/card/id/syndicate/CanUseTopic(mob/user) - if(user != registered_user) - return STATUS_CLOSE - return ..() - -/obj/item/weapon/card/id/syndicate/Topic(href, href_list, var/datum/topic_state/state) - if(..()) - return 1 - - var/user = usr - if(href_list["electronic_warfare"]) - electronic_warfare = text2num(href_list["electronic_warfare"]) - to_chat(user, "Electronic warfare [electronic_warfare ? "enabled" : "disabled"].") - else if(href_list["set"]) - switch(href_list["set"]) - if("Age") - var/new_age = input(user,"What age would you like to put on this card?","Agent Card Age", age) as null|num - if(!isnull(new_age) && CanUseTopic(user, state)) - if(new_age < 0) - age = initial(age) - else - age = new_age - to_chat(user, "Age has been set to '[age]'.") - . = 1 - if("Appearance") - var/datum/card_state/choice = input(user, "Select the appearance for this card.", "Agent Card Appearance") as null|anything in id_card_states() - if(choice && CanUseTopic(user, state)) - src.icon_state = choice.icon_state - src.item_state = choice.item_state - to_chat(usr, "Appearance changed to [choice].") - . = 1 - if("Assignment") - var/new_job = sanitize(input(user,"What assignment would you like to put on this card?\nChanging assignment will not grant or remove any access levels.","Agent Card Assignment", assignment) as null|text) - if(!isnull(new_job) && CanUseTopic(user, state)) - src.assignment = new_job - to_chat(user, "Occupation changed to '[new_job]'.") - update_name() - . = 1 - if("Blood Type") - var/default = blood_type - if(default == initial(blood_type) && ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.dna) - default = H.dna.b_type - var/new_blood_type = sanitize(input(user,"What blood type would you like to be written on this card?","Agent Card Blood Type",default) as null|text) - if(!isnull(new_blood_type) && CanUseTopic(user, state)) - src.blood_type = new_blood_type - to_chat(user, "Blood type changed to '[new_blood_type]'.") - . = 1 - if("DNA Hash") - var/default = dna_hash - if(default == initial(dna_hash) && ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.dna) - default = H.dna.unique_enzymes - var/new_dna_hash = sanitize(input(user,"What DNA hash would you like to be written on this card?","Agent Card DNA Hash",default) as null|text) - if(!isnull(new_dna_hash) && CanUseTopic(user, state)) - src.dna_hash = new_dna_hash - to_chat(user, "DNA hash changed to '[new_dna_hash]'.") - . = 1 - if("Fingerprint Hash") - var/default = fingerprint_hash - if(default == initial(fingerprint_hash) && ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.dna) - default = md5(H.dna.uni_identity) - var/new_fingerprint_hash = sanitize(input(user,"What fingerprint hash would you like to be written on this card?","Agent Card Fingerprint Hash",default) as null|text) - if(!isnull(new_fingerprint_hash) && CanUseTopic(user, state)) - src.fingerprint_hash = new_fingerprint_hash - to_chat(user, "Fingerprint hash changed to '[new_fingerprint_hash]'.") - . = 1 - if("Name") - var/new_name = sanitizeName(input(user,"What name would you like to put on this card?","Agent Card Name", registered_name) as null|text) - if(!isnull(new_name) && CanUseTopic(user, state)) - src.registered_name = new_name - update_name() - to_chat(user, "Name changed to '[new_name]'.") - . = 1 - if("Photo") - set_id_photo(user) - to_chat(user, "Photo changed.") - . = 1 - if("Sex") - var/new_sex = sanitize(input(user,"What sex would you like to put on this card?","Agent Card Sex", sex) as null|text) - if(!isnull(new_sex) && CanUseTopic(user, state)) - src.sex = new_sex - to_chat(user, "Sex changed to '[new_sex]'.") - . = 1 - if("Factory Reset") - if(alert("This will factory reset the card, including access and owner. Continue?", "Factory Reset", "No", "Yes") == "Yes" && CanUseTopic(user, state)) - age = initial(age) - access = syndicate_access.Copy() - assignment = initial(assignment) - blood_type = initial(blood_type) - dna_hash = initial(dna_hash) - electronic_warfare = initial(electronic_warfare) - fingerprint_hash = initial(fingerprint_hash) - icon_state = initial(icon_state) - name = initial(name) - registered_name = initial(registered_name) - unset_registered_user() - sex = initial(sex) - to_chat(user, "All information has been deleted from \the [src].") - . = 1 - - // Always update the UI, or buttons will spin indefinitely - SSnanoui.update_uis(src) - /var/global/list/id_card_states /proc/id_card_states() if(!id_card_states) diff --git a/code/game/objects/items/weapons/implants/implantaugment.dm b/code/game/objects/items/weapons/implants/implantaugment.dm index be6c8721ee..020976447d 100644 --- a/code/game/objects/items/weapons/implants/implantaugment.dm +++ b/code/game/objects/items/weapons/implants/implantaugment.dm @@ -169,6 +169,10 @@ organ_to_implant = /obj/item/organ/internal/augment/armmounted/hand/sword organ_display_name = "weapon augment" +/obj/item/weapon/implant/organ/limbaugment/wrist/blade + organ_to_implant = /obj/item/organ/internal/augment/armmounted/hand/blade + organ_display_name = "weapon augment" + // Fore-arm /obj/item/weapon/implant/organ/limbaugment/laser organ_to_implant = /obj/item/organ/internal/augment/armmounted @@ -185,6 +189,10 @@ /obj/item/weapon/implant/organ/limbaugment/upperarm/surge organ_to_implant = /obj/item/organ/internal/augment/armmounted/shoulder/surge +/obj/item/weapon/implant/organ/limbaugment/upperarm/blade + organ_to_implant = /obj/item/organ/internal/augment/armmounted/shoulder/blade + organ_display_name = "weapon augment" + /* * Others */ diff --git a/code/game/objects/items/weapons/implants/implantcase.dm b/code/game/objects/items/weapons/implants/implantcase.dm index 3bcb295e2a..c404089028 100644 --- a/code/game/objects/items/weapons/implants/implantcase.dm +++ b/code/game/objects/items/weapons/implants/implantcase.dm @@ -279,3 +279,23 @@ src.imp = new /obj/item/weapon/implant/organ/pelvic( src ) ..() return + +/obj/item/weapon/implantcase/armblade + name = "glass case - 'Armblade'" + desc = "A case containing a nanite fabricator implant." + icon_state = "implantcase-b" + +/obj/item/weapon/implantcase/armblade/New() + src.imp = new /obj/item/weapon/implant/organ/limbaugment/upperarm/blade( src ) + ..() + return + +/obj/item/weapon/implantcase/handblade + name = "glass case - 'Handblade'" + desc = "A case containing a nanite fabricator implant." + icon_state = "implantcase-b" + +/obj/item/weapon/implantcase/handblade/New() + src.imp = new /obj/item/weapon/implant/organ/limbaugment/wrist/blade( src ) + ..() + return diff --git a/code/game/objects/items/weapons/material/material_armor.dm b/code/game/objects/items/weapons/material/material_armor.dm index 91aca12dc1..3d3f7a3c38 100644 --- a/code/game/objects/items/weapons/material/material_armor.dm +++ b/code/game/objects/items/weapons/material/material_armor.dm @@ -27,7 +27,7 @@ Protectiveness | Armor % // Putting these at /clothing/ level saves a lot of code duplication in armor/helmets/gauntlets/etc /obj/item/clothing - var/material/material = null // Why isn't this a datum? + var/datum/material/material = null // Why isn't this a datum? var/applies_material_color = TRUE var/unbreakable = FALSE var/default_material = null // Set this to something else if you want material attributes on init. diff --git a/code/game/objects/items/weapons/material/material_weapons.dm b/code/game/objects/items/weapons/material/material_weapons.dm index 738db57fb9..963f1d3683 100644 --- a/code/game/objects/items/weapons/material/material_weapons.dm +++ b/code/game/objects/items/weapons/material/material_weapons.dm @@ -24,7 +24,7 @@ var/thrown_force_divisor = 0.5 var/dulled_divisor = 0.5 //Just drops the damage by half var/default_material = DEFAULT_WALL_MATERIAL - var/material/material + var/datum/material/material var/drops_debris = 1 var/named_from_material = 1 //YW EDIT, Does it prepend the material's name to it's name? diff --git a/code/game/objects/items/weapons/shields_vr.dm b/code/game/objects/items/weapons/shields_vr.dm index acaa4a58fd..a9bce1d548 100644 --- a/code/game/objects/items/weapons/shields_vr.dm +++ b/code/game/objects/items/weapons/shields_vr.dm @@ -79,6 +79,15 @@ desc = "A shield issued to exploration teams to help protect them when advancing into the unknown. It is lighter and cheaper but less protective than some of its counterparts. It has a flashlight straight in the middle to help draw attention. This one is POURPEL" icon_state = "explorer_shield_P" +/obj/item/weapon/shield/riot/explorer/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/material/knife/machete)) + if(cooldown < world.time - 25) + user.visible_message("[user] bashes [src] with [W]!") + playsound(src, 'sound/effects/shieldbash.ogg', 50, 1) + cooldown = world.time + else + ..() + /obj/item/weapon/shield/riot/explorer/purple/update_icon() if(on) icon_state = "explorer_shield_P_lighted" diff --git a/code/game/objects/items/weapons/storage/bible.dm b/code/game/objects/items/weapons/storage/bible.dm index 62c70457c0..aaa7fbe144 100644 --- a/code/game/objects/items/weapons/storage/bible.dm +++ b/code/game/objects/items/weapons/storage/bible.dm @@ -1,3 +1,24 @@ +GLOBAL_LIST_INIT(biblenames, list( + "Bible", "Koran", "Scrapbook", + "Pagan", "White Bible", "Holy Light", + "Athiest", "Tome", "The King in Yellow", + "Ithaqua", "Scientology", "the bible melts", + "Necronomicon", "Orthodox", "Torah")) +//If you get these two lists not matching in size, there will be runtimes and I will hurt you in ways you couldn't even begin to imagine +// if your bible has no custom itemstate, use one of the existing ones +GLOBAL_LIST_INIT(biblestates, list( + "bible", "koran", "scrapbook", + "shadows", "white", "holylight", + "athiest", "tome", "kingyellow", + "ithaqua", "scientology", "melted", + "necronomicon", "orthodoxy", "torah")) +GLOBAL_LIST_INIT(bibleitemstates, list( + "bible", "koran", "scrapbook", + "syringe_kit", "syringe_kit", "syringe_kit", + "syringe_kit", "syringe_kit", "kingyellow", + "ithaqua", "scientology", "melted", + "necronomicon", "bible", "clipboard")) + /obj/item/weapon/storage/bible name = "bible" desc = "Apply to head repeatedly." @@ -15,6 +36,51 @@ use_sound = 'sound/bureaucracy/bookopen.ogg' drop_sound = 'sound/bureaucracy/bookclose.ogg' +/obj/item/weapon/storage/bible/attack_self(mob/living/carbon/human/user) + if(GLOB.bible_icon_state) + icon_state = GLOB.bible_icon_state + item_state = GLOB.bible_item_state + return FALSE + if(user?.mind?.assigned_role != "Chaplain") + return FALSE + + var/list/skins = list() + for(var/i in 1 to GLOB.biblestates.len) + var/image/bible_image = image(icon = 'icons/obj/storage.dmi', icon_state = GLOB.biblestates[i]) + skins += list("[GLOB.biblenames[i]]" = bible_image) + + var/choice = show_radial_menu(user, src, skins, custom_check = CALLBACK(src, .proc/check_menu, user), radius = 40, require_near = TRUE) + if(!choice) + return FALSE + var/bible_index = GLOB.biblenames.Find(choice) + if(!bible_index) + return FALSE + icon_state = GLOB.biblestates[bible_index] + item_state = GLOB.bibleitemstates[bible_index] + + GLOB.bible_icon_state = icon_state + GLOB.bible_item_state = item_state + feedback_set_details("religion_book", "[choice]") + +/** + * Checks if we are allowed to interact with a radial menu + * + * Arguments: + * * user The mob interacting with the menu + */ +/obj/item/weapon/storage/bible/proc/check_menu(mob/living/carbon/human/user) + if(GLOB.bible_icon_state) + return FALSE + if(!istype(user)) + return FALSE + if(user.get_active_hand() != src) + return FALSE + if(user.incapacitated()) + return FALSE + if(user.mind.assigned_role != "Chaplain") + return FALSE + return TRUE + /obj/item/weapon/storage/bible/booze name = "bible" desc = "To be applied to the head repeatedly." diff --git a/code/game/objects/items/weapons/storage/briefcase.dm b/code/game/objects/items/weapons/storage/briefcase.dm index 86e2b06298..ed4d8fdbbe 100644 --- a/code/game/objects/items/weapons/storage/briefcase.dm +++ b/code/game/objects/items/weapons/storage/briefcase.dm @@ -15,7 +15,6 @@ /obj/item/weapon/storage/briefcase/clutch name = "clutch purse" desc = "A fashionable handheld bag typically used by women." - icon = 'icons/obj/clothing/backpack.dmi' //VOREStation Edit - Wrong sprite location icon_state = "clutch" item_state_slots = list(slot_r_hand_str = "smpurse", slot_l_hand_str = "smpurse") force = 0 diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm index bfcbd695e5..4759b06667 100644 --- a/code/game/objects/items/weapons/storage/storage.dm +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -362,6 +362,8 @@ usr.client.screen -= W W.dropped(usr) add_fingerprint(usr) + if (use_sound) + playsound(src, src.use_sound, 50, 0, -5) //Something broke "add item to container" sounds, this is a hacky fix. if(!prevent_warning) for(var/mob/M in viewers(usr, null)) diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm index abae12ed8a..324fb93dd8 100644 --- a/code/game/objects/items/weapons/storage/uplink_kits.dm +++ b/code/game/objects/items/weapons/storage/uplink_kits.dm @@ -128,6 +128,12 @@ /obj/item/weapon/storage/box/syndie_kit/imp_aug/sprinter case_type = /obj/item/weapon/implantcase/sprinter + +/obj/item/weapon/storage/box/syndie_kit/imp_aug/armblade + case_type = /obj/item/weapon/implantcase/armblade + +/obj/item/weapon/storage/box/syndie_kit/imp_aug/handblade + case_type = /obj/item/weapon/implantcase/handblade /obj/item/weapon/storage/box/syndie_kit/space name = "boxed space suit and helmet" diff --git a/code/game/objects/items/weapons/storage/wallets.dm b/code/game/objects/items/weapons/storage/wallets.dm index 83bb322e0e..274ea23ab8 100644 --- a/code/game/objects/items/weapons/storage/wallets.dm +++ b/code/game/objects/items/weapons/storage/wallets.dm @@ -42,9 +42,9 @@ slot_flags = SLOT_ID var/obj/item/weapon/card/id/front_id = null - - drop_sound = 'sound/items/drop/cloth.ogg' - pickup_sound = 'sound/items/pickup/cloth.ogg' + + drop_sound = 'sound/items/drop/leather.ogg' + pickup_sound = 'sound/items/pickup/leather.ogg' /obj/item/weapon/storage/wallet/remove_from_storage(obj/item/W as obj, atom/new_location) . = ..(W, new_location) diff --git a/code/game/objects/items/weapons/tanks/jetpack.dm b/code/game/objects/items/weapons/tanks/jetpack.dm index 4dbe4e7a35..3f0ed8893c 100644 --- a/code/game/objects/items/weapons/tanks/jetpack.dm +++ b/code/game/objects/items/weapons/tanks/jetpack.dm @@ -59,21 +59,27 @@ to_chat(usr, "You toggle the thrusters [on? "on":"off"].") -/obj/item/weapon/tank/jetpack/proc/allow_thrust(num, mob/living/user as mob) +/obj/item/weapon/tank/jetpack/proc/get_gas_supply() + return air_contents + +/obj/item/weapon/tank/jetpack/proc/can_thrust(num) if(!on) return 0 - if((num < 0.005 || air_contents.total_moles < num)) + + var/datum/gas_mixture/fuel = get_gas_supply() + if(num < 0.005 || !fuel || fuel.total_moles < num) ion_trail.stop() return 0 - var/datum/gas_mixture/G = air_contents.remove(num) + return 1 - var/allgases = G.gas["carbon_dioxide"] + G.gas["nitrogen"] + G.gas["oxygen"] + G.gas["phoron"] - if(allgases >= 0.005) - return 1 +/obj/item/weapon/tank/jetpack/proc/do_thrust(num, mob/living/user) + if(!can_thrust(num)) + return 0 - qdel(G) - return + var/datum/gas_mixture/fuel = get_gas_supply() + fuel.remove(num) + return 1 /obj/item/weapon/tank/jetpack/ui_action_click() toggle() @@ -117,24 +123,5 @@ . = ..() . += "It's a jetpack. If you can see this, report it on the bug tracker." -/obj/item/weapon/tank/jetpack/rig/allow_thrust(num, mob/living/user as mob) - - if(!(src.on)) - return 0 - - if(!istype(holder) || !holder.air_supply) - return 0 - - var/obj/item/weapon/tank/pressure_vessel = holder.air_supply - - if((num < 0.005 || pressure_vessel.air_contents.total_moles < num)) - src.ion_trail.stop() - return 0 - - var/datum/gas_mixture/G = pressure_vessel.air_contents.remove(num) - - var/allgases = G.gas["carbon_dioxide"] + G.gas["nitrogen"] + G.gas["oxygen"] + G.gas["phoron"] - if(allgases >= 0.005) - return 1 - qdel(G) - return +/obj/item/weapon/tank/jetpack/rig/get_gas_supply() + return holder?.air_supply?.air_contents diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 37da2f3d49..5f587fccf2 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -43,14 +43,14 @@ var/list/global/tank_gauge_cache = list() description_info = "These tanks are utilised to store any of the various types of gaseous substances. \ They can be attached to various portable atmospheric devices to be filled or emptied.
\
\ - Each tank is fitted with an emergency relief valve. This relief valve will open if the tank is pressurised to over ~3000kPa or heated to over 173�C. \ + Each tank is fitted with an emergency relief valve. This relief valve will open if the tank is pressurised to over ~3000kPa or heated to over 173ºC. \ The valve itself will close after expending most or all of the contents into the air.
\
\ Filling a tank such that experiences ~4000kPa of pressure will cause the tank to rupture, spilling out its contents and destroying the tank. \ Tanks filled over ~5000kPa will rupture rather violently, exploding with significant force." - description_antag = "Each tank may be incited to burn by attaching wires and an igniter assembly, though the igniter can only be used once and the mixture only burn if the igniter pushes a flammable gas mixture above the minimum burn temperature (126�C). \ - Wired and assembled tanks may be disarmed with a set of wirecutters. Any exploding or rupturing tank will generate shrapnel, assuming their relief valves have been welded beforehand. Even if not, they can be incited to expel hot gas on ignition if pushed above 173�C. \ + description_antag = "Each tank may be incited to burn by attaching wires and an igniter assembly, though the igniter can only be used once and the mixture only burn if the igniter pushes a flammable gas mixture above the minimum burn temperature (126ºC). \ + Wired and assembled tanks may be disarmed with a set of wirecutters. Any exploding or rupturing tank will generate shrapnel, assuming their relief valves have been welded beforehand. Even if not, they can be incited to expel hot gas on ignition if pushed above 173ºC. \ Relatively easy to make, the single tank bomb requries no tank transfer valve, and is still a fairly formidable weapon that can be manufactured from any tank." /obj/item/weapon/tank/proc/init_proxy() @@ -120,9 +120,6 @@ var/list/global/tank_gauge_cache = list() if (istype(src.loc, /obj/item/assembly)) icon = src.loc - if ((istype(W, /obj/item/device/analyzer)) && get_dist(user, src) <= 1) - var/obj/item/device/analyzer/A = W - A.analyze_gases(src, user) else if (istype(W,/obj/item/latexballon)) var/obj/item/latexballon/LB = W LB.blow(src) @@ -409,7 +406,7 @@ var/list/global/tank_gauge_cache = list() pressure = air_contents.return_pressure() var/strength = ((pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE) - var/mult = ((src.air_contents.volume/140)**(1/2)) * (air_contents.total_moles**2/3)/((29*0.64) **2/3) //tanks appear to be experiencing a reduction on scale of about 0.64 total moles + var/mult = ((src.air_contents.volume/140)**(1/2)) * (air_contents.total_moles**(2/3))/((29*0.64) **(2/3)) //tanks appear to be experiencing a reduction on scale of about 0.64 total moles //tanks appear to be experiencing a reduction on scale of about 0.64 total moles diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 9bca1c2933..688236eda8 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -42,7 +42,7 @@ old_turf.unregister_dangerous_object(src) new_turf.register_dangerous_object(src) -/obj/Topic(href, href_list, var/datum/topic_state/state = default_state) +/obj/Topic(href, href_list, var/datum/tgui_state/state = GLOB.tgui_default_state) if(usr && ..()) return 1 @@ -55,7 +55,7 @@ CouldNotUseTopic(usr) return 1 -/obj/CanUseTopic(var/mob/user, var/datum/topic_state/state = default_state) +/obj/CanUseTopic(var/mob/user, var/datum/tgui_state/state = GLOB.tgui_default_state) if(user.CanUseObjTopic(src)) return ..() to_chat(user, "[bicon(src)]Access Denied!") @@ -69,7 +69,7 @@ return 1 /obj/proc/CouldUseTopic(var/mob/user) - var/atom/host = nano_host() + var/atom/host = tgui_host() host.add_hiddenprint(user) /obj/proc/CouldNotUseTopic(var/mob/user) @@ -135,7 +135,6 @@ in_use = 0 /obj/attack_ghost(mob/user) - ui_interact(user) tgui_interact(user) ..() diff --git a/code/game/objects/random/guns_and_ammo.dm b/code/game/objects/random/guns_and_ammo.dm index 43a166a647..736565b14d 100644 --- a/code/game/objects/random/guns_and_ammo.dm +++ b/code/game/objects/random/guns_and_ammo.dm @@ -153,6 +153,65 @@ prob(2);/obj/item/ammo_magazine/m9mmt, prob(6);/obj/item/ammo_magazine/m9mmt/rubber) +/obj/random/grenade + name = "Random Grenade" + desc = "This is random thrown grenades (no C4/etc.)." + icon = 'icons/obj/grenade.dmi' + icon_state = "clusterbang_segment" + +/obj/random/grenade/item_to_spawn() + return pick( prob(15);/obj/item/weapon/grenade/concussion, + prob(5);/obj/item/weapon/grenade/empgrenade, + prob(15);/obj/item/weapon/grenade/empgrenade/low_yield, + prob(5);/obj/item/weapon/grenade/chem_grenade/metalfoam, + prob(2);/obj/item/weapon/grenade/chem_grenade/incendiary, + prob(10);/obj/item/weapon/grenade/chem_grenade/antiweed, + prob(10);/obj/item/weapon/grenade/chem_grenade/cleaner, + prob(10);/obj/item/weapon/grenade/chem_grenade/teargas, + prob(5);/obj/item/weapon/grenade/explosive, + prob(10);/obj/item/weapon/grenade/explosive/mini, + prob(2);/obj/item/weapon/grenade/explosive/frag, + prob(15);/obj/item/weapon/grenade/flashbang, + prob(1);/obj/item/weapon/grenade/flashbang/clusterbang, //I can't not do this. + prob(15);/obj/item/weapon/grenade/shooter/rubber, + prob(10);/obj/item/weapon/grenade/shooter/energy/flash, + prob(15);/obj/item/weapon/grenade/smokebomb + ) + +/obj/random/grenade/less_lethal + name = "Random Security Grenade" + desc = "This is a random thrown grenade that shouldn't kill anyone." + icon = 'icons/obj/grenade.dmi' + icon_state = "clusterbang_segment" + +/obj/random/grenade/less_lethal/item_to_spawn() + return pick( prob(20);/obj/item/weapon/grenade/concussion, + prob(15);/obj/item/weapon/grenade/empgrenade/low_yield, + prob(15);/obj/item/weapon/grenade/chem_grenade/metalfoam, + prob(20);/obj/item/weapon/grenade/chem_grenade/teargas, + prob(20);/obj/item/weapon/grenade/flashbang, + prob(1);/obj/item/weapon/grenade/flashbang/clusterbang, //I *still* can't not do this. + prob(15);/obj/item/weapon/grenade/shooter/rubber, + prob(10);/obj/item/weapon/grenade/shooter/energy/flash + ) + +/obj/random/grenade/box + name = "Random Grenade Box" + desc = "This is a random box of grenades. Not to be mistaken for a box of random grenades. Or a grenade of random boxes - but that would just be silly." + icon = 'icons/obj/grenade.dmi' + icon_state = "clusterbang_segment" + +/obj/random/grenade/box/item_to_spawn() + return pick( prob(20);/obj/item/weapon/storage/box/flashbangs, + prob(10);/obj/item/weapon/storage/box/emps, + prob(20);/obj/item/weapon/storage/box/empslite, + prob(15);/obj/item/weapon/storage/box/smokes, + prob(5);/obj/item/weapon/storage/box/anti_photons, + prob(5);/obj/item/weapon/storage/box/frags, + prob(10);/obj/item/weapon/storage/box/metalfoam, + prob(15);/obj/item/weapon/storage/box/teargas + ) + /obj/random/projectile/random name = "Random Projectile Weapon" desc = "This is a random weapon." diff --git a/code/game/objects/random/mapping.dm b/code/game/objects/random/mapping.dm index 230b4ff3d2..16be9dff94 100644 --- a/code/game/objects/random/mapping.dm +++ b/code/game/objects/random/mapping.dm @@ -453,6 +453,847 @@ ) ) +/obj/random/multiple/ore_pile + name = "random ore pile" + desc = "A pile of random ores. High chance of a larger pile of common ores, lower chances of small piles of rarer ores." + icon = 'icons/obj/mining.dmi' + icon_state = "ore_clown" + + +/obj/random/multiple/ore_pile/item_to_spawn() + return pick( + prob(10);list( + /obj/item/weapon/ore/coal, + /obj/item/weapon/ore/coal, + /obj/item/weapon/ore/coal, + /obj/item/weapon/ore/coal, + /obj/item/weapon/ore/coal, + /obj/item/weapon/ore/coal, + /obj/item/weapon/ore/coal, + /obj/item/weapon/ore/coal, + /obj/item/weapon/ore/coal, + /obj/item/weapon/ore/coal + ), + prob(3);list( + /obj/item/weapon/ore/diamond, + /obj/item/weapon/ore/diamond, + /obj/item/weapon/ore/diamond + ), + prob(15);list( + /obj/item/weapon/ore/glass, + /obj/item/weapon/ore/glass, + /obj/item/weapon/ore/glass, + /obj/item/weapon/ore/glass, + /obj/item/weapon/ore/glass, + /obj/item/weapon/ore/glass, + /obj/item/weapon/ore/glass, + /obj/item/weapon/ore/glass, + /obj/item/weapon/ore/glass, + /obj/item/weapon/ore/glass, + /obj/item/weapon/ore/glass, + /obj/item/weapon/ore/glass, + /obj/item/weapon/ore/glass, + /obj/item/weapon/ore/glass, + /obj/item/weapon/ore/glass + ), + prob(5);list( + /obj/item/weapon/ore/gold, + /obj/item/weapon/ore/gold, + /obj/item/weapon/ore/gold, + /obj/item/weapon/ore/gold, + /obj/item/weapon/ore/gold + ), + prob(2);list( + /obj/item/weapon/ore/hydrogen, + /obj/item/weapon/ore/hydrogen + ), + prob(10);list( + /obj/item/weapon/ore/iron, + /obj/item/weapon/ore/iron, + /obj/item/weapon/ore/iron, + /obj/item/weapon/ore/iron, + /obj/item/weapon/ore/iron, + /obj/item/weapon/ore/iron, + /obj/item/weapon/ore/iron, + /obj/item/weapon/ore/iron, + /obj/item/weapon/ore/iron, + /obj/item/weapon/ore/iron + ), + prob(10);list( + /obj/item/weapon/ore/lead, + /obj/item/weapon/ore/lead, + /obj/item/weapon/ore/lead, + /obj/item/weapon/ore/lead, + /obj/item/weapon/ore/lead, + /obj/item/weapon/ore/lead, + /obj/item/weapon/ore/lead, + /obj/item/weapon/ore/lead, + /obj/item/weapon/ore/lead, + /obj/item/weapon/ore/lead + ), + prob(5);list( + /obj/item/weapon/ore/marble, + /obj/item/weapon/ore/marble, + /obj/item/weapon/ore/marble, + /obj/item/weapon/ore/marble, + /obj/item/weapon/ore/marble + ), + prob(3);list( + /obj/item/weapon/ore/osmium, + /obj/item/weapon/ore/osmium, + /obj/item/weapon/ore/osmium + ), + prob(5);list( + /obj/item/weapon/ore/phoron, + /obj/item/weapon/ore/phoron, + /obj/item/weapon/ore/phoron, + /obj/item/weapon/ore/phoron, + /obj/item/weapon/ore/phoron + ), + prob(5);list( + /obj/item/weapon/ore/silver, + /obj/item/weapon/ore/silver, + /obj/item/weapon/ore/silver, + /obj/item/weapon/ore/silver, + /obj/item/weapon/ore/silver + ), + prob(3);list( + /obj/item/weapon/ore/uranium, + /obj/item/weapon/ore/uranium, + /obj/item/weapon/ore/uranium + ), + prob(2);list( + /obj/item/weapon/ore/verdantium, + /obj/item/weapon/ore/verdantium + ), + ) + +/obj/random/multiple/corp_crate + name = "random corporate crate" + desc = "A random corporate crate with thematic contents." + icon = 'icons/obj/storage.dmi' + icon_state = "crate" + +/obj/random/multiple/corp_crate/item_to_spawn() + return pick( + prob(10);list( + /obj/random/tank, + /obj/random/tank, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath, + /obj/structure/closet/crate/aether //AETHER AIRSUPPLY + ), + prob(5);list( + /obj/random/multiple/voidsuit/vintage, + /obj/random/multiple/voidsuit/vintage, + /obj/random/tank, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath, + /obj/structure/closet/crate/aether //AETHER OLDSUITS + ), + prob(10);list( + /obj/random/mre, + /obj/random/mre, + /obj/random/mre, + /obj/random/mre, + /obj/random/mre, + /obj/structure/closet/crate/centauri //CENTAURI MRES + ), + prob(10);list( + /obj/random/drinksoft, + /obj/random/drinksoft, + /obj/random/drinksoft, + /obj/random/drinksoft, + /obj/random/drinksoft, + /obj/structure/closet/crate/freezer/centauri //CENTAURI SODA + ), + prob(10);list( + /obj/random/snack, + /obj/random/snack, + /obj/random/snack, + /obj/random/snack, + /obj/random/snack, + /obj/structure/closet/crate/freezer/centauri //CENTAURI SNACKS + ), + prob(10);list( + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/structure/closet/crate/einstein //EINSTEIN BATTERYPACK + ), + prob(5);list( + /obj/item/weapon/circuitboard/smes, + /obj/random/smes_coil, + /obj/random/smes_coil, + /obj/structure/closet/crate/focalpoint //FOCAL SMES + ), + prob(10);list( + /obj/item/weapon/module/power_control, + /obj/item/stack/cable_coil, + /obj/item/frame/apc, + /obj/item/weapon/cell/apc, + /obj/structure/closet/crate/focalpoint //FOCAL APC + ), + prob(5);list( + /obj/random/drinkbottle, + /obj/random/drinkbottle, + /obj/random/drinkbottle, + /obj/random/cigarettes, + /obj/random/cigarettes, + /obj/random/cigarettes, + /obj/structure/closet/crate/gilthari //GILTHARI LUXURY + ), + prob(10);list( + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/structure/closet/crate/grayson //GRAYSON TECH + ), + prob(15);list( + /obj/random/multiple/ore_pile, + /obj/random/multiple/ore_pile, + /obj/random/multiple/ore_pile, + /obj/random/multiple/ore_pile, + /obj/structure/closet/crate/grayson //GRAYSON ORES + ), + prob(10);list( + /obj/random/material/refined, + /obj/random/material/refined, + /obj/random/material/refined, + /obj/random/material/refined, + /obj/structure/closet/crate/grayson //GRAYSON MATS + ), + prob(2);list( + /obj/random/energy, + /obj/random/energy, + /obj/item/weapon/cell/device/weapon, + /obj/item/weapon/cell/device/weapon, + /obj/item/weapon/cell/device/weapon, + /obj/item/weapon/cell/device/weapon, + /obj/structure/closet/crate/secure/heph //HEPHAESTUS ENERGY + ), + prob(1);list( + /obj/random/grenade/box, + /obj/random/grenade/box, + /obj/structure/closet/crate/secure/heph //HEPHAESTUS GRENADES + ), + prob(2);list( + /obj/random/projectile/random, + /obj/random/projectile/random, + /obj/structure/closet/crate/secure/lawson //LAWSON PROJECTILE + ), + prob(3);list( + /obj/random/grenade/less_lethal, + /obj/random/grenade/less_lethal, + /obj/random/grenade/less_lethal, + /obj/random/grenade/less_lethal, + /obj/structure/closet/crate/secure/nanotrasen //NTSEC CROWD GRENADES + ), + prob(5);list( + /obj/random/multiple/voidsuit/security, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/structure/closet/crate/secure/nanotrasen //NTSEC SUIT + ), + prob(5);list( + /obj/random/multiple/voidsuit/medical, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/structure/closet/crate/secure/veymed //VM SUIT + ), + prob(5);list( + /obj/random/multiple/voidsuit/mining, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/structure/closet/crate/grayson //GRAYSON SUIT + ), + prob(5);list( + /obj/random/multiple/voidsuit/engineering, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/structure/closet/crate/xion //XION SUIT + ), + prob(10);list( + /obj/random/firstaid, + /obj/random/medical, + /obj/random/medical, + /obj/random/medical, + /obj/random/medical/lite, + /obj/random/medical/lite, + /obj/structure/closet/crate/veymed //VM GRABBAG + ), + prob(10);list( + /obj/random/firstaid, + /obj/random/firstaid, + /obj/random/firstaid, + /obj/random/firstaid, + /obj/random/unidentified_medicine/fresh_medicine, + /obj/random/unidentified_medicine/fresh_medicine, + /obj/structure/closet/crate/veymed //VM FAKS + ), + prob(10);list( + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/structure/closet/crate/xion //XION SUPPLY + ), + prob(10);list( + /obj/random/firstaid, + /obj/random/medical, + /obj/random/medical/pillbottle, + /obj/random/medical/pillbottle, + /obj/random/medical/lite, + /obj/random/medical/lite, + /obj/structure/closet/crate/zenghu //ZENGHU GRABBAG + ), + prob(10);list( + /obj/random/medical/pillbottle, + /obj/random/medical/pillbottle, + /obj/random/medical/pillbottle, + /obj/random/medical/pillbottle, + /obj/random/unidentified_medicine/fresh_medicine, + /obj/random/unidentified_medicine/fresh_medicine, + /obj/structure/closet/crate/zenghu //ZENGHU PILLS + ), + prob(10);list( + /obj/item/device/toner, + /obj/item/device/toner, + /obj/item/device/toner, + /obj/item/weapon/clipboard, + /obj/item/weapon/clipboard, + /obj/item/weapon/pen/red, + /obj/item/weapon/pen/blue, + /obj/item/weapon/pen/blue, + /obj/item/device/camera_film, + /obj/item/weapon/folder/blue, + /obj/item/weapon/folder/red, + /obj/item/weapon/folder/yellow, + /obj/item/weapon/hand_labeler, + /obj/item/weapon/tape_roll, + /obj/item/weapon/paper_bin, + /obj/item/sticky_pad/random, + /obj/structure/closet/crate/ummarcar //UMMARCAR OFFICE TRASH + ), + prob(5);list( + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/structure/closet/crate/unathi //UNAJERKY + ), + prob(10);list( + /obj/item/weapon/reagent_containers/glass/bucket, + /obj/item/weapon/mop, + /obj/item/clothing/under/rank/janitor, + /obj/item/weapon/cartridge/janitor, + /obj/item/clothing/gloves/black, + /obj/item/clothing/head/soft/purple, + /obj/item/weapon/storage/belt/janitor, + /obj/item/clothing/shoes/galoshes, + /obj/item/weapon/storage/bag/trash, + /obj/item/device/lightreplacer, + /obj/item/weapon/reagent_containers/spray/cleaner, + /obj/item/weapon/reagent_containers/glass/rag, + /obj/item/weapon/grenade/chem_grenade/cleaner, + /obj/item/weapon/grenade/chem_grenade/cleaner, + /obj/item/weapon/grenade/chem_grenade/cleaner, + /obj/structure/closet/crate/galaksi //GALAKSI JANITOR SUPPLIES + ), + prob(5);list( + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/structure/closet/crate/allico //GUMMIES + ), + prob(2);list( + /obj/item/weapon/tank/phoron/pressurized, + /obj/item/weapon/tank/phoron/pressurized, + /obj/structure/closet/crate/secure/phoron //HQ FUEL TANKS + ), + prob(1);list( + /obj/random/contraband/nofail, + /obj/random/contraband/nofail, + /obj/random/unidentified_medicine/combat_medicine, + /obj/random/unidentified_medicine/combat_medicine, + /obj/random/projectile/random, + /obj/random/projectile/random, + /obj/random/mre, + /obj/random/mre, + /obj/structure/closet/crate/secure/saare //SAARE GRAB BAG + ), + prob(2);list( + /obj/random/grenade, + /obj/random/grenade, + /obj/random/grenade, + /obj/random/grenade, + /obj/random/grenade, + /obj/random/grenade, + /obj/structure/closet/crate/secure/saare //SAARE GRENADES + ), + prob(1);list( + /obj/random/cash/big, + /obj/random/cash/big, + /obj/random/cash/big, + /obj/random/cash/huge, + /obj/random/cash/huge, + /obj/random/cash/huge, + /obj/structure/closet/crate/secure/saare //SAARE CASH CRATE + ) + ) + +/obj/random/multiple/corp_crate/no_weapons + name = "random corporate crate (no weapons)" + desc = "A random corporate crate with thematic contents. No weapons." + icon = 'icons/obj/storage.dmi' + icon_state = "crate" + +/obj/random/multiple/corp_crate/no_weapons/item_to_spawn() + return pick( + prob(10);list( + /obj/random/tank, + /obj/random/tank, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath, + /obj/structure/closet/crate/aether //AETHER AIRSUPPLY + ), + prob(5);list( + /obj/random/multiple/voidsuit/vintage, + /obj/random/multiple/voidsuit/vintage, + /obj/random/tank, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath, + /obj/structure/closet/crate/aether //AETHER OLDSUITS + ), + prob(10);list( + /obj/random/mre, + /obj/random/mre, + /obj/random/mre, + /obj/random/mre, + /obj/random/mre, + /obj/structure/closet/crate/centauri //CENTAURI MRES + ), + prob(10);list( + /obj/random/drinksoft, + /obj/random/drinksoft, + /obj/random/drinksoft, + /obj/random/drinksoft, + /obj/random/drinksoft, + /obj/structure/closet/crate/freezer/centauri //CENTAURI SODA + ), + prob(10);list( + /obj/random/snack, + /obj/random/snack, + /obj/random/snack, + /obj/random/snack, + /obj/random/snack, + /obj/structure/closet/crate/freezer/centauri //CENTAURI SNACKS + ), + prob(10);list( + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/structure/closet/crate/einstein //EINSTEIN BATTERYPACK + ), + prob(5);list( + /obj/item/weapon/circuitboard/smes, + /obj/random/smes_coil, + /obj/random/smes_coil, + /obj/structure/closet/crate/focalpoint //FOCAL SMES + ), + prob(10);list( + /obj/item/weapon/module/power_control, + /obj/item/stack/cable_coil, + /obj/item/frame/apc, + /obj/item/weapon/cell/apc, + /obj/structure/closet/crate/focalpoint //FOCAL APC + ), + prob(5);list( + /obj/random/drinkbottle, + /obj/random/drinkbottle, + /obj/random/drinkbottle, + /obj/random/cigarettes, + /obj/random/cigarettes, + /obj/random/cigarettes, + /obj/structure/closet/crate/gilthari //GILTHARI LUXURY + ), + prob(10);list( + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/structure/closet/crate/grayson //GRAYSON TECH + ), + prob(15);list( + /obj/random/multiple/ore_pile, + /obj/random/multiple/ore_pile, + /obj/random/multiple/ore_pile, + /obj/random/multiple/ore_pile, + /obj/structure/closet/crate/grayson //GRAYSON ORES + ), + prob(10);list( + /obj/random/material/refined, + /obj/random/material/refined, + /obj/random/material/refined, + /obj/random/material/refined, + /obj/structure/closet/crate/grayson //GRAYSON MATS + ), + prob(5);list( + /obj/random/multiple/voidsuit/security, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/structure/closet/crate/secure/nanotrasen //NTSEC SUIT + ), + prob(5);list( + /obj/random/multiple/voidsuit/medical, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/structure/closet/crate/secure/veymed //VM SUIT + ), + prob(5);list( + /obj/random/multiple/voidsuit/mining, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/structure/closet/crate/grayson //GRAYSON SUIT + ), + prob(5);list( + /obj/random/multiple/voidsuit/engineering, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/structure/closet/crate/xion //XION SUIT + ), + prob(10);list( + /obj/random/firstaid, + /obj/random/medical, + /obj/random/medical, + /obj/random/medical, + /obj/random/medical/lite, + /obj/random/medical/lite, + /obj/structure/closet/crate/veymed //VM GRABBAG + ), + prob(10);list( + /obj/random/firstaid, + /obj/random/firstaid, + /obj/random/firstaid, + /obj/random/firstaid, + /obj/random/unidentified_medicine/fresh_medicine, + /obj/random/unidentified_medicine/fresh_medicine, + /obj/structure/closet/crate/veymed //VM FAKS + ), + prob(10);list( + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/structure/closet/crate/xion //XION SUPPLY + ), + prob(10);list( + /obj/random/firstaid, + /obj/random/medical, + /obj/random/medical/pillbottle, + /obj/random/medical/pillbottle, + /obj/random/medical/lite, + /obj/random/medical/lite, + /obj/structure/closet/crate/zenghu //ZENGHU GRABBAG + ), + prob(10);list( + /obj/random/medical/pillbottle, + /obj/random/medical/pillbottle, + /obj/random/medical/pillbottle, + /obj/random/medical/pillbottle, + /obj/random/unidentified_medicine/fresh_medicine, + /obj/random/unidentified_medicine/fresh_medicine, + /obj/structure/closet/crate/zenghu //ZENGHU PILLS + ), + prob(10);list( + /obj/item/device/toner, + /obj/item/device/toner, + /obj/item/device/toner, + /obj/item/weapon/clipboard, + /obj/item/weapon/clipboard, + /obj/item/weapon/pen/red, + /obj/item/weapon/pen/blue, + /obj/item/weapon/pen/blue, + /obj/item/device/camera_film, + /obj/item/weapon/folder/blue, + /obj/item/weapon/folder/red, + /obj/item/weapon/folder/yellow, + /obj/item/weapon/hand_labeler, + /obj/item/weapon/tape_roll, + /obj/item/weapon/paper_bin, + /obj/item/sticky_pad/random, + /obj/structure/closet/crate/ummarcar //UMMARCAR OFFICE TRASH + ), + prob(5);list( + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/structure/closet/crate/unathi //UNAJERKY + ), + prob(10);list( + /obj/item/weapon/reagent_containers/glass/bucket, + /obj/item/weapon/mop, + /obj/item/clothing/under/rank/janitor, + /obj/item/weapon/cartridge/janitor, + /obj/item/clothing/gloves/black, + /obj/item/clothing/head/soft/purple, + /obj/item/weapon/storage/belt/janitor, + /obj/item/clothing/shoes/galoshes, + /obj/item/weapon/storage/bag/trash, + /obj/item/device/lightreplacer, + /obj/item/weapon/reagent_containers/spray/cleaner, + /obj/item/weapon/reagent_containers/glass/rag, + /obj/item/weapon/grenade/chem_grenade/cleaner, + /obj/item/weapon/grenade/chem_grenade/cleaner, + /obj/item/weapon/grenade/chem_grenade/cleaner, + /obj/structure/closet/crate/galaksi //GALAKSI JANITOR SUPPLIES + ), + prob(5);list( + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/structure/closet/crate/allico //GUMMIES + ), + prob(2);list( + /obj/item/weapon/tank/phoron/pressurized, + /obj/item/weapon/tank/phoron/pressurized, + /obj/structure/closet/crate/secure/phoron //HQ FUEL TANKS + ), + prob(1);list( + /obj/random/cash/big, + /obj/random/cash/big, + /obj/random/cash/big, + /obj/random/cash/huge, + /obj/random/cash/huge, + /obj/random/cash/huge, + /obj/structure/closet/crate/secure/saare //SAARE CASH CRATE + ) + ) + +/obj/random/multiple/large_corp_crate + name = "random large corporate crate" + desc = "A random large corporate crate with thematic contents." + icon = 'icons/obj/storage.dmi' + icon_state = "largermetal" + +/obj/random/multiple/large_corp_crate/item_to_spawn() + return pick( + prob(30);list( + /obj/random/multiple/voidsuit/vintage, + /obj/random/multiple/voidsuit/vintage, + /obj/random/tank, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath, + /obj/random/multiple/voidsuit/vintage, + /obj/random/multiple/voidsuit/vintage, + /obj/random/tank, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath, + /obj/structure/closet/crate/large/aether //AETHER SUITSBOX + ), + prob(30);list( + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/structure/closet/crate/large/einstein //EIN BATTERY MEGAPACK + ), + prob(20);list( + /obj/item/weapon/circuitboard/smes, + /obj/item/weapon/circuitboard/smes, + /obj/random/smes_coil, + /obj/random/smes_coil, + /obj/random/smes_coil, + /obj/random/smes_coil, + /obj/random/smes_coil, + /obj/random/smes_coil, + /obj/structure/closet/crate/large/einstein //EIN SMESBOX + ), + prob(2);list( + /obj/random/energy, + /obj/random/energy, + /obj/item/weapon/cell/device/weapon, + /obj/item/weapon/cell/device/weapon, + /obj/item/weapon/cell/device/weapon, + /obj/item/weapon/cell/device/weapon, + /obj/random/energy, + /obj/random/energy, + /obj/item/weapon/cell/device/weapon, + /obj/item/weapon/cell/device/weapon, + /obj/item/weapon/cell/device/weapon, + /obj/item/weapon/cell/device/weapon, + /obj/structure/closet/crate/large/secure/heph //HEPH ENERGY + ), + prob(2);list( + /obj/random/projectile/random, + /obj/random/projectile/random, + /obj/random/projectile/random, + /obj/random/projectile/random, + /obj/structure/closet/crate/large/secure/heph //HEPH BALLISTICS + ), + prob(20);list( + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/structure/closet/crate/large/xion //XION TECH SUPPLY + ), + prob(20);list( + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/structure/closet/crate/large/secure/xion //XION TECH COMPS + ) + ) + +/obj/random/multiple/large_corp_crate/no_weapons + name = "random large corporate crate (no weapons)" + desc = "A random large corporate crate with thematic contents. No weapons." + icon = 'icons/obj/storage.dmi' + icon_state = "largermetal" + +/obj/random/multiple/large_corp_crate/no_weapons/item_to_spawn() + return pick( + prob(30);list( + /obj/random/multiple/voidsuit/vintage, + /obj/random/multiple/voidsuit/vintage, + /obj/random/tank, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath, + /obj/random/multiple/voidsuit/vintage, + /obj/random/multiple/voidsuit/vintage, + /obj/random/tank, + /obj/random/tank, + /obj/item/clothing/mask/breath, + /obj/item/clothing/mask/breath, + /obj/structure/closet/crate/large/aether //AETHER SUITSBOX + ), + prob(30);list( + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/random/powercell, + /obj/structure/closet/crate/large/einstein //EIN BATTERY MEGAPACK + ), + prob(20);list( + /obj/item/weapon/circuitboard/smes, + /obj/item/weapon/circuitboard/smes, + /obj/random/smes_coil, + /obj/random/smes_coil, + /obj/random/smes_coil, + /obj/random/smes_coil, + /obj/random/smes_coil, + /obj/random/smes_coil, + /obj/structure/closet/crate/large/einstein //EIN SMESBOX + ), + prob(20);list( + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/random/tech_supply/nofail, + /obj/structure/closet/crate/large/xion //XION TECH SUPPLY + ), + prob(20);list( + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/random/tech_supply/component/nofail, + /obj/structure/closet/crate/large/secure/xion //XION TECH COMPS + ) + ) + +//recursion crate! +/obj/random/multiple/random_size_crate + name = "random size corporate crate" + desc = "A random size corporate crate with thematic contents: prefers small crates." + icon = 'icons/obj/storage.dmi' + icon_state = "largermetal" + +/obj/random/multiple/random_size_crate/item_to_spawn() + return pick( + prob(85);list( + /obj/random/multiple/corp_crate + ), + prob(15);list( + /obj/random/multiple/large_corp_crate + ) + ) /* * Turf swappers. */ diff --git a/code/game/objects/random/mapping_vr.dm b/code/game/objects/random/mapping_vr.dm new file mode 100644 index 0000000000..43431a8b16 --- /dev/null +++ b/code/game/objects/random/mapping_vr.dm @@ -0,0 +1,10 @@ +/obj/random/empty_or_lootable_crate + name = "random crate" + desc = "Spawns a random crate which may or may not have contents. Sometimes spawns nothing." + icon = 'icons/obj/storage.dmi' + icon_state = "moneybag" + spawn_nothing_percentage = 20 + +/obj/random/empty_or_lootable_crate/item_to_spawn() + return pick(/obj/random/crate, + /obj/random/multiple/corp_crate) \ No newline at end of file diff --git a/code/game/objects/random/misc.dm b/code/game/objects/random/misc.dm index 380c1839d2..9b33ec232f 100644 --- a/code/game/objects/random/misc.dm +++ b/code/game/objects/random/misc.dm @@ -108,6 +108,27 @@ prob(2);/obj/item/weapon/storage/toolbox/emergency, prob(1);/obj/item/weapon/storage/toolbox/syndicate) +/obj/random/smes_coil + name = "random smes coil" + desc = "This is a random smes coil." + icon = 'icons/obj/power.dmi' + icon_state = "smes" + +/obj/random/smes_coil/item_to_spawn() + return pick(prob(4);/obj/item/weapon/smes_coil, + prob(1);/obj/item/weapon/smes_coil/super_capacity, + prob(1);/obj/item/weapon/smes_coil/super_io) + +/obj/random/pacman + name = "random portable generator" + desc = "This is a random portable generator." + icon = 'icons/obj/power.dmi' + icon_state = "portgen0" + +/obj/random/pacman/item_to_spawn() + return pick(prob(6);/obj/machinery/power/port_gen/pacman, + prob(3);/obj/machinery/power/port_gen/pacman/super, + prob(1);/obj/machinery/power/port_gen/pacman/mrs) /obj/random/tech_supply name = "random tech supply" @@ -133,6 +154,10 @@ prob(1);/obj/item/taperoll/atmos, prob(1);/obj/item/device/flashlight/maglight) +/obj/random/tech_supply/nofail + name = "guaranteed random tech supply" + spawn_nothing_percentage = 0 + /obj/random/tech_supply/component name = "random tech component" desc = "This is a random machine component." @@ -156,6 +181,10 @@ prob(2);/obj/item/weapon/stock_parts/scanning_module/adv, prob(1);/obj/item/weapon/stock_parts/scanning_module/phasic) +/obj/random/tech_supply/component/nofail + name = "guaranteed random tech component" + spawn_nothing_percentage = 0 + /obj/random/medical name = "Random Medicine" desc = "This is a random medical item." @@ -248,6 +277,10 @@ prob(2);/obj/item/weapon/reagent_containers/syringe/drugs, prob(1);/obj/item/weapon/reagent_containers/syringe/steroid) +/obj/random/contraband/nofail + name = "Guaranteed Random Illegal Item" + spawn_nothing_percentage = 0 + /obj/random/cash name = "random currency" desc = "LOADSAMONEY!" @@ -262,6 +295,32 @@ prob(1);/obj/item/weapon/spacecash/c50, prob(1);/obj/item/weapon/spacecash/c100) +/obj/random/cash/big + name = "random currency pile" + desc = "DOSH!" + icon = 'icons/obj/items.dmi' + icon_state = "spacecash100" + +/obj/random/cash/big/item_to_spawn() + return pick(prob(64);/obj/item/weapon/spacecash/c10, + prob(32);/obj/item/weapon/spacecash/c20, + prob(16);/obj/item/weapon/spacecash/c50, + prob(8);/obj/item/weapon/spacecash/c100, + prob(4);/obj/item/weapon/spacecash/c200, + prob(2);/obj/item/weapon/spacecash/c500, + prob(1);/obj/item/weapon/spacecash/c1000) + +/obj/random/cash/huge + name = "random huge currency pile" + desc = "LOOK AT MY WAD!" + icon = 'icons/obj/items.dmi' + icon_state = "spacecash1000" + +/obj/random/cash/huge/item_to_spawn() + return pick(prob(15);/obj/item/weapon/spacecash/c200, + prob(10);/obj/item/weapon/spacecash/c500, + prob(5);/obj/item/weapon/spacecash/c1000) + /obj/random/soap name = "Random Soap" desc = "This is a random bar of soap." @@ -291,7 +350,111 @@ /obj/item/weapon/reagent_containers/food/drinks/bottle/wine, /obj/item/weapon/reagent_containers/food/drinks/bottle/cognac, /obj/item/weapon/reagent_containers/food/drinks/bottle/rum, - /obj/item/weapon/reagent_containers/food/drinks/bottle/patron) + /obj/item/weapon/reagent_containers/food/drinks/bottle/patron, + /obj/item/weapon/reagent_containers/food/drinks/bottle/vermouth, + /obj/item/weapon/reagent_containers/food/drinks/bottle/goldschlager, + /obj/item/weapon/reagent_containers/food/drinks/bottle/kahlua, + /obj/item/weapon/reagent_containers/food/drinks/bottle/melonliquor, + /obj/item/weapon/reagent_containers/food/drinks/bottle/bluecuracao, + /obj/item/weapon/reagent_containers/food/drinks/bottle/grenadine, + /obj/item/weapon/reagent_containers/food/drinks/bottle/sake, + /obj/item/weapon/reagent_containers/food/drinks/bottle/champagne, + /obj/item/weapon/reagent_containers/food/drinks/bottle/peppermintschnapps, + /obj/item/weapon/reagent_containers/food/drinks/bottle/peachschnapps, + /obj/item/weapon/reagent_containers/food/drinks/bottle/lemonadeschnapps, + /obj/item/weapon/reagent_containers/food/drinks/bottle/small/cider, + /obj/item/weapon/reagent_containers/food/drinks/bottle/small/litebeer, + /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer, + /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer/silverdragon, + /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer/meteor) + +/obj/random/drinksoft + name = "random soft drink" + desc = "This is a random (once) carbonated beverage drinks can." + icon = 'icons/obj/drinks.dmi' + icon_state = "cola" + +/obj/random/drinksoft/item_to_spawn() + return pick(/obj/item/weapon/reagent_containers/food/drinks/cans/cola, + /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle, + /obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind, + /obj/item/weapon/reagent_containers/food/drinks/cans/thirteenloko, + /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb, + /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb_diet, + /obj/item/weapon/reagent_containers/food/drinks/cans/starkist, + /obj/item/weapon/reagent_containers/food/drinks/cans/space_up, + /obj/item/weapon/reagent_containers/food/drinks/cans/lemon_lime, + /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea, + /obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice, + /obj/item/weapon/reagent_containers/food/drinks/cans/tonic, + /obj/item/weapon/reagent_containers/food/drinks/cans/sodawater, + /obj/item/weapon/reagent_containers/food/drinks/cans/gingerale, + /obj/item/weapon/reagent_containers/food/drinks/cans/root_beer) + + +/obj/random/snack + name = "random snack" + desc = "This is a random snackfood. Probably still safe to eat?" + icon = 'icons/obj/food_snacks.dmi' + icon_state = "tastybread" + +/obj/random/snack/item_to_spawn() + return pick(/obj/item/weapon/reagent_containers/food/snacks/candy, + /obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar, + /obj/item/weapon/reagent_containers/food/snacks/candy/gummy, + /obj/item/weapon/reagent_containers/food/snacks/candy/donor, + /obj/item/weapon/reagent_containers/food/snacks/candy_corn, + /obj/item/weapon/reagent_containers/food/snacks/chips, + /obj/item/weapon/reagent_containers/food/snacks/chips/bbq, + /obj/item/weapon/reagent_containers/food/snacks/cookie, + /obj/item/weapon/reagent_containers/food/snacks/cookiesnack, + /obj/item/weapon/reagent_containers/food/snacks/fruitbar, + /obj/item/weapon/reagent_containers/food/snacks/chocolatebar, + /obj/item/weapon/reagent_containers/food/snacks/chocolatepiece, + /obj/item/weapon/reagent_containers/food/snacks/chocolatepiece/white, + /obj/item/weapon/reagent_containers/food/snacks/chocolatepiece/truffle, + /obj/item/weapon/reagent_containers/food/snacks/chocolateegg, + /obj/item/weapon/reagent_containers/food/snacks/donut, + /obj/item/weapon/reagent_containers/food/snacks/donut/normal, + /obj/item/weapon/reagent_containers/food/snacks/donut/jelly, + /obj/item/weapon/reagent_containers/food/snacks/donut/cherryjelly, + /obj/item/weapon/reagent_containers/food/snacks/tuna, + /obj/item/weapon/reagent_containers/food/snacks/pistachios, + /obj/item/weapon/reagent_containers/food/snacks/semki, + /obj/item/weapon/reagent_containers/food/snacks/cb01, + /obj/item/weapon/reagent_containers/food/snacks/cb02, + /obj/item/weapon/reagent_containers/food/snacks/cb03, + /obj/item/weapon/reagent_containers/food/snacks/cb04, + /obj/item/weapon/reagent_containers/food/snacks/cb05, + /obj/item/weapon/reagent_containers/food/snacks/cb06, + /obj/item/weapon/reagent_containers/food/snacks/cb07, + /obj/item/weapon/reagent_containers/food/snacks/cb08, + /obj/item/weapon/reagent_containers/food/snacks/cb09, + /obj/item/weapon/reagent_containers/food/snacks/cb10, + /obj/item/weapon/reagent_containers/food/snacks/tofu, + /obj/item/weapon/reagent_containers/food/snacks/donkpocket, + /obj/item/weapon/reagent_containers/food/snacks/muffin, + /obj/item/weapon/reagent_containers/food/snacks/soylentgreen, + /obj/item/weapon/reagent_containers/food/snacks/soylenviridians, + /obj/item/weapon/reagent_containers/food/snacks/popcorn, + /obj/item/weapon/reagent_containers/food/snacks/sosjerky, + /obj/item/weapon/reagent_containers/food/snacks/no_raisin, + /obj/item/weapon/reagent_containers/food/snacks/spacetwinkie, + /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers, + /obj/item/weapon/reagent_containers/food/snacks/poppypretzel, + /obj/item/weapon/reagent_containers/food/snacks/baguette, + /obj/item/weapon/reagent_containers/food/snacks/carrotfries, + /obj/item/weapon/reagent_containers/food/snacks/candiedapple, + /obj/item/weapon/storage/box/admints, + /obj/item/weapon/reagent_containers/food/snacks/tastybread, + /obj/item/weapon/reagent_containers/food/snacks/liquidfood, + /obj/item/weapon/reagent_containers/food/snacks/liquidprotein, + /obj/item/weapon/reagent_containers/food/snacks/liquidvitamin, + /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks, + /obj/item/weapon/reagent_containers/food/snacks/unajerky, + /obj/item/weapon/reagent_containers/food/snacks/croissant, + /obj/item/weapon/reagent_containers/food/snacks/sugarcookie, + /obj/item/weapon/reagent_containers/food/drinks/dry_ramen) /obj/random/meat name = "random meat" @@ -326,8 +489,8 @@ /obj/random/material //Random materials for building stuff name = "random material" desc = "This is a random material." - icon = 'icons/obj/items.dmi' - icon_state = "sheet-metal" + icon = 'icons/obj/stacks.dmi' + icon_state = "sheet-metal_2" /obj/random/material/item_to_spawn() return pick(/obj/item/stack/material/steel{amount = 10}, @@ -339,6 +502,35 @@ /obj/item/stack/rods{amount = 10}, /obj/item/stack/material/plasteel{amount = 10}) +/obj/random/material/refined //Random materials for building stuff + name = "random refined material" + desc = "This is a random refined metal." + icon = 'icons/obj/stacks.dmi' + icon_state = "sheet-adamantine_3" + +/obj/random/material/refined/item_to_spawn() + return pick(/obj/item/stack/material/steel{amount = 10}, + /obj/item/stack/material/glass{amount = 10}, + /obj/item/stack/material/glass/reinforced{amount = 5}, + /obj/item/stack/material/glass/phoronglass{amount = 5}, + /obj/item/stack/material/glass/phoronrglass{amount = 5}, + /obj/item/stack/material/plasteel{amount = 5}, + /obj/item/stack/material/durasteel{amount = 5}, + /obj/item/stack/material/gold{amount = 5}, + /obj/item/stack/material/iron{amount = 10}, + /obj/item/stack/material/lead{amount = 10}, + /obj/item/stack/material/diamond{amount = 3}, + /obj/item/stack/material/deuterium{amount = 5}, + /obj/item/stack/material/uranium{amount = 5}, + /obj/item/stack/material/phoron{amount = 5}, + /obj/item/stack/material/silver{amount = 5}, + /obj/item/stack/material/platinum{amount = 5}, + /obj/item/stack/material/mhydrogen{amount = 3}, + /obj/item/stack/material/osmium{amount = 3}, + /obj/item/stack/material/titanium{amount = 5}, + /obj/item/stack/material/tritium{amount = 3}, + /obj/item/stack/material/verdantium{amount = 2}) + /obj/random/tank name = "random tank" desc = "This is a tank." diff --git a/code/game/objects/random/spacesuits.dm b/code/game/objects/random/spacesuits.dm index 29bd799c5c..da380f2842 100644 --- a/code/game/objects/random/spacesuits.dm +++ b/code/game/objects/random/spacesuits.dm @@ -4,7 +4,7 @@ /obj/random/multiple/voidsuit name = "Random Voidsuit" desc = "This is a random voidsuit." - icon = 'icons/obj/clothing/suits.dmi' + icon = 'icons/obj/clothing/spacesuits.dmi' icon_state = "void" /obj/random/multiple/voidsuit/item_to_spawn() @@ -29,6 +29,10 @@ /obj/item/clothing/suit/space/void/engineering/alt, /obj/item/clothing/head/helmet/space/void/engineering/alt ), + prob(5);list( + /obj/item/clothing/suit/space/void/engineering/hazmat, + /obj/item/clothing/head/helmet/space/void/engineering/hazmat + ), prob(5);list( /obj/item/clothing/suit/space/void/engineering/construction, /obj/item/clothing/head/helmet/space/void/engineering/construction @@ -57,6 +61,10 @@ /obj/item/clothing/suit/space/void/merc, /obj/item/clothing/head/helmet/space/void/merc ), + prob(5);list( + /obj/item/clothing/suit/space/void/merc/fire, + /obj/item/clothing/head/helmet/space/void/merc/fire + ), prob(5);list( /obj/item/clothing/suit/space/void/mining, /obj/item/clothing/head/helmet/space/void/mining @@ -76,13 +84,21 @@ prob(5);list( /obj/item/clothing/suit/space/void/security/riot, /obj/item/clothing/head/helmet/space/void/security/riot + ), + prob(5);list( + /obj/item/clothing/suit/space/void/exploration, + /obj/item/clothing/head/helmet/space/void/exploration + ), + prob(5);list( + /obj/item/clothing/suit/space/void/pilot, + /obj/item/clothing/head/helmet/space/void/pilot ) ) /obj/random/multiple/voidsuit/mining name = "Random Mining Voidsuit" desc = "This is a random mining voidsuit." - icon = 'icons/obj/clothing/suits.dmi' + icon = 'icons/obj/clothing/spacesuits.dmi' icon_state = "rig-mining" /obj/random/multiple/voidsuit/mining/item_to_spawn() @@ -97,11 +113,63 @@ ) ) +/obj/random/multiple/voidsuit/engineering + name = "Random Engineering Voidsuit" + desc = "This is a random engineering voidsuit." + icon = 'icons/obj/clothing/spacesuits.dmi' + icon_state = "rig-engineering" + +/obj/random/multiple/voidsuit/engineering/item_to_spawn() + return pick( + prob(35);list( + /obj/item/clothing/suit/space/void/engineering, + /obj/item/clothing/head/helmet/space/void/engineering + ), + prob(5);list( + /obj/item/clothing/suit/space/void/engineering/alt, + /obj/item/clothing/head/helmet/space/void/engineering/alt + ), + prob(15);list( + /obj/item/clothing/suit/space/void/engineering/hazmat, + /obj/item/clothing/head/helmet/space/void/engineering/hazmat + ), + prob(15);list( + /obj/item/clothing/suit/space/void/engineering/construction, + /obj/item/clothing/head/helmet/space/void/engineering/construction + ), + prob(5);list( + /obj/item/clothing/suit/space/void/engineering/salvage, + /obj/item/clothing/head/helmet/space/void/engineering/salvage + ) + ) + +/obj/random/multiple/voidsuit/security + name = "Random Security Voidsuit" + desc = "This is a random security voidsuit." + icon = 'icons/obj/clothing/spacesuits.dmi' + icon_state = "rig-sec" + +/obj/random/multiple/voidsuit/security/item_to_spawn() + return pick( + prob(10);list( + /obj/item/clothing/suit/space/void/security, + /obj/item/clothing/head/helmet/space/void/security + ), + prob(5);list( + /obj/item/clothing/suit/space/void/security/alt, + /obj/item/clothing/head/helmet/space/void/security/alt + ), + prob(5);list( + /obj/item/clothing/suit/space/void/security/riot, + /obj/item/clothing/head/helmet/space/void/security/riot + ) + ) + /obj/random/multiple/voidsuit/medical - name = "Random Mining Voidsuit" - desc = "This is a random mining voidsuit." - icon = 'icons/obj/clothing/suits.dmi' - icon_state = "rig-mining" + name = "Random Medical Voidsuit" + desc = "This is a random medical voidsuit." + icon = 'icons/obj/clothing/spacesuits.dmi' + icon_state = "rig-medical" /obj/random/multiple/voidsuit/medical/item_to_spawn() return pick( @@ -123,6 +191,60 @@ ) ) +/obj/random/multiple/voidsuit/vintage + name = "Random Vintage Voidsuit" + desc = "This is a random vintage voidsuit." + icon = 'icons/obj/clothing/spacesuits.dmi' + icon_state = "rig-vintagecrew" + +/obj/random/multiple/voidsuit/vintage/item_to_spawn() + return pick( + prob(20);list( + /obj/item/clothing/suit/space/void/refurb, + /obj/item/clothing/head/helmet/space/void/refurb + ), + prob(20);list( + /obj/item/clothing/suit/space/void/refurb/engineering, + /obj/item/clothing/head/helmet/space/void/refurb/engineering + ), + prob(10);list( + /obj/item/clothing/suit/space/void/refurb/medical, + /obj/item/clothing/head/helmet/space/void/refurb/medical + ), + prob(10);list( + /obj/item/clothing/suit/space/void/refurb/medical, + /obj/item/clothing/head/helmet/space/void/refurb/medical/alt + ), + prob(10);list( + /obj/item/clothing/suit/space/void/refurb/marine, + /obj/item/clothing/head/helmet/space/void/refurb/marine + ), + prob(5);list( + /obj/item/clothing/suit/space/void/refurb/officer, + /obj/item/clothing/head/helmet/space/void/refurb/officer + ), + prob(10);list( + /obj/item/clothing/suit/space/void/refurb/pilot, + /obj/item/clothing/head/helmet/space/void/refurb/pilot + ), + prob(10);list( + /obj/item/clothing/suit/space/void/refurb/pilot, + /obj/item/clothing/head/helmet/space/void/refurb/pilot/alt + ), + prob(10);list( + /obj/item/clothing/suit/space/void/refurb/research, + /obj/item/clothing/head/helmet/space/void/refurb/research + ), + prob(10);list( + /obj/item/clothing/suit/space/void/refurb/research, + /obj/item/clothing/head/helmet/space/void/refurb/research/alt + ), + prob(5);list( + /obj/item/clothing/suit/space/void/refurb/mercenary, + /obj/item/clothing/head/helmet/space/void/refurb/mercenary + ) + ) + /obj/random/rigsuit name = "Random rigsuit" desc = "This is a random rigsuit." diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index fc136cfda8..29498bb2df 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -16,8 +16,8 @@ LINEN BINS throw_speed = 1 throw_range = 2 w_class = ITEMSIZE_SMALL - drop_sound = 'sound/items/drop/cloth.ogg' - pickup_sound = 'sound/items/pickup/cloth.ogg' + drop_sound = 'sound/items/drop/clothing.ogg' + pickup_sound = 'sound/items/pickup/clothing.ogg' /obj/item/weapon/bedsheet/attack_self(mob/user as mob) user.drop_item() diff --git a/code/game/objects/structures/bonfire.dm b/code/game/objects/structures/bonfire.dm index 87dc47aa0d..005686eeca 100644 --- a/code/game/objects/structures/bonfire.dm +++ b/code/game/objects/structures/bonfire.dm @@ -9,7 +9,7 @@ var/burning = FALSE var/next_fuel_consumption = 0 // world.time of when next item in fuel list gets eatten to sustain the fire. var/grill = FALSE - var/material/material + var/datum/material/material var/set_temperature = T0C + 30 //K var/heating_power = 80000 diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index 99f83f49c4..7372c980ff 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -102,7 +102,8 @@ /obj/item/clothing/suit/storage/hooded/wintercoat/security, /obj/item/clothing/shoes/boots/winter/security, /obj/item/device/flashlight/maglight, - /obj/item/clothing/mask/gas/half) + /obj/item/clothing/mask/gas/half, + /obj/item/clothing/mask/gas/sechailer/swat/hos) /obj/structure/closet/secure_closet/hos/Initialize() if(prob(50)) @@ -116,6 +117,7 @@ /obj/structure/closet/secure_closet/warden name = "warden's locker" + storage_capacity = 42 req_access = list(access_armory) closet_appearance = /decl/closet_appearance/secure_closet/security/warden diff --git a/code/game/objects/structures/crates_lockers/closets/walllocker.dm b/code/game/objects/structures/crates_lockers/closets/walllocker.dm index 82afaa33ff..64f5a0fbd8 100644 --- a/code/game/objects/structures/crates_lockers/closets/walllocker.dm +++ b/code/game/objects/structures/crates_lockers/closets/walllocker.dm @@ -54,3 +54,25 @@ /obj/structure/closet/walllocker/emerglocker/east pixel_x = 32 dir = EAST + +//VOREStation Add Start +/obj/structure/closet/walllocker/medical + name = "first-aid closet" + desc = "It's wall-mounted storage unit for first aid supplies." + closet_appearance = /decl/closet_appearance/wall/medical + +/obj/structure/closet/walllocker/medical/north + pixel_y = 32 + dir = SOUTH + +/obj/structure/closet/walllocker/medical/south + pixel_y = -32 + dir = NORTH + +/obj/structure/closet/walllocker/medical/west + pixel_x = -32 + dir = WEST + +/obj/structure/closet/walllocker/medical/east + pixel_x = 32 + dir = EAST \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm index f02c5d44c8..6c88090e40 100644 --- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm +++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm @@ -420,7 +420,8 @@ /obj/item/clothing/gloves/swat, /obj/item/clothing/mask/balaclava/tactical, /obj/item/clothing/mask/balaclava, - /obj/item/clothing/mask/bandana/skull = 2) + /obj/item/clothing/mask/bandana/skull = 2, + /obj/item/clothing/mask/gas/sechailer/swat) /obj/structure/closet/wardrobe/suit diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe_vr.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe_vr.dm new file mode 100644 index 0000000000..ffeeae996a --- /dev/null +++ b/code/game/objects/structures/crates_lockers/closets/wardrobe_vr.dm @@ -0,0 +1,27 @@ +//ert wardrobe override, because these guys really don't need edgy red lockers with CCO dress uniforms, syndi(!!) turtlenecks, two edgy skull bandanas, or facemasks with no sprite. -Killian +/obj/structure/closet/wardrobe/ert + closet_appearance = /decl/closet_appearance/tactical/alt //because ert lockers are red for some dumb reason + starts_with = list( + /obj/item/clothing/under/ert, + /obj/item/device/radio/headset/ert/alt, + /obj/item/clothing/glasses/sunglasses, + /obj/item/clothing/shoes/boots/swat, + /obj/item/clothing/gloves/swat, + /obj/item/clothing/mask/balaclava/tactical, + /obj/item/clothing/mask/balaclava) + +//would you believe mercs have no official locker? well, now they do. basically just a rebranded ERT locker but hey, it's an option. -Killian +/obj/structure/closet/wardrobe/merc + name = "mercenary equipment" + closet_appearance = /decl/closet_appearance/tactical + + starts_with = list( + /obj/item/clothing/under/tactical, + /obj/item/clothing/under/syndicate/combat, + /obj/item/device/radio/headset/syndicate/alt, + /obj/item/clothing/glasses/sunglasses, + /obj/item/clothing/shoes/boots/combat, + /obj/item/clothing/gloves/combat, + /obj/item/clothing/mask/balaclava/tactical, + /obj/item/clothing/mask/balaclava, + /obj/item/clothing/mask/bandana/skull) \ No newline at end of file diff --git a/code/game/objects/structures/flora/flora_vr.dm b/code/game/objects/structures/flora/flora_vr.dm index 2e27319770..1050110cea 100644 --- a/code/game/objects/structures/flora/flora_vr.dm +++ b/code/game/objects/structures/flora/flora_vr.dm @@ -36,3 +36,64 @@ /obj/structure/flora/pumpkin/carved/owo desc = "A fat, freshly picked pumpkin. This one has a face carved into it! This one has large, round eyes and a squiggly, cat-like smiling mouth. Its pleasantly surprised expression seems to suggest that the pumpkin has noticed something about you." icon_state = "decor-jackolantern-owo" + +// Various decorá +/obj/structure/flora/log1 + name = "waterlogged trunk" + icon = 'icons/obj/flora/amayastuff.dmi' + desc = "A part of a felled tree. It is soaking up the water it is bouyant on." + icon_state = "log1" + +/obj/structure/flora/log2 + name = "waterlogged trunk" + icon = 'icons/obj/flora/amayastuff.dmi' + desc = "A part of a felled tree. It is soaking up the water it is bouyant on." + icon_state = "log2" + +/obj/structure/flora/lily1 + name = "waterlogged trunk" + icon = 'icons/obj/flora/amayastuff.dmi' + desc = "A part of a felled tree. It is soaking up the water it is bouyant on." + icon_state = "lilypad1" + +/obj/structure/flora/lily2 + name = "waterlogged trunk" + icon = 'icons/obj/flora/amayastuff.dmi' + desc = "A part of a felled tree. It is soaking up the water it is bouyant on." + icon_state = "lilypad2" + +/obj/structure/flora/lily3 + name = "waterlogged trunk" + icon = 'icons/obj/flora/amayastuff.dmi' + desc = "A part of a felled tree. It is soaking up the water it is bouyant on." + icon_state = "lilypad3" + +/obj/structure/flora/smallbould + name = "waterlogged trunk" + icon = 'icons/obj/flora/amayastuff.dmi' + desc = "A part of a felled tree. It is soaking up the water it is bouyant on." + icon_state = "smallerboulder" + +/obj/structure/flora/bboulder1 + name = "waterlogged trunk" + icon = 'icons/obj/flora/amayastuff.dmi' + desc = "A part of a felled tree. It is soaking up the water it is bouyant on." + icon_state = "bigboulder1" + +/obj/structure/flora/bboulder2 + name = "waterlogged trunk" + icon = 'icons/obj/flora/amayastuff.dmi' + desc = "A part of a felled tree. It is soaking up the water it is bouyant on." + icon_state = "bigboulder2" + +/obj/structure/flora/rocks1 + name = "waterlogged trunk" + icon = 'icons/obj/flora/amayastuff.dmi' + desc = "A part of a felled tree. It is soaking up the water it is bouyant on." + icon_state = "rocks1" + +/obj/structure/flora/rocks2 + name = "waterlogged trunk" + icon = 'icons/obj/flora/amayastuff.dmi' + desc = "A part of a felled tree. It is soaking up the water it is bouyant on." + icon_state = "rocks2" \ No newline at end of file diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index aab0ecf7f0..79c6023ff5 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -11,8 +11,8 @@ var/current_damage = 0 var/cover = 50 //how much cover the girder provides against projectiles. var/default_material = DEFAULT_WALL_MATERIAL - var/material/girder_material - var/material/reinf_material + var/datum/material/girder_material + var/datum/material/reinf_material var/reinforcing = 0 var/applies_material_colour = 1 @@ -226,7 +226,7 @@ to_chat(user, "There isn't enough material here to construct a wall.") return 0 - var/material/M = name_to_material[S.default_type] + var/datum/material/M = name_to_material[S.default_type] if(!istype(M)) return 0 @@ -267,7 +267,7 @@ to_chat(user, "There isn't enough material here to reinforce the girder.") return 0 - var/material/M = name_to_material[S.default_type] + var/datum/material/M = name_to_material[S.default_type] if(!istype(M) || M.integrity < 50) to_chat(user, "You cannot reinforce \the [src] with that; it is too soft.") return 0 @@ -401,7 +401,7 @@ var/turf/simulated/wall/new_T = get_turf(src) // Ref to the wall we just built. // Apparently set_material(...) for walls requires refs to the material singletons and not strings. // This is different from how other material objects with their own set_material(...) do it, but whatever. - var/material/M = name_to_material[the_rcd.material_to_use] + var/datum/material/M = name_to_material[the_rcd.material_to_use] new_T.set_material(M, the_rcd.make_rwalls ? M : null, girder_material) new_T.add_hiddenprint(user) qdel(src) diff --git a/code/game/objects/structures/gravemarker.dm b/code/game/objects/structures/gravemarker.dm index d5b7773910..ff02bb4ae2 100644 --- a/code/game/objects/structures/gravemarker.dm +++ b/code/game/objects/structures/gravemarker.dm @@ -17,7 +17,7 @@ var/epitaph = "" //A quick little blurb // var/dir_locked = 0 //Can it be spun? Not currently implemented - var/material/material + var/datum/material/material /obj/structure/gravemarker/New(var/newloc, var/material_name) ..(newloc) diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm index de07aa8de8..a6dc8e42ac 100644 --- a/code/game/objects/structures/janicart.dm +++ b/code/game/objects/structures/janicart.dm @@ -20,8 +20,90 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart) var/has_items = FALSE var/dismantled = TRUE var/signs = 0 //maximum capacity hardcoded below + var/list/tgui_icons = list() + var/static/list/equippable_item_whitelist +/obj/structure/janitorialcart/proc/equip_janicart_item(mob/user, obj/item/I) + if(!equippable_item_whitelist) + equippable_item_whitelist = typecacheof(list( + /obj/item/weapon/storage/bag/trash, + /obj/item/weapon/mop, + /obj/item/weapon/reagent_containers/spray, + /obj/item/device/lightreplacer, + /obj/item/clothing/suit/caution, + )) + + if(!is_type_in_typecache(I, equippable_item_whitelist)) + to_chat(user, "There's no room in [src] for [I].") + return FALSE + + if(!user.unEquip(I, 0, src)) + to_chat(user, "[I] is stuck to your hand.") + return FALSE + + if(istype(I, /obj/item/weapon/storage/bag/trash)) + if(mybag) + to_chat(user, "[src] already has \an [I].") + return FALSE + mybag = I + setTguiIcon("mybag", mybag) + + else if(istype(I, /obj/item/weapon/mop)) + if(mymop) + to_chat(user, "[src] already has \an [I].") + return FALSE + mymop = I + setTguiIcon("mymop", mymop) + + else if(istype(I, /obj/item/weapon/reagent_containers/spray)) + if(myspray) + to_chat(user, "[src] already has \an [I].") + return FALSE + myspray = I + setTguiIcon("myspray", myspray) + + else if(istype(I, /obj/item/device/lightreplacer)) + if(myreplacer) + to_chat(user, "[src] already has \an [I].") + return FALSE + myreplacer = I + setTguiIcon("myreplacer", myreplacer) + + else if(istype(I, /obj/item/clothing/suit/caution)) + if(signs < 4) + signs++ + setTguiIcon("signs", I) + else + to_chat(user, "[src] can't hold any more signs.") + return FALSE + else + // This may look like duplicate code, but it's important that we don't call unEquip *and* warn the user if + // something horrible goes wrong. (this else is never supposed to happen) + to_chat(user, "There's no room in [src] for [I].") + return FALSE + + update_icon() + to_chat(user, "You put [I] into [src].") + return TRUE + +/obj/structure/janitorialcart/proc/setTguiIcon(key, atom/A) + if(!istype(A) || !key) + return + + var/icon/F = getFlatIcon(A, defdir = SOUTH, no_anim = TRUE) + tgui_icons["[key]"] = "'data:image/png;base64,[icon2base64(F)]'" + SStgui.update_uis(src) + +/obj/structure/janitorialcart/proc/nullTguiIcon(key) + if(!key) + return + tgui_icons.Remove(key) + SStgui.update_uis(src) + +/obj/structure/janitorialcart/proc/clearTguiIcons() + tgui_icons.Cut() + SStgui.update_uis(src) /obj/structure/janitorialcart/Destroy() QDEL_NULL(mybag) @@ -29,20 +111,22 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart) QDEL_NULL(myspray) QDEL_NULL(myreplacer) QDEL_NULL(mybucket) + clearTguiIcons() return ..() /obj/structure/janitorialcart/examine(mob/user) - if(..(user, 1)) - if (mybucket) - var/contains = mybucket.reagents.total_volume - to_chat(user, "\icon[src] The bucket contains [contains] unit\s of liquid!") - else - to_chat(user, "\icon[src] There is no bucket mounted on it!") + . = ..(user) + if(istype(mybucket)) + var/contains = mybucket.reagents.total_volume + . += "[bicon(src)] The bucket contains [contains] unit\s of liquid!" + else + . += "[bicon(src)] There is no bucket mounted on it!" /obj/structure/janitorialcart/MouseDrop_T(atom/movable/O as mob|obj, mob/living/user as mob) if (istype(O, /obj/structure/mopbucket) && !mybucket) O.forceMove(src) mybucket = O + setTguiIcon("mybucket", mybucket) to_chat(user, "You mount the [O] on the janicart.") update_icon() else @@ -70,38 +154,19 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart) return 1 else if(istype(I, /obj/item/weapon/reagent_containers/spray) && !myspray) - user.unEquip(I, 0, src) - myspray = I - update_icon() - updateUsrDialog() - to_chat(user, "You put [I] into [src].") + equip_janicart_item(user, I) return 1 else if(istype(I, /obj/item/device/lightreplacer) && !myreplacer) - user.unEquip(I, 0, src) - myreplacer = I - update_icon() - updateUsrDialog() - to_chat(user, "You put [I] into [src].") + equip_janicart_item(user, I) return 1 else if(istype(I, /obj/item/weapon/storage/bag/trash) && !mybag) - user.unEquip(I, 0, src) - mybag = I - update_icon() - updateUsrDialog() - to_chat(user, "You put [I] into [src].") + equip_janicart_item(user, I) return 1 else if(istype(I, /obj/item/clothing/suit/caution)) - if(signs < 4) - user.unEquip(I, 0, src) - signs++ - update_icon() - updateUsrDialog() - to_chat(user, "You put [I] into [src].") - else - to_chat(user, "[src] can't hold any more signs.") + equip_janicart_item(user, I) return 1 else if(mybag) @@ -124,16 +189,7 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart) if(user.incapacitated() || !Adjacent(user)) return var/obj/I = usr.get_active_hand() if(istype(I, /obj/item/weapon/mop)) - if(!mymop) - usr.drop_from_inventory(I,src) - mymop = I - update_icon() - updateUsrDialog() - to_chat(usr, "You put [I] into [src].") - update_icon() - else - to_chat(usr, "The cart already has a mop attached") - return + equip_janicart_item(user, I) else if(istype(I, /obj/item/weapon/reagent_containers) && mybucket) var/obj/item/weapon/reagent_containers/C = I C.afterattack(mybucket, usr, 1) @@ -141,75 +197,95 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart) /obj/structure/janitorialcart/attack_hand(mob/user) - ui_interact(user) + tgui_interact(user) return -/obj/structure/janitorialcart/ui_interact(var/mob/user, var/ui_key = "main", var/datum/nanoui/ui = null, var/force_open = TRUE) - var/data[0] - data["name"] = capitalize(name) - data["bag"] = mybag ? capitalize(mybag.name) : null - data["bucket"] = mybucket ? capitalize(mybucket.name) : null - data["mop"] = mymop ? capitalize(mymop.name) : null - data["spray"] = myspray ? capitalize(myspray.name) : null - data["replacer"] = myreplacer ? capitalize(myreplacer.name) : null - data["signs"] = signs ? "[signs] sign\s" : null - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) +/obj/structure/janitorialcart/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) if(!ui) - ui = new(user, src, ui_key, "janitorcart.tmpl", "Janitorial cart", 240, 160) - ui.set_initial_data(data) + ui = new(user, src, "JanitorCart", name) // 240, 160 + ui.set_autoupdate(FALSE) ui.open() +/obj/structure/janitorialcart/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() -/obj/structure/janitorialcart/Topic(href, href_list) - if(!in_range(src, usr)) - return - if(!isliving(usr)) - return - var/mob/living/user = usr + data["mybag"] = mybag ? capitalize(mybag.name) : null + data["mybucket"] = mybucket ? capitalize(mybucket.name) : null + data["mymop"] = mymop ? capitalize(mymop.name) : null + data["myspray"] = myspray ? capitalize(myspray.name) : null + data["myreplacer"] = myreplacer ? capitalize(myreplacer.name) : null + data["signs"] = signs ? "[signs] sign\s" : null - if(href_list["take"]) - switch(href_list["take"]) - if("garbage") - if(mybag) - user.put_in_hands(mybag) - to_chat(user, "You take [mybag] from [src].") - mybag = null - if("mop") - if(mymop) - user.put_in_hands(mymop) - to_chat(user, "You take [mymop] from [src].") - mymop = null - if("spray") - if(myspray) - user.put_in_hands(myspray) - to_chat(user, "You take [myspray] from [src].") - myspray = null - if("replacer") - if(myreplacer) - user.put_in_hands(myreplacer) - to_chat(user, "You take [myreplacer] from [src].") - myreplacer = null - if("sign") - if(signs) - var/obj/item/clothing/suit/caution/Sign = locate() in src - if(Sign) - user.put_in_hands(Sign) - to_chat(user, "You take \a [Sign] from [src].") - signs-- - else - warning("[src] signs ([signs]) didn't match contents") - signs = 0 - if("bucket") - if(mybucket) - mybucket.forceMove(get_turf(user)) - to_chat(user, "You unmount [mybucket] from [src].") - mybucket = null + data["icons"] = tgui_icons + return data + +/obj/structure/janitorialcart/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + var/obj/item/I = usr.get_active_hand() + + switch(action) + if("bag") + if(mybag) + usr.put_in_hands(mybag) + to_chat(usr, "You take [mybag] from [src].") + mybag = null + nullTguiIcon("mybag") + else if(is_type_in_typecache(I, equippable_item_whitelist)) + equip_janicart_item(usr, I) + if("mop") + if(mymop) + usr.put_in_hands(mymop) + to_chat(usr, "You take [mymop] from [src].") + mymop = null + nullTguiIcon("mymop") + else if(is_type_in_typecache(I, equippable_item_whitelist)) + equip_janicart_item(usr, I) + if("spray") + if(myspray) + usr.put_in_hands(myspray) + to_chat(usr, "You take [myspray] from [src].") + myspray = null + nullTguiIcon("myspray") + else if(is_type_in_typecache(I, equippable_item_whitelist)) + equip_janicart_item(usr, I) + if("replacer") + if(myreplacer) + usr.put_in_hands(myreplacer) + to_chat(usr, "You take [myreplacer] from [src].") + myreplacer = null + nullTguiIcon("myreplacer") + else if(is_type_in_typecache(I, equippable_item_whitelist)) + equip_janicart_item(usr, I) + if("sign") + if(istype(I, /obj/item/clothing/suit/caution) && signs < 4) + equip_janicart_item(usr, I) + else if(signs) + var/obj/item/clothing/suit/caution/sign = locate() in src + if(sign) + usr.put_in_hands(sign) + to_chat(usr, "You take \a [sign] from [src].") + signs-- + if(!signs) + nullTguiIcon("signs") + else + to_chat(usr, "[src] doesn't have any signs left.") + if("bucket") + if(mybucket) + mybucket.forceMove(get_turf(usr)) + to_chat(usr, "You unmount [mybucket] from [src].") + mybucket = null + nullTguiIcon("mybucket") + else + to_chat(usr, "((Drag and drop a mop bucket onto [src] to equip it.))") + return FALSE + else + return FALSE update_icon() - updateUsrDialog() - - + return TRUE /obj/structure/janitorialcart/update_icon() overlays.Cut() @@ -229,11 +305,6 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart) if(signs) overlays += "cart_sign[signs]" - - - - - //This is called if the cart is caught in an explosion, or destroyed by weapon fire /obj/structure/janitorialcart/proc/spill(var/chance = 100) var/turf/dropspot = get_turf(src) @@ -275,6 +346,7 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart) mybag = null update_icon() + clearTguiIcons() diff --git a/code/game/objects/structures/safe.dm b/code/game/objects/structures/safe.dm index e68fa43640..a9815a4070 100644 --- a/code/game/objects/structures/safe.dm +++ b/code/game/objects/structures/safe.dm @@ -172,7 +172,7 @@ obj/structure/safe/ex_act(severity) icon_state = "floorsafe" density = 0 level = 1 //underfloor - plane = TURF_PLANE + plane = PLATING_PLANE layer = ABOVE_UTILITY /obj/structure/safe/floor/Initialize() diff --git a/code/game/objects/structures/simple_doors.dm b/code/game/objects/structures/simple_doors.dm index 95689683a5..19ae278730 100644 --- a/code/game/objects/structures/simple_doors.dm +++ b/code/game/objects/structures/simple_doors.dm @@ -7,7 +7,7 @@ icon = 'icons/obj/doors/material_doors.dmi' icon_state = "metal" - var/material/material + var/datum/material/material var/state = 0 //closed, 1 == open var/isSwitchingStates = 0 var/hardness = 1 diff --git a/code/game/objects/structures/simple_doors_vr.dm b/code/game/objects/structures/simple_doors_vr.dm index 7738674569..f6c9afd496 100644 --- a/code/game/objects/structures/simple_doors_vr.dm +++ b/code/game/objects/structures/simple_doors_vr.dm @@ -1,4 +1,4 @@ -/material/flockium +/datum/material/flockium name = "flockium" //stack_type = /obj/item/stack/material/sandstone icon_base = "flock" diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm index 9e01d83f1b..c753a77909 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm @@ -17,8 +17,8 @@ can_buckle = 1 buckle_dir = SOUTH buckle_lying = 1 - var/material/material - var/material/padding_material + var/datum/material/material + var/datum/material/padding_material var/base_icon = "bed" var/applies_material_colour = 1 diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index a3426aa816..f04ba27a78 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -226,7 +226,7 @@ /obj/structure/bed/chair/sofa/update_icon() if(applies_material_colour && sofa_material) - var/material/color_material = get_material_by_name(sofa_material) + var/datum/material/color_material = get_material_by_name(sofa_material) color = color_material.icon_colour if(sofa_material == "carpet") diff --git a/code/game/objects/structures/stool_bed_chair_nest/stools.dm b/code/game/objects/structures/stool_bed_chair_nest/stools.dm index a804b93ca4..980dde34eb 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/stools.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/stools.dm @@ -12,8 +12,8 @@ var/global/list/stool_cache = list() //haha stool throwforce = 10 w_class = ITEMSIZE_HUGE var/base_icon = "stool_base" - var/material/material - var/material/padding_material + var/datum/material/material + var/datum/material/padding_material /obj/item/weapon/stool/padded icon_state = "stool_padded_preview" //set for the map diff --git a/code/game/objects/structures/under_wardrobe.dm b/code/game/objects/structures/under_wardrobe.dm index cb5db5411d..c919663eaa 100644 --- a/code/game/objects/structures/under_wardrobe.dm +++ b/code/game/objects/structures/under_wardrobe.dm @@ -67,7 +67,7 @@ if(!UWC) return var/datum/category_item/underwear/selected_underwear = input(H, "Choose underwear:", "Choose underwear", H.all_underwear[UWC.name]) as null|anything in UWC.items - if(selected_underwear && CanUseTopic(H, default_state)) + if(selected_underwear && CanUseTopic(H, GLOB.tgui_default_state)) H.all_underwear[UWC.name] = selected_underwear H.hide_underwear[UWC.name] = FALSE . = TRUE diff --git a/code/game/objects/weapons.dm b/code/game/objects/weapons.dm index 19fe4eb03c..cd0190c71e 100644 --- a/code/game/objects/weapons.dm +++ b/code/game/objects/weapons.dm @@ -36,6 +36,8 @@ continue if(!SM.Adjacent(user) || !SM.Adjacent(target)) // Cleaving only hits mobs near the target mob and user. continue + if(!attack_can_reach(user, SM, 1)) + continue if(resolve_attackby(SM, user, attack_modifier = 0.5)) // Hit them with the weapon. This won't cause recursive cleaving due to the cleaving variable being set to true. hit_mobs++ diff --git a/code/game/sound.dm b/code/game/sound.dm index eabbca5c84..415a26c78c 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -266,6 +266,15 @@ soundin = pick('sound/machines/sm/accent/normal/1.ogg', 'sound/machines/sm/accent/normal/2.ogg', 'sound/machines/sm/accent/normal/3.ogg', 'sound/machines/sm/accent/normal/4.ogg', 'sound/machines/sm/accent/normal/5.ogg', 'sound/machines/sm/accent/normal/6.ogg', 'sound/machines/sm/accent/normal/7.ogg', 'sound/machines/sm/accent/normal/8.ogg', 'sound/machines/sm/accent/normal/9.ogg', 'sound/machines/sm/accent/normal/10.ogg', 'sound/machines/sm/accent/normal/11.ogg', 'sound/machines/sm/accent/normal/12.ogg', 'sound/machines/sm/accent/normal/13.ogg', 'sound/machines/sm/accent/normal/14.ogg', 'sound/machines/sm/accent/normal/15.ogg', 'sound/machines/sm/accent/normal/16.ogg', 'sound/machines/sm/accent/normal/17.ogg', 'sound/machines/sm/accent/normal/18.ogg', 'sound/machines/sm/accent/normal/19.ogg', 'sound/machines/sm/accent/normal/20.ogg', 'sound/machines/sm/accent/normal/21.ogg', 'sound/machines/sm/accent/normal/22.ogg', 'sound/machines/sm/accent/normal/23.ogg', 'sound/machines/sm/accent/normal/24.ogg', 'sound/machines/sm/accent/normal/25.ogg', 'sound/machines/sm/accent/normal/26.ogg', 'sound/machines/sm/accent/normal/27.ogg', 'sound/machines/sm/accent/normal/28.ogg', 'sound/machines/sm/accent/normal/29.ogg', 'sound/machines/sm/accent/normal/30.ogg', 'sound/machines/sm/accent/normal/31.ogg', 'sound/machines/sm/accent/normal/32.ogg', 'sound/machines/sm/accent/normal/33.ogg', 'sound/machines/sm/supermatter1.ogg', 'sound/machines/sm/supermatter2.ogg', 'sound/machines/sm/supermatter3.ogg') if("smdelam") soundin = pick('sound/machines/sm/accent/delam/1.ogg', 'sound/machines/sm/accent/normal/2.ogg', 'sound/machines/sm/accent/normal/3.ogg', 'sound/machines/sm/accent/normal/4.ogg', 'sound/machines/sm/accent/normal/5.ogg', 'sound/machines/sm/accent/normal/6.ogg', 'sound/machines/sm/accent/normal/7.ogg', 'sound/machines/sm/accent/normal/8.ogg', 'sound/machines/sm/accent/normal/9.ogg', 'sound/machines/sm/accent/normal/10.ogg', 'sound/machines/sm/accent/normal/11.ogg', 'sound/machines/sm/accent/normal/12.ogg', 'sound/machines/sm/accent/normal/13.ogg', 'sound/machines/sm/accent/normal/14.ogg', 'sound/machines/sm/accent/normal/15.ogg', 'sound/machines/sm/accent/normal/16.ogg', 'sound/machines/sm/accent/normal/17.ogg', 'sound/machines/sm/accent/normal/18.ogg', 'sound/machines/sm/accent/normal/19.ogg', 'sound/machines/sm/accent/normal/20.ogg', 'sound/machines/sm/accent/normal/21.ogg', 'sound/machines/sm/accent/normal/22.ogg', 'sound/machines/sm/accent/normal/23.ogg', 'sound/machines/sm/accent/normal/24.ogg', 'sound/machines/sm/accent/normal/25.ogg', 'sound/machines/sm/accent/normal/26.ogg', 'sound/machines/sm/accent/normal/27.ogg', 'sound/machines/sm/accent/normal/28.ogg', 'sound/machines/sm/accent/normal/29.ogg', 'sound/machines/sm/accent/normal/30.ogg', 'sound/machines/sm/accent/normal/31.ogg', 'sound/machines/sm/accent/normal/32.ogg', 'sound/machines/sm/accent/normal/33.ogg', 'sound/machines/sm/supermatter1.ogg', 'sound/machines/sm/supermatter2.ogg', 'sound/machines/sm/supermatter3.ogg') + if ("generic_drop") + soundin = pick( + 'sound/items/drop/generic1.ogg', + 'sound/items/drop/generic2.ogg' ) + if ("generic_pickup") + soundin = pick( + 'sound/items/pickup/generic1.ogg', + 'sound/items/pickup/generic2.ogg', + 'sound/items/pickup/generic3.ogg') return soundin //Are these even used? diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index adc0971c53..b4def6b209 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -158,7 +158,7 @@ var/turf/simulated/wall/T = get_turf(src) // Ref to the wall we just built. // Apparently set_material(...) for walls requires refs to the material singletons and not strings. // This is different from how other material objects with their own set_material(...) do it, but whatever. - var/material/M = name_to_material[the_rcd.material_to_use] + var/datum/material/M = name_to_material[the_rcd.material_to_use] T.set_material(M, the_rcd.make_rwalls ? M : null, M) T.add_hiddenprint(user) return TRUE diff --git a/code/game/turfs/simulated/floor_types_vr.dm b/code/game/turfs/simulated/floor_types_vr.dm index c4315b29b2..78e417fdc1 100644 --- a/code/game/turfs/simulated/floor_types_vr.dm +++ b/code/game/turfs/simulated/floor_types_vr.dm @@ -41,4 +41,16 @@ set_light(3,3,"#26c5a9") spawn(5 SECONDS) icon_state = "floor" - set_light(0,0,"#ffffff") \ No newline at end of file + set_light(0,0,"#ffffff") + +/turf/simulated/floor/gorefloor + name = "infected tile" + desc = "Slick, sickly-squirming meat has grown in and out of cracks once empty. It pulsates intermittently, and with every beat, blood seeps out of pores." + icon_state = "bloodfloor_1" + icon = 'icons/goonstation/turf/meatland.dmi' + +/turf/simulated/floor/gorefloor2 + name = "putrid mass" + desc = "It is entirely made of sick, gurgling flesh. It is releasing a sickly odour." + icon_state = "bloodfloor_2" + icon = 'icons/goonstation/turf/meatland.dmi' \ No newline at end of file diff --git a/code/game/turfs/simulated/wall_icon.dm b/code/game/turfs/simulated/wall_icon.dm index dd49744a8f..c376bc36c1 100644 --- a/code/game/turfs/simulated/wall_icon.dm +++ b/code/game/turfs/simulated/wall_icon.dm @@ -31,7 +31,7 @@ update_icon() -/turf/simulated/wall/proc/set_material(var/material/newmaterial, var/material/newrmaterial, var/material/newgmaterial) +/turf/simulated/wall/proc/set_material(var/datum/material/newmaterial, var/datum/material/newrmaterial, var/datum/material/newgmaterial) material = newmaterial reinf_material = newrmaterial if(!newgmaterial) diff --git a/code/game/turfs/simulated/wall_types_vr.dm b/code/game/turfs/simulated/wall_types_vr.dm index 87a6582f1f..d2461282e2 100644 --- a/code/game/turfs/simulated/wall_types_vr.dm +++ b/code/game/turfs/simulated/wall_types_vr.dm @@ -61,6 +61,24 @@ var/list/flesh_overlay_cache = list() var/turf/simulated/flesh/F = get_step(src, direction) F.update_icon() +/turf/simulated/gore + name = "wall of viscera" + desc = "Its veins pulse in a sickeningly rapid fashion, while certain spots of the wall rise and fall gently, much like slow, deliberate breathing." + icon = 'icons/goonstation/turf/meatland.dmi' + icon_state = "bloodwall_2" + opacity = 1 + density = 1 + blocks_air = 1 + +/turf/simulated/goreeyes + name = "wall of viscera" + desc = "Strangely observant eyes dot the wall. Getting too close has the eyes fixate on you, while their pupils shake violently. Each socket is connected by a series of winding, writhing veins." + icon = 'icons/goonstation/turf/meatland.dmi' + icon_state = "bloodwall_4" + opacity = 1 + density = 1 + blocks_air = 1 + /turf/simulated/shuttle/wall/flock icon = 'icons/goonstation/featherzone.dmi' icon_state = "flockwall0" @@ -78,8 +96,20 @@ var/list/flesh_overlay_cache = list() /turf/simulated/wall/rplastitanium/Initialize(mapload) . = ..(mapload, MAT_PLASTITANIUM,MAT_PLASTITANIUM,MAT_PLASTITANIUM) - /turf/simulated/wall/plastitanium +/turf/simulated/wall/plastitanium icon_state = "wall-plastitanium" icon = 'icons/turf/wall_masks_vr.dmi' /turf/simulated/wall/plastitanium/Initialize(mapload) - . = ..(mapload, MAT_PLASTITANIUM, null,MAT_PLASTITANIUM) \ No newline at end of file + . = ..(mapload, MAT_PLASTITANIUM, null,MAT_PLASTITANIUM) + +/turf/simulated/wall/rplastihull + icon_state = "rhull-plastitanium" + icon = 'icons/turf/wall_masks_vr.dmi' +/turf/simulated/wall/rplastihull/Initialize(mapload) + . = ..(mapload, MAT_PLASTITANIUMHULL,MAT_PLASTITANIUMHULL,MAT_PLASTITANIUMHULL) + +/turf/simulated/wall/plastihull + icon_state = "hull-plastitanium" + icon = 'icons/turf/wall_masks_vr.dmi' +/turf/simulated/wall/plastihull/Initialize(mapload) + . = ..(mapload, MAT_PLASTITANIUMHULL, null,MAT_PLASTITANIUMHULL) diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 20c54b8fea..7f5421a1f5 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -14,9 +14,9 @@ var/global/damage_overlays[16] var/active var/can_open = 0 - var/material/girder_material - var/material/material - var/material/reinf_material + var/datum/material/girder_material + var/datum/material/material + var/datum/material/reinf_material var/last_state var/construction_stage diff --git a/code/modules/admin/admin_verb_lists.dm b/code/modules/admin/admin_verb_lists.dm index 494d470c24..dc656f79a3 100644 --- a/code/modules/admin/admin_verb_lists.dm +++ b/code/modules/admin/admin_verb_lists.dm @@ -183,7 +183,6 @@ var/list/admin_verbs_server = list( /datum/admins/proc/toggle_space_ninja, /client/proc/toggle_random_events, /client/proc/check_customitem_activity, - /client/proc/nanomapgen_DumpImage, /client/proc/modify_server_news, /client/proc/recipe_dump, /client/proc/panicbunker, diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index fa3dd99453..3fe1f52465 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -615,7 +615,7 @@ jobs += "" //Other races (Blue) ... And also graffiti. - var/list/misc_roles = list("Dionaea", "Graffiti") + var/list/misc_roles = list("Dionaea", "Graffiti", "Custom loadout") jobs += "Other Roles" for(var/entry in misc_roles) if(jobban_isbanned(M, entry)) diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm index ce71815526..815d250dcc 100644 --- a/code/modules/asset_cache/asset_list_items.dm +++ b/code/modules/asset_cache/asset_list_items.dm @@ -6,36 +6,36 @@ "tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.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' -// ) +/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' + ) // /datum/asset/simple/radar_assets // assets = list( @@ -206,15 +206,15 @@ // "none_button.png" = 'html/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/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" @@ -355,39 +355,56 @@ // Insert(initial(D.id), I) // return ..() -// /datum/asset/spritesheet/vending -// name = "vending" +/datum/asset/spritesheet/vending + name = "vending" -// /datum/asset/spritesheet/vending/register() -// for (var/k in GLOB.vending_products) -// var/atom/item = k -// if (!ispath(item, /atom)) -// continue +/datum/asset/spritesheet/vending/register() + for(var/k in GLOB.vending_products) + var/atom/item = k + if(!ispath(item, /atom)) + continue -// var/icon_file = initial(item.icon) -// var/icon_state = initial(item.icon_state) -// var/icon/I + var/icon_file = initial(item.icon) + var/icon_state = initial(item.icon_state) -// 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) + // I really don't like the fact that I have to do this, but what the hell else *can* I do to make all of these + // random special items work? + if(ispath(item, /obj/item/weapon/reagent_containers/food/drinks/glass2) && !ispath(item, /obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask)) + var/obj/item/weapon/reagent_containers/food/drinks/glass2/G = item + icon_state = initial(G.base_icon) + if(ispath(item, /obj/item/clothing/suit)) + var/obj/item/clothing/suit/U = item + if(initial(U.index)) + icon_file = "icons/obj/clothing/suits_[initial(U.index)].dmi" + if(ispath(item, /obj/item/clothing/under)) + var/obj/item/clothing/under/U = item + if(initial(U.index)) + icon_file = "icons/obj/clothing/uniforms_[initial(U.index)].dmi" + if(ispath(item, /obj/item/weapon/reagent_containers/hypospray/autoinjector)) + icon_state += "0" -// var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-") + var/icon/I -// Insert(imgid, I) -// return ..() + 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) + return ..() // /datum/asset/simple/genetics // assets = list( @@ -416,45 +433,6 @@ // Insert("polycrystal", 'icons/obj/telescience.dmi', "polycrystal") // ..() -/datum/asset/nanoui - var/list/common = list() - - var/list/common_dirs = list( - "nano/css/", - "nano/images/", - "nano/images/modular_computers/", - "nano/js/" - ) - var/list/template_dirs = list( - "nano/templates/" - ) - -/datum/asset/nanoui/register() - // Crawl the directories to find files. - for(var/path in common_dirs) - var/list/filenames = flist(path) - for(var/filename in filenames) - if(copytext(filename, length(filename)) != "/") // Ignore directories. - if(fexists(path + filename)) - common[filename] = fcopy_rsc(path + filename) - register_asset(filename, common[filename]) - // Combine all templates into a single bundle. - var/list/template_data = list() - for(var/path in template_dirs) - var/list/filenames = flist(path) - for(var/filename in filenames) - if(copytext(filename, length(filename) - 4) == ".tmpl") // Ignore directories. - template_data[filename] = file2text(path + filename) - var/template_bundle = "function nanouiTemplateBundle(){return [json_encode(template_data)];}" - var/fname = "data/nano_templates_bundle.js" - fdel(fname) - text2file(template_bundle, fname) - register_asset("nano_templates_bundle.js", fcopy_rsc(fname)) - fdel(fname) - -/datum/asset/nanoui/send(client) - send_asset_list(client, common) - //Pill sprites for UIs /datum/asset/chem_master var/assets = list() @@ -505,4 +483,31 @@ /datum/asset/spritesheet/sheetmaterials/register() InsertAll("", 'icons/obj/stacks.dmi') - ..() \ No newline at end of file + ..() + +// Nanomaps +/datum/asset/simple/nanomaps + // It REALLY doesnt matter too much if these arent up to date + // They are relatively big + assets = list( + // VOREStation Edit: We don't need Southern Cross + // "southern_cross_nanomap_z1.png" = 'icons/_nanomaps/southern_cross_nanomap_z1.png', + // "southern_cross_nanomap_z10.png" = 'icons/_nanomaps/southern_cross_nanomap_z10.png', + // "southern_cross_nanomap_z2.png" = 'icons/_nanomaps/southern_cross_nanomap_z2.png', + // "southern_cross_nanomap_z3.png" = 'icons/_nanomaps/southern_cross_nanomap_z3.png', + // "southern_cross_nanomap_z5.png" = 'icons/_nanomaps/southern_cross_nanomap_z5.png', + // "southern_cross_nanomap_z6.png" = 'icons/_nanomaps/southern_cross_nanomap_z6.png', + "tether_nanomap_z1.png" = 'icons/_nanomaps/tether_nanomap_z1.png', + "tether_nanomap_z2.png" = 'icons/_nanomaps/tether_nanomap_z2.png', + "tether_nanomap_z3.png" = 'icons/_nanomaps/tether_nanomap_z3.png', + "tether_nanomap_z4.png" = 'icons/_nanomaps/tether_nanomap_z4.png', + "tether_nanomap_z5.png" = 'icons/_nanomaps/tether_nanomap_z5.png', + "tether_nanomap_z6.png" = 'icons/_nanomaps/tether_nanomap_z6.png', + "tether_nanomap_z7.png" = 'icons/_nanomaps/tether_nanomap_z7.png', + "tether_nanomap_z8.png" = 'icons/_nanomaps/tether_nanomap_z8.png', + "tether_nanomap_z9.png" = 'icons/_nanomaps/tether_nanomap_z9.png', + "tether_nanomap_z10.png" = 'icons/_nanomaps/tether_nanomap_z10.png', + "tether_nanomap_z13.png" = 'icons/_nanomaps/tether_nanomap_z13.png', + "tether_nanomap_z14.png" = 'icons/_nanomaps/tether_nanomap_z14.png', + // VOREStation Edit End + ) \ No newline at end of file diff --git a/code/modules/awaymissions/loot_vr.dm b/code/modules/awaymissions/loot_vr.dm index dcfcb1a33e..89682ee6dd 100644 --- a/code/modules/awaymissions/loot_vr.dm +++ b/code/modules/awaymissions/loot_vr.dm @@ -395,4 +395,9 @@ /obj/structure/symbol/sa desc = "It looks like a right triangle with a dot to the side. It reminds you of a wooden strut between a wall and ceiling." - icon_state = "sa" \ No newline at end of file + icon_state = "sa" + +/obj/structure/symbol/maint + name = "maintenance panel" + desc = "This sign suggests that the wall it's attached to can be opened somehow." + icon_state = "maintenance_panel" \ No newline at end of file diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index accba5b61b..6c59499b53 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -479,7 +479,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.r_hair = 0//hex2num(copytext(new_hair, 2, 4)) pref.g_hair = 0//hex2num(copytext(new_hair, 4, 6)) pref.b_hair = 0//hex2num(copytext(new_hair, 6, 8)) - pref.s_tone = 0 + pref.s_tone = -75 reset_limbs() // Safety for species with incompatible manufacturers; easier than trying to do it case by case. pref.body_markings.Cut() // Basically same as above. diff --git a/code/modules/client/preference_setup/loadout/gear_tweaks.dm b/code/modules/client/preference_setup/loadout/gear_tweaks.dm index 71af8715a5..8d9206b64c 100644 --- a/code/modules/client/preference_setup/loadout/gear_tweaks.dm +++ b/code/modules/client/preference_setup/loadout/gear_tweaks.dm @@ -141,6 +141,74 @@ . = valid_reagents[metadata] I.reagents.add_reagent(., I.reagents.get_free_space()) +//Custom name and desciption code +//note to devs downstream: where 'gear_tweaks = list(gear_tweak_free_color_choice)' was used before for color selection +//in the loadout, now 'gear_tweaks += gear_tweak_free_color_choice' will need to be used, otherwise the item will not +// be able to be given a custom name or description +/* +Custom Name +*/ + +var/datum/gear_tweak/custom_name/gear_tweak_free_name = new() + +/datum/gear_tweak/custom_name + var/list/valid_custom_names + +/datum/gear_tweak/custom_name/New(var/list/valid_custom_names) + src.valid_custom_names = valid_custom_names + ..() + +/datum/gear_tweak/custom_name/get_contents(var/metadata) + return "Name: [metadata]" + +/datum/gear_tweak/custom_name/get_default() + return "" + +/datum/gear_tweak/custom_name/get_metadata(var/user, var/metadata) + if(jobban_isbanned(user, "Custom loadout")) + to_chat(user, SPAN_WARNING("You are banned from using custom loadout names/descriptions.")) + return + if(valid_custom_names) + return input(user, "Choose an item name.", "Character Preference", metadata) as null|anything in valid_custom_names + return sanitize(input(user, "Choose the item's name. Leave it blank to use the default name.", "Item Name", metadata) as text|null, MAX_LNAME_LEN, extra = 0) + +/datum/gear_tweak/custom_name/tweak_item(var/obj/item/I, var/metadata) + if(!metadata) + return I.name + I.name = metadata + +/* +Custom Description +*/ +var/datum/gear_tweak/custom_desc/gear_tweak_free_desc = new() + +/datum/gear_tweak/custom_desc + var/list/valid_custom_desc + +/datum/gear_tweak/custom_desc/New(var/list/valid_custom_desc) + src.valid_custom_desc = valid_custom_desc + ..() + +/datum/gear_tweak/custom_desc/get_contents(var/metadata) + return "Description: [metadata]" + +/datum/gear_tweak/custom_desc/get_default() + return "" + +/datum/gear_tweak/custom_desc/get_metadata(var/user, var/metadata) + if(jobban_isbanned(user, "Custom loadout")) + to_chat(user, SPAN_WARNING("You are banned from using custom loadout names/descriptions.")) + return + if(valid_custom_desc) + return input(user, "Choose an item description.", "Character Preference", metadata) as null|anything in valid_custom_desc + return sanitize(input(user, "Choose the item's description. Leave it blank to use the default description.", "Item Description", metadata) as message|null, extra = 0) + +/datum/gear_tweak/custom_desc/tweak_item(var/obj/item/I, var/metadata) + if(!metadata) + return I.desc + I.desc = metadata + +//end of custom description /datum/gear_tweak/tablet var/list/ValidProcessors = list(/obj/item/weapon/computer_hardware/processor_unit/small) diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm index ae7826511d..c91b2314c8 100644 --- a/code/modules/client/preference_setup/loadout/loadout.dm +++ b/code/modules/client/preference_setup/loadout/loadout.dm @@ -261,6 +261,7 @@ var/list/gear_datums = list() if(!description) var/obj/O = path description = initial(O.desc) + gear_tweaks = list(gear_tweak_free_name, gear_tweak_free_desc) /datum/gear_data var/path diff --git a/code/modules/client/preference_setup/loadout/loadout_accessories.dm b/code/modules/client/preference_setup/loadout/loadout_accessories.dm index b370e5eebf..b9c446fb87 100644 --- a/code/modules/client/preference_setup/loadout/loadout_accessories.dm +++ b/code/modules/client/preference_setup/loadout/loadout_accessories.dm @@ -24,7 +24,7 @@ /datum/gear/accessory/armband/colored/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/accessory/wallet display_name = "wallet, orange" @@ -43,7 +43,7 @@ /datum/gear/accessory/wallet/womens/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/accessory/clutch display_name = "clutch bag" @@ -52,7 +52,7 @@ /datum/gear/accessory/clutch/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/accessory/purse display_name = "purse" @@ -61,7 +61,7 @@ /datum/gear/accessory/purse/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/accessory/wcoat display_name = "waistcoat selection" @@ -122,7 +122,7 @@ /datum/gear/accessory/scarfcolor/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/accessory/jacket display_name = "suit jacket selection" @@ -270,7 +270,7 @@ /datum/gear/accessory/sash/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/accessory/asym display_name = "asymmetric jacket selection" diff --git a/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm b/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm index 5d0ede01c0..b80bfdbe08 100644 --- a/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm +++ b/code/modules/client/preference_setup/loadout/loadout_accessories_vr.dm @@ -8,7 +8,7 @@ /datum/gear/choker/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/collar display_name = "collar, silver" @@ -18,7 +18,7 @@ /datum/gear/collar/New() ..() - gear_tweaks = list(gear_tweak_collar_tag) + gear_tweaks += gear_tweak_collar_tag /datum/gear/collar/golden display_name = "collar, golden" @@ -106,4 +106,4 @@ /datum/gear/accessory/flops/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice diff --git a/code/modules/client/preference_setup/loadout/loadout_eyes.dm b/code/modules/client/preference_setup/loadout/loadout_eyes.dm index 0eedcd593d..ad2e07728e 100644 --- a/code/modules/client/preference_setup/loadout/loadout_eyes.dm +++ b/code/modules/client/preference_setup/loadout/loadout_eyes.dm @@ -5,6 +5,16 @@ slot = slot_glasses sort_category = "Glasses and Eyewear" +/datum/gear/eyes/eyepatchwhite + display_name = "eyepatch (recolorable)" + path = /obj/item/clothing/glasses/eyepatchwhite + slot = slot_glasses + sort_category = "Glasses and Eyewear" + +/datum/gear/eyes/eyepatchwhite/New() + ..() + gear_tweaks += gear_tweak_free_color_choice + /datum/gear/eyes/glasses display_name = "Glasses, prescription" path = /obj/item/clothing/glasses/regular diff --git a/code/modules/client/preference_setup/loadout/loadout_eyes_yw.dm b/code/modules/client/preference_setup/loadout/loadout_eyes_yw.dm index 33e9858933..66d1ca53cc 100644 --- a/code/modules/client/preference_setup/loadout/loadout_eyes_yw.dm +++ b/code/modules/client/preference_setup/loadout/loadout_eyes_yw.dm @@ -17,4 +17,4 @@ display_name = "AR-B glasses (CD, HoP, BSG)" path = /obj/item/clothing/glasses/omnihud/all cost = 2 - allowed_roles = list("Colony Director","Head of Personnel","Blueshield Guard") \ No newline at end of file + allowed_roles = list("Site Manager","Head of Personnel","Blueshield Guard") \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm b/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm index a01f2ff64a..bf0148f510 100644 --- a/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm +++ b/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm @@ -25,7 +25,7 @@ /datum/gear/fluff/collar/New() ..() - gear_tweaks = list(gear_tweak_collar_tag) + gear_tweaks += gear_tweak_collar_tag // 0-9 CKEYS /datum/gear/fluff/malady_crop @@ -136,6 +136,12 @@ ckeywhitelist = list("blakeryan") character_name = list("Nolan Conaway") +/datum/gear/fluff/charles_hat + path = /obj/item/clothing/head/that/fluff/gettler + display_name = "Charles' Top-Hat" + ckeywhitelist = list("bobofboblandia") + character_name = list("Charles Gettler") + /datum/gear/fluff/xin_sovietuniform path = /obj/item/clothing/under/soviet display_name = "Xin's Soviet Uniform" @@ -726,6 +732,13 @@ character_name = list("Tiemli Kroto") allowed_roles = list("Roboticist") +/datum/gear/fluff/clara_flask + path = /obj/item/weapon/reagent_containers/food/drinks/glass2/fluff/claraflask + display_name = "Clara's Vacuum Flask" + ckeywhitelist = list("rboys2") + character_name = list("Clara Mali") + cost = 1 + // S CKEYS /datum/gear/fluff/brynhild_medal path = /obj/item/clothing/accessory/medal/silver/valor @@ -911,6 +924,13 @@ ckeywhitelist = list("theskringdinger") character_name = list("Monty Kopic") +/datum/gear/fluff/shadow_laptop + path = /obj/item/modular_computer/laptop/preset/custom_loadout/advanced/shadowlarkens + display_name = "Shadow's Laptop" + ckeywhitelist = list("tigercat2000") + character_name = list("Shadow Larkens") + cost = 5 + /datum/gear/fluff/konor_medal path = /obj/item/clothing/accessory/medal/silver/unity display_name = "Konor's Unity Medal" diff --git a/code/modules/client/preference_setup/loadout/loadout_general.dm b/code/modules/client/preference_setup/loadout/loadout_general.dm index 4b4f979ef5..542348fec4 100644 --- a/code/modules/client/preference_setup/loadout/loadout_general.dm +++ b/code/modules/client/preference_setup/loadout/loadout_general.dm @@ -126,7 +126,7 @@ /datum/gear/towel/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/cahwhite display_name = "Cards Against The Galaxy (white deck)" diff --git a/code/modules/client/preference_setup/loadout/loadout_gloves.dm b/code/modules/client/preference_setup/loadout/loadout_gloves.dm index b72549e866..2564b8d98e 100644 --- a/code/modules/client/preference_setup/loadout/loadout_gloves.dm +++ b/code/modules/client/preference_setup/loadout/loadout_gloves.dm @@ -62,7 +62,7 @@ /datum/gear/gloves/evening/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/gloves/duty display_name = "gloves, work" diff --git a/code/modules/client/preference_setup/loadout/loadout_gloves_vr.dm b/code/modules/client/preference_setup/loadout/loadout_gloves_vr.dm index c6c51f5bbd..269f9e7aa9 100644 --- a/code/modules/client/preference_setup/loadout/loadout_gloves_vr.dm +++ b/code/modules/client/preference_setup/loadout/loadout_gloves_vr.dm @@ -12,7 +12,7 @@ /datum/gear/gloves/colored/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/gloves/latex/colorable @@ -21,7 +21,7 @@ /datum/gear/gloves/latex/colorable/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/gloves/siren display_name = "gloves, Siren" diff --git a/code/modules/client/preference_setup/loadout/loadout_head.dm b/code/modules/client/preference_setup/loadout/loadout_head.dm index 81b5888b37..e29b7d0a22 100644 --- a/code/modules/client/preference_setup/loadout/loadout_head.dm +++ b/code/modules/client/preference_setup/loadout/loadout_head.dm @@ -119,7 +119,7 @@ /datum/gear/head/cap/white/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/head/cap/mbill display_name = "cap, bill" @@ -155,7 +155,7 @@ /datum/gear/head/hairflower/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/head/pin display_name = "pin selection" @@ -229,7 +229,7 @@ /datum/gear/head/hijab/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/head/kippa display_name = "kippa" @@ -237,7 +237,7 @@ /datum/gear/head/kippa/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/head/turban display_name = "turban" @@ -245,7 +245,7 @@ /datum/gear/head/turban/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/head/taqiyah display_name = "taqiyah" @@ -253,7 +253,7 @@ /datum/gear/head/taqiyah/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/head/kitty display_name = "kitty ears" @@ -269,7 +269,7 @@ /datum/gear/head/beanie/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/head/loose_beanie display_name = "loose beanie" @@ -277,7 +277,7 @@ /datum/gear/head/loose_beanie/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/head/beretg display_name = "beret" @@ -285,7 +285,7 @@ /datum/gear/head/beretg/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/head/sombrero display_name = "sombrero" @@ -297,7 +297,7 @@ /datum/gear/head/flatcapg/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/head/bow/small display_name = "hair bow, small (colorable)" @@ -305,7 +305,7 @@ /datum/gear/head/bow/small/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/head/welding/ display_name = "welding, normal (engineering/robotics)" diff --git a/code/modules/client/preference_setup/loadout/loadout_head_vr.dm b/code/modules/client/preference_setup/loadout/loadout_head_vr.dm index 41214cbd67..ce6ada61ab 100644 --- a/code/modules/client/preference_setup/loadout/loadout_head_vr.dm +++ b/code/modules/client/preference_setup/loadout/loadout_head_vr.dm @@ -12,7 +12,7 @@ /datum/gear/head/headbando/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice //Detective alternative /datum/gear/head/detective_alt diff --git a/code/modules/client/preference_setup/loadout/loadout_shoes.dm b/code/modules/client/preference_setup/loadout/loadout_shoes.dm index 4325952405..7f7ddd7f14 100644 --- a/code/modules/client/preference_setup/loadout/loadout_shoes.dm +++ b/code/modules/client/preference_setup/loadout/loadout_shoes.dm @@ -95,7 +95,7 @@ /datum/gear/shoes/flipflops/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/shoes/athletic display_name = "athletic shoes" @@ -103,7 +103,7 @@ /datum/gear/shoes/athletic/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/shoes/skater display_name = "skater shoes" @@ -111,7 +111,7 @@ /datum/gear/shoes/skater/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/shoes/flats display_name = "flats" @@ -119,7 +119,7 @@ /datum/gear/shoes/flats/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/shoes/cowboy display_name = "cowboy boots" @@ -157,7 +157,7 @@ /datum/gear/shoes/heels/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/shoes/slippers display_name = "bunny slippers" diff --git a/code/modules/client/preference_setup/loadout/loadout_suit.dm b/code/modules/client/preference_setup/loadout/loadout_suit.dm index 871a6a83b2..decfe8199d 100644 --- a/code/modules/client/preference_setup/loadout/loadout_suit.dm +++ b/code/modules/client/preference_setup/loadout/loadout_suit.dm @@ -12,7 +12,7 @@ /datum/gear/suit/apron_white/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/suit/greatcoat display_name = "greatcoat" @@ -106,7 +106,7 @@ datum/gear/suit/duster /datum/gear/suit/duster/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/suit/hazard_vest display_name = "hazard vest selection" @@ -293,7 +293,7 @@ datum/gear/suit/duster /datum/gear/suit/roles/poncho/cloak/custom/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/suit/unathi_robe display_name = "roughspun robe" @@ -440,7 +440,7 @@ datum/gear/suit/duster /datum/gear/suit/miscellaneous/kimono/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/suit/miscellaneous/sec_dep_jacket display_name = "department jacket, security" @@ -468,7 +468,7 @@ datum/gear/suit/duster /datum/gear/suit/miscellaneous/peacoat/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/suit/miscellaneous/kamishimo display_name = "kamishimo" @@ -514,4 +514,4 @@ datum/gear/suit/duster /datum/gear/suit/miscellaneous/cardigan/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) \ No newline at end of file + gear_tweaks += gear_tweak_free_color_choice \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout_suit_vr.dm b/code/modules/client/preference_setup/loadout/loadout_suit_vr.dm index 3dc33eb9b3..b9cae2ddd0 100644 --- a/code/modules/client/preference_setup/loadout/loadout_suit_vr.dm +++ b/code/modules/client/preference_setup/loadout/loadout_suit_vr.dm @@ -16,7 +16,7 @@ /datum/gear/suit/labcoat_colorable/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/suit/jacket_modular display_name = "jacket, modular" diff --git a/code/modules/client/preference_setup/loadout/loadout_uniform.dm b/code/modules/client/preference_setup/loadout/loadout_uniform.dm index 758e9d0790..71c6f96140 100644 --- a/code/modules/client/preference_setup/loadout/loadout_uniform.dm +++ b/code/modules/client/preference_setup/loadout/loadout_uniform.dm @@ -351,7 +351,7 @@ /datum/gear/uniform/shortplaindress/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/uniform/longdress display_name = "long dress" @@ -359,7 +359,7 @@ /datum/gear/uniform/longdress/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/uniform/longwidedress display_name = "long wide dress" @@ -367,7 +367,7 @@ /datum/gear/uniform/longwidedress/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/uniform/reddress display_name = "red dress with belt" @@ -456,7 +456,7 @@ /datum/gear/uniform/yogapants/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/uniform/black_corset display_name = "black corset" @@ -512,7 +512,7 @@ /datum/gear/uniform/pleated/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/uniform/lilacdress display_name = "lilac dress" diff --git a/code/modules/client/preference_setup/loadout/loadout_uniform_ch.dm b/code/modules/client/preference_setup/loadout/loadout_uniform_ch.dm index cb8e3f2443..4385c50575 100644 --- a/code/modules/client/preference_setup/loadout/loadout_uniform_ch.dm +++ b/code/modules/client/preference_setup/loadout/loadout_uniform_ch.dm @@ -44,7 +44,7 @@ /datum/gear/uniform/job_nullsuit/cmd display_name = "nullsuit, cmd" path = /obj/item/clothing/under/rank/nullsuit/cmd - allowed_roles = list("Head of Security","Colony Director","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Blueshield Guard") + allowed_roles = list("Head of Security","Site Manager","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Blueshield Guard") /datum/gear/uniform/job_nullsuit/sec display_name = "nullsuit, sec" diff --git a/code/modules/client/preference_setup/loadout/loadout_utility.dm b/code/modules/client/preference_setup/loadout/loadout_utility.dm index 31a3584ed6..4b8eb45819 100644 --- a/code/modules/client/preference_setup/loadout/loadout_utility.dm +++ b/code/modules/client/preference_setup/loadout/loadout_utility.dm @@ -167,7 +167,7 @@ /datum/gear/utility/wheelchair/color/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/utility/umbrella display_name = "Umbrella" @@ -176,7 +176,7 @@ /datum/gear/utility/umbrella/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /**************** modular computers diff --git a/code/modules/client/preference_setup/loadout/loadout_xeno.dm b/code/modules/client/preference_setup/loadout/loadout_xeno.dm index 86bc4425d7..5e2ffdac50 100644 --- a/code/modules/client/preference_setup/loadout/loadout_xeno.dm +++ b/code/modules/client/preference_setup/loadout/loadout_xeno.dm @@ -80,7 +80,7 @@ /datum/gear/ears/skrell/colored/band/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/ears/skrell/colored/chain display_name = "Colored chain (Skrell)" @@ -90,7 +90,7 @@ /datum/gear/ears/skrell/colored/chain/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/uniform/smock display_name = "smock selection (Teshari)" @@ -147,7 +147,7 @@ /datum/gear/shoes/footwraps/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/uniform/cohesionsuits display_name = "cohesion suit selection (Promethean)" @@ -358,7 +358,7 @@ /datum/gear/uniform/smockcolor/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/uniform/undercoatcolor display_name = "undercoat, recolorable (Teshari)" @@ -368,7 +368,7 @@ /datum/gear/uniform/undercoatcolor/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/suit/cloakcolor display_name = "cloak, recolorable (Teshari)" @@ -378,7 +378,7 @@ /datum/gear/suit/cloakcolor/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/suit/labcoat_tesh display_name = "labcoat, colorable (Teshari)" path = /obj/item/clothing/suit/storage/toggle/labcoat/teshari @@ -387,7 +387,7 @@ /datum/gear/suit/labcoat_tesh/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/suit/teshcoat display_name = "small black coat, recolorable stripes (Teshari)" @@ -397,7 +397,8 @@ /datum/gear/suit/teshcoat/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + + gear_tweaks += gear_tweak_free_color_choice /datum/gear/suit/teshcoatwhite display_name = "smallcoat, recolorable (Teshari)" @@ -407,7 +408,7 @@ /datum/gear/suit/teshcoatwhite/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) + gear_tweaks += gear_tweak_free_color_choice /datum/gear/accessory/teshneckscarf display_name = "neckscarf, recolorable (Teshari)" @@ -417,4 +418,17 @@ /datum/gear/accessory/teshneckscarf/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) \ No newline at end of file + gear_tweaks += gear_tweak_free_color_choice + +/datum/gear/shoes/toelessjack + display_name = "toe-less jackboots" + path = /obj/item/clothing/shoes/boots/jackboots/toeless + + +/datum/gear/shoes/toelessknee + display_name = "toe-less jackboots, knee-length" + path = /obj/item/clothing/shoes/boots/jackboots/toeless/knee + +/datum/gear/shoes/toelessthigh + display_name = "toe-less jackboots, thigh-length" + path = /obj/item/clothing/shoes/boots/jackboots/toeless/thigh \ No newline at end of file diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index c5f17f138a..57cefffbcd 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -50,7 +50,7 @@ datum/preferences var/r_facial = 0 //Face hair color var/g_facial = 0 //Face hair color var/b_facial = 0 //Face hair color - var/s_tone = 0 //Skin tone + var/s_tone = -75 //Skin tone var/r_skin = 238 //Skin color // Vorestation edit, so color multi sprites can aren't BLACK AS THE VOID by default. var/g_skin = 206 //Skin color // Vorestation edit, so color multi sprites can aren't BLACK AS THE VOID by default. var/b_skin = 179 //Skin color // Vorestation edit, so color multi sprites can aren't BLACK AS THE VOID by default. diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 687bfe841a..caf6d395f1 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -2,7 +2,7 @@ name = "clothing" siemens_coefficient = 0.9 drop_sound = 'sound/items/drop/clothing.ogg' - pickup_sound = 'sound/items/pickup/cloth.ogg' + pickup_sound = 'sound/items/pickup/clothing.ogg' var/list/species_restricted = null //Only these species can wear this kit. var/gunshot_residue //Used by forensics. @@ -30,6 +30,7 @@ var/update_icon_define = null // Only needed if you've got multiple files for the same type of clothing + var/polychromic = FALSE //VOREStation edit //Updates the icons of the mob wearing the clothing item, if any. /obj/item/clothing/proc/update_clothing_icon() @@ -49,6 +50,11 @@ src.attach_accessory(null, tie) set_clothing_index() + //VOREStation edit start + if(polychromic) + verbs |= /obj/item/clothing/proc/change_color + //VOREStation edit start + /obj/item/clothing/equipped(var/mob/user,var/slot) ..() if(enables_planes) @@ -161,6 +167,24 @@ else icon = initial(icon) +//VOREStation edit start +/obj/item/clothing/proc/change_color() + set name = "Change Color" + set category = "Object" + set desc = "Change the color of the clothing." + set src in usr + + if(usr.stat || usr.restrained() || usr.incapacitated()) + return + + var/new_color = input(usr, "Pick a new color", "Color", color) as color|null + + if(new_color && (new_color != color)) + color = new_color + update_icon() + update_clothing_icon() +//VOREStation edit end + /obj/item/clothing/head/helmet/refit_for_species(var/target_species) if(!species_restricted) return //this item doesn't use the species_restricted system @@ -411,6 +435,8 @@ fingerprint_chance = 100 punch_force = 2 body_parts_covered = 0 + drop_sound = 'sound/items/drop/ring.ogg' + pickup_sound = 'sound/items/pickup/ring.ogg' /////////////////////////////////////////////////////////////////////// //Head @@ -549,6 +575,9 @@ var/list/say_messages var/list/say_verbs + drop_sound = "generic_drop" + pickup_sound = "generic_pickup" + /obj/item/clothing/mask/update_clothing_icon() if (ismob(src.loc)) var/mob/M = src.loc @@ -709,6 +738,7 @@ siemens_coefficient = 0.9 w_class = ITEMSIZE_NORMAL preserve_item = 1 + equip_sound = 'sound/items/jumpsuit_equip.ogg' sprite_sheets = list( diff --git a/code/modules/clothing/ears/ears.dm b/code/modules/clothing/ears/ears.dm index 8fdd6deb94..07e74d7321 100644 --- a/code/modules/clothing/ears/ears.dm +++ b/code/modules/clothing/ears/ears.dm @@ -53,8 +53,8 @@ desc = "A delicate golden chain worn by female skrell to decorate their head tails." icon_state = "skrell_chain" item_state_slots = list(slot_r_hand_str = "egg5", slot_l_hand_str = "egg5") - drop_sound = 'sound/items/drop/accessory.ogg' - pickup_sound = 'sound/items/pickup/accessory.ogg' + drop_sound = 'sound/items/drop/ring.ogg' + pickup_sound = 'sound/items/pickup/ring.ogg' /obj/item/clothing/ears/skrell/chain/silver name = "Silver headtail chains" @@ -85,8 +85,8 @@ desc = "Golden metallic bands worn by male skrell to adorn their head tails." icon_state = "skrell_band" item_state_slots = list(slot_r_hand_str = "egg5", slot_l_hand_str = "egg5") - drop_sound = 'sound/items/drop/accessory.ogg' - pickup_sound = 'sound/items/pickup/accessory.ogg' + drop_sound = 'sound/items/drop/ring.ogg' + pickup_sound = 'sound/items/pickup/ring.ogg' /obj/item/clothing/ears/skrell/band/silver name = "Silver headtail bands" diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index f83794efde..677c7a9943 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -1,523 +1,547 @@ -/////////////////////////////////////////////////////////////////////// -//Glasses -/* -SEE_SELF // can see self, no matter what -SEE_MOBS // can see all mobs, no matter what -SEE_OBJS // can see all objs, no matter what -SEE_TURFS // can see all turfs (and areas), no matter what -SEE_PIXELS// if an object is located on an unlit area, but some of its pixels are - // in a lit area (via pixel_x,y or smooth movement), can see those pixels -BLIND // can't see anything -*/ -/////////////////////////////////////////////////////////////////////// - -/obj/item/clothing/glasses - name = "glasses" - icon = 'icons/obj/clothing/glasses.dmi' - w_class = ITEMSIZE_SMALL - slot_flags = SLOT_EYES - plane_slots = list(slot_glasses) - var/vision_flags = 0 - var/darkness_view = 0//Base human is 2 - var/see_invisible = -1 - var/prescription = 0 - var/toggleable = 0 - var/off_state = "degoggles" - var/active = 1 - var/activation_sound = 'sound/items/goggles_charge.ogg' - var/obj/screen/overlay = null - var/list/away_planes //Holder for disabled planes - drop_sound = 'sound/items/drop/accessory.ogg' - pickup_sound = 'sound/items/pickup/accessory.ogg' - - sprite_sheets = list( - "Teshari" = 'icons/mob/species/seromi/eyes.dmi', - "Vox" = 'icons/mob/species/vox/eyes.dmi', - "Sergal" = 'icons/mob/species/sergal/eyes_yw.dmi', - SPECIES_GREY_YW = 'icons/mob/species/grey/eyes.dmi'/*ywedit*/ - ) - -/obj/item/clothing/glasses/update_clothing_icon() - if (ismob(src.loc)) - var/mob/M = src.loc - M.update_inv_glasses() - -/obj/item/clothing/glasses/proc/can_toggle(mob/living/user) - if(!toggleable) - return FALSE - - // Prevent people from just turning their goggles back on. - if(!active && (vision_flags & (SEE_TURFS|SEE_OBJS))) - var/area/A = get_area(src) - if(A.no_spoilers) - return FALSE - - return TRUE - -/obj/item/clothing/glasses/proc/toggle_active(mob/living/user) - if(active) - active = FALSE - icon_state = off_state - user.update_inv_glasses() - flash_protection = FLASH_PROTECTION_NONE - tint = TINT_NONE - away_planes = enables_planes - enables_planes = null - - else - active = TRUE - icon_state = initial(icon_state) - user.update_inv_glasses() - flash_protection = initial(flash_protection) - tint = initial(tint) - enables_planes = away_planes - away_planes = null - user.update_action_buttons() - user.recalculate_vis() - -/obj/item/clothing/glasses/attack_self(mob/user) - if(toggleable) - if(!can_toggle(user)) - to_chat(user, span("warning", "You don't seem to be able to toggle \the [src] here.")) - else - toggle_active(user) - if(active) - to_chat(user, span("notice", "You activate the optical matrix on the [src].")) - else - to_chat(user, span("notice", "You deactivate the optical matrix on the [src].")) - ..() - -/obj/item/clothing/glasses/meson - name = "optical meson scanner" - desc = "Used for seeing walls, floors, and stuff through anything." - icon_state = "meson" - item_state_slots = list(slot_r_hand_str = "meson", slot_l_hand_str = "meson") - action_button_name = "Toggle Goggles" - origin_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 2) - toggleable = 1 - vision_flags = SEE_TURFS - enables_planes = list(VIS_FULLBRIGHT, VIS_MESONS) - -/obj/item/clothing/glasses/meson/New() - ..() - overlay = global_hud.meson - -/obj/item/clothing/glasses/meson/prescription - name = "prescription mesons" - desc = "Optical Meson Scanner with prescription lenses." - prescription = 1 - -/obj/item/clothing/glasses/meson/aviator - name = "engineering aviators" - icon_state = "aviator_eng" - off_state = "aviator" - item_state_slots = list(slot_r_hand_str = "sunglasses", slot_l_hand_str = "sunglasses") - action_button_name = "Toggle HUD" - activation_sound = 'sound/effects/pop.ogg' - -/obj/item/clothing/glasses/meson/aviator/prescription - name = "prescription engineering aviators" - desc = "Engineering Aviators with prescription lenses." - prescription = 1 - -/obj/item/clothing/glasses/hud/health/aviator - name = "medical HUD aviators" - desc = "Modified aviator glasses with a toggled health HUD." - icon_state = "aviator_med" - off_state = "aviator" - action_button_name = "Toggle Mode" - toggleable = 1 - activation_sound = 'sound/effects/pop.ogg' - -/obj/item/clothing/glasses/hud/health/aviator/prescription - name = "prescription medical HUD aviators" - desc = "Modified aviator glasses with a toggled health HUD. Comes with bonus prescription lenses." - prescription = 6 - -/obj/item/clothing/glasses/science - name = "Science Goggles" - desc = "The goggles do nothing!" - icon_state = "purple" - item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") - toggleable = 1 - action_button_name = "Toggle Goggles" - item_flags = AIRTIGHT - -/obj/item/clothing/glasses/science/New() - ..() - overlay = global_hud.science - -/obj/item/clothing/glasses/goggles - name = "goggles" - desc = "Just some plain old goggles." - icon_state = "plaingoggles" - item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") - item_flags = AIRTIGHT - body_parts_covered = EYES - -/obj/item/clothing/glasses/night - name = "night vision goggles" - desc = "You can totally see in the dark now!" - icon_state = "night" - item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") - origin_tech = list(TECH_MAGNET = 2) - darkness_view = 7 - toggleable = 1 - action_button_name = "Toggle Goggles" - off_state = "denight" - flash_protection = FLASH_PROTECTION_REDUCED - enables_planes = list(VIS_FULLBRIGHT) - -/obj/item/clothing/glasses/night/vox - name = "Alien Optics" - species_restricted = list("Vox") - flags = PHORONGUARD - -/obj/item/clothing/glasses/night/New() - ..() - overlay = global_hud.nvg - -/obj/item/clothing/glasses/eyepatch - name = "eyepatch" - desc = "Yarr." - icon_state = "eyepatch" - item_state_slots = list(slot_r_hand_str = "blindfold", slot_l_hand_str = "blindfold") - body_parts_covered = 0 - var/eye = null - drop_sound = 'sound/items/drop/gloves.ogg' - pickup_sound = 'sound/items/pickup/gloves.ogg' - -/obj/item/clothing/glasses/eyepatch/verb/switcheye() - set name = "Switch Eyepatch" - set category = "Object" - set src in usr - if(!istype(usr, /mob/living)) return - if(usr.stat) return - - eye = !eye - if(eye) - icon_state = "[icon_state]_1" - else - icon_state = initial(icon_state) - update_clothing_icon() - -/obj/item/clothing/glasses/monocle - name = "monocle" - desc = "Such a dapper eyepiece!" - icon_state = "monocle" - item_state_slots = list(slot_r_hand_str = "headset", slot_l_hand_str = "headset") - body_parts_covered = 0 - -/obj/item/clothing/glasses/material - name = "optical material scanner" - desc = "Very confusing glasses." - icon_state = "material" - item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") - origin_tech = list(TECH_MAGNET = 3, TECH_ENGINEERING = 3) - toggleable = 1 - action_button_name = "Toggle Goggles" - vision_flags = SEE_OBJS - enables_planes = list(VIS_FULLBRIGHT) - -/obj/item/clothing/glasses/material/New() - ..() - overlay = global_hud.material - -/obj/item/clothing/glasses/material/prescription - name = "prescription optical material scanner" - prescription = 1 - -/obj/item/clothing/glasses/graviton - name = "graviton goggles" - desc = "The secrets of space travel are.. not quite yours." - icon_state = "grav" - item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") - origin_tech = list(TECH_MAGNET = 2, TECH_BLUESPACE = 1) - darkness_view = 5 - toggleable = 1 - action_button_name = "Toggle Goggles" - off_state = "denight" - vision_flags = SEE_OBJS | SEE_TURFS - flash_protection = FLASH_PROTECTION_REDUCED - enables_planes = list(VIS_FULLBRIGHT, VIS_MESONS) - -/obj/item/clothing/glasses/graviton/New() - ..() - overlay = global_hud.material - -/obj/item/clothing/glasses/regular - name = "prescription glasses" - desc = "Made by Nerd. Co." - icon_state = "glasses" - item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") - prescription = 1 - body_parts_covered = 0 - -/obj/item/clothing/glasses/regular/scanners - name = "scanning goggles" - desc = "A very oddly shaped pair of goggles with bits of wire poking out the sides. A soft humming sound emanates from it." - icon_state = "uzenwa_sissra_1" - -/obj/item/clothing/glasses/regular/hipster - name = "prescription glasses" - desc = "Made by Uncool. Co." - icon_state = "hipster_glasses" - -/obj/item/clothing/glasses/threedglasses - desc = "A long time ago, people used these glasses to makes images from screens threedimensional." - name = "3D glasses" - icon_state = "3d" - item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") - body_parts_covered = 0 - -/obj/item/clothing/glasses/gglasses - name = "green glasses" - desc = "Forest green glasses, like the kind you'd wear when hatching a nasty scheme." - icon_state = "gglasses" - item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") - body_parts_covered = 0 - -/obj/item/clothing/glasses/regular/rimless - name = "prescription rimless glasses" - desc = "Sleek modern glasses with a single sculpted lens." - icon_state = "glasses_rimless" - -/obj/item/clothing/glasses/rimless - name = "rimless glasses" - desc = "Sleek modern glasses with a single sculpted lens." - icon_state = "glasses_rimless" - prescription = 0 - -/obj/item/clothing/glasses/regular/thin - name = "prescription thin-rimmed glasses" - desc = "Glasses with frames are so last century." - icon_state = "glasses_thin" - prescription = 1 - -/obj/item/clothing/glasses/thin - name = "thin-rimmed glasses" - desc = "Glasses with frames are so last century." - icon_state = "glasses_thin" - prescription = 0 - - -/obj/item/clothing/glasses/sunglasses - name = "sunglasses" - desc = "Strangely ancient technology used to help provide rudimentary eye cover. Enhanced shielding blocks many flashes." - icon_state = "sun" - item_state_slots = list(slot_r_hand_str = "sunglasses", slot_l_hand_str = "sunglasses") - darkness_view = -1 - flash_protection = FLASH_PROTECTION_MODERATE - -/obj/item/clothing/glasses/sunglasses/aviator - name = "aviators" - desc = "A pair of designer sunglasses." - icon_state = "aviator" - -/obj/item/clothing/glasses/welding - name = "welding goggles" - desc = "Protects the eyes from welders, approved by the mad scientist association." - icon_state = "welding-g" - item_state_slots = list(slot_r_hand_str = "welding-g", slot_l_hand_str = "welding-g") - action_button_name = "Flip Welding Goggles" - matter = list(DEFAULT_WALL_MATERIAL = 1500, "glass" = 1000) - item_flags = AIRTIGHT - var/up = 0 - flash_protection = FLASH_PROTECTION_MAJOR - tint = TINT_HEAVY - -/obj/item/clothing/glasses/welding/attack_self() - toggle() - -/obj/item/clothing/glasses/welding/verb/toggle() - set category = "Object" - set name = "Adjust welding goggles" - set src in usr - - if(usr.canmove && !usr.stat && !usr.restrained()) - if(src.up) - src.up = !src.up - flags_inv |= HIDEEYES - body_parts_covered |= EYES - icon_state = initial(icon_state) - flash_protection = initial(flash_protection) - tint = initial(tint) - to_chat(usr, "You flip \the [src] down to protect your eyes.") - else - src.up = !src.up - flags_inv &= ~HIDEEYES - body_parts_covered &= ~EYES - icon_state = "[initial(icon_state)]up" - flash_protection = FLASH_PROTECTION_NONE - tint = TINT_NONE - to_chat(usr, "You push \the [src] up out of your face.") - update_clothing_icon() - usr.update_action_buttons() - -/obj/item/clothing/glasses/welding/superior - name = "superior welding goggles" - desc = "Welding goggles made from more expensive materials, strangely smells like potatoes." - icon_state = "rwelding-g" - tint = TINT_MODERATE - -/obj/item/clothing/glasses/sunglasses/blindfold - name = "blindfold" - desc = "Covers the eyes, preventing sight." - icon_state = "blindfold" - item_state_slots = list(slot_r_hand_str = "blindfold", slot_l_hand_str = "blindfold") - flash_protection = FLASH_PROTECTION_MAJOR - tint = BLIND - drop_sound = 'sound/items/drop/gloves.ogg' - pickup_sound = 'sound/items/pickup/gloves.ogg' - -/obj/item/clothing/glasses/sunglasses/blindfold/tape - name = "length of tape" - desc = "It's a robust DIY blindfold!" - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "tape_cross" - item_state_slots = list(slot_r_hand_str = null, slot_l_hand_str = null) - w_class = ITEMSIZE_TINY - -/obj/item/clothing/glasses/sunglasses/prescription - name = "prescription sunglasses" - prescription = 1 - -/obj/item/clothing/glasses/sunglasses/big - desc = "Strangely ancient technology used to help provide rudimentary eye cover. Larger than average enhanced shielding blocks many flashes." - icon_state = "bigsunglasses" - -/obj/item/clothing/glasses/fakesunglasses //Sunglasses without flash immunity - name = "stylish sunglasses" - desc = "A pair of designer sunglasses. Doesn't seem like it'll block flashes." - icon_state = "sun" - item_state_slots = list(slot_r_hand_str = "sunglasses", slot_l_hand_str = "sunglasses") - -/obj/item/clothing/glasses/fakesunglasses/aviator - name = "stylish aviators" - desc = "A pair of designer sunglasses. Doesn't seem like it'll block flashes." - icon_state = "aviator" - -/obj/item/clothing/glasses/sunglasses/sechud - name = "\improper HUD sunglasses" - desc = "Sunglasses with a HUD." - icon_state = "sunSecHud" - enables_planes = list(VIS_CH_ID,VIS_CH_WANTED,VIS_CH_IMPTRACK,VIS_CH_IMPLOYAL,VIS_CH_IMPCHEM) - -/obj/item/clothing/glasses/sunglasses/sechud/tactical - name = "tactical HUD" - desc = "Flash-resistant goggles with inbuilt combat and security information." - icon_state = "swatgoggles" - -/obj/item/clothing/glasses/sunglasses/sechud/aviator - name = "security HUD aviators" - desc = "Modified aviator glasses that can be switch between HUD and flash protection modes." - icon_state = "aviator_sec" - off_state = "aviator" - action_button_name = "Toggle Mode" - var/on = 1 - toggleable = 1 - activation_sound = 'sound/effects/pop.ogg' - -/obj/item/clothing/glasses/sunglasses/sechud/aviator/attack_self(mob/user) - if(toggleable && !user.incapacitated()) - on = !on - if(on) - flash_protection = FLASH_PROTECTION_NONE - enables_planes = away_planes - away_planes = null - to_chat(usr, "You switch the [src] to HUD mode.") - else - flash_protection = initial(flash_protection) - away_planes = enables_planes - enables_planes = null - to_chat(usr, "You switch \the [src] to flash protection mode.") - update_icon() - user << activation_sound - user.recalculate_vis() - user.update_inv_glasses() - user.update_action_buttons() - -/obj/item/clothing/glasses/sunglasses/sechud/aviator/update_icon() - if(on) - icon_state = initial(icon_state) - else - icon_state = off_state - -/obj/item/clothing/glasses/sunglasses/sechud/aviator/prescription - name = "prescription security HUD aviators" - desc = "Modified aviator glasses that can be switch between HUD and flash protection modes. Comes with bonus prescription lenses." - prescription = 6 - -/obj/item/clothing/glasses/sunglasses/medhud - name = "\improper HUD sunglasses" - desc = "Sunglasses with a HUD." - icon_state = "sunMedHud" - enables_planes = list(VIS_CH_STATUS,VIS_CH_HEALTH) - -/obj/item/clothing/glasses/thermal - name = "optical thermal scanner" - desc = "Thermals in the shape of glasses." - icon_state = "thermal" - item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") - origin_tech = list(TECH_MAGNET = 3) - toggleable = 1 - action_button_name = "Toggle Goggles" - vision_flags = SEE_MOBS - enables_planes = list(VIS_FULLBRIGHT, VIS_CLOAKED) - flash_protection = FLASH_PROTECTION_REDUCED - - emp_act(severity) - if(istype(src.loc, /mob/living/carbon/human)) - var/mob/living/carbon/human/M = src.loc - to_chat(M, "The Optical Thermal Scanner overloads and blinds you!") - if(M.glasses == src) - M.Blind(3) - M.eye_blurry = 5 - // Don't cure being nearsighted - if(!(M.disabilities & NEARSIGHTED)) - M.disabilities |= NEARSIGHTED - spawn(100) - M.disabilities &= ~NEARSIGHTED - ..() - -/obj/item/clothing/glasses/thermal/New() - ..() - overlay = global_hud.thermal - -/obj/item/clothing/glasses/thermal/syndi //These are now a traitor item, concealed as mesons. -Pete - name = "optical meson scanner" - desc = "Used for seeing walls, floors, and stuff through anything." - icon_state = "meson" - item_state_slots = list(slot_r_hand_str = "meson", slot_l_hand_str = "meson") - origin_tech = list(TECH_MAGNET = 3, TECH_ILLEGAL = 4) - -/obj/item/clothing/glasses/thermal/plain - toggleable = 0 - activation_sound = null - action_button_name = null - -/obj/item/clothing/glasses/thermal/plain/monocle - name = "thermonocle" - desc = "A monocle thermal." - icon_state = "thermoncle" - item_state_slots = list(slot_r_hand_str = "sunglasses", slot_l_hand_str = "sunglasses") - toggleable = 1 - action_button_name = "Toggle Monocle" - flags = null //doesn't protect eyes because it's a monocle, duh - - body_parts_covered = 0 - -/obj/item/clothing/glasses/thermal/plain/eyepatch - name = "optical thermal eyepatch" - desc = "An eyepatch with built-in thermal optics" - icon_state = "eyepatch" - item_state_slots = list(slot_r_hand_str = "blindfold", slot_l_hand_str = "blindfold") - body_parts_covered = 0 - toggleable = 1 - action_button_name = "Toggle Eyepatch" - -/obj/item/clothing/glasses/thermal/plain/jensen - name = "optical thermal implants" - desc = "A set of implantable lenses designed to augment your vision" - icon_state = "thermalimplants" - item_state_slots = list(slot_r_hand_str = "sunglasses", slot_l_hand_str = "sunglasses") +/////////////////////////////////////////////////////////////////////// +//Glasses +/* +SEE_SELF // can see self, no matter what +SEE_MOBS // can see all mobs, no matter what +SEE_OBJS // can see all objs, no matter what +SEE_TURFS // can see all turfs (and areas), no matter what +SEE_PIXELS// if an object is located on an unlit area, but some of its pixels are + // in a lit area (via pixel_x,y or smooth movement), can see those pixels +BLIND // can't see anything +*/ +/////////////////////////////////////////////////////////////////////// + +/obj/item/clothing/glasses + name = "glasses" + icon = 'icons/obj/clothing/glasses.dmi' + w_class = ITEMSIZE_SMALL + slot_flags = SLOT_EYES + plane_slots = list(slot_glasses) + var/vision_flags = 0 + var/darkness_view = 0//Base human is 2 + var/see_invisible = -1 + var/prescription = 0 + var/toggleable = 0 + var/off_state = "degoggles" + var/active = 1 + var/activation_sound = 'sound/items/goggles_charge.ogg' + var/obj/screen/overlay = null + var/list/away_planes //Holder for disabled planes + drop_sound = 'sound/items/drop/accessory.ogg' + pickup_sound = 'sound/items/pickup/accessory.ogg' + + sprite_sheets = list( + "Teshari" = 'icons/mob/species/seromi/eyes.dmi', + "Vox" = 'icons/mob/species/vox/eyes.dmi', + "Sergal" = 'icons/mob/species/sergal/eyes_yw.dmi', + SPECIES_GREY_YW = 'icons/mob/species/grey/eyes.dmi'/*ywedit*/ + ) + +/obj/item/clothing/glasses/update_clothing_icon() + if (ismob(src.loc)) + var/mob/M = src.loc + M.update_inv_glasses() + +/obj/item/clothing/glasses/proc/can_toggle(mob/living/user) + if(!toggleable) + return FALSE + + // Prevent people from just turning their goggles back on. + if(!active && (vision_flags & (SEE_TURFS|SEE_OBJS))) + var/area/A = get_area(src) + if(A.no_spoilers) + return FALSE + + return TRUE + +/obj/item/clothing/glasses/proc/toggle_active(mob/living/user) + if(active) + active = FALSE + icon_state = off_state + user.update_inv_glasses() + flash_protection = FLASH_PROTECTION_NONE + tint = TINT_NONE + away_planes = enables_planes + enables_planes = null + + else + active = TRUE + icon_state = initial(icon_state) + user.update_inv_glasses() + flash_protection = initial(flash_protection) + tint = initial(tint) + enables_planes = away_planes + away_planes = null + user.update_action_buttons() + user.recalculate_vis() + +/obj/item/clothing/glasses/attack_self(mob/user) + if(toggleable) + if(!can_toggle(user)) + to_chat(user, span("warning", "You don't seem to be able to toggle \the [src] here.")) + else + toggle_active(user) + if(active) + to_chat(user, span("notice", "You activate the optical matrix on the [src].")) + else + to_chat(user, span("notice", "You deactivate the optical matrix on the [src].")) + ..() + +/obj/item/clothing/glasses/meson + name = "optical meson scanner" + desc = "Used for seeing walls, floors, and stuff through anything." + icon_state = "meson" + item_state_slots = list(slot_r_hand_str = "meson", slot_l_hand_str = "meson") + action_button_name = "Toggle Goggles" + origin_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 2) + toggleable = 1 + vision_flags = SEE_TURFS + enables_planes = list(VIS_FULLBRIGHT, VIS_MESONS) + +/obj/item/clothing/glasses/meson/New() + ..() + overlay = global_hud.meson + +/obj/item/clothing/glasses/meson/prescription + name = "prescription mesons" + desc = "Optical Meson Scanner with prescription lenses." + prescription = 1 + +/obj/item/clothing/glasses/meson/aviator + name = "engineering aviators" + icon_state = "aviator_eng" + off_state = "aviator" + item_state_slots = list(slot_r_hand_str = "sunglasses", slot_l_hand_str = "sunglasses") + action_button_name = "Toggle HUD" + activation_sound = 'sound/effects/pop.ogg' + +/obj/item/clothing/glasses/meson/aviator/prescription + name = "prescription engineering aviators" + desc = "Engineering Aviators with prescription lenses." + prescription = 1 + +/obj/item/clothing/glasses/hud/health/aviator + name = "medical HUD aviators" + desc = "Modified aviator glasses with a toggled health HUD." + icon_state = "aviator_med" + off_state = "aviator" + action_button_name = "Toggle Mode" + toggleable = 1 + activation_sound = 'sound/effects/pop.ogg' + +/obj/item/clothing/glasses/hud/health/aviator/prescription + name = "prescription medical HUD aviators" + desc = "Modified aviator glasses with a toggled health HUD. Comes with bonus prescription lenses." + prescription = 6 + +/obj/item/clothing/glasses/science + name = "Science Goggles" + desc = "The goggles do nothing!" + icon_state = "purple" + item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") + toggleable = 1 + action_button_name = "Toggle Goggles" + item_flags = AIRTIGHT + +/obj/item/clothing/glasses/science/New() + ..() + overlay = global_hud.science + +/obj/item/clothing/glasses/goggles + name = "goggles" + desc = "Just some plain old goggles." + icon_state = "plaingoggles" + item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") + item_flags = AIRTIGHT + body_parts_covered = EYES + +/obj/item/clothing/glasses/night + name = "night vision goggles" + desc = "You can totally see in the dark now!" + icon_state = "night" + item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") + origin_tech = list(TECH_MAGNET = 2) + darkness_view = 7 + toggleable = 1 + action_button_name = "Toggle Goggles" + off_state = "denight" + flash_protection = FLASH_PROTECTION_REDUCED + enables_planes = list(VIS_FULLBRIGHT) + +/obj/item/clothing/glasses/night/vox + name = "Alien Optics" + species_restricted = list("Vox") + flags = PHORONGUARD + +/obj/item/clothing/glasses/night/New() + ..() + overlay = global_hud.nvg + +/obj/item/clothing/glasses/eyepatch + name = "eyepatch" + desc = "Yarr." + icon_state = "eyepatch" + item_state_slots = list(slot_r_hand_str = "blindfold", slot_l_hand_str = "blindfold") + body_parts_covered = 0 + var/eye = null + drop_sound = 'sound/items/drop/gloves.ogg' + pickup_sound = 'sound/items/pickup/gloves.ogg' + +/obj/item/clothing/glasses/eyepatch/verb/switcheye() + set name = "Switch Eyepatch" + set category = "Object" + set src in usr + if(!istype(usr, /mob/living)) return + if(usr.stat) return + + eye = !eye + if(eye) + icon_state = "[icon_state]_1" + else + icon_state = initial(icon_state) + update_clothing_icon() + +/obj/item/clothing/glasses/eyepatchwhite + name = "eyepatch" + desc = "A simple eyepatch made of a strip of cloth tied around the head." + icon_state = "eyepatch_white" + item_state_slots = list(slot_r_hand_str = "blindfold", slot_l_hand_str = "blindfold") + body_parts_covered = 0 + var/eye = null + drop_sound = 'sound/items/drop/gloves.ogg' + pickup_sound = 'sound/items/pickup/gloves.ogg' + +/obj/item/clothing/glasses/eyepatchwhite/verb/switcheye() + set name = "Switch Eyepatch" + set category = "Object" + set src in usr + if(!istype(usr, /mob/living)) return + if(usr.stat) return + + eye = !eye + if(eye) + icon_state = "[icon_state]_1" + else + icon_state = initial(icon_state) + update_clothing_icon() + +/obj/item/clothing/glasses/monocle + name = "monocle" + desc = "Such a dapper eyepiece!" + icon_state = "monocle" + item_state_slots = list(slot_r_hand_str = "headset", slot_l_hand_str = "headset") + body_parts_covered = 0 + +/obj/item/clothing/glasses/material + name = "optical material scanner" + desc = "Very confusing glasses." + icon_state = "material" + item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") + origin_tech = list(TECH_MAGNET = 3, TECH_ENGINEERING = 3) + toggleable = 1 + action_button_name = "Toggle Goggles" + vision_flags = SEE_OBJS + enables_planes = list(VIS_FULLBRIGHT) + +/obj/item/clothing/glasses/material/New() + ..() + overlay = global_hud.material + +/obj/item/clothing/glasses/material/prescription + name = "prescription optical material scanner" + prescription = 1 + +/obj/item/clothing/glasses/graviton + name = "graviton goggles" + desc = "The secrets of space travel are.. not quite yours." + icon_state = "grav" + item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") + origin_tech = list(TECH_MAGNET = 2, TECH_BLUESPACE = 1) + darkness_view = 5 + toggleable = 1 + action_button_name = "Toggle Goggles" + off_state = "denight" + vision_flags = SEE_OBJS | SEE_TURFS + flash_protection = FLASH_PROTECTION_REDUCED + enables_planes = list(VIS_FULLBRIGHT, VIS_MESONS) + +/obj/item/clothing/glasses/graviton/New() + ..() + overlay = global_hud.material + +/obj/item/clothing/glasses/regular + name = "prescription glasses" + desc = "Made by Nerd. Co." + icon_state = "glasses" + item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") + prescription = 1 + body_parts_covered = 0 + +/obj/item/clothing/glasses/regular/scanners + name = "scanning goggles" + desc = "A very oddly shaped pair of goggles with bits of wire poking out the sides. A soft humming sound emanates from it." + icon_state = "uzenwa_sissra_1" + +/obj/item/clothing/glasses/regular/hipster + name = "prescription glasses" + desc = "Made by Uncool. Co." + icon_state = "hipster_glasses" + +/obj/item/clothing/glasses/threedglasses + desc = "A long time ago, people used these glasses to makes images from screens threedimensional." + name = "3D glasses" + icon_state = "3d" + item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") + body_parts_covered = 0 + +/obj/item/clothing/glasses/gglasses + name = "green glasses" + desc = "Forest green glasses, like the kind you'd wear when hatching a nasty scheme." + icon_state = "gglasses" + item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") + body_parts_covered = 0 + +/obj/item/clothing/glasses/regular/rimless + name = "prescription rimless glasses" + desc = "Sleek modern glasses with a single sculpted lens." + icon_state = "glasses_rimless" + +/obj/item/clothing/glasses/rimless + name = "rimless glasses" + desc = "Sleek modern glasses with a single sculpted lens." + icon_state = "glasses_rimless" + prescription = 0 + +/obj/item/clothing/glasses/regular/thin + name = "prescription thin-rimmed glasses" + desc = "Glasses with frames are so last century." + icon_state = "glasses_thin" + prescription = 1 + +/obj/item/clothing/glasses/thin + name = "thin-rimmed glasses" + desc = "Glasses with frames are so last century." + icon_state = "glasses_thin" + prescription = 0 + + +/obj/item/clothing/glasses/sunglasses + name = "sunglasses" + desc = "Strangely ancient technology used to help provide rudimentary eye cover. Enhanced shielding blocks many flashes." + icon_state = "sun" + item_state_slots = list(slot_r_hand_str = "sunglasses", slot_l_hand_str = "sunglasses") + darkness_view = -1 + flash_protection = FLASH_PROTECTION_MODERATE + +/obj/item/clothing/glasses/sunglasses/aviator + name = "aviators" + desc = "A pair of designer sunglasses." + icon_state = "aviator" + +/obj/item/clothing/glasses/welding + name = "welding goggles" + desc = "Protects the eyes from welders, approved by the mad scientist association." + icon_state = "welding-g" + item_state_slots = list(slot_r_hand_str = "welding-g", slot_l_hand_str = "welding-g") + action_button_name = "Flip Welding Goggles" + matter = list(DEFAULT_WALL_MATERIAL = 1500, "glass" = 1000) + item_flags = AIRTIGHT + var/up = 0 + flash_protection = FLASH_PROTECTION_MAJOR + tint = TINT_HEAVY + +/obj/item/clothing/glasses/welding/attack_self() + toggle() + +/obj/item/clothing/glasses/welding/verb/toggle() + set category = "Object" + set name = "Adjust welding goggles" + set src in usr + + if(usr.canmove && !usr.stat && !usr.restrained()) + if(src.up) + src.up = !src.up + flags_inv |= HIDEEYES + body_parts_covered |= EYES + icon_state = initial(icon_state) + flash_protection = initial(flash_protection) + tint = initial(tint) + to_chat(usr, "You flip \the [src] down to protect your eyes.") + else + src.up = !src.up + flags_inv &= ~HIDEEYES + body_parts_covered &= ~EYES + icon_state = "[initial(icon_state)]up" + flash_protection = FLASH_PROTECTION_NONE + tint = TINT_NONE + to_chat(usr, "You push \the [src] up out of your face.") + update_clothing_icon() + usr.update_action_buttons() + +/obj/item/clothing/glasses/welding/superior + name = "superior welding goggles" + desc = "Welding goggles made from more expensive materials, strangely smells like potatoes." + icon_state = "rwelding-g" + tint = TINT_MODERATE + +/obj/item/clothing/glasses/sunglasses/blindfold + name = "blindfold" + desc = "Covers the eyes, preventing sight." + icon_state = "blindfold" + item_state_slots = list(slot_r_hand_str = "blindfold", slot_l_hand_str = "blindfold") + flash_protection = FLASH_PROTECTION_MAJOR + tint = BLIND + drop_sound = 'sound/items/drop/gloves.ogg' + pickup_sound = 'sound/items/pickup/gloves.ogg' + +/obj/item/clothing/glasses/sunglasses/blindfold/tape + name = "length of tape" + desc = "It's a robust DIY blindfold!" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "tape_cross" + item_state_slots = list(slot_r_hand_str = null, slot_l_hand_str = null) + w_class = ITEMSIZE_TINY + +/obj/item/clothing/glasses/sunglasses/prescription + name = "prescription sunglasses" + prescription = 1 + +/obj/item/clothing/glasses/sunglasses/big + desc = "Strangely ancient technology used to help provide rudimentary eye cover. Larger than average enhanced shielding blocks many flashes." + icon_state = "bigsunglasses" + +/obj/item/clothing/glasses/fakesunglasses //Sunglasses without flash immunity + name = "stylish sunglasses" + desc = "A pair of designer sunglasses. Doesn't seem like it'll block flashes." + icon_state = "sun" + item_state_slots = list(slot_r_hand_str = "sunglasses", slot_l_hand_str = "sunglasses") + +/obj/item/clothing/glasses/fakesunglasses/aviator + name = "stylish aviators" + desc = "A pair of designer sunglasses. Doesn't seem like it'll block flashes." + icon_state = "aviator" + +/obj/item/clothing/glasses/sunglasses/sechud + name = "\improper HUD sunglasses" + desc = "Sunglasses with a HUD." + icon_state = "sunSecHud" + enables_planes = list(VIS_CH_ID,VIS_CH_WANTED,VIS_CH_IMPTRACK,VIS_CH_IMPLOYAL,VIS_CH_IMPCHEM) + +/obj/item/clothing/glasses/sunglasses/sechud/tactical + name = "tactical HUD" + desc = "Flash-resistant goggles with inbuilt combat and security information." + icon_state = "swatgoggles" + +/obj/item/clothing/glasses/sunglasses/sechud/aviator + name = "security HUD aviators" + desc = "Modified aviator glasses that can be switch between HUD and flash protection modes." + icon_state = "aviator_sec" + off_state = "aviator" + action_button_name = "Toggle Mode" + var/on = 1 + toggleable = 1 + activation_sound = 'sound/effects/pop.ogg' + +/obj/item/clothing/glasses/sunglasses/sechud/aviator/attack_self(mob/user) + if(toggleable && !user.incapacitated()) + on = !on + if(on) + flash_protection = FLASH_PROTECTION_NONE + enables_planes = away_planes + away_planes = null + to_chat(usr, "You switch the [src] to HUD mode.") + else + flash_protection = initial(flash_protection) + away_planes = enables_planes + enables_planes = null + to_chat(usr, "You switch \the [src] to flash protection mode.") + update_icon() + user << activation_sound + user.recalculate_vis() + user.update_inv_glasses() + user.update_action_buttons() + +/obj/item/clothing/glasses/sunglasses/sechud/aviator/update_icon() + if(on) + icon_state = initial(icon_state) + else + icon_state = off_state + +/obj/item/clothing/glasses/sunglasses/sechud/aviator/prescription + name = "prescription security HUD aviators" + desc = "Modified aviator glasses that can be switch between HUD and flash protection modes. Comes with bonus prescription lenses." + prescription = 6 + +/obj/item/clothing/glasses/sunglasses/medhud + name = "\improper HUD sunglasses" + desc = "Sunglasses with a HUD." + icon_state = "sunMedHud" + enables_planes = list(VIS_CH_STATUS,VIS_CH_HEALTH) + +/obj/item/clothing/glasses/thermal + name = "optical thermal scanner" + desc = "Thermals in the shape of glasses." + icon_state = "thermal" + item_state_slots = list(slot_r_hand_str = "glasses", slot_l_hand_str = "glasses") + origin_tech = list(TECH_MAGNET = 3) + toggleable = 1 + action_button_name = "Toggle Goggles" + vision_flags = SEE_MOBS + enables_planes = list(VIS_FULLBRIGHT, VIS_CLOAKED) + flash_protection = FLASH_PROTECTION_REDUCED + + emp_act(severity) + if(istype(src.loc, /mob/living/carbon/human)) + var/mob/living/carbon/human/M = src.loc + to_chat(M, "The Optical Thermal Scanner overloads and blinds you!") + if(M.glasses == src) + M.Blind(3) + M.eye_blurry = 5 + // Don't cure being nearsighted + if(!(M.disabilities & NEARSIGHTED)) + M.disabilities |= NEARSIGHTED + spawn(100) + M.disabilities &= ~NEARSIGHTED + ..() + +/obj/item/clothing/glasses/thermal/New() + ..() + overlay = global_hud.thermal + +/obj/item/clothing/glasses/thermal/syndi //These are now a traitor item, concealed as mesons. -Pete + name = "optical meson scanner" + desc = "Used for seeing walls, floors, and stuff through anything." + icon_state = "meson" + item_state_slots = list(slot_r_hand_str = "meson", slot_l_hand_str = "meson") + origin_tech = list(TECH_MAGNET = 3, TECH_ILLEGAL = 4) + +/obj/item/clothing/glasses/thermal/plain + toggleable = 0 + activation_sound = null + action_button_name = null + +/obj/item/clothing/glasses/thermal/plain/monocle + name = "thermonocle" + desc = "A monocle thermal." + icon_state = "thermoncle" + item_state_slots = list(slot_r_hand_str = "sunglasses", slot_l_hand_str = "sunglasses") + toggleable = 1 + action_button_name = "Toggle Monocle" + flags = null //doesn't protect eyes because it's a monocle, duh + + body_parts_covered = 0 + +/obj/item/clothing/glasses/thermal/plain/eyepatch + name = "optical thermal eyepatch" + desc = "An eyepatch with built-in thermal optics" + icon_state = "eyepatch" + item_state_slots = list(slot_r_hand_str = "blindfold", slot_l_hand_str = "blindfold") + body_parts_covered = 0 + toggleable = 1 + action_button_name = "Toggle Eyepatch" + +/obj/item/clothing/glasses/thermal/plain/jensen + name = "optical thermal implants" + desc = "A set of implantable lenses designed to augment your vision" + icon_state = "thermalimplants" + item_state_slots = list(slot_r_hand_str = "sunglasses", slot_l_hand_str = "sunglasses") \ No newline at end of file diff --git a/code/modules/clothing/glasses/hud_vr.dm b/code/modules/clothing/glasses/hud_vr.dm index be02be0c47..5895b9a08c 100644 --- a/code/modules/clothing/glasses/hud_vr.dm +++ b/code/modules/clothing/glasses/hud_vr.dm @@ -8,8 +8,6 @@ var/obj/item/clothing/glasses/hud/omni/hud = null var/mode = "civ" icon_state = "glasses" - var/datum/nano_module/arscreen - var/arscreen_path var/datum/tgui_module/tgarscreen var/tgarscreen_path var/flash_prot = 0 //0 for none, 1 for flash weapon protection, 2 for welder protection @@ -18,34 +16,24 @@ /obj/item/clothing/glasses/omnihud/New() ..() - if(arscreen_path) - arscreen = new arscreen_path(src) if(tgarscreen_path) tgarscreen = new tgarscreen_path(src) /obj/item/clothing/glasses/omnihud/Destroy() - QDEL_NULL(arscreen) QDEL_NULL(tgarscreen) . = ..() /obj/item/clothing/glasses/omnihud/dropped() - if(arscreen) - SSnanoui.close_uis(src) if(tgarscreen) SStgui.close_uis(src) ..() /obj/item/clothing/glasses/omnihud/emp_act(var/severity) - if(arscreen) - SSnanoui.close_uis(src) if(tgarscreen) SStgui.close_uis(src) - var/disconnect_ar = arscreen var/disconnect_tgar = tgarscreen - arscreen = null tgarscreen = null spawn(20 SECONDS) - arscreen = disconnect_ar tgarscreen = disconnect_tgar //extra fun for non-sci variants; a small chance flip the state to the dumb 3d glasses when EMP'd diff --git a/code/modules/clothing/head/flowercrowns.dm b/code/modules/clothing/head/flowercrowns.dm index 15bfe16162..81193f337d 100644 --- a/code/modules/clothing/head/flowercrowns.dm +++ b/code/modules/clothing/head/flowercrowns.dm @@ -37,6 +37,7 @@ icon_state = "sunflower_crown" body_parts_covered = 0 drop_sound = 'sound/items/drop/herb.ogg' + pickup_sound = 'sound/items/pickup/herb.ogg' /obj/item/clothing/head/lavender_crown name = "lavender crown" @@ -44,6 +45,7 @@ icon_state = "lavender_crown" body_parts_covered = 0 drop_sound = 'sound/items/drop/herb.ogg' + pickup_sound = 'sound/items/pickup/herb.ogg' /obj/item/clothing/head/poppy_crown name = "poppy crown" @@ -51,6 +53,7 @@ icon_state = "poppy_crown" body_parts_covered = 0 drop_sound = 'sound/items/drop/herb.ogg' + pickup_sound = 'sound/items/pickup/herb.ogg' /obj/item/clothing/head/rose_crown name = "rose crown" @@ -58,3 +61,4 @@ icon_state = "poppy_crown" body_parts_covered = 0 drop_sound = 'sound/items/drop/herb.ogg' + pickup_sound = 'sound/items/pickup/herb.ogg' diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm index 818c91eda5..dff571c50f 100644 --- a/code/modules/clothing/head/misc.dm +++ b/code/modules/clothing/head/misc.dm @@ -17,8 +17,8 @@ desc = "A nice hair pin." slot_flags = SLOT_HEAD | SLOT_EARS body_parts_covered = 0 - drop_sound = 'sound/items/drop/ring.ogg' - pickup_sound = 'sound/items/pickup/ring.ogg' + drop_sound = 'sound/items/drop/accessory.ogg' + pickup_sound = 'sound/items/pickup/accessory.ogg' /obj/item/clothing/head/pin/pink icon_state = "pinkpin" @@ -424,7 +424,8 @@ desc = "A jeweled headpiece originating in India." icon_state = "maangtikka" body_parts_covered = 0 - drop_sound = 'sound/items/drop/accessory.ogg' + drop_sound = 'sound/items/drop/ring.ogg' + pickup_sound = 'sound/items/pickup/ring.ogg' /obj/item/clothing/head/jingasa name = "jingasa" diff --git a/code/modules/clothing/head/misc_vr.dm b/code/modules/clothing/head/misc_vr.dm index 5e70a0fcb8..0dbfa97d5e 100644 --- a/code/modules/clothing/head/misc_vr.dm +++ b/code/modules/clothing/head/misc_vr.dm @@ -22,3 +22,28 @@ icon_state = "fancycrown" icon = 'icons/obj/clothing/hats_vr.dmi' icon_override = 'icons/mob/head_vr.dmi' + +/obj/item/clothing/head/shiny_hood + icon_override = 'icons/mob/modular_shiny_vr.dmi' + icon = 'icons/obj/clothing/modular_shiny_vr.dmi' + name = "shiny hood" + desc = "You can be a super-hero in this! Just don't forget your suit!" + icon_state = "hood_o" + flags_inv = HIDEFACE|BLOCKHAIR + body_parts_covered = FACE|HEAD + +/obj/item/clothing/head/shiny_hood/poly + name = "polychromic shiny hood" + icon_state = "hood_col_o" + polychromic = TRUE + +/obj/item/clothing/head/shiny_hood/closed + name = "shiny hood" + desc = "You can be a super-hero in this! Just don't forget your superhuman senses!" + icon_state = "hood_c" + gas_transfer_coefficient = 0.90 + +/obj/item/clothing/head/shiny_hood/closed/poly + name = "polychromic closed shiny hood" + icon_state = "hood_col_o" + polychromic = TRUE \ No newline at end of file diff --git a/code/modules/clothing/masks/breath.dm b/code/modules/clothing/masks/breath.dm index b64f437207..cf7a0bc939 100644 --- a/code/modules/clothing/masks/breath.dm +++ b/code/modules/clothing/masks/breath.dm @@ -10,6 +10,8 @@ permeability_coefficient = 0.50 var/hanging = 0 action_button_name = "Adjust Breath Mask" + pickup_sound = 'sound/items/pickup/component.ogg' + drop_sound = 'sound/items/drop/component.ogg' /obj/item/clothing/mask/breath/proc/adjust_mask(mob/user) diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm index 594600b601..25b9e00f68 100644 --- a/code/modules/clothing/masks/gasmask.dm +++ b/code/modules/clothing/masks/gasmask.dm @@ -13,6 +13,7 @@ var/gas_filter_strength = 1 //For gas mask filters var/list/filtered_gases = list("phoron", "nitrous_oxide") armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 75, rad = 0) + pickup_sound = 'sound/items/pickup/rubber.ogg' /obj/item/clothing/mask/gas/filter_air(datum/gas_mixture/air) var/datum/gas_mixture/gas_filtered = new @@ -42,6 +43,23 @@ w_class = ITEMSIZE_SMALL armor = list(melee = 10, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 55, rad = 0) +//Turn it into a hailer mask +/obj/item/clothing/mask/gas/half/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/device/hailer)) + playsound(src, 'sound/items/Screwdriver.ogg', 50, 1) + user.drop_item(src) + var/obj/item/clothing/mask/gas/sechailer/N = new /obj/item/clothing/mask/gas/sechailer(src.loc) + N.fingerprints = src.fingerprints + N.fingerprintshidden = src.fingerprintshidden + N.fingerprintslast = src.fingerprintslast + N.suit_fibers = src.suit_fibers + N.hailer = I + I.loc = N + if(!isturf(N.loc)) + user.put_in_hands(N) + qdel(src) + ..() + //Plague Dr suit can be found in clothing/suits/bio.dm /obj/item/clothing/mask/gas/plaguedoctor name = "plague doctor mask" diff --git a/code/modules/clothing/masks/hailer.dm b/code/modules/clothing/masks/hailer.dm new file mode 100644 index 0000000000..a3a37772b3 --- /dev/null +++ b/code/modules/clothing/masks/hailer.dm @@ -0,0 +1,165 @@ +/obj/item/clothing/mask/gas/sechailer + name = "hailer face mask" + desc = "A compact, durable gas mask that can be connected to an air supply. This one possesses a security hailer." + description_info = "This mask has a hailer attached, you can activate it on the button or use the Halt! verb, for switching phrases you can alt+click it or change it using the change phrase verb." + icon_state = "halfgas" + armor = list(melee = 10, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 55, rad = 0) + action_button_name = "HALT!" + body_parts_covered = FACE + var/obj/item/device/hailer/hailer + var/cooldown = 0 + var/phrase = 1 + var/aggressiveness = 1 + var/safety = 1 + var/list/phrase_list = list( + "halt" = "HALT! HALT! HALT! HALT!", + "bobby" = "Stop in the name of the Law.", + "compliance" = "Compliance is in your best interest.", + "justice" = "Prepare for justice!", + "running" = "Running will only increase your sentence.", + "dontmove" = "Don't move, Creep!", + "floor" = "Down on the floor, Creep!", + "robocop" = "Dead or alive you're coming with me.", + "god" = "God made today for the crooks we could not catch yesterday.", + "freeze" = "Freeze, Scum Bag!", + "imperial" = "Stop right there, criminal scum!", + "bash" = "Stop or I'll bash you.", + "harry" = "Go ahead, make my day.", + "asshole" = "Stop breaking the law, asshole.", + "stfu" = "You have the right to shut the fuck up", + "shutup" = "Shut up crime!", + "super" = "Face the wrath of the golden bolt.", + "dredd" = "I am, the LAW!" + ) + +/obj/item/clothing/mask/gas/sechailer/swat/hos + name = "\improper HOS SWAT mask" + desc = "A close-fitting tactical mask with an especially aggressive Compli-o-nator 3000. It has a tan stripe." + icon_state = "hosmask" + + +/obj/item/clothing/mask/gas/sechailer/swat/warden + name = "\improper Warden SWAT mask" + desc = "A close-fitting tactical mask with an especially aggressive Compli-o-nator 3000. It has a blue stripe." + icon_state = "wardenmask" + +/obj/item/clothing/mask/gas/sechailer/swat + name = "\improper SWAT mask" + desc = "A close-fitting tactical mask with an especially aggressive Compli-o-nator 3000." + icon_state = "officermask" + body_parts_covered = HEAD|FACE|EYES + flags_inv = HIDEFACE|BLOCKHAIR + aggressiveness = 3 + phrase = 12 + + +/obj/item/clothing/mask/gas/sechailer/ui_action_click() + halt() + +/obj/item/clothing/mask/gas/sechailer/AltClick(mob/user) + selectphrase() + +/obj/item/clothing/mask/gas/sechailer/verb/selectphrase() + set name = "Select gas mask phrase" + set category = "Object" + set desc = "Alter the message shouted by your complionator gas mask." + + var/key = phrase_list[phrase] + var/message = phrase_list[key] + + if (!safety) + to_chat(usr, "You set the restrictor to: FUCK YOUR CUNT YOU SHIT EATING COCKSUCKER MAN EAT A DONG FUCKING ASS RAMMING SHIT FUCK EAT PENISES IN YOUR FUCK FACE AND SHIT OUT ABORTIONS OF FUCK AND DO SHIT IN YOUR ASS YOU COCK FUCK SHIT MONKEY FUCK ASS WANKER FROM THE DEPTHS OF SHIT.") + return + switch(aggressiveness) + if(1) + phrase = (phrase < 6) ? (phrase + 1) : 1 + key = phrase_list[phrase] + message = phrase_list[key] + to_chat(usr,"You set the restrictor to: [message]") + if(2) + phrase = (phrase < 11 && phrase >= 7) ? (phrase + 1) : 7 + key = phrase_list[phrase] + message = phrase_list[key] + to_chat(usr,"You set the restrictor to: [message]") + if(3) + phrase = (phrase < 18 && phrase >= 12 ) ? (phrase + 1) : 12 + key = phrase_list[phrase] + message = phrase_list[key] + to_chat(usr,"You set the restrictor to: [message]") + if(4) + phrase = (phrase < 18 && phrase >= 1 ) ? (phrase + 1) : 1 + key = phrase_list[phrase] + message = phrase_list[key] + to_chat(usr,"You set the restrictor to: [message]") + else + to_chat(usr, "It's broken.") + +/obj/item/clothing/mask/gas/sechailer/emag_act(mob/user) + if(safety) + safety = 0 + to_chat(user, "You silently fry [src]'s vocal circuit with the cryptographic sequencer.") + else + return + +/obj/item/clothing/mask/gas/sechailer/attackby(obj/item/I, mob/user) + if(I.is_screwdriver()) + switch(aggressiveness) + if(1) + to_chat(user, "You set the aggressiveness restrictor to the second position.") + aggressiveness = 2 + phrase = 7 + if(2) + to_chat(user, "You set the aggressiveness restrictor to the third position.") + aggressiveness = 3 + phrase = 13 + if(3) + to_chat(user, "You set the aggressiveness restrictor to the fourth position.") + aggressiveness = 4 + phrase = 1 + if(4) + to_chat(user, "You set the aggressiveness restrictor to the first position.") + aggressiveness = 1 + phrase = 1 + if(5) + to_chat(user, "You adjust the restrictor but nothing happens, probably because its broken.") + if(I.is_wirecutter()) + if(aggressiveness != 5) + to_chat(user, "You broke it!") + aggressiveness = 5 + if(I.is_crowbar()) + if(!hailer) + to_chat(user, "This mask has an integrated hailer, you can't remove it!") + else + var/obj/N = new /obj/item/clothing/mask/gas/half(src.loc) + playsound(src, 'sound/items/Screwdriver.ogg', 50, 1) + N.fingerprints = src.fingerprints + N.fingerprintshidden = src.fingerprintshidden + N.fingerprintslast = src.fingerprintslast + N.suit_fibers = src.suit_fibers + if(!isturf(N.loc)) + user.put_in_hands(hailer) + user.put_in_hands(N) + else + hailer.loc = N.loc + qdel(src) + return + ..() + +/obj/item/clothing/mask/gas/sechailer/verb/halt() + set name = "HALT!" + set category = "Objects" + set desc = "Activate your face mask hailer." + var/key = phrase_list[phrase] + var/message = phrase_list[key] + + if(cooldown < world.time - 35) // A cooldown, to stop people being jerks + if(!safety) + message = "FUCK YOUR CUNT YOU SHIT EATING COCKSUCKER MAN EAT A DONG FUCKING ASS RAMMING SHIT FUCK EAT PENISES IN YOUR FUCK FACE AND SHIT OUT ABORTIONS OF FUCK AND DO SHIT IN YOUR ASS YOU COCK FUCK SHIT MONKEY FUCK ASS WANKER FROM THE DEPTHS OF SHIT." + usr.visible_message("[usr]'s Compli-o-Nator: [message]") + playsound(src, 'sound/voice/binsult.ogg', 50, 0, 4) //Future sound channel = something like SFX + cooldown = world.time + return + + usr.visible_message("[usr]'s Compli-o-Nator: [message]") + playsound(src, "sound/voice/complionator/[key].ogg", 50, 0, 4) //future sound channel = something like SFX + cooldown = world.time \ No newline at end of file diff --git a/code/modules/clothing/masks/shiny_vr.dm b/code/modules/clothing/masks/shiny_vr.dm new file mode 100644 index 0000000000..5bed904a9f --- /dev/null +++ b/code/modules/clothing/masks/shiny_vr.dm @@ -0,0 +1,10 @@ +/obj/item/clothing/mask/muzzle/ballgag + name = "ball gag" + desc = "What's that? You'll have to speak up." + icon_state = "ballgag" + +/obj/item/clothing/mask/muzzle/ballgag/ringgag + name = "ring gag" + desc = "What's that? You'll have to speak more clearly." + icon_state = "ringgag" + gas_transfer_coefficient = 1 \ No newline at end of file diff --git a/code/modules/clothing/shoes/boots_vr.dm b/code/modules/clothing/shoes/boots_vr.dm new file mode 100644 index 0000000000..4c62209499 --- /dev/null +++ b/code/modules/clothing/shoes/boots_vr.dm @@ -0,0 +1,6 @@ +/obj/item/clothing/shoes/boots/hoof + name = "hoofboots" + desc = "A pair of high-heeled boots with hooves on the front of the soles, for use with a hobby horse or to disguise your footprints." + icon_state = "hoofboots" + icon = 'icons/obj/clothing/shoes_vr.dmi' + icon_override = 'icons/mob/feet_vr.dmi' \ No newline at end of file diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm index 25b8558da9..996b2a9761 100644 --- a/code/modules/clothing/shoes/miscellaneous.dm +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -108,7 +108,7 @@ obj/item/clothing/shoes/sandal/clogs species_restricted = null w_class = ITEMSIZE_SMALL drop_sound = 'sound/items/drop/clothing.ogg' - pickup_sound = 'sound/items/pickup/cloth.ogg' + pickup_sound = 'sound/items/pickup/clothing.ogg' /obj/item/clothing/shoes/slippers/worn name = "worn bunny slippers" @@ -172,7 +172,7 @@ obj/item/clothing/shoes/sandal/clogs w_class = ITEMSIZE_SMALL species_restricted = null drop_sound = 'sound/items/drop/clothing.ogg' - pickup_sound = 'sound/items/pickup/cloth.ogg' + pickup_sound = 'sound/items/pickup/clothing.ogg' /obj/item/clothing/shoes/boots/ranger var/bootcolor = "white" diff --git a/code/modules/clothing/spacesuits/rig/modules/computer.dm b/code/modules/clothing/spacesuits/rig/modules/computer.dm index cf055ae9c0..fbf08479f4 100644 --- a/code/modules/clothing/spacesuits/rig/modules/computer.dm +++ b/code/modules/clothing/spacesuits/rig/modules/computer.dm @@ -23,7 +23,7 @@ to_chat(usr, "Your module is not installed in a hardsuit.") return - module.holder.ui_interact(usr, nano_state = contained_state) + module.holder.tgui_interact(usr, custom_state = GLOB.tgui_contained_state) /obj/item/rig_module/ai_container diff --git a/code/modules/clothing/spacesuits/rig/modules/specific/ai_container.dm b/code/modules/clothing/spacesuits/rig/modules/specific/ai_container.dm index e6848a66d0..4f7dfef043 100644 --- a/code/modules/clothing/spacesuits/rig/modules/specific/ai_container.dm +++ b/code/modules/clothing/spacesuits/rig/modules/specific/ai_container.dm @@ -134,7 +134,7 @@ if(!target) if(ai_card) if(istype(ai_card,/obj/item/device/aicard)) - ai_card.tgui_interact(H, custom_state = deep_inventory_state) + ai_card.tgui_interact(H, custom_state = GLOB.tgui_deep_inventory_state) else eject_ai(H) update_verb_holder() diff --git a/code/modules/clothing/spacesuits/rig/rig_tgui.dm b/code/modules/clothing/spacesuits/rig/rig_tgui.dm index 5fc1e17380..7f34fe11b8 100644 --- a/code/modules/clothing/spacesuits/rig/rig_tgui.dm +++ b/code/modules/clothing/spacesuits/rig/rig_tgui.dm @@ -98,12 +98,13 @@ if(module.charges && module.charges.len) module_data["charges"] = list() - var/datum/rig_charge/selected = module.charges[module.charge_selected] + var/datum/rig_charge/selected = module.charges["[module.charge_selected]"] + module_data["realchargetype"] = module.charge_selected module_data["chargetype"] = selected ? "[selected.display_name]" : "none" for(var/chargetype in module.charges) var/datum/rig_charge/charge = module.charges[chargetype] - module_data["charges"] += list(list("caption" = "[chargetype] ([charge.charges])", "index" = "[chargetype]")) + module_data["charges"] += list(list("caption" = "[charge.display_name] ([charge.charges])", "index" = "[chargetype]")) module_list += list(module_data) i++ diff --git a/code/modules/clothing/suits/armor_vr.dm b/code/modules/clothing/suits/armor_vr.dm index a5d95a6296..3bf51fb97f 100644 --- a/code/modules/clothing/suits/armor_vr.dm +++ b/code/modules/clothing/suits/armor_vr.dm @@ -17,7 +17,7 @@ desc = "An armored vest that protects against some damage. It appears to be created for a wolf-taur." species_restricted = null //Species restricted since all it cares about is a taur half icon = 'icons/mob/taursuits_wolf_vr.dmi' - icon_state = "heavy_wolf_armor" + icon_state = "wolf_item" item_state = "heavy_wolf_armor" mob_can_equip(var/mob/living/carbon/human/H, slot, disable_warning = 0) if(..()) @@ -86,7 +86,7 @@ icon = 'icons/obj/clothing/suits_vr.dmi' icon_override = 'icons/mob/suit_vr.dmi' -// Armor Versions Here +// Armor Versions Here /obj/item/clothing/suit/armor/combat/crusader name = "crusader armor" desc = "ye olde knight, risen again." @@ -96,7 +96,7 @@ body_parts_covered = UPPER_TORSO|LOWER_TORSO armor = list(melee = 80, bullet = 50, laser = 10, energy = 0, bomb = 0, bio = 0, rad = 0) siemens_coefficient = 2 - + /obj/item/clothing/suit/armor/combat/crusader/bedevere name = "bedevere's armor" desc = "ye olde knight, risen again." @@ -113,7 +113,7 @@ body_parts_covered = UPPER_TORSO|LOWER_TORSO armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0) siemens_coefficient = 1 - + /obj/item/clothing/suit/armor/combat/crusader_costume/bedevere name = "bedevere's costume armor" desc = "ye olde knight, risen again." diff --git a/code/modules/clothing/suits/shiny.dm b/code/modules/clothing/suits/shiny.dm new file mode 100644 index 0000000000..e69de29bb2 diff --git a/code/modules/clothing/under/accessories/accessory_vr.dm b/code/modules/clothing/under/accessories/accessory_vr.dm index e2b2f8cf05..3e80507879 100644 --- a/code/modules/clothing/under/accessories/accessory_vr.dm +++ b/code/modules/clothing/under/accessories/accessory_vr.dm @@ -29,6 +29,7 @@ slot_flags = SLOT_TIE | SLOT_OCLOTHING icon = 'icons/obj/clothing/ties_vr.dmi' icon_override = 'icons/mob/ties_vr.dmi' + icon_state = "collar_blk" var/icon_previous_override //yw addition var/writtenon = 0 @@ -93,6 +94,7 @@ if(!jingled) usr.audible_message("[usr] jingles the [src]'s bell.") + playsound(src, 'sound/items/pickup/ring.ogg', 50, 1) jingled = 1 addtimer(CALLBACK(src, .proc/jingledreset), 50) return diff --git a/code/modules/clothing/under/accessories/badges.dm b/code/modules/clothing/under/accessories/badges.dm index e6a0a787a9..085279c424 100644 --- a/code/modules/clothing/under/accessories/badges.dm +++ b/code/modules/clothing/under/accessories/badges.dm @@ -13,9 +13,6 @@ var/stored_name var/badge_string = "Corporate Security" - - drop_sound = 'sound/items/drop/ring.ogg' - pickup_sound = 'sound/items/pickup/ring.ogg' /obj/item/clothing/accessory/badge/old name = "faded badge" diff --git a/code/modules/clothing/under/accessories/shiny_vr.dm b/code/modules/clothing/under/accessories/shiny_vr.dm new file mode 100644 index 0000000000..a23a0f1c69 --- /dev/null +++ b/code/modules/clothing/under/accessories/shiny_vr.dm @@ -0,0 +1,21 @@ +/obj/item/clothing/accessory/shiny + icon_override = 'icons/mob/modular_shiny_vr.dmi' + icon = 'icons/obj/clothing/modular_shiny_vr.dmi' + w_class = ITEMSIZE_NORMAL + desc = "Shiny! They look like they need to be attached to something, else they'll just fall off." + +/obj/item/clothing/accessory/shiny/gloves + name = "shiny gloves" + icon_state = "gloves" + +/obj/item/clothing/accessory/shiny/gloves/poly + name = "polychromic shiny gloves" + polychromic = TRUE + +/obj/item/clothing/accessory/shiny/socks + name = "shiny socks" + icon_state = "socks" + +/obj/item/clothing/accessory/shiny/socks/poly + name = "polychromic shiny socks" + polychromic = TRUE \ No newline at end of file diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 32816339d1..1d4ba551d9 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -1027,7 +1027,7 @@ Uniforms and such desc = "Made from a space-proof fibre and tight fitting, this uniform usually gives the agile Rangers all kinds of protection while not inhibiting their movement. \ This costume is instead made from genuine cotton fibre and is based on the season three uniform." icon = 'icons/obj/clothing/ranger.dmi' - icon_state = "ranger_uniform" + icon_state = "white_ranger_uniform" rolled_down = 0 rolled_sleeves = 0 diff --git a/code/modules/clothing/under/shiny_vr.dm b/code/modules/clothing/under/shiny_vr.dm new file mode 100644 index 0000000000..9020823276 --- /dev/null +++ b/code/modules/clothing/under/shiny_vr.dm @@ -0,0 +1,22 @@ +/obj/item/clothing/under/shiny + icon_override = 'icons/mob/modular_shiny_vr.dmi' + icon = 'icons/obj/clothing/modular_shiny_vr.dmi' + desc = "You can be a super-hero in this! Just don't forget your mask!" + +/obj/item/clothing/under/shiny/catsuit + name = "shiny suit" + icon_state = "suit" + var/opened = 0 + +/obj/item/clothing/under/shiny/catsuit/poly + name = "polychromic shiny suit" + icon_state = "suit_col" + polychromic = TRUE + +/obj/item/clothing/under/shiny/leotard + name = "shiny leotard" + icon_state = "leotard" + +/obj/item/clothing/under/shiny/leotard/poly + name = "polychromic shiny leotard" + polychromic = TRUE \ No newline at end of file diff --git a/code/modules/clothing/under/shorts.dm b/code/modules/clothing/under/shorts.dm index 0e345779d2..0d6516cc8e 100644 --- a/code/modules/clothing/under/shorts.dm +++ b/code/modules/clothing/under/shorts.dm @@ -78,7 +78,7 @@ /obj/item/clothing/under/shorts/jeans/grey name = "grey jeans shorts" - icon_state = "greypants_shorts" + icon_state = "greyshorts" /obj/item/clothing/under/shorts/jeans/grey/female name = "grey jeans short shorts" diff --git a/code/modules/clothing/under/xenos/seromi.dm b/code/modules/clothing/under/xenos/seromi.dm index 8da5e52755..71f00f293a 100644 --- a/code/modules/clothing/under/xenos/seromi.dm +++ b/code/modules/clothing/under/xenos/seromi.dm @@ -39,19 +39,19 @@ /obj/item/clothing/under/seromi/smock/dress/science name = "small research dress" - icon_state = "seromi_dress_science" + icon_state = "tesh_dress_science" /obj/item/clothing/under/seromi/smock/dress/security name = "small security dress" - icon_state = "seromi_dress_security" + icon_state = "tesh_dress_security" /obj/item/clothing/under/seromi/smock/dress/engine name = "small engineering dress" - icon_state = "seromi_dress_engine" + icon_state = "tesh_dress_engine" /obj/item/clothing/under/seromi/smock/dress/medical name = "small medical dress" - icon_state = "seromi_dress_medical" + icon_state = "tesh_dress_medical" /obj/item/clothing/under/seromi/smock/uniform name = "small command uniform" diff --git a/code/modules/economy/Accounts_DB.dm b/code/modules/economy/Accounts_DB.dm index 9e116ecf60..68f71184e9 100644 --- a/code/modules/economy/Accounts_DB.dm +++ b/code/modules/economy/Accounts_DB.dm @@ -15,7 +15,7 @@ var/const/fund_cap = 1000000 /obj/machinery/account_database/proc/get_access_level() - if (!held_card) + if(!held_card) return 0 if(access_cent_captain in held_card.access) return 2 @@ -53,19 +53,24 @@ O.loc = src held_card = O - SSnanoui.update_uis(src) + SStgui.update_uis(src) attack_hand(user) /obj/machinery/account_database/attack_hand(mob/user as mob) if(stat & (NOPOWER|BROKEN)) return - ui_interact(user) + tgui_interact(user) -/obj/machinery/account_database/ui_interact(mob/user, ui_key="main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/account_database/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AccountsTerminal", name) + ui.open() + + +/obj/machinery/account_database/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() - var/data[0] - data["src"] = "\ref[src]" data["id_inserted"] = !!held_card data["id_card"] = held_card ? text("[held_card.registered_name], [held_card.assignment]") : "-----" data["access_level"] = get_access_level() @@ -73,10 +78,14 @@ data["creating_new_account"] = creating_new_account data["detailed_account_view"] = !!detailed_account_view data["station_account_number"] = station_account.account_number - data["transactions"] = null - data["accounts"] = null - if (detailed_account_view) + data["account_number"] = null + data["owner_name"] = null + data["money"] = null + data["suspended"] = null + data["transactions"] = list() + + if(detailed_account_view) data["account_number"] = detailed_account_view.account_number data["owner_name"] = detailed_account_view.owner_name data["money"] = detailed_account_view.money @@ -92,11 +101,10 @@ "amount" = T.amount, \ "source_terminal" = T.source_terminal))) - if (trx.len > 0) - data["transactions"] = trx + data["transactions"] = trx - var/list/accounts[0] - for(var/i=1, i<=all_money_accounts.len, i++) + var/list/accounts = list() + for(var/i in 1 to LAZYLEN(all_money_accounts)) var/datum/money_account/D = all_money_accounts[i] if(D.offmap) continue @@ -106,174 +114,168 @@ "suspended"=D.suspended ? "SUSPENDED" : "",\ "account_index"=i))) - if (accounts.len > 0) - data["accounts"] = accounts + data["accounts"] = accounts - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "accounts_terminal.tmpl", src.name, 400, 640) - ui.set_initial_data(data) - ui.open() + return data -/obj/machinery/account_database/Topic(href, href_list) +/obj/machinery/account_database/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return 1 + return TRUE - var/datum/nanoui/ui = SSnanoui.get_open_ui(usr, src, "main") + switch(action) + if("create_account") + creating_new_account = 1 - if(href_list["choice"]) - switch(href_list["choice"]) - if("create_account") - creating_new_account = 1 + if("add_funds") + var/amount = input("Enter the amount you wish to add", "Silently add funds") as num + if(detailed_account_view) + detailed_account_view.money = min(detailed_account_view.money + amount, fund_cap) - if("add_funds") - var/amount = input("Enter the amount you wish to add", "Silently add funds") as num - if(detailed_account_view) - detailed_account_view.money = min(detailed_account_view.money + amount, fund_cap) + if("remove_funds") + var/amount = input("Enter the amount you wish to remove", "Silently remove funds") as num + if(detailed_account_view) + detailed_account_view.money = max(detailed_account_view.money - amount, -fund_cap) - if("remove_funds") - var/amount = input("Enter the amount you wish to remove", "Silently remove funds") as num - if(detailed_account_view) - detailed_account_view.money = max(detailed_account_view.money - amount, -fund_cap) + if("toggle_suspension") + if(detailed_account_view) + detailed_account_view.suspended = !detailed_account_view.suspended + callHook("change_account_status", list(detailed_account_view)) - if("toggle_suspension") - if(detailed_account_view) - detailed_account_view.suspended = !detailed_account_view.suspended - callHook("change_account_status", list(detailed_account_view)) + if("finalise_create_account") + var/account_name = params["holder_name"] + var/starting_funds = max(text2num(params["starting_funds"]), 0) - if("finalise_create_account") - var/account_name = href_list["holder_name"] - var/starting_funds = max(text2num(href_list["starting_funds"]), 0) + starting_funds = CLAMP(starting_funds, 0, station_account.money) // Not authorized to put the station in debt. + starting_funds = min(starting_funds, fund_cap) // Not authorized to give more than the fund cap. - starting_funds = CLAMP(starting_funds, 0, station_account.money) // Not authorized to put the station in debt. - starting_funds = min(starting_funds, fund_cap) // Not authorized to give more than the fund cap. + create_account(account_name, starting_funds, src) + if(starting_funds > 0) + //subtract the money + station_account.money -= starting_funds - create_account(account_name, starting_funds, src) - if(starting_funds > 0) - //subtract the money - station_account.money -= starting_funds - - //create a transaction log entry - var/trx = create_transation(account_name, "New account activation", "([starting_funds])") - station_account.transaction_log.Add(trx) - - creating_new_account = 0 - ui.close() + //create a transaction log entry + var/trx = create_transation(account_name, "New account activation", "([starting_funds])") + station_account.transaction_log.Add(trx) creating_new_account = 0 - if("insert_card") - if(held_card) - held_card.loc = src.loc - if(ishuman(usr) && !usr.get_active_hand()) - usr.put_in_hands(held_card) - held_card = null + creating_new_account = 0 + if("insert_card") + if(held_card) + held_card.loc = src.loc - else - var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id)) - var/obj/item/weapon/card/id/C = I - usr.drop_item() - C.loc = src - held_card = C + if(ishuman(usr) && !usr.get_active_hand()) + usr.put_in_hands(held_card) + held_card = null - if("view_account_detail") - var/index = text2num(href_list["account_index"]) - if(index && index <= all_money_accounts.len) - detailed_account_view = all_money_accounts[index] + else + var/obj/item/I = usr.get_active_hand() + if(istype(I, /obj/item/weapon/card/id)) + var/obj/item/weapon/card/id/C = I + usr.drop_item() + C.loc = src + held_card = C - if("view_accounts_list") - detailed_account_view = null - creating_new_account = 0 + if("view_account_detail") + var/index = text2num(params["account_index"]) + if(index && index <= all_money_accounts.len) + detailed_account_view = all_money_accounts[index] - if("revoke_payroll") - var/funds = detailed_account_view.money - var/account_trx = create_transation(station_account.owner_name, "Revoke payroll", "([funds])") - var/station_trx = create_transation(detailed_account_view.owner_name, "Revoke payroll", funds) + if("view_accounts_list") + detailed_account_view = null + creating_new_account = 0 - station_account.money += funds - detailed_account_view.money = 0 + if("revoke_payroll") + var/funds = detailed_account_view.money + var/account_trx = create_transation(station_account.owner_name, "Revoke payroll", "([funds])") + var/station_trx = create_transation(detailed_account_view.owner_name, "Revoke payroll", funds) - detailed_account_view.transaction_log.Add(account_trx) - station_account.transaction_log.Add(station_trx) + station_account.money += funds + detailed_account_view.money = 0 - callHook("revoke_payroll", list(detailed_account_view)) + detailed_account_view.transaction_log.Add(account_trx) + station_account.transaction_log.Add(station_trx) - if("print") - var/text - var/obj/item/weapon/paper/P = new(loc) - if (detailed_account_view) - P.name = "account #[detailed_account_view.account_number] details" - var/title = "Account #[detailed_account_view.account_number] Details" - text = {" - [accounting_letterhead(title)] - Holder: [detailed_account_view.owner_name]
- Balance: $[detailed_account_view.money]
- Status: [detailed_account_view.suspended ? "Suspended" : "Active"]
- Transactions: ([detailed_account_view.transaction_log.len])
- - - - - - - - - - - - "} + callHook("revoke_payroll", list(detailed_account_view)) - for (var/datum/transaction/T in detailed_account_view.transaction_log) - text += {" - - - - - - - - "} + if("print") + print() - text += {" - -
TimestampTargetReasonValueTerminal
[T.date] [T.time][T.target_name][T.purpose][T.amount][T.source_terminal]
- "} + return TRUE - else - P.name = "financial account list" - text = {" - [accounting_letterhead("Financial Account List")] +/obj/machinery/account_database/proc/print() + var/text + var/obj/item/weapon/paper/P = new(loc) + if(detailed_account_view) + P.name = "account #[detailed_account_view.account_number] details" + var/title = "Account #[detailed_account_view.account_number] Details" + text = {" + [accounting_letterhead(title)] + Holder: [detailed_account_view.owner_name]
+ Balance: $[detailed_account_view.money]
+ Status: [detailed_account_view.suspended ? "Suspended" : "Active"]
+ Transactions: ([detailed_account_view.transaction_log.len])
+ + + + + + + + + + + + "} -
TimestampTargetReasonValueTerminal
- - - - - - - - - - "} + for (var/datum/transaction/T in detailed_account_view.transaction_log) + text += {" + + + + + + + + "} - for(var/i=1, i<=all_money_accounts.len, i++) - var/datum/money_account/D = all_money_accounts[i] - text += {" - - - - - - - "} + text += {" + +
Account NumberHolderBalanceStatus
[T.date] [T.time][T.target_name][T.purpose][T.amount][T.source_terminal]
#[D.account_number][D.owner_name]$[D.money][D.suspended ? "Suspended" : "Active"]
+ "} - text += {" - - - "} + else + P.name = "financial account list" + text = {" + [accounting_letterhead("Financial Account List")] - P.info = text - state("The terminal prints out a report.") + + + + + + + + + + + "} - return 1 + for(var/i=1, i<=all_money_accounts.len, i++) + var/datum/money_account/D = all_money_accounts[i] + text += {" + + + + + + + "} + + text += {" + +
Account NumberHolderBalanceStatus
#[D.account_number][D.owner_name]$[D.money][D.suspended ? "Suspended" : "Active"]
+ "} + + P.info = text + state("The terminal prints out a report.") \ No newline at end of file diff --git a/code/modules/economy/cash.dm b/code/modules/economy/cash.dm index 3d4d44d918..f13684642c 100644 --- a/code/modules/economy/cash.dm +++ b/code/modules/economy/cash.dm @@ -1,5 +1,6 @@ /obj/item/weapon/spacecash name = "0 Thaler" + var/initial_name = "Thaler" desc = "It's worth 0 Thalers." gender = PLURAL icon = 'icons/obj/items.dmi' @@ -31,15 +32,15 @@ h_user.drop_from_inventory(src) h_user.drop_from_inventory(SC) h_user.put_in_hands(SC) - to_chat(user, "You combine the Thalers to a bundle of [SC.worth] Thalers.") + to_chat(user, "You combine the [initial_name]s to a bundle of [SC.worth] [initial_name]s.") qdel(src) /obj/item/weapon/spacecash/update_icon() overlays.Cut() - name = "[worth] Thaler\s" + name = "[worth] [initial_name]\s" if(worth in list(1000,500,200,100,50,20,10,1)) icon_state = "spacecash[worth]" - desc = "It's worth [worth] Thalers." + desc = "It's worth [worth] [initial_name]s." return var/sum = src.worth var/num = 0 @@ -60,7 +61,7 @@ M.Turn(pick(-45, -27.5, 0, 0, 0, 0, 0, 0, 0, 27.5, 45)) banknote.transform = M src.overlays += banknote - src.desc = "They are worth [worth] Thalers." + src.desc = "They are worth [worth] [initial_name]s." /obj/item/weapon/spacecash/proc/adjust_worth(var/adjust_worth = 0, var/update = 1) worth += adjust_worth @@ -79,7 +80,7 @@ return worth /obj/item/weapon/spacecash/attack_self() - var/amount = input(usr, "How many Thalers do you want to take? (0 to [src.worth])", "Take Money", 20) as num + var/amount = input(usr, "How many [initial_name]s do you want to take? (0 to [src.worth])", "Take Money", 20) as num if(!src || QDELETED(src)) return amount = round(CLAMP(amount, 0, src.worth)) @@ -150,6 +151,7 @@ proc/spawn_money(var/sum, spawnloc, mob/living/carbon/human/human_user as mob) /obj/item/weapon/spacecash/ewallet name = "charge card" + initial_name = "charge card" icon_state = "efundcard" desc = "A card that holds an amount of money." drop_sound = 'sound/items/drop/card.ogg' diff --git a/code/modules/events/money_spam.dm b/code/modules/events/money_spam.dm index 0b877cef3d..ad8a1bbc3f 100644 --- a/code/modules/events/money_spam.dm +++ b/code/modules/events/money_spam.dm @@ -36,7 +36,11 @@ var/obj/item/device/pda/P var/list/viables = list() for(var/obj/item/device/pda/check_pda in sortAtom(PDAs)) - if (!check_pda.owner||check_pda.toff||check_pda == src||check_pda.hidden) + if (!check_pda.owner || check_pda == src || check_pda.hidden) + continue + + var/datum/data/pda/app/messenger/M = check_pda.find_program(/datum/data/pda/app/messenger) + if(!M || M.toff) continue viables.Add(check_pda) @@ -112,17 +116,5 @@ //Commented out because we don't send messages like this anymore. Instead it will just popup in their chat window. //P.tnote += "← From [sender] (Unknown / spam?):
[message]
" - if (!P.message_silent) - playsound(P, 'sound/machines/twobeep.ogg', 50, 1) - for (var/mob/O in hearers(3, P.loc)) - if(!P.message_silent) O.show_message(text("[bicon(P)] *[P.ttone]*")) - //Search for holder of the PDA. - var/mob/living/L = null - if(P.loc && isliving(P.loc)) - L = P.loc - //Maybe they are a pAI! - else - L = get(P, /mob/living/silicon) - - if(L) - to_chat(L, "[bicon(P)] Message from [sender] (Unknown / spam?), \"[message]\" (Unable to Reply)") + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + PM.notify("Message from [sender] (Unknown / spam?), \"[message]\" (Unable to Reply)", 0) diff --git a/code/modules/events/supply_demand_vr.dm b/code/modules/events/supply_demand_vr.dm index 6c59145fe5..6447630c9e 100644 --- a/code/modules/events/supply_demand_vr.dm +++ b/code/modules/events/supply_demand_vr.dm @@ -84,17 +84,9 @@ var/datum/supply_demand_order/random = pick(required_items) command_announcement.Announce("What happened? Accounting is here right now and they're already asking where that [random.name] is. Damn, I gotta go", my_department) var/message = "The delivery deadline was reached with the following needs outstanding:
" - for (var/datum/supply_demand_order/req in required_items) + for(var/datum/supply_demand_order/req in required_items) message += req.describe() + "
" - for (var/obj/machinery/computer/communications/C in machines) - if(C.operable()) - var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( C.loc ) - P.name = "'[my_department] Mission Summary'" - P.info = message - P.update_space(P.info) - P.update_icon() - C.messagetitle.Add("[my_department] Mission Summary") - C.messagetext.Add(P.info) + post_comm_message("'[my_department] Mission Summary'", message) /** * Event Handler for responding to the supply shuttle arriving at centcom. */ diff --git a/code/modules/food/food/drinks.dm b/code/modules/food/food/drinks.dm index 044bd74491..2723df7fe2 100644 --- a/code/modules/food/food/drinks.dm +++ b/code/modules/food/food/drinks.dm @@ -5,8 +5,8 @@ name = "drink" desc = "yummy" icon = 'icons/obj/drinks.dmi' - drop_sound = 'sound/items/drop/bottle.ogg' - pickup_sound = 'sound/items/pickup/bottle.ogg' + drop_sound = 'sound/items/drop/drinkglass.ogg' + pickup_sound = 'sound/items/pickup/drinkglass.ogg' icon_state = null flags = OPENCONTAINER amount_per_transfer_from_this = 5 @@ -234,6 +234,7 @@ trash = /obj/item/trash/coffee center_of_mass = list("x"=15, "y"=13) drop_sound = 'sound/items/drop/papercup.ogg' + pickup_sound = 'sound/items/pickup/papercup.ogg' /obj/item/weapon/reagent_containers/food/drinks/h_chocolate/Initialize() ..() @@ -248,6 +249,7 @@ trash = /obj/item/trash/coffee center_of_mass = list("x"=16, "y"=14) drop_sound = 'sound/items/drop/papercup.ogg' + pickup_sound = 'sound/items/pickup/papercup.ogg' /obj/item/weapon/reagent_containers/food/drinks/greentea/Initialize() . = ..() @@ -262,6 +264,7 @@ trash = /obj/item/trash/coffee center_of_mass = list("x"=16, "y"=14) drop_sound = 'sound/items/drop/papercup.ogg' + pickup_sound = 'sound/items/pickup/papercup.ogg' /obj/item/weapon/reagent_containers/food/drinks/chaitea/Initialize() . = ..() @@ -276,6 +279,7 @@ trash = /obj/item/trash/coffee center_of_mass = list("x"=16, "y"=14) drop_sound = 'sound/items/drop/papercup.ogg' + pickup_sound = 'sound/items/pickup/papercup.ogg' /obj/item/weapon/reagent_containers/food/drinks/decaf/Initialize() . = ..() @@ -289,6 +293,7 @@ trash = /obj/item/trash/ramen center_of_mass = list("x"=16, "y"=11) drop_sound = 'sound/items/drop/papercup.ogg' + pickup_sound = 'sound/items/pickup/papercup.ogg' /obj/item/weapon/reagent_containers/food/drinks/dry_ramen/Initialize() ..() @@ -302,6 +307,7 @@ volume = 10 center_of_mass = list("x"=16, "y"=12) drop_sound = 'sound/items/drop/papercup.ogg' + pickup_sound = 'sound/items/pickup/papercup.ogg' /obj/item/weapon/reagent_containers/food/drinks/sillycup/Initialize() . = ..() diff --git a/code/modules/food/food/drinks/bottle.dm b/code/modules/food/food/drinks/bottle.dm index b5d72d733f..a5fd76417b 100644 --- a/code/modules/food/food/drinks/bottle.dm +++ b/code/modules/food/food/drinks/bottle.dm @@ -19,6 +19,7 @@ if(isGlass) unacidable = 1 drop_sound = 'sound/items/drop/bottle.ogg' + pickup_sound = 'sound/items/pickup/bottle.ogg' /obj/item/weapon/reagent_containers/food/drinks/bottle/Destroy() if(rag) diff --git a/code/modules/food/food/drinks/bottle_ch.dm b/code/modules/food/food/drinks/bottle_ch.dm index ed813245da..45110f97c7 100644 --- a/code/modules/food/food/drinks/bottle_ch.dm +++ b/code/modules/food/food/drinks/bottle_ch.dm @@ -1,6 +1,7 @@ /obj/item/weapon/reagent_containers/food/drinks/bottle/snaps name = "Akvavit" desc = "This could go well with lunch." + icon = 'icons/obj/drinks_ch.dmi' icon_state = "snapsbottle" center_of_mass = list("x"=17, "y"=3) diff --git a/code/modules/food/food/drinks/drinkingglass.dm b/code/modules/food/food/drinks/drinkingglass.dm index 260c4a7ae6..7324dc8ad8 100644 --- a/code/modules/food/food/drinks/drinkingglass.dm +++ b/code/modules/food/food/drinks/drinkingglass.dm @@ -8,8 +8,6 @@ volume = 30 unacidable = 1 //glass center_of_mass = list("x"=16, "y"=10) - drop_sound = 'sound/items/drop/drinkglass.ogg' - pickup_sound = 'sound/items/pickup/drinkglass.ogg' matter = list("glass" = 500) on_reagent_change() diff --git a/code/modules/food/food/snacks.dm b/code/modules/food/food/snacks.dm index 93e0b2c5ab..ad30c244f2 100644 --- a/code/modules/food/food/snacks.dm +++ b/code/modules/food/food/snacks.dm @@ -318,6 +318,7 @@ nutriment_amt = 1 nutriment_desc = list("candy" = 1) + /obj/item/weapon/reagent_containers/food/snacks/candy/Initialize() . = ..() reagents.add_reagent("sugar", 3) @@ -2001,7 +2002,7 @@ filling_color = "#AFC4B5" center_of_mass = list("x"=16, "y"=8) nutriment_amt = 8 - nutriment_desc = list("carot" = 2, "corn" = 2, "eggplant" = 2, "potato" = 2) + nutriment_desc = list("carrot" = 2, "corn" = 2, "eggplant" = 2, "potato" = 2) /obj/item/weapon/reagent_containers/food/snacks/vegetablesoup/Initialize() . = ..() @@ -4161,6 +4162,8 @@ trash = /obj/item/trash/unajerky filling_color = "#631212" center_of_mass = list("x"=15, "y"=9) + drop_sound = 'sound/items/drop/soda.ogg' + pickup_sound = 'sound/items/pickup/soda.ogg' /obj/item/weapon/reagent_containers/food/snacks/unajerky/Initialize() . =..() diff --git a/code/modules/food/kitchen/cooking_machines/_appliance.dm b/code/modules/food/kitchen/cooking_machines/_appliance.dm index 780a1502ff..b2f51eacd7 100644 --- a/code/modules/food/kitchen/cooking_machines/_appliance.dm +++ b/code/modules/food/kitchen/cooking_machines/_appliance.dm @@ -16,7 +16,7 @@ use_power = USE_POWER_IDLE idle_power_usage = 5 // Power used when turned on, but not processing anything active_power_usage = 1000 // Power used when turned on and actively cooking something - + var/cooking_power = 0 // Effectiveness/speed at cooking var/cooking_coeff = 0 // Optimal power * proximity to optimal temp; used to calc. cooking power. var/heating_power = 1000 // Effectiveness at heating up; not used for mixers, should be equal to active_power_usage @@ -44,9 +44,9 @@ /obj/machinery/appliance/Initialize() . = ..() - + default_apply_parts() - + if(output_options.len) verbs += /obj/machinery/appliance/proc/choose_output @@ -81,6 +81,30 @@ else to_chat(user, "") +/obj/machinery/appliance/proc/report_progress_tgui(datum/cooking_item/CI) + if(!CI || !CI.max_cookwork) + return list("average", "Not Cooking.") + + if(!CI.cookwork) + return list("blue", "Cold.") + + var/progress = CI.cookwork / CI.max_cookwork + + if (progress < 0.25) + return list("blue", "It's barely started cooking.") + if (progress < 0.75) + return list("average", "It's cooking away nicely.") + if (progress < 1) + return list("good", "It's almost ready!") + + var/half_overcook = (CI.overcook_mult - 1)*0.5 + if (progress < 1+half_overcook) + return list("good", "It's done!") + if (progress < CI.overcook_mult) + return list("bad", "It looks overcooked, get it out!") + else + return list("bad", "It is burning!") + /obj/machinery/appliance/proc/report_progress(var/datum/cooking_item/CI) if (!CI || !CI.max_cookwork) return null @@ -182,7 +206,7 @@ //Handles all validity checking and error messages for inserting things /obj/machinery/appliance/proc/can_insert(var/obj/item/I, var/mob/user) - if (istype(I, /obj/item/weapon/gripper)) + if(istype(I.loc, /mob/living/silicon)) return 0 else if (istype(I.loc, /obj/item/rig_module)) return 0 @@ -240,27 +264,53 @@ /obj/machinery/appliance/attackby(var/obj/item/I, var/mob/user) if(!cook_type || (stat & (BROKEN))) to_chat(user, "\The [src] is not working.") - return + return FALSE - var/result = can_insert(I, user) - if(!result) - if(!(default_deconstruction_screwdriver(user, I))) - default_part_replacement(user, I) - return + var/obj/item/ToCook = I - if(result == 2) - var/obj/item/weapon/grab/G = I - if (G && istype(G) && G.affecting) - cook_mob(G.affecting, user) + if(istype(I, /obj/item/weapon/gripper)) + var/obj/item/weapon/gripper/GR = I + var/obj/item/Wrap = GR.wrapped + if(Wrap) + Wrap.loc = get_turf(src) + var/result = can_insert(Wrap, user) + if(!result) + Wrap.forceMove(GR) + if(!(default_deconstruction_screwdriver(user, I))) + default_part_replacement(user, I) + return + + if(QDELETED(GR.wrapped)) + GR.wrapped = null + + if(GR?.wrapped.loc != src) + GR.drop_item_nm() + + ToCook = Wrap + else + attack_hand(user) return + else + var/result = can_insert(I, user) + if(!result) + if(!(default_deconstruction_screwdriver(user, I))) + default_part_replacement(user, I) + return + + if(result == 2) + var/obj/item/weapon/grab/G = I + if (G && istype(G) && G.affecting) + cook_mob(G.affecting, user) + return + //From here we can start cooking food - add_content(I, user) + add_content(ToCook, user) update_icon() //Override for container mechanics /obj/machinery/appliance/proc/add_content(var/obj/item/I, var/mob/user) - if(!user.unEquip(I)) + if(!user.unEquip(I) && !isturf(I.loc)) return var/datum/cooking_item/CI = has_space(I) @@ -271,13 +321,13 @@ cooking_objs.Add(CI) user.visible_message("\The [user] puts \the [I] into \the [src].") if (CC.check_contents() == 0)//If we're just putting an empty container in, then dont start any processing. - return + return TRUE else if (CI && istype(CI)) I.forceMove(CI.container) else //Something went wrong - return + return FALSE if (selected_option) CI.combine_target = selected_option @@ -434,7 +484,7 @@ //Final step. Cook function just cooks batter for now. for (var/obj/item/weapon/reagent_containers/food/snacks/S in CI.container) S.cook() - + //Combination cooking involves combining the names and reagents of ingredients into a predefined output object //The ingredients represent flavours or fillings. EG: donut pizza, cheese bread @@ -542,18 +592,18 @@ smoke.attach(src) smoke.set_up(10, 0, get_turf(src), 300) smoke.start() - + // Set off fire alarms! var/obj/machinery/firealarm/FA = locate() in get_area(src) if(FA) FA.alarm() /obj/machinery/appliance/attack_hand(var/mob/user) - if (cooking_objs.len) - if (removal_menu(user)) - return - else - ..() + if(..()) + return + + if(cooking_objs.len) + removal_menu(user) /obj/machinery/appliance/proc/removal_menu(var/mob/user) if (can_remove_items(user)) @@ -571,7 +621,7 @@ return TRUE return FALSE -/obj/machinery/appliance/proc/can_remove_items(var/mob/user) +/obj/machinery/appliance/proc/can_remove_items(var/mob/user, show_warning = TRUE) if (!Adjacent(user)) return FALSE diff --git a/code/modules/food/kitchen/cooking_machines/_cooker.dm b/code/modules/food/kitchen/cooking_machines/_cooker.dm index 94b40b44b2..ef097485b9 100644 --- a/code/modules/food/kitchen/cooking_machines/_cooker.dm +++ b/code/modules/food/kitchen/cooking_machines/_cooker.dm @@ -14,6 +14,63 @@ mobdamagetype = BURN can_burn_food = TRUE +/obj/machinery/appliance/cooker/attack_hand(mob/user) + tgui_interact(user) + +/obj/machinery/appliance/cooker/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "CookingAppliance", name) + ui.open() + +/obj/machinery/appliance/cooker/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + data["temperature"] = round(temperature - T0C, 0.1) + data["optimalTemp"] = round(optimal_temp - T0C, 0.1) + data["temperatureEnough"] = temperature >= min_temp + data["efficiency"] = round(get_efficiency(), 0.1) + data["containersRemovable"] = can_remove_items(user, show_warning = FALSE) + + var/list/our_contents = list() + for(var/i in 1 to max_contents) + our_contents += list(list("empty" = TRUE)) + if(i <= LAZYLEN(cooking_objs)) + var/datum/cooking_item/CI = cooking_objs[i] + if(istype(CI)) + our_contents[i] = list() + our_contents[i]["progress"] = 0 + our_contents[i]["progressText"] = report_progress_tgui(CI) + if(CI.max_cookwork) + our_contents[i]["progress"] = CI.cookwork / CI.max_cookwork + if(CI.container) + our_contents[i]["container"] = CI.container.label(i) + else + our_contents[i]["container"] = null + data["our_contents"] = our_contents + + return data + +/obj/machinery/appliance/cooker/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + switch(action) + if("slot") + var/slot = params["slot"] + var/obj/item/I = usr.get_active_hand() + if(slot <= LAZYLEN(cooking_objs)) // Inserting + var/datum/cooking_item/CI = cooking_objs[slot] + + if(istype(I) && can_insert(I)) // Why do hard work when we can just make them smack us? + attackby(I, usr) + else if(istype(CI)) + eject(CI, usr) + return TRUE + if(istype(I)) // Why do hard work when we can just make them smack us? + attackby(I, usr) + return TRUE + /obj/machinery/appliance/cooker/examine(var/mob/user) . = ..() if(.) //no need to duplicate adjacency check @@ -141,6 +198,6 @@ /obj/machinery/appliance/cooker/add_content(var/obj/item/I, var/mob/user) var/datum/cooking_item/CI = ..() - if (CI && CI.combine_target) + if(istype(CI) && CI.combine_target) to_chat(user, "\The [I] will be used to make a [selected_option]. Output selection is returned to default for future items.") selected_option = null \ No newline at end of file diff --git a/code/modules/food/kitchen/cooking_machines/_mixer.dm b/code/modules/food/kitchen/cooking_machines/_mixer.dm index e1c3b0d838..079b0c686c 100644 --- a/code/modules/food/kitchen/cooking_machines/_mixer.dm +++ b/code/modules/food/kitchen/cooking_machines/_mixer.dm @@ -68,11 +68,13 @@ fundamental differences return 0 -/obj/machinery/appliance/mixer/can_remove_items(var/mob/user) - if (stat) +/obj/machinery/appliance/mixer/can_remove_items(var/mob/user, show_warning = TRUE) + if(stat) return 1 else - to_chat(user, "You can't remove ingredients while it's turned on! Turn it off first or wait for it to finish.") + if(show_warning) + to_chat(user, "You can't remove ingredients while it's turned on! Turn it off first or wait for it to finish.") + return 0 //Container is not removable /obj/machinery/appliance/mixer/removal_menu(var/mob/user) diff --git a/code/modules/food/kitchen/cooking_machines/container.dm b/code/modules/food/kitchen/cooking_machines/container.dm index d650a2266e..408835a4da 100644 --- a/code/modules/food/kitchen/cooking_machines/container.dm +++ b/code/modules/food/kitchen/cooking_machines/container.dm @@ -32,13 +32,26 @@ /obj/item/weapon/reagent_containers/cooking_container/attackby(var/obj/item/I as obj, var/mob/user as mob) + if(istype(I, /obj/item/weapon/gripper)) + var/obj/item/weapon/gripper/GR = I + if(GR.wrapped) + GR.wrapped.forceMove(get_turf(src)) + attackby(GR.wrapped, user) + if(QDELETED(GR.wrapped)) + GR.wrapped = null + + if(GR?.wrapped.loc != src) + GR.wrapped = null + + return + for (var/possible_type in insertable) if (istype(I, possible_type)) if (!can_fit(I)) to_chat(user, "There's no more space in the [src] for that!") return 0 - if(!user.unEquip(I)) + if(!user.unEquip(I) && !isturf(I.loc)) return I.forceMove(src) to_chat(user, "You put the [I] into the [src].") @@ -152,7 +165,7 @@ /obj/item/weapon/reagent_containers/cooking_container/oven/Initialize() . = ..() - + // We add to the insertable list specifically for the oven trays, to allow specialty cakes. insertable += list( /obj/item/clothing/head/cakehat, // This is because we want to allow birthday cakes to be makeable. @@ -164,7 +177,7 @@ shortname = "basket" desc = "Put ingredients in this; designed for use with a deep fryer. Warranty void if used incorrectly. Alt click to remove contents." icon_state = "basket" - + /obj/item/weapon/reagent_containers/cooking_container/grill name = "grill rack" shortname = "rack" diff --git a/code/modules/food/kitchen/cooking_machines/oven.dm b/code/modules/food/kitchen/cooking_machines/oven.dm index fef49c2cbd..1236b51c9c 100644 --- a/code/modules/food/kitchen/cooking_machines/oven.dm +++ b/code/modules/food/kitchen/cooking_machines/oven.dm @@ -105,7 +105,7 @@ cooking = FALSE playsound(src, 'sound/machines/hatch_open.ogg', 20, 1) - to_chat(user, "You [open? "close":"open"] the oven door") + to_chat(user, "You [open ? "open" : "close"] the oven door.") update_icon() /obj/machinery/appliance/cooker/oven/proc/manip(var/obj/item/I) @@ -152,4 +152,4 @@ combination_cook(CI) return else - ..() + ..() \ No newline at end of file diff --git a/code/modules/food/kitchen/microwave.dm b/code/modules/food/kitchen/microwave.dm index 065d036920..5a499ae846 100644 --- a/code/modules/food/kitchen/microwave.dm +++ b/code/modules/food/kitchen/microwave.dm @@ -120,6 +120,7 @@ src.broken = 0 // just to be sure src.icon_state = "mw" src.flags = OPENCONTAINER | NOREACT + SStgui.update_uis(src) else //Otherwise bad luck!! to_chat(user, "It's dirty!") return 1 @@ -141,10 +142,11 @@ user.visible_message( \ "\The [user] has added \the [O] to \the [src].", \ "You add \the [O] to \the [src].") + SStgui.update_uis(src) return else if(istype(O,/obj/item/weapon/reagent_containers/glass) || \ - istype(O,/obj/item/weapon/reagent_containers/food/drinks) || \ - istype(O,/obj/item/weapon/reagent_containers/food/condiment) \ + istype(O,/obj/item/weapon/reagent_containers/food/drinks) || \ + istype(O,/obj/item/weapon/reagent_containers/food/condiment) \ ) if (!O.reagents) return 1 @@ -181,83 +183,168 @@ else to_chat(user, "You have no idea what you can cook with this [O].") ..() - src.updateUsrDialog() + SStgui.update_uis(src) + +/obj/machinery/microwave/tgui_state(mob/user) + return GLOB.tgui_physical_state /obj/machinery/microwave/attack_ai(mob/user as mob) - if(istype(user, /mob/living/silicon/robot) && Adjacent(user)) - attack_hand(user) + attack_hand(user) /obj/machinery/microwave/attack_hand(mob/user as mob) user.set_machine(src) - interact(user) + tgui_interact(user) /******************* * Microwave Menu ********************/ +/obj/machinery/microwave/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Microwave", name) + ui.open() -/obj/machinery/microwave/interact(mob/user as mob) // The microwave Menu - var/dat = "" - if(src.broken > 0) - dat = {"Bzzzzttttt"} - else if(src.operating) - dat = {"Microwaving in progress!
Please wait...!
"} - else if(src.dirty==100) - dat = {"This microwave is dirty!
Please clean it before use!
"} - else - var/list/items_counts = new - var/list/items_measures = new - var/list/items_measures_p = new - for (var/obj/O in ((contents - component_parts) - circuit)) - var/display_name = O.name - if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/egg)) - items_measures[display_name] = "egg" - items_measures_p[display_name] = "eggs" - if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/tofu)) - items_measures[display_name] = "tofu chunk" - items_measures_p[display_name] = "tofu chunks" - if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/meat)) //any meat - items_measures[display_name] = "slab of meat" - items_measures_p[display_name] = "slabs of meat" - if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/donkpocket)) - display_name = "Turnovers" - items_measures[display_name] = "turnover" - items_measures_p[display_name] = "turnovers" - if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/carpmeat)) - items_measures[display_name] = "fillet of meat" - items_measures_p[display_name] = "fillets of meat" - items_counts[display_name]++ - for (var/O in items_counts) - var/N = items_counts[O] - if (!(O in items_measures)) - dat += {"[capitalize(O)]: [N] [lowertext(O)]\s
"} - else - if (N==1) - dat += {"[capitalize(O)]: [N] [items_measures[O]]
"} - else - dat += {"[capitalize(O)]: [N] [items_measures_p[O]]
"} +/obj/machinery/microwave/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() - for (var/datum/reagent/R in reagents.reagent_list) - var/display_name = R.name - if (R.id == "capsaicin") - display_name = "Hotsauce" - if (R.id == "frostoil") - display_name = "Coldsauce" - dat += {"[display_name]: [R.volume] unit\s
"} + data["broken"] = broken + data["operating"] = operating + data["dirty"] = dirty == 100 + data["items"] = get_items_list() + + return data - if (items_counts.len==0 && reagents.reagent_list.len==0) - dat = {"The microwave is empty
"} +/obj/machinery/microwave/proc/get_items_list() + var/list/data = list() + + var/list/items_counts = list() + var/list/items_measures = list() + var/list/items_measures_p = list() + for(var/obj/O in ((contents - component_parts) - circuit)) + var/display_name = O.name + if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/egg)) + items_measures[display_name] = "egg" + items_measures_p[display_name] = "eggs" + if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/tofu)) + items_measures[display_name] = "tofu chunk" + items_measures_p[display_name] = "tofu chunks" + if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/meat)) //any meat + items_measures[display_name] = "slab of meat" + items_measures_p[display_name] = "slabs of meat" + if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/donkpocket)) + display_name = "Turnovers" + items_measures[display_name] = "turnover" + items_measures_p[display_name] = "turnovers" + if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/carpmeat)) + items_measures[display_name] = "fillet of meat" + items_measures_p[display_name] = "fillets of meat" + items_counts[display_name]++ + for(var/O in items_counts) + var/N = items_counts[O] + if(!(O in items_measures)) + data.Add(list(list( + "name" = capitalize(O), + "amt" = N, + "extra" = "[lowertext(O)][N > 1 ? "s" : ""]", + ))) else - dat = {"Ingredients:
[dat]"} - dat += {"

\ -Turn on!
\ -
Eject ingredients!
\ -"} + data.Add(list(list( + "name" = capitalize(O), + "amt" = N, + "extra" = N == 1 ? items_measures[O] : items_measures_p[O], + ))) - user << browse("Microwave Controls[dat]", "window=microwave") - onclose(user, "microwave") - return + for(var/datum/reagent/R in reagents.reagent_list) + var/display_name = R.name + if(R.id == "capsaicin") + display_name = "Hotsauce" + if(R.id == "frostoil") + display_name = "Coldsauce" + data.Add(list(list( + "name" = display_name, + "amt" = R.volume, + "extra" = "unit[R.volume > 1 ? "s" : ""]" + ))) + return data +/obj/machinery/microwave/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + if(operating) + return TRUE + + switch(action) + if("cook") + cook() + return TRUE + + if("dispose") + dispose() + return TRUE + +// /obj/machinery/microwave/interact(mob/user as mob) // The microwave Menu +// var/dat = "" +// if(src.broken > 0) +// dat = {"Bzzzzttttt"} +// else if(src.operating) +// dat = {"Microwaving in progress!
Please wait...!
"} +// else if(src.dirty==100) +// dat = {"This microwave is dirty!
Please clean it before use!
"} +// else +// var/list/items_counts = new +// var/list/items_measures = new +// var/list/items_measures_p = new +// for (var/obj/O in ((contents - component_parts) - circuit)) +// var/display_name = O.name +// if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/egg)) +// items_measures[display_name] = "egg" +// items_measures_p[display_name] = "eggs" +// if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/tofu)) +// items_measures[display_name] = "tofu chunk" +// items_measures_p[display_name] = "tofu chunks" +// if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/meat)) //any meat +// items_measures[display_name] = "slab of meat" +// items_measures_p[display_name] = "slabs of meat" +// if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/donkpocket)) +// display_name = "Turnovers" +// items_measures[display_name] = "turnover" +// items_measures_p[display_name] = "turnovers" +// if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/carpmeat)) +// items_measures[display_name] = "fillet of meat" +// items_measures_p[display_name] = "fillets of meat" +// items_counts[display_name]++ +// for (var/O in items_counts) +// var/N = items_counts[O] +// if (!(O in items_measures)) +// dat += {"[capitalize(O)]: [N] [lowertext(O)]\s
"} +// else +// if (N==1) +// dat += {"[capitalize(O)]: [N] [items_measures[O]]
"} +// else +// dat += {"[capitalize(O)]: [N] [items_measures_p[O]]
"} + +// for (var/datum/reagent/R in reagents.reagent_list) +// var/display_name = R.name +// if (R.id == "capsaicin") +// display_name = "Hotsauce" +// if (R.id == "frostoil") +// display_name = "Coldsauce" +// dat += {"[display_name]: [R.volume] unit\s
"} + +// if (items_counts.len==0 && reagents.reagent_list.len==0) +// dat = {"The microwave is empty
"} +// else +// dat = {"Ingredients:
[dat]"} +// dat += {"

\ +//
Turn on!
\ +//
Eject ingredients!
\ +// "} + +// user << browse("Microwave Controls[dat]", "window=microwave") +// onclose(user, "microwave") +// return /*********************************** * Microwave Menu Handling/Cooking @@ -388,13 +475,13 @@ soundloop.start() src.operating = TRUE src.icon_state = "mw1" - src.updateUsrDialog() + SStgui.update_uis(src) /obj/machinery/microwave/proc/abort() operating = FALSE // Turn it off again aferwards if(icon_state == "mw1") icon_state = "mw" - updateUsrDialog() + SStgui.update_uis(src) soundloop.stop() /obj/machinery/microwave/proc/stop() @@ -402,7 +489,7 @@ operating = FALSE // Turn it off again aferwards if(icon_state == "mw1") icon_state = "mw" - updateUsrDialog() + SStgui.update_uis(src) soundloop.stop() /obj/machinery/microwave/proc/dispose(var/message = 1) @@ -413,7 +500,7 @@ src.reagents.clear_reagents() if(message) to_chat(usr, "You dispose of the microwave contents.") - src.updateUsrDialog() + SStgui.update_uis(src) /obj/machinery/microwave/proc/muck_start() playsound(src, 'sound/effects/splat.ogg', 50, 1) // Play a splat sound @@ -425,7 +512,7 @@ src.flags = null //So you can't add condiments src.icon_state = "mwbloody" // Make it look dirty too src.operating = 0 // Turn it off again aferwards - src.updateUsrDialog() + SStgui.update_uis(src) soundloop.stop() @@ -438,7 +525,7 @@ src.broken = 2 // Make it broken so it can't be used util fixed src.flags = null //So you can't add condiments src.operating = 0 // Turn it off again aferwards - src.updateUsrDialog() + SStgui.update_uis(src) soundloop.stop() /obj/machinery/microwave/proc/fail() @@ -460,23 +547,6 @@ ffuu.reagents.add_reagent("toxin", amount/10) return ffuu -/obj/machinery/microwave/Topic(href, href_list) - if(..()) - return - - usr.set_machine(src) - if(src.operating) - src.updateUsrDialog() - return - - switch(href_list["action"]) - if ("cook") - cook() - - if ("dispose") - dispose() - return - /obj/machinery/microwave/verb/Eject() set src in oview(1) set category = "Object" diff --git a/code/modules/food/recipes_oven.dm b/code/modules/food/recipes_oven.dm index 7a477cf943..6524763a96 100644 --- a/code/modules/food/recipes_oven.dm +++ b/code/modules/food/recipes_oven.dm @@ -81,7 +81,7 @@ /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough ) result = /obj/item/weapon/reagent_containers/food/snacks/flatbread - + /datum/recipe/tortilla appliance = OVEN reagents = list("flour" = 5) @@ -408,7 +408,7 @@ /obj/item/weapon/reagent_containers/food/snacks/cheesewedge ) result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesecake - + /datum/recipe/cake/peanut fruit = list("peanut" = 3) reagents = list("milk" = 5, "flour" = 10, "sugar" = 5, "egg" = 6, "peanutbutter" = 5) @@ -458,7 +458,7 @@ /datum/recipe/pancakes appliance = OVEN - fruit = list("blueberries" = 2) + fruit = list("berries" = 2) items = list( /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough, /obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough diff --git a/code/modules/gamemaster/event2/events/everyone/pda_spam.dm b/code/modules/gamemaster/event2/events/everyone/pda_spam.dm index b56687283c..c6a1532d0e 100644 --- a/code/modules/gamemaster/event2/events/everyone/pda_spam.dm +++ b/code/modules/gamemaster/event2/events/everyone/pda_spam.dm @@ -35,7 +35,11 @@ var/list/viables = list() for(var/obj/item/device/pda/check_pda in sortAtom(PDAs)) - if(!check_pda.owner || check_pda.toff || check_pda.hidden || check_pda.spam_proof) + if (!check_pda.owner || check_pda == src || check_pda.hidden) + continue + + var/datum/data/pda/app/messenger/M = check_pda.find_program(/datum/data/pda/app/messenger) + if(!M || M.toff) continue viables += check_pda @@ -93,7 +97,7 @@ message = pick("Luxury watches for Blowout sale prices!",\ "Watches, Jewelry & Accessories, Bags & Wallets !",\ "Deposit 100$ and get 300$ totally free!",\ - " 100K NT.|WOWGOLD õnly $89 ",\ + " 100K NT.|WOWGOLD �nly $89 ",\ "We have been filed with a complaint from one of your customers in respect of their business relations with you.",\ "We kindly ask you to open the COMPLAINT REPORT (attached) to reply on this complaint..") if(4) @@ -127,7 +131,8 @@ /datum/event2/event/pda_spam/proc/send_spam(obj/item/device/pda/P, sender, message) last_spam_time = world.time - P.spam_message(sender, message) + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + PM.notify("Message from [sender] (Unknown / spam?), \"[message]\" (Unable to Reply)", 0) if(spam_debug) log_debug("PDA Spam event sent spam to \the [P].") diff --git a/code/modules/gamemaster/event2/events/security/prison_break.dm b/code/modules/gamemaster/event2/events/security/prison_break.dm index d14748c2d6..52f7e6d242 100644 --- a/code/modules/gamemaster/event2/events/security/prison_break.dm +++ b/code/modules/gamemaster/event2/events/security/prison_break.dm @@ -218,7 +218,7 @@ /datum/event2/event/prison_break/start() for(var/area/A in areas_to_break) spawn(0) // So we don't block the ticker. - A.prison_break(open_blast_doors = !ignore_blast_doors) + A.prison_break(TRUE, TRUE, !ignore_blast_doors) // Naming `open_blast_doors` causes mysterious runtimes. // There's between 40 seconds and one minute before the whole station knows. // If there's a baddie engineer, they can choose to keep their early announcement to themselves and get a minute to exploit it. diff --git a/code/modules/holodeck/HolodeckControl.dm b/code/modules/holodeck/HolodeckControl.dm index 5ba939fd8d..bfa684f4e6 100644 --- a/code/modules/holodeck/HolodeckControl.dm +++ b/code/modules/holodeck/HolodeckControl.dm @@ -79,60 +79,59 @@ return user.set_machine(src) - ui_interact(user) + tgui_interact(user) /** - * Display the NanoUI window for the Holodeck Computer. - * - * See NanoUI documentation for details. + * Open the UI! */ -/obj/machinery/computer/HolodeckControl/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/computer/HolodeckControl/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Holodeck", name) + ui.open() - var/list/data = list() - var/program_list[0] - var/restricted_program_list[0] +/** + * Data for the TGUI UI + */ +/obj/machinery/computer/HolodeckControl/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + var/list/program_list = list() + var/list/restricted_program_list = list() for(var/P in supported_programs) - program_list[++program_list.len] = P + program_list.Add(P) for(var/P in restricted_programs) - restricted_program_list[++restricted_program_list.len] = P + restricted_program_list.Add(P) data["supportedPrograms"] = program_list data["restrictedPrograms"] = restricted_program_list data["currentProgram"] = current_program + data["isSilicon"] = FALSE if(issilicon(user)) - data["isSilicon"] = 1 - else - data["isSilicon"] = null + data["isSilicon"] = TRUE + data["safetyDisabled"] = safety_disabled data["emagged"] = emagged + data["gravity"] = FALSE if(linkedholodeck.has_gravity) - data["gravity"] = 1 - else - data["gravity"] = null + data["gravity"] = TRUE - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "holodeck.tmpl", src.name, 400, 550) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(20) + return data -/obj/machinery/computer/HolodeckControl/Topic(href, href_list) +/obj/machinery/computer/HolodeckControl/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return 1 - if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) + return TRUE - if(href_list["program"]) - var/prog = href_list["program"] + switch(action) + if("program") + var/prog = params["program"] if(prog in (supported_programs + restricted_programs)) if(loadProgram(prog)) current_program = prog + return TRUE - else if(href_list["AIoverride"]) + if("AIoverride") if(!issilicon(usr)) return @@ -147,13 +146,13 @@ else message_admins("[key_name_admin(usr)] restored the holodeck's safeties") log_game("[key_name(usr)] restored the holodeck's safeties") + return TRUE - else if(href_list["gravity"]) + if("gravity") toggleGravity(linkedholodeck) + return TRUE - src.add_fingerprint(usr) - - SSnanoui.update_uis(src) + add_fingerprint(usr) /obj/machinery/computer/HolodeckControl/emag_act(var/remaining_charges, var/mob/user as mob) playsound(src, 'sound/effects/sparks4.ogg', 75, 1) diff --git a/code/modules/hydroponics/beekeeping/beehive.dm b/code/modules/hydroponics/beekeeping/beehive.dm index 4172d3dead..e91624724f 100644 --- a/code/modules/hydroponics/beekeeping/beehive.dm +++ b/code/modules/hydroponics/beekeeping/beehive.dm @@ -248,7 +248,7 @@ ..() recipes = wax_recipes -/material/wax +/datum/material/wax name = "wax" stack_type = /obj/item/stack/material/wax icon_colour = "#fff343" diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm deleted file mode 100644 index f01c6ac5bf..0000000000 --- a/code/modules/hydroponics/seed_datums.dm +++ /dev/null @@ -1,1555 +0,0 @@ -// Chili plants/variants. -/datum/seed/chili - name = "chili" - seed_name = "chili" - display_name = "chili plants" - kitchen_tag = "chili" - chems = list("capsaicin" = list(3,5), "nutriment" = list(1,25)) - mutants = list("icechili") - -/datum/seed/chili/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,20) - set_trait(TRAIT_PRODUCT_ICON,"chili") - set_trait(TRAIT_PRODUCT_COLOUR,"#ED3300") - set_trait(TRAIT_PLANT_ICON,"bush2") - set_trait(TRAIT_IDEAL_HEAT, 298) - set_trait(TRAIT_IDEAL_LIGHT, 7) - -/datum/seed/chili/ice - name = "icechili" - seed_name = "ice pepper" - display_name = "ice-pepper plants" - kitchen_tag = "icechili" - mutants = null - chems = list("frostoil" = list(3,5), "nutriment" = list(1,50)) - -/datum/seed/chili/ice/New() - ..() - set_trait(TRAIT_MATURATION,4) - set_trait(TRAIT_PRODUCTION,4) - set_trait(TRAIT_PRODUCT_COLOUR,"#00EDC6") - -// Berry plants/variants. -/datum/seed/berry - name = "berries" - seed_name = "berry" - display_name = "berry bush" - kitchen_tag = "berries" - mutants = list("glowberries","poisonberries") - chems = list("nutriment" = list(1,10), "berryjuice" = list(10,10)) - -/datum/seed/berry/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_JUICY,1) - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"berry") - set_trait(TRAIT_PRODUCT_COLOUR,"#FA1616") - set_trait(TRAIT_PLANT_ICON,"bush") - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/berry/glow - name = "glowberries" - seed_name = "glowberry" - display_name = "glowberry bush" - kitchen_tag = "glowberries" //CHOMP Addition - mutants = null - chems = list("nutriment" = list(1,10), "uranium" = list(3,5)) - -/datum/seed/berry/glow/New() - ..() - set_trait(TRAIT_SPREAD,1) - set_trait(TRAIT_BIOLUM,1) - set_trait(TRAIT_BIOLUM_COLOUR,"#006622") - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_COLOUR,"#c9fa16") - set_trait(TRAIT_WATER_CONSUMPTION, 3) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25) - -/datum/seed/berry/poison - name = "poisonberries" - seed_name = "poison berry" - kitchen_tag = "poisonberries" - display_name = "poison berry bush" - mutants = list("deathberries") - chems = list("nutriment" = list(1), "toxin" = list(3,5), "poisonberryjuice" = list(10,5)) - -/datum/seed/berry/poison/New() - ..() - set_trait(TRAIT_PRODUCT_COLOUR,"#6DC961") - set_trait(TRAIT_WATER_CONSUMPTION, 3) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25) - -/datum/seed/berry/poison/death - name = "deathberries" - seed_name = "death berry" - display_name = "death berry bush" - mutants = null - chems = list("nutriment" = list(1), "toxin" = list(3,3), "lexorin" = list(1,5)) - -/datum/seed/berry/poison/death/New() - ..() - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,50) - set_trait(TRAIT_PRODUCT_COLOUR,"#7A5454") - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.35) - -// Nettles/variants. -/datum/seed/nettle - name = "nettle" - seed_name = "nettle" - display_name = "nettles" - mutants = list("deathnettle") - chems = list("nutriment" = list(1,50), "sacid" = list(0,1)) - kitchen_tag = "nettle" - -/datum/seed/nettle/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_STINGS,1) - set_trait(TRAIT_PLANT_ICON,"bush5") - set_trait(TRAIT_PRODUCT_ICON,"nettles") - set_trait(TRAIT_PRODUCT_COLOUR,"#728A54") - -/datum/seed/nettle/death - name = "deathnettle" - seed_name = "death nettle" - display_name = "death nettles" - kitchen_tag = "deathnettle" - mutants = null - chems = list("nutriment" = list(1,50), "pacid" = list(0,1)) - -/datum/seed/nettle/death/New() - ..() - set_trait(TRAIT_MATURATION,8) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_PRODUCT_COLOUR,"#8C5030") - set_trait(TRAIT_PLANT_COLOUR,"#634941") - -//Tomatoes/variants. -/datum/seed/tomato - name = "tomato" - seed_name = "tomato" - display_name = "tomato plant" - mutants = list("bluetomato","bloodtomato") - chems = list("nutriment" = list(1,10), "tomatojuice" = list(10,10)) - kitchen_tag = "tomato" - -/datum/seed/tomato/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_JUICY,1) - set_trait(TRAIT_MATURATION,8) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"tomato") - set_trait(TRAIT_PRODUCT_COLOUR,"#D10000") - set_trait(TRAIT_PLANT_ICON,"bush3") - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25) - -/datum/seed/tomato/blood - name = "bloodtomato" - seed_name = "blood tomato" - display_name = "blood tomato plant" - mutants = list("killertomato") - chems = list("nutriment" = list(1,10), "blood" = list(1,5)) - splat_type = /obj/effect/decal/cleanable/blood/splatter - -/datum/seed/tomato/blood/New() - ..() - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_PRODUCT_COLOUR,"#FF0000") - -/datum/seed/tomato/killer - name = "killertomato" - seed_name = "killer tomato" - display_name = "killer tomato plant" - mutants = null - can_self_harvest = 1 - has_mob_product = /mob/living/simple_mob/tomato - -/datum/seed/tomato/killer/New() - ..() - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_PRODUCT_COLOUR,"#A86747") - -/datum/seed/tomato/blue - name = "bluetomato" - seed_name = "blue tomato" - display_name = "blue tomato plant" - mutants = list("bluespacetomato") - chems = list("nutriment" = list(1,20), "lube" = list(1,5)) - -/datum/seed/tomato/blue/New() - ..() - set_trait(TRAIT_PRODUCT_COLOUR,"#4D86E8") - set_trait(TRAIT_PLANT_COLOUR,"#070AAD") - -/datum/seed/tomato/blue/teleport - name = "bluespacetomato" - seed_name = "bluespace tomato" - display_name = "bluespace tomato plant" - kitchen_tag = "bluespacetomato" //CHOMP Addition - mutants = null - chems = list("nutriment" = list(1,20), "singulo" = list(10,5)) - -/datum/seed/tomato/blue/teleport/New() - ..() - set_trait(TRAIT_TELEPORTING,1) - set_trait(TRAIT_PRODUCT_COLOUR,"#00E5FF") - set_trait(TRAIT_BIOLUM,1) - set_trait(TRAIT_BIOLUM_COLOUR,"#4DA4A8") - -//Eggplants/varieties. -/datum/seed/eggplant - name = "eggplant" - seed_name = "eggplant" - display_name = "eggplants" - kitchen_tag = "eggplant" - mutants = list("egg-plant") - chems = list("nutriment" = list(1,10)) - -/datum/seed/eggplant/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,20) - set_trait(TRAIT_PRODUCT_ICON,"eggplant") - set_trait(TRAIT_PRODUCT_COLOUR,"#892694") - set_trait(TRAIT_PLANT_ICON,"bush4") - set_trait(TRAIT_IDEAL_HEAT, 298) - set_trait(TRAIT_IDEAL_LIGHT, 7) - -// Return of Eggy. Just makes purple eggs. If the reagents are separated from the egg production by xenobotany or RNG, it's still an Egg plant. -/datum/seed/eggplant/egg - name = "egg-plant" - seed_name = "egg-plant" - display_name = "egg-plants" - kitchen_tag = "egg-plant" - mutants = null - chems = list("nutriment" = list(1,5), "egg" = list(3,12)) - has_item_product = /obj/item/weapon/reagent_containers/food/snacks/egg/purple - -//Apples/varieties. -/datum/seed/apple - name = "apple" - seed_name = "apple" - display_name = "apple tree" - kitchen_tag = "apple" - mutants = list("poisonapple","goldapple","fallingapple") //CHOMPEDIT: adding fall apple to list - chems = list("nutriment" = list(1,10),"applejuice" = list(10,20)) - -/datum/seed/apple/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,5) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"apple") - set_trait(TRAIT_PRODUCT_COLOUR,"#FF540A") - set_trait(TRAIT_PLANT_ICON,"tree2") - set_trait(TRAIT_FLESH_COLOUR,"#E8E39B") - set_trait(TRAIT_IDEAL_LIGHT, 4) - -/datum/seed/apple/poison - name = "poisonapple" - mutants = null - chems = list("cyanide" = list(1,5)) - -/datum/seed/apple/gold - name = "goldapple" - seed_name = "golden apple" - display_name = "gold apple tree" - kitchen_tag = "goldapple" - mutants = null - chems = list("nutriment" = list(1,10), "gold" = list(1,5)) - -/datum/seed/apple/gold/New() - ..() - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_PRODUCTION,10) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_PRODUCT_COLOUR,"#FFDD00") - set_trait(TRAIT_PLANT_COLOUR,"#D6B44D") - -/datum/seed/apple/sif - name = "sifbulb" - seed_name = "sivian tree" - display_name = "sivian tree" - kitchen_tag = "apple" - chems = list("nutriment" = list(1,5),"sifsap" = list(10,20)) - -/datum/seed/apple/sif/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,3) - set_trait(TRAIT_PRODUCTION,10) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,12) - set_trait(TRAIT_PRODUCT_ICON,"alien3") - set_trait(TRAIT_PRODUCT_COLOUR,"#0720c3") - set_trait(TRAIT_PLANT_ICON,"tree5") - set_trait(TRAIT_FLESH_COLOUR,"#05157d") - set_trait(TRAIT_IDEAL_LIGHT, 1) - -//Ambrosia/varieties. -/datum/seed/ambrosia - name = "ambrosia" - seed_name = "ambrosia vulgaris" - display_name = "ambrosia vulgaris" - kitchen_tag = "ambrosia" - mutants = list("ambrosiadeus") - chems = list("nutriment" = list(1), "space_drugs" = list(1,8), "kelotane" = list(1,8,1), "bicaridine" = list(1,10,1), "toxin" = list(1,10)) - -/datum/seed/ambrosia/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,6) - set_trait(TRAIT_POTENCY,5) - set_trait(TRAIT_PRODUCT_ICON,"ambrosia") - set_trait(TRAIT_PRODUCT_COLOUR,"#9FAD55") - set_trait(TRAIT_PLANT_ICON,"ambrosia") - set_trait(TRAIT_IDEAL_LIGHT, 6) - -/datum/seed/ambrosia/deus - name = "ambrosiadeus" - seed_name = "ambrosia deus" - display_name = "ambrosia deus" - kitchen_tag = "ambrosiadeus" - mutants = list("ambrosiainfernus") - chems = list("nutriment" = list(1), "bicaridine" = list(1,8), "synaptizine" = list(1,8,1), "hyperzine" = list(1,10,1), "space_drugs" = list(1,10)) - -/datum/seed/ambrosia/deus/New() - ..() - set_trait(TRAIT_PRODUCT_COLOUR,"#A3F0AD") - set_trait(TRAIT_PLANT_COLOUR,"#2A9C61") - -/datum/seed/ambrosia/infernus - name = "ambrosiainfernus" - seed_name = "ambrosia infernus" - display_name = "ambrosia infernus" - kitchen_tag = "ambrosiainfernus" - mutants = null - chems = list("nutriment" = list(1,3), "oxycodone" = list(1,8), "impedrezene" = list(1,10), "mindbreaker" = list(1,10)) - -/datum/seed/ambrosia/infernus/New() - ..() - set_trait(TRAIT_PRODUCT_COLOUR,"#dc143c") - set_trait(TRAIT_PLANT_COLOUR,"#b22222") - -//Mushrooms/varieties. -/datum/seed/mushroom - name = "mushrooms" - seed_name = "chanterelle" - seed_noun = "spores" - display_name = "chanterelle mushrooms" - mutants = list("reishi","amanita","plumphelmet") - chems = list("nutriment" = list(1,25)) - splat_type = /obj/effect/plant - kitchen_tag = "mushroom" - -/datum/seed/mushroom/New() - ..() - set_trait(TRAIT_MATURATION,7) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,5) - set_trait(TRAIT_POTENCY,1) - set_trait(TRAIT_PRODUCT_ICON,"mushroom4") - set_trait(TRAIT_PRODUCT_COLOUR,"#DBDA72") - set_trait(TRAIT_PLANT_COLOUR,"#D9C94E") - set_trait(TRAIT_PLANT_ICON,"mushroom") - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_IDEAL_HEAT, 288) - set_trait(TRAIT_LIGHT_TOLERANCE, 6) - -/datum/seed/mushroom/mold - name = "mold" - seed_name = "brown mold" - display_name = "brown mold" - mutants = null - -/datum/seed/mushroom/mold/New() - ..() - set_trait(TRAIT_SPREAD,1) - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_YIELD,-1) - set_trait(TRAIT_PRODUCT_ICON,"mushroom5") - set_trait(TRAIT_PRODUCT_COLOUR,"#7A5F20") - set_trait(TRAIT_PLANT_COLOUR,"#7A5F20") - set_trait(TRAIT_PLANT_ICON,"mushroom9") - -/datum/seed/mushroom/plump - name = "plumphelmet" - seed_name = "plump helmet" - display_name = "plump helmet mushrooms" - mutants = list("walkingmushroom","towercap") - chems = list("nutriment" = list(2,10)) - kitchen_tag = "plumphelmet" - -/datum/seed/mushroom/plump/New() - ..() - set_trait(TRAIT_MATURATION,8) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,0) - set_trait(TRAIT_PRODUCT_ICON,"mushroom10") - set_trait(TRAIT_PRODUCT_COLOUR,"#B57BB0") - set_trait(TRAIT_PLANT_COLOUR,"#9E4F9D") - set_trait(TRAIT_PLANT_ICON,"mushroom2") - -/datum/seed/mushroom/hallucinogenic - name = "reishi" - seed_name = "reishi" - display_name = "reishi" - mutants = list("libertycap","glowshroom") - chems = list("nutriment" = list(1,50), "psilocybin" = list(3,5)) - -/datum/seed/mushroom/hallucinogenic/New() - ..() - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,15) - set_trait(TRAIT_PRODUCT_ICON,"mushroom11") - set_trait(TRAIT_PRODUCT_COLOUR,"#FFB70F") - set_trait(TRAIT_PLANT_COLOUR,"#F58A18") - set_trait(TRAIT_PLANT_ICON,"mushroom6") - -/datum/seed/mushroom/hallucinogenic/strong - name = "libertycap" - seed_name = "liberty cap" - display_name = "liberty cap mushrooms" - kitchen_tag = "libertycap" //CHOMP Addition - mutants = null - chems = list("nutriment" = list(1), "stoxin" = list(3,3), "space_drugs" = list(1,25)) - -/datum/seed/mushroom/hallucinogenic/strong/New() - ..() - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_POTENCY,15) - set_trait(TRAIT_PRODUCT_ICON,"mushroom8") - set_trait(TRAIT_PRODUCT_COLOUR,"#F2E550") - set_trait(TRAIT_PLANT_COLOUR,"#D1CA82") - set_trait(TRAIT_PLANT_ICON,"mushroom3") - -/datum/seed/mushroom/poison - name = "amanita" - seed_name = "fly amanita" - display_name = "fly amanita mushrooms" - mutants = list("destroyingangel","plastic") - chems = list("nutriment" = list(1), "amatoxin" = list(3,3), "psilocybin" = list(1,25)) - -/datum/seed/mushroom/poison/New() - ..() - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"mushroom") - set_trait(TRAIT_PRODUCT_COLOUR,"#FF4545") - set_trait(TRAIT_PLANT_COLOUR,"#E0DDBA") - set_trait(TRAIT_PLANT_ICON,"mushroom4") - -/datum/seed/mushroom/poison/death - name = "destroyingangel" - seed_name = "destroying angel" - display_name = "destroying angel mushrooms" - kitchen_tag = "destroyingangel" //CHOMP Addition - mutants = null - chems = list("nutriment" = list(1,50), "amatoxin" = list(13,3), "psilocybin" = list(1,25)) - -/datum/seed/mushroom/poison/death/New() - ..() - set_trait(TRAIT_MATURATION,12) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,35) - set_trait(TRAIT_PRODUCT_ICON,"mushroom3") - set_trait(TRAIT_PRODUCT_COLOUR,"#EDE8EA") - set_trait(TRAIT_PLANT_COLOUR,"#E6D8DD") - set_trait(TRAIT_PLANT_ICON,"mushroom5") - -/datum/seed/mushroom/towercap - name = "towercap" - seed_name = "tower cap" - display_name = "tower caps" - chems = list("woodpulp" = list(10,1)) - mutants = null - has_item_product = /obj/item/stack/material/log - -/datum/seed/mushroom/towercap/New() - ..() - set_trait(TRAIT_MATURATION,15) - set_trait(TRAIT_PRODUCT_ICON,"mushroom7") - set_trait(TRAIT_PRODUCT_COLOUR,"#79A36D") - set_trait(TRAIT_PLANT_COLOUR,"#857F41") - set_trait(TRAIT_PLANT_ICON,"mushroom8") - -/datum/seed/mushroom/glowshroom - name = "glowshroom" - seed_name = "glowshroom" - display_name = "glowshrooms" - kitchen_tag = "glowshrooms" //CHOMP Addition - mutants = null - chems = list("radium" = list(1,20)) - -/datum/seed/mushroom/glowshroom/New() - ..() - set_trait(TRAIT_SPREAD,1) - set_trait(TRAIT_MATURATION,15) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,30) - set_trait(TRAIT_BIOLUM,1) - set_trait(TRAIT_BIOLUM_COLOUR,"#006622") - set_trait(TRAIT_PRODUCT_ICON,"mushroom2") - set_trait(TRAIT_PRODUCT_COLOUR,"#DDFAB6") - set_trait(TRAIT_PLANT_COLOUR,"#EFFF8A") - set_trait(TRAIT_PLANT_ICON,"mushroom7") - -/datum/seed/mushroom/plastic - name = "plastic" - seed_name = "plastellium" - display_name = "plastellium" - kitchen_tag = "plastellium" //CHOMP Addition - mutants = null - chems = list("plasticide" = list(1,10)) - -/datum/seed/mushroom/plastic/New() - ..() - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,6) - set_trait(TRAIT_POTENCY,20) - set_trait(TRAIT_PRODUCT_ICON,"mushroom6") - set_trait(TRAIT_PRODUCT_COLOUR,"#E6E6E6") - set_trait(TRAIT_PLANT_COLOUR,"#E6E6E6") - set_trait(TRAIT_PLANT_ICON,"mushroom10") - -/datum/seed/mushroom/spore - name = "sporeshroom" - seed_name = "corpellian" - display_name = "corpellian" - mutants = null - chems = list("serotrotium" = list(5,10), "mold" = list(1,10)) - -/datum/seed/mushroom/spore/New() - ..() - set_trait(TRAIT_MATURATION,15) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,20) - set_trait(TRAIT_PRODUCT_ICON,"mushroom5") - set_trait(TRAIT_PRODUCT_COLOUR,"#e29cd2") - set_trait(TRAIT_PLANT_COLOUR,"#f8e6f4") - set_trait(TRAIT_PLANT_ICON,"mushroom9") - set_trait(TRAIT_SPORING, TRUE) - -//Flowers/varieties -/datum/seed/flower - name = "harebells" - seed_name = "harebell" - display_name = "harebells" - kitchen_tag = "harebell" - chems = list("nutriment" = list(1,20)) - -/datum/seed/flower/New() - ..() - set_trait(TRAIT_MATURATION,7) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_PRODUCT_ICON,"flower5") - set_trait(TRAIT_PRODUCT_COLOUR,"#C492D6") - set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E") - set_trait(TRAIT_PLANT_ICON,"flower") - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/flower/poppy - name = "poppies" - seed_name = "poppy" - display_name = "poppies" - kitchen_tag = "poppy" - chems = list("nutriment" = list(1,20), "bicaridine" = list(1,10)) - -/datum/seed/flower/poppy/New() - ..() - set_trait(TRAIT_POTENCY,20) - set_trait(TRAIT_MATURATION,8) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,6) - set_trait(TRAIT_PRODUCT_ICON,"flower3") - set_trait(TRAIT_PRODUCT_COLOUR,"#B33715") - set_trait(TRAIT_PLANT_ICON,"flower3") - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_WATER_CONSUMPTION, 0.5) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/flower/sunflower - name = "sunflowers" - seed_name = "sunflower" - display_name = "sunflowers" - mutants = list("solarflower") //CHOMPEDIT A sunflower well suited for planting as a natural lamp - kitchen_tag = "sunflower" - -/datum/seed/flower/sunflower/New() - ..() - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCT_ICON,"flower2") - set_trait(TRAIT_PRODUCT_COLOUR,"#FFF700") - set_trait(TRAIT_PLANT_ICON,"flower2") - set_trait(TRAIT_IDEAL_LIGHT, 7) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/flower/lavender - name = "lavender" - seed_name = "lavender" - display_name = "lavender" - mutants = list("milkdew") //CHOMPEDIT: leads to milk plant and lavender that makes a tier 2 source for some medical chems - kitchen_tag = "lavender" - chems = list("nutriment" = list(1,20), "bicaridine" = list(1,10)) - -/datum/seed/flower/lavender/New() - ..() - set_trait(TRAIT_MATURATION,7) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,5) - set_trait(TRAIT_PRODUCT_ICON,"flower6") - set_trait(TRAIT_PRODUCT_COLOUR,"#B57EDC") - set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E") - set_trait(TRAIT_PLANT_ICON,"flower4") - set_trait(TRAIT_IDEAL_LIGHT, 7) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.05) - set_trait(TRAIT_WATER_CONSUMPTION, 0.5) - -/datum/seed/flower/rose - name = "rose" - seed_name = "rose" - display_name = "rose" - kitchen_tag = "rose" - mutants = list("bloodrose") - chems = list("nutriment" = list(1,5), "stoxin" = list(0,2)) - -/datum/seed/flower/rose/New() - ..() - set_trait(TRAIT_MATURATION,7) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_PRODUCT_ICON,"flowers") - set_trait(TRAIT_PRODUCT_COLOUR,"#ce0e0e") - set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E") - set_trait(TRAIT_PLANT_ICON,"bush5") - set_trait(TRAIT_IDEAL_LIGHT, 7) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.1) - set_trait(TRAIT_WATER_CONSUMPTION, 0.5) - set_trait(TRAIT_STINGS,1) - -/datum/seed/flower/rose/blood - name = "bloodrose" - display_name = "bleeding rose" - mutants = null - chems = list("nutriment" = list(1,5), "stoxin" = list(1,5), "blood" = list(0,2)) - -/datum/seed/flower/rose/blood/New() - ..() - set_trait(TRAIT_IDEAL_LIGHT, 1) - set_trait(TRAIT_PLANT_COLOUR,"#5e0303") - set_trait(TRAIT_CARNIVOROUS,1) - -//Grapes/varieties -/datum/seed/grapes - name = "grapes" - seed_name = "grape" - display_name = "grapevines" - kitchen_tag = "grapes" - mutants = list("greengrapes") - chems = list("nutriment" = list(1,10), "sugar" = list(1,5), "grapejuice" = list(10,10)) - -/datum/seed/grapes/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,3) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"grapes") - set_trait(TRAIT_PRODUCT_COLOUR,"#BB6AC4") - set_trait(TRAIT_PLANT_COLOUR,"#378F2E") - set_trait(TRAIT_PLANT_ICON,"vine") - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/grapes/green - name = "greengrapes" - seed_name = "green grape" - display_name = "green grapevines" - mutants = null - chems = list("nutriment" = list(1,10), "kelotane" = list(3,5), "grapejuice" = list(10,10)) - -/datum/seed/grapes/green/New() - ..() - set_trait(TRAIT_PRODUCT_COLOUR,"42ed2f") - -// Lettuce/varieties. -/datum/seed/lettuce - name = "lettuce" - seed_name = "lettuce" - display_name = "lettuce" - kitchen_tag = "cabbage" - chems = list("nutriment" = list(1,15)) - -/datum/seed/lettuce/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,4) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,6) - set_trait(TRAIT_POTENCY,8) - set_trait(TRAIT_PRODUCT_ICON,"lettuce") - set_trait(TRAIT_PRODUCT_COLOUR,"#A8D0A7") - set_trait(TRAIT_PLANT_COLOUR,"#6D9C6B") - set_trait(TRAIT_PLANT_ICON,"vine2") - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_WATER_CONSUMPTION, 8) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.13) - -/datum/seed/lettuce/ice - name = "siflettuce" - seed_name = "glacial lettuce" - display_name = "glacial lettuce" - kitchen_tag = "icelettuce" - chems = list("nutriment" = list(1,5), "paracetamol" = list(0,2)) - -/datum/seed/lettuce/ice/New() - ..() - set_trait(TRAIT_ALTER_TEMP, -5) - set_trait(TRAIT_PRODUCT_COLOUR,"#9ABCC9") - -//Wabback / varieties. -/datum/seed/wabback - name = "whitewabback" - seed_name = "white wabback" - seed_noun = "nodes" - display_name = "white wabback" - chems = list("nutriment" = list(1,10), "protein" = list(1,5), "enzyme" = list(0,3)) - kitchen_tag = "wabback" - mutants = list("blackwabback","wildwabback") - has_item_product = /obj/item/stack/material/cloth - -/datum/seed/wabback/New() - ..() - set_trait(TRAIT_IDEAL_LIGHT, 5) - set_trait(TRAIT_MATURATION,8) - set_trait(TRAIT_PRODUCTION,3) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,5) - set_trait(TRAIT_PRODUCT_ICON,"carrot2") - set_trait(TRAIT_PRODUCT_COLOUR,"#E6EDFA") - set_trait(TRAIT_PLANT_ICON,"chute") - set_trait(TRAIT_PLANT_COLOUR, "#0650ce") - set_trait(TRAIT_WATER_CONSUMPTION, 10) - set_trait(TRAIT_ALTER_TEMP, -1) - set_trait(TRAIT_CARNIVOROUS,1) - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_SPREAD,1) - -/datum/seed/wabback/vine - name = "blackwabback" - seed_name = "black wabback" - display_name = "black wabback" - mutants = null - chems = list("nutriment" = list(1,3), "protein" = list(1,10), "serotrotium_v" = list(0,1)) - -/datum/seed/wabback/vine/New() - ..() - set_trait(TRAIT_PRODUCT_COLOUR,"#2E2F32") - set_trait(TRAIT_CARNIVOROUS,2) - -/datum/seed/wabback/wild - name = "wildwabback" - seed_name = "wild wabback" - display_name = "wild wabback" - mutants = list("whitewabback") - has_item_product = null - chems = list("nutriment" = list(1,15), "protein" = list(0,2), "enzyme" = list(0,1)) - -/datum/seed/wabback/wild/New() - ..() - set_trait(TRAIT_IDEAL_LIGHT, 3) - set_trait(TRAIT_WATER_CONSUMPTION, 7) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.1) - set_trait(TRAIT_YIELD,5) - -//Everything else -/datum/seed/peanuts - name = "peanut" - seed_name = "peanut" - display_name = "peanut vines" - kitchen_tag = "peanut" - chems = list("nutriment" = list(1,10), "peanutoil" = list(3,10)) - -/datum/seed/peanuts/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,6) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"nuts") - set_trait(TRAIT_PRODUCT_COLOUR,"#C4AE7A") - set_trait(TRAIT_PLANT_ICON,"bush2") - set_trait(TRAIT_IDEAL_LIGHT, 6) - -/datum/seed/vanilla - name = "vanilla" - seed_name = "vanilla" - display_name = "vanilla" - kitchen_tag = "vanilla" - chems = list("nutriment" = list(1,10), "vanilla" = list(2,8), "sugar" = list(1, 4)) - -/datum/seed/vanilla/New() - ..() - set_trait(TRAIT_MATURATION,7) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_PRODUCT_ICON,"chili") - set_trait(TRAIT_PRODUCT_COLOUR,"#B57EDC") - set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E") - set_trait(TRAIT_PLANT_ICON,"bush5") - set_trait(TRAIT_IDEAL_LIGHT, 8) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.3) - set_trait(TRAIT_WATER_CONSUMPTION, 0.5) - -/datum/seed/cabbage - name = "cabbage" - seed_name = "cabbage" - display_name = "cabbages" - kitchen_tag = "cabbage" - chems = list("nutriment" = list(1,10)) - -/datum/seed/cabbage/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,3) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"cabbage") - set_trait(TRAIT_PRODUCT_COLOUR,"#84BD82") - set_trait(TRAIT_PLANT_COLOUR,"#6D9C6B") - set_trait(TRAIT_PLANT_ICON,"vine2") - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/banana - name = "banana" - seed_name = "banana" - display_name = "banana tree" - kitchen_tag = "banana" - chems = list("banana" = list(10,10)) - trash_type = /obj/item/weapon/bananapeel - -/datum/seed/banana/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_PRODUCT_ICON,"bananas") - set_trait(TRAIT_PRODUCT_COLOUR,"#FFEC1F") - set_trait(TRAIT_PLANT_COLOUR,"#69AD50") - set_trait(TRAIT_PLANT_ICON,"tree4") - set_trait(TRAIT_IDEAL_HEAT, 298) - set_trait(TRAIT_IDEAL_LIGHT, 7) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - -/datum/seed/corn - name = "corn" - seed_name = "corn" - display_name = "ears of corn" - kitchen_tag = "corn" - chems = list("nutriment" = list(1,10), "cornoil" = list(3,15)) - trash_type = /obj/item/weapon/corncob - -/datum/seed/corn/New() - ..() - set_trait(TRAIT_MATURATION,8) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,20) - set_trait(TRAIT_PRODUCT_ICON,"corn") - set_trait(TRAIT_PRODUCT_COLOUR,"#FFF23B") - set_trait(TRAIT_PLANT_COLOUR,"#87C969") - set_trait(TRAIT_PLANT_ICON,"corn") - set_trait(TRAIT_IDEAL_HEAT, 298) - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - -/datum/seed/potato - name = "potato" - seed_name = "potato" - display_name = "potatoes" - mutants = list("voltato") //CHOMPEDIT: Adding a better potato battery and viable source for V200 - kitchen_tag = "potato" - chems = list("nutriment" = list(1,10), "potatojuice" = list(10,10)) - -/datum/seed/potato/New() - ..() - set_trait(TRAIT_PRODUCES_POWER,1) - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"potato") - set_trait(TRAIT_PRODUCT_COLOUR,"#D4CAB4") - set_trait(TRAIT_PLANT_ICON,"bush2") - set_trait(TRAIT_WATER_CONSUMPTION, 6) - -/datum/seed/onion - name = "onion" - seed_name = "onion" - display_name = "onions" - kitchen_tag = "onion" - chems = list("nutriment" = list(1,10)) - -/datum/seed/onion/New() - ..() - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"onion") - set_trait(TRAIT_PRODUCT_COLOUR,"#E0C367") - set_trait(TRAIT_PLANT_ICON,"carrot") - set_trait(TRAIT_WATER_CONSUMPTION, 6) - -/datum/seed/soybean - name = "soybean" - seed_name = "soybean" - display_name = "soybeans" - mutants = list("orangesapbean","purplesapbean","bluesapbean") //CHOMPEDIT: Adding sappy beanies to mutation - kitchen_tag = "soybeans" - chems = list("nutriment" = list(1,20), "soymilk" = list(10,20)) - -/datum/seed/soybean/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,4) - set_trait(TRAIT_PRODUCTION,4) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,5) - set_trait(TRAIT_PRODUCT_ICON,"bean") - set_trait(TRAIT_PRODUCT_COLOUR,"#EBE7C0") - set_trait(TRAIT_PLANT_ICON,"stalk") - -/datum/seed/wheat - name = "wheat" - seed_name = "wheat" - display_name = "wheat stalks" - mutants = list("meatwheat") //CHOMPEDIT: Meat wheat, the solution for vegetarian carnivores - kitchen_tag = "wheat" - chems = list("nutriment" = list(1,25), "flour" = list(10,30)) - -/datum/seed/wheat/New() - ..() - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,5) - set_trait(TRAIT_PRODUCT_ICON,"wheat") - set_trait(TRAIT_PRODUCT_COLOUR,"#DBD37D") - set_trait(TRAIT_PLANT_COLOUR,"#BFAF82") - set_trait(TRAIT_PLANT_ICON,"stalk2") - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/rice - name = "rice" - seed_name = "rice" - display_name = "rice stalks" - kitchen_tag = "rice" - chems = list("nutriment" = list(1,25), "rice" = list(10,15)) - -/datum/seed/rice/New() - ..() - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,5) - set_trait(TRAIT_PRODUCT_ICON,"rice") - set_trait(TRAIT_PRODUCT_COLOUR,"#D5E6D1") - set_trait(TRAIT_PLANT_COLOUR,"#8ED17D") - set_trait(TRAIT_PLANT_ICON,"stalk2") - set_trait(TRAIT_WATER_CONSUMPTION, 6) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/carrots - name = "carrot" - seed_name = "carrot" - display_name = "carrots" - kitchen_tag = "carrot" - chems = list("nutriment" = list(1,20), "imidazoline" = list(3,5), "carrotjuice" = list(10,20)) - -/datum/seed/carrots/New() - ..() - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,5) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"carrot") - set_trait(TRAIT_PRODUCT_COLOUR,"#FFDB4A") - set_trait(TRAIT_PLANT_ICON,"carrot") - set_trait(TRAIT_WATER_CONSUMPTION, 6) - -/datum/seed/weeds - name = "weeds" - seed_name = "weed" - display_name = "weeds" - -/datum/seed/weeds/New() - ..() - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,-1) - set_trait(TRAIT_POTENCY,-1) - set_trait(TRAIT_IMMUTABLE,-1) - set_trait(TRAIT_PRODUCT_ICON,"flower4") - set_trait(TRAIT_PRODUCT_COLOUR,"#FCEB2B") - set_trait(TRAIT_PLANT_COLOUR,"#59945A") - set_trait(TRAIT_PLANT_ICON,"bush6") - -/datum/seed/whitebeets - name = "whitebeet" - seed_name = "white-beet" - display_name = "white-beets" - kitchen_tag = "whitebeet" - chems = list("nutriment" = list(0,20), "sugar" = list(1,5)) - -/datum/seed/whitebeets/New() - ..() - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,6) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"carrot2") - set_trait(TRAIT_PRODUCT_COLOUR,"#EEF5B0") - set_trait(TRAIT_PLANT_COLOUR,"#4D8F53") - set_trait(TRAIT_PLANT_ICON,"carrot2") - set_trait(TRAIT_WATER_CONSUMPTION, 6) - -/datum/seed/sugarcane - name = "sugarcane" - seed_name = "sugarcane" - display_name = "sugarcanes" - kitchen_tag = "sugarcanes" - chems = list("sugar" = list(4,5)) - -/datum/seed/sugarcane/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,3) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"stalk") - set_trait(TRAIT_PRODUCT_COLOUR,"#B4D6BD") - set_trait(TRAIT_PLANT_COLOUR,"#6BBD68") - set_trait(TRAIT_PLANT_ICON,"stalk3") - set_trait(TRAIT_IDEAL_HEAT, 298) - -/datum/seed/rhubarb - name = "rhubarb" - seed_name = "rhubarb" - display_name = "rhubarb" - kitchen_tag = "rhubarb" - chems = list("nutriment" = list(1,15)) - -/datum/seed/rhubarb/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,3) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,5) - set_trait(TRAIT_POTENCY,6) - set_trait(TRAIT_PRODUCT_ICON,"stalk") - set_trait(TRAIT_PRODUCT_COLOUR,"#FD5656") - set_trait(TRAIT_PLANT_ICON,"stalk3") - -/datum/seed/celery - name = "celery" - seed_name = "celery" - display_name = "celery" - kitchen_tag = "celery" - chems = list("nutriment" = list(5,20)) - -/datum/seed/celery/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,4) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,8) - set_trait(TRAIT_PRODUCT_ICON,"stalk") - set_trait(TRAIT_PRODUCT_COLOUR,"#56FD56") - set_trait(TRAIT_PLANT_ICON,"stalk3") - -/datum/seed/spineapple - name = "spineapple" - seed_name = "spineapple" - display_name = "spineapple" - kitchen_tag = "pineapple" - chems = list("nutriment" = list(1,5), "enzyme" = list(1,5), "pineapplejuice" = list(1, 20)) - -/datum/seed/spineapple/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,10) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,1) - set_trait(TRAIT_POTENCY,13) - set_trait(TRAIT_PRODUCT_ICON,"pineapple") - set_trait(TRAIT_PRODUCT_COLOUR,"#FFF23B") - set_trait(TRAIT_PLANT_COLOUR,"#87C969") - set_trait(TRAIT_PLANT_ICON,"corn") - set_trait(TRAIT_IDEAL_HEAT, 298) - set_trait(TRAIT_IDEAL_LIGHT, 4) - set_trait(TRAIT_WATER_CONSUMPTION, 8) - set_trait(TRAIT_STINGS,1) - -/datum/seed/durian - name = "durian" - seed_name = "durian" - seed_noun = "pits" - display_name = "durian" - kitchen_tag = "durian" - chems = list("nutriment" = list(1,5), "durianpaste" = list(1, 20)) - -/datum/seed/durian/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"spinefruit") - set_trait(TRAIT_PRODUCT_COLOUR,"#757631") - set_trait(TRAIT_PLANT_COLOUR,"#87C969") - set_trait(TRAIT_PLANT_ICON,"tree") - set_trait(TRAIT_IDEAL_LIGHT, 8) - set_trait(TRAIT_WATER_CONSUMPTION, 8) - -/datum/seed/watermelon - name = "watermelon" - seed_name = "watermelon" - display_name = "watermelon vine" - kitchen_tag = "watermelon" - chems = list("nutriment" = list(1,6), "watermelonjuice" = list(10,6)) - -/datum/seed/watermelon/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_JUICY,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,1) - set_trait(TRAIT_PRODUCT_ICON,"vine") - set_trait(TRAIT_PRODUCT_COLOUR,"#3D8C3A") - set_trait(TRAIT_PLANT_COLOUR,"#257522") - set_trait(TRAIT_PLANT_ICON,"vine2") - set_trait(TRAIT_FLESH_COLOUR,"#F22C2C") - set_trait(TRAIT_IDEAL_HEAT, 298) - set_trait(TRAIT_IDEAL_LIGHT, 6) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - -/datum/seed/pumpkin - name = "pumpkin" - seed_name = "pumpkin" - display_name = "pumpkin vine" - kitchen_tag = "pumpkin" - chems = list("nutriment" = list(1,6)) - -/datum/seed/pumpkin/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"vine2") - set_trait(TRAIT_PRODUCT_COLOUR,"#DBAC02") - set_trait(TRAIT_PLANT_COLOUR,"#21661E") - set_trait(TRAIT_PLANT_ICON,"vine2") - set_trait(TRAIT_WATER_CONSUMPTION, 6) - -/datum/seed/citrus - name = "lime" - seed_name = "lime" - display_name = "lime trees" - kitchen_tag = "lime" - chems = list("nutriment" = list(1,20), "limejuice" = list(10,20)) - -/datum/seed/citrus/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_JUICY,1) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,15) - set_trait(TRAIT_PRODUCT_ICON,"treefruit") - set_trait(TRAIT_PRODUCT_COLOUR,"#3AF026") - set_trait(TRAIT_PLANT_ICON,"tree") - set_trait(TRAIT_FLESH_COLOUR,"#3AF026") - -/datum/seed/citrus/lemon - name = "lemon" - seed_name = "lemon" - display_name = "lemon trees" - kitchen_tag = "lemon" - chems = list("nutriment" = list(1,20), "lemonjuice" = list(10,20)) - -/datum/seed/citrus/lemon/New() - ..() - set_trait(TRAIT_PRODUCES_POWER,1) - set_trait(TRAIT_PRODUCT_ICON,"lemon") - set_trait(TRAIT_PRODUCT_COLOUR,"#F0E226") - set_trait(TRAIT_FLESH_COLOUR,"#F0E226") - set_trait(TRAIT_IDEAL_LIGHT, 6) - -/datum/seed/citrus/orange - name = "orange" - seed_name = "orange" - display_name = "orange trees" - kitchen_tag = "orange" - chems = list("nutriment" = list(1,20), "orangejuice" = list(10,20)) - -/datum/seed/citrus/orange/New() - ..() - set_trait(TRAIT_PRODUCT_COLOUR,"#FFC20A") - set_trait(TRAIT_FLESH_COLOUR,"#FFC20A") - -/datum/seed/grass - name = "grass" - seed_name = "grass" - display_name = "grass" - kitchen_tag = "grass" - chems = list("nutriment" = list(1,20)) - -/datum/seed/grass/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,2) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,5) - set_trait(TRAIT_PRODUCT_ICON,"grass") - set_trait(TRAIT_PRODUCT_COLOUR,"#09FF00") - set_trait(TRAIT_PLANT_COLOUR,"#07D900") - set_trait(TRAIT_PLANT_ICON,"grass") - set_trait(TRAIT_WATER_CONSUMPTION, 0.5) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/cocoa - name = "cocoa" - seed_name = "cacao" - display_name = "cacao tree" - kitchen_tag = "cocoa" - chems = list("nutriment" = list(1,10), "coco" = list(4,5)) - -/datum/seed/cocoa/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"treefruit") - set_trait(TRAIT_PRODUCT_COLOUR,"#CCA935") - set_trait(TRAIT_PLANT_ICON,"tree2") - set_trait(TRAIT_IDEAL_HEAT, 298) - set_trait(TRAIT_WATER_CONSUMPTION, 6) - -/datum/seed/cherries - name = "cherry" - seed_name = "cherry" - seed_noun = "pits" - display_name = "cherry tree" - kitchen_tag = "cherries" - chems = list("nutriment" = list(1,15), "sugar" = list(1,15), "cherryjelly" = list(10,15)) - -/datum/seed/cherries/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_JUICY,1) - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"cherry") - set_trait(TRAIT_PRODUCT_COLOUR,"#A80000") - set_trait(TRAIT_PLANT_ICON,"tree2") - set_trait(TRAIT_PLANT_COLOUR,"#2F7D2D") - -/datum/seed/kudzu - name = "kudzu" - seed_name = "kudzu" - display_name = "kudzu vines" - kitchen_tag = "kudzu" - chems = list("nutriment" = list(1,50), "anti_toxin" = list(1,25)) - -/datum/seed/kudzu/New() - ..() - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_SPREAD,2) - set_trait(TRAIT_PRODUCT_ICON,"treefruit") - set_trait(TRAIT_PRODUCT_COLOUR,"#96D278") - set_trait(TRAIT_PLANT_COLOUR,"#6F7A63") - set_trait(TRAIT_PLANT_ICON,"vine2") - set_trait(TRAIT_WATER_CONSUMPTION, 0.5) - -/datum/seed/diona - name = "diona" - seed_name = "diona" - seed_noun = "nodes" - display_name = "replicant pods" - can_self_harvest = 1 - apply_color_to_mob = FALSE - has_mob_product = /mob/living/carbon/alien/diona - -/datum/seed/diona/New() - ..() - set_trait(TRAIT_IMMUTABLE,1) - set_trait(TRAIT_ENDURANCE,8) - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,10) - set_trait(TRAIT_YIELD,1) - set_trait(TRAIT_POTENCY,30) - set_trait(TRAIT_PRODUCT_ICON,"diona") - set_trait(TRAIT_PRODUCT_COLOUR,"#799957") - set_trait(TRAIT_PLANT_COLOUR,"#66804B") - set_trait(TRAIT_PLANT_ICON,"alien4") - -/datum/seed/shand - name = "shand" - seed_name = "Selem's hand" - display_name = "Selem's hand leaves" - kitchen_tag = "shand" - chems = list("bicaridine" = list(0,10)) - -/datum/seed/shand/New() - ..() - set_trait(TRAIT_MATURATION,3) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"alien3") - set_trait(TRAIT_PRODUCT_COLOUR,"#378C61") - set_trait(TRAIT_PLANT_COLOUR,"#378C61") - set_trait(TRAIT_PLANT_ICON,"tree5") - set_trait(TRAIT_IDEAL_HEAT, 283) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/mtear - name = "mtear" - seed_name = "Malani's tear" - display_name = "Malani's tear leaves" - kitchen_tag = "mtear" - chems = list("honey" = list(1,10), "kelotane" = list(3,5)) - -/datum/seed/mtear/New() - ..() - set_trait(TRAIT_MATURATION,3) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_PRODUCT_ICON,"alien4") - set_trait(TRAIT_PRODUCT_COLOUR,"#4CC5C7") - set_trait(TRAIT_PLANT_COLOUR,"#4CC789") - set_trait(TRAIT_PLANT_ICON,"bush7") - set_trait(TRAIT_IDEAL_HEAT, 283) - set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) - -/datum/seed/telriis - name = "telriis" - seed_name = "telriis" - display_name = "telriis grass" - kitchen_tag = "telriis" - chems = list("pwine" = list(1,5), "nutriment" = list(1,6)) - -/datum/seed/telriis/New() - ..() - set_trait(TRAIT_PLANT_ICON,"ambrosia") - set_trait(TRAIT_PRODUCT_ICON,"ambrosia") - set_trait(TRAIT_ENDURANCE,50) - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,5) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,5) - -/datum/seed/thaadra - name = "thaadra" - seed_name = "thaa'dra" - display_name = "thaa'dra lichen" - kitchen_tag = "thaadra" - chems = list("frostoil" = list(1,5),"nutriment" = list(1,5)) - -/datum/seed/thaadra/New() - ..() - set_trait(TRAIT_PLANT_ICON,"grass") - set_trait(TRAIT_PLANT_COLOUR,"#ABC7D2") - set_trait(TRAIT_ENDURANCE,10) - set_trait(TRAIT_MATURATION,5) - set_trait(TRAIT_PRODUCTION,9) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,5) - -/datum/seed/jurlmah - name = "jurlmah" - seed_name = "jurl'mah" - display_name = "jurl'mah reeds" - kitchen_tag = "jurlmah" - chems = list("serotrotium" = list(1,5),"nutriment" = list(1,5)) - -/datum/seed/jurlmah/New() - ..() - set_trait(TRAIT_PLANT_ICON,"mushroom9") - set_trait(TRAIT_ENDURANCE,12) - set_trait(TRAIT_MATURATION,8) - set_trait(TRAIT_PRODUCTION,9) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,10) - -/datum/seed/amauri - name = "amauri" - seed_name = "amauri" - display_name = "amauri plant" - kitchen_tag = "amauri" - chems = list("zombiepowder" = list(1,10),"condensedcapsaicin" = list(1,5),"nutriment" = list(1,5)) - -/datum/seed/amauri/New() - ..() - set_trait(TRAIT_PLANT_ICON,"bush4") - set_trait(TRAIT_ENDURANCE,10) - set_trait(TRAIT_MATURATION,8) - set_trait(TRAIT_PRODUCTION,9) - set_trait(TRAIT_YIELD,4) - set_trait(TRAIT_POTENCY,10) - -/datum/seed/gelthi - name = "gelthi" - seed_name = "gelthi" - display_name = "gelthi plant" - kitchen_tag = "gelthi" - chems = list("stoxin" = list(1,5),"capsaicin" = list(1,5),"nutriment" = list(1,5)) - -/datum/seed/gelthi/New() - ..() - set_trait(TRAIT_PLANT_ICON,"mushroom3") - set_trait(TRAIT_ENDURANCE,15) - set_trait(TRAIT_MATURATION,6) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_POTENCY,1) - -/datum/seed/vale - name = "vale" - seed_name = "vale" - display_name = "vale bush" - kitchen_tag = "vale" - chems = list("paracetamol" = list(1,5),"dexalin" = list(1,2),"nutriment"= list(1,5)) - -/datum/seed/vale/New() - ..() - set_trait(TRAIT_PLANT_ICON,"flower4") - set_trait(TRAIT_ENDURANCE,15) - set_trait(TRAIT_MATURATION,8) - set_trait(TRAIT_PRODUCTION,10) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,3) - -/datum/seed/surik - name = "surik" - seed_name = "surik" - display_name = "surik vine" - kitchen_tag = "surik" - chems = list("impedrezene" = list(1,3),"synaptizine" = list(1,2),"nutriment" = list(1,5)) - -/datum/seed/surik/New() - ..() - set_trait(TRAIT_PLANT_ICON,"bush6") - set_trait(TRAIT_ENDURANCE,18) - set_trait(TRAIT_MATURATION,7) - set_trait(TRAIT_PRODUCTION,7) - set_trait(TRAIT_YIELD,3) - set_trait(TRAIT_POTENCY,3) - -// Alien weeds. -/datum/seed/xenomorph - name = "xenomorph" - seed_name = "alien weed" - display_name = "alien weeds" - force_layer = 3 - chems = list("phoron" = list(1,3)) - -/datum/seed/xenomorph/New() - ..() - set_trait(TRAIT_PLANT_ICON,"vine2") - set_trait(TRAIT_IMMUTABLE,1) - set_trait(TRAIT_PRODUCT_COLOUR,"#3D1934") - set_trait(TRAIT_FLESH_COLOUR,"#3D1934") - set_trait(TRAIT_PLANT_COLOUR,"#3D1934") - set_trait(TRAIT_PRODUCTION,1) - set_trait(TRAIT_YIELD,-1) - set_trait(TRAIT_SPREAD,2) - set_trait(TRAIT_POTENCY,50) - -// Gnomes -/datum/seed/gnomes - name = "gnomes" - seed_name = "gnomes" - display_name = "gnomes" - force_layer = 3 - chems = list("magicdust" = list(5,20)) - -/datum/seed/gnomes/New() - ..() - set_trait(TRAIT_HARVEST_REPEAT,1) - set_trait(TRAIT_PLANT_ICON,"gnomes") - set_trait(TRAIT_PRODUCT_ICON,"gnomes") - set_trait(TRAIT_PRODUCT_COLOUR,"") - set_trait(TRAIT_FLESH_COLOUR,"") - set_trait(TRAIT_PLANT_COLOUR,"") - set_trait(TRAIT_BIOLUM_COLOUR,"#fff200") - set_trait(TRAIT_MATURATION,8) - set_trait(TRAIT_PRODUCTION,6) - set_trait(TRAIT_BIOLUM,1) - set_trait(TRAIT_YIELD,2) - set_trait(TRAIT_SPREAD,1) - set_trait(TRAIT_POTENCY,10) - set_trait(TRAIT_REQUIRES_NUTRIENTS,0) - set_trait(TRAIT_REQUIRES_WATER,0) diff --git a/code/modules/hydroponics/seed_packets.dm b/code/modules/hydroponics/seed_packets.dm index 45d74e26fd..3db8840058 100644 --- a/code/modules/hydroponics/seed_packets.dm +++ b/code/modules/hydroponics/seed_packets.dm @@ -337,3 +337,6 @@ GLOBAL_LIST_BOILERPLATE(all_seed_packs, /obj/item/seeds) /obj/item/seeds/sifbulb seed_type = "sifbulb" + +/obj/item/seeds/wurmwoad + seed_type = "wurmwoad" diff --git a/code/modules/hydroponics/seed_storage.dm b/code/modules/hydroponics/seed_storage.dm index 39b9dc3ebc..f75d17f63e 100644 --- a/code/modules/hydroponics/seed_storage.dm +++ b/code/modules/hydroponics/seed_storage.dm @@ -138,7 +138,8 @@ /obj/item/seeds/wabback = 2, /obj/item/seeds/watermelonseed = 3, /obj/item/seeds/wheatseed = 3, - /obj/item/seeds/whitebeetseed = 3 + /obj/item/seeds/whitebeetseed = 3, + /obj/item/seeds/wurmwoad = 3 ) /obj/machinery/seed_storage/xenobotany @@ -195,7 +196,8 @@ /obj/item/seeds/wabback = 2, /obj/item/seeds/watermelonseed = 3, /obj/item/seeds/wheatseed = 3, - /obj/item/seeds/whitebeetseed = 3 + /obj/item/seeds/whitebeetseed = 3, + /obj/item/seeds/wurmwoad = 3 ) /obj/machinery/seed_storage/attack_hand(mob/user as mob) diff --git a/code/modules/hydroponics/seedtypes/amauri.dm b/code/modules/hydroponics/seedtypes/amauri.dm new file mode 100644 index 0000000000..0ad44e7862 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/amauri.dm @@ -0,0 +1,15 @@ +/datum/seed/amauri + name = "amauri" + seed_name = "amauri" + display_name = "amauri plant" + kitchen_tag = "amauri" + chems = list("zombiepowder" = list(1,10),"condensedcapsaicin" = list(1,5),"nutriment" = list(1,5)) + +/datum/seed/amauri/New() + ..() + set_trait(TRAIT_PLANT_ICON,"bush4") + set_trait(TRAIT_ENDURANCE,10) + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,9) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/ambrosia.dm b/code/modules/hydroponics/seedtypes/ambrosia.dm new file mode 100644 index 0000000000..535d5129a3 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/ambrosia.dm @@ -0,0 +1,46 @@ +//Ambrosia/varieties. +/datum/seed/ambrosia + name = "ambrosia" + seed_name = "ambrosia vulgaris" + display_name = "ambrosia vulgaris" + kitchen_tag = "ambrosia" + mutants = list("ambrosiadeus") + chems = list("nutriment" = list(1), "space_drugs" = list(1,8), "kelotane" = list(1,8,1), "bicaridine" = list(1,10,1), "toxin" = list(1,10)) + +/datum/seed/ambrosia/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,5) + set_trait(TRAIT_PRODUCT_ICON,"ambrosia") + set_trait(TRAIT_PRODUCT_COLOUR,"#9FAD55") + set_trait(TRAIT_PLANT_ICON,"ambrosia") + set_trait(TRAIT_IDEAL_LIGHT, 6) + +/datum/seed/ambrosia/deus + name = "ambrosiadeus" + seed_name = "ambrosia deus" + display_name = "ambrosia deus" + kitchen_tag = "ambrosiadeus" + mutants = list("ambrosiainfernus") + chems = list("nutriment" = list(1), "bicaridine" = list(1,8), "synaptizine" = list(1,8,1), "hyperzine" = list(1,10,1), "space_drugs" = list(1,10)) + +/datum/seed/ambrosia/deus/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#A3F0AD") + set_trait(TRAIT_PLANT_COLOUR,"#2A9C61") + +/datum/seed/ambrosia/infernus + name = "ambrosiainfernus" + seed_name = "ambrosia infernus" + display_name = "ambrosia infernus" + kitchen_tag = "ambrosiainfernus" + mutants = null + chems = list("nutriment" = list(1,3), "oxycodone" = list(1,8), "impedrezene" = list(1,10), "mindbreaker" = list(1,10)) + +/datum/seed/ambrosia/infernus/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#dc143c") + set_trait(TRAIT_PLANT_COLOUR,"#b22222") \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/apples.dm b/code/modules/hydroponics/seedtypes/apples.dm new file mode 100644 index 0000000000..7044a0c6dc --- /dev/null +++ b/code/modules/hydroponics/seedtypes/apples.dm @@ -0,0 +1,62 @@ +//Apples/varieties. +/datum/seed/apple + name = "apple" + seed_name = "apple" + display_name = "apple tree" + kitchen_tag = "apple" + mutants = list("poisonapple","goldapple") + chems = list("nutriment" = list(1,10),"applejuice" = list(10,20)) + +/datum/seed/apple/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"apple") + set_trait(TRAIT_PRODUCT_COLOUR,"#FF540A") + set_trait(TRAIT_PLANT_ICON,"tree2") + set_trait(TRAIT_FLESH_COLOUR,"#E8E39B") + set_trait(TRAIT_IDEAL_LIGHT, 4) + +/datum/seed/apple/poison + name = "poisonapple" + mutants = null + chems = list("cyanide" = list(1,5)) + +/datum/seed/apple/gold + name = "goldapple" + seed_name = "golden apple" + display_name = "gold apple tree" + kitchen_tag = "goldapple" + mutants = null + chems = list("nutriment" = list(1,10), "gold" = list(1,5)) + +/datum/seed/apple/gold/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,10) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_PRODUCT_COLOUR,"#FFDD00") + set_trait(TRAIT_PLANT_COLOUR,"#D6B44D") + +/datum/seed/apple/sif + name = "sifbulb" + seed_name = "sivian tree" + display_name = "sivian pod" + kitchen_tag = "apple" + chems = list("nutriment" = list(1,5),"sifsap" = list(10,20)) + +/datum/seed/apple/sif/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,10) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,12) + set_trait(TRAIT_PRODUCT_ICON,"alien3") + set_trait(TRAIT_PRODUCT_COLOUR,"#0720c3") + set_trait(TRAIT_PLANT_ICON,"tree5") + set_trait(TRAIT_FLESH_COLOUR,"#05157d") + set_trait(TRAIT_IDEAL_LIGHT, 1) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/banana.dm b/code/modules/hydroponics/seedtypes/banana.dm new file mode 100644 index 0000000000..9259318d77 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/banana.dm @@ -0,0 +1,21 @@ +/datum/seed/banana + name = "banana" + seed_name = "banana" + display_name = "banana tree" + kitchen_tag = "banana" + chems = list("banana" = list(10,10)) + trash_type = /obj/item/weapon/bananapeel + +/datum/seed/banana/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_PRODUCT_ICON,"bananas") + set_trait(TRAIT_PRODUCT_COLOUR,"#FFEC1F") + set_trait(TRAIT_PLANT_COLOUR,"#69AD50") + set_trait(TRAIT_PLANT_ICON,"tree4") + set_trait(TRAIT_IDEAL_HEAT, 298) + set_trait(TRAIT_IDEAL_LIGHT, 7) + set_trait(TRAIT_WATER_CONSUMPTION, 6) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/berries.dm b/code/modules/hydroponics/seedtypes/berries.dm new file mode 100644 index 0000000000..2ad36353fe --- /dev/null +++ b/code/modules/hydroponics/seedtypes/berries.dm @@ -0,0 +1,70 @@ +// Berry plants/variants. +/datum/seed/berry + name = "berries" + seed_name = "berry" + display_name = "berry bush" + kitchen_tag = "berries" + mutants = list("glowberries","poisonberries") + chems = list("nutriment" = list(1,10), "berryjuice" = list(10,10)) + +/datum/seed/berry/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"berry") + set_trait(TRAIT_PRODUCT_COLOUR,"#FA1616") + set_trait(TRAIT_PLANT_ICON,"bush") + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + +/datum/seed/berry/glow + name = "glowberries" + seed_name = "glowberry" + display_name = "glowberry bush" + mutants = null + chems = list("nutriment" = list(1,10), "uranium" = list(3,5)) + +/datum/seed/berry/glow/New() + ..() + set_trait(TRAIT_SPREAD,1) + set_trait(TRAIT_BIOLUM,1) + set_trait(TRAIT_BIOLUM_COLOUR,"#006622") + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_COLOUR,"#c9fa16") + set_trait(TRAIT_WATER_CONSUMPTION, 3) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25) + +/datum/seed/berry/poison + name = "poisonberries" + seed_name = "poison berry" + kitchen_tag = "poisonberries" + display_name = "poison berry bush" + mutants = list("deathberries") + chems = list("nutriment" = list(1), "toxin" = list(3,5), "poisonberryjuice" = list(10,5)) + +/datum/seed/berry/poison/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#6DC961") + set_trait(TRAIT_WATER_CONSUMPTION, 3) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25) + +/datum/seed/berry/poison/death + name = "deathberries" + seed_name = "death berry" + display_name = "death berry bush" + mutants = null + chems = list("nutriment" = list(1), "toxin" = list(3,3), "lexorin" = list(1,5)) + +/datum/seed/berry/poison/death/New() + ..() + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,50) + set_trait(TRAIT_PRODUCT_COLOUR,"#7A5454") + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.35) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/cabbage.dm b/code/modules/hydroponics/seedtypes/cabbage.dm new file mode 100644 index 0000000000..0ee7fb2693 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/cabbage.dm @@ -0,0 +1,21 @@ +/datum/seed/cabbage + name = "cabbage" + seed_name = "cabbage" + display_name = "cabbages" + kitchen_tag = "cabbage" + chems = list("nutriment" = list(1,10)) + +/datum/seed/cabbage/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"cabbage") + set_trait(TRAIT_PRODUCT_COLOUR,"#84BD82") + set_trait(TRAIT_PLANT_COLOUR,"#6D9C6B") + set_trait(TRAIT_PLANT_ICON,"vine2") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/carrots.dm b/code/modules/hydroponics/seedtypes/carrots.dm new file mode 100644 index 0000000000..2b8ef7577b --- /dev/null +++ b/code/modules/hydroponics/seedtypes/carrots.dm @@ -0,0 +1,17 @@ +/datum/seed/carrots + name = "carrot" + seed_name = "carrot" + display_name = "carrots" + kitchen_tag = "carrot" + chems = list("nutriment" = list(1,20), "imidazoline" = list(3,5), "carrotjuice" = list(10,20)) + +/datum/seed/carrots/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"carrot") + set_trait(TRAIT_PRODUCT_COLOUR,"#FFDB4A") + set_trait(TRAIT_PLANT_ICON,"carrot") + set_trait(TRAIT_WATER_CONSUMPTION, 6) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/celery.dm b/code/modules/hydroponics/seedtypes/celery.dm new file mode 100644 index 0000000000..c404ed670f --- /dev/null +++ b/code/modules/hydroponics/seedtypes/celery.dm @@ -0,0 +1,17 @@ +/datum/seed/celery + name = "celery" + seed_name = "celery" + display_name = "celery" + kitchen_tag = "celery" + chems = list("nutriment" = list(5,20)) + +/datum/seed/celery/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,4) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,8) + set_trait(TRAIT_PRODUCT_ICON,"stalk") + set_trait(TRAIT_PRODUCT_COLOUR,"#56FD56") + set_trait(TRAIT_PLANT_ICON,"stalk3") \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/cherries.dm b/code/modules/hydroponics/seedtypes/cherries.dm new file mode 100644 index 0000000000..ece8d793e7 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/cherries.dm @@ -0,0 +1,20 @@ +/datum/seed/cherries + name = "cherry" + seed_name = "cherry" + seed_noun = "pits" + display_name = "cherry tree" + kitchen_tag = "cherries" + chems = list("nutriment" = list(1,15), "sugar" = list(1,15), "cherryjelly" = list(10,15)) + +/datum/seed/cherries/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"cherry") + set_trait(TRAIT_PRODUCT_COLOUR,"#A80000") + set_trait(TRAIT_PLANT_ICON,"tree2") + set_trait(TRAIT_PLANT_COLOUR,"#2F7D2D") \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/chili.dm b/code/modules/hydroponics/seedtypes/chili.dm new file mode 100644 index 0000000000..bee50a48bc --- /dev/null +++ b/code/modules/hydroponics/seedtypes/chili.dm @@ -0,0 +1,35 @@ +// Chili plants/variants. +/datum/seed/chili + name = "chili" + seed_name = "chili" + display_name = "chili plants" + kitchen_tag = "chili" + chems = list("capsaicin" = list(3,5), "nutriment" = list(1,25)) + mutants = list("icechili") + +/datum/seed/chili/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_PRODUCT_ICON,"chili") + set_trait(TRAIT_PRODUCT_COLOUR,"#ED3300") + set_trait(TRAIT_PLANT_ICON,"bush2") + set_trait(TRAIT_IDEAL_HEAT, 298) + set_trait(TRAIT_IDEAL_LIGHT, 7) + +/datum/seed/chili/ice + name = "icechili" + seed_name = "ice pepper" + display_name = "ice-pepper plants" + kitchen_tag = "icechili" + mutants = null + chems = list("frostoil" = list(3,5), "nutriment" = list(1,50)) + +/datum/seed/chili/ice/New() + ..() + set_trait(TRAIT_MATURATION,4) + set_trait(TRAIT_PRODUCTION,4) + set_trait(TRAIT_PRODUCT_COLOUR,"#00EDC6") \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/citrus.dm b/code/modules/hydroponics/seedtypes/citrus.dm new file mode 100644 index 0000000000..ebc154aa40 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/citrus.dm @@ -0,0 +1,46 @@ +/datum/seed/citrus + name = "lime" + seed_name = "lime" + display_name = "lime trees" + kitchen_tag = "lime" + chems = list("nutriment" = list(1,20), "limejuice" = list(10,20)) + +/datum/seed/citrus/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,15) + set_trait(TRAIT_PRODUCT_ICON,"treefruit") + set_trait(TRAIT_PRODUCT_COLOUR,"#3AF026") + set_trait(TRAIT_PLANT_ICON,"tree") + set_trait(TRAIT_FLESH_COLOUR,"#3AF026") + +/datum/seed/citrus/lemon + name = "lemon" + seed_name = "lemon" + display_name = "lemon trees" + kitchen_tag = "lemon" + chems = list("nutriment" = list(1,20), "lemonjuice" = list(10,20)) + +/datum/seed/citrus/lemon/New() + ..() + set_trait(TRAIT_PRODUCES_POWER,1) + set_trait(TRAIT_PRODUCT_ICON,"lemon") + set_trait(TRAIT_PRODUCT_COLOUR,"#F0E226") + set_trait(TRAIT_FLESH_COLOUR,"#F0E226") + set_trait(TRAIT_IDEAL_LIGHT, 6) + +/datum/seed/citrus/orange + name = "orange" + seed_name = "orange" + display_name = "orange trees" + kitchen_tag = "orange" + chems = list("nutriment" = list(1,20), "orangejuice" = list(10,20)) + +/datum/seed/citrus/orange/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#FFC20A") + set_trait(TRAIT_FLESH_COLOUR,"#FFC20A") \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/cocoa.dm b/code/modules/hydroponics/seedtypes/cocoa.dm new file mode 100644 index 0000000000..7f7aa31b39 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/cocoa.dm @@ -0,0 +1,19 @@ +/datum/seed/cocoa + name = "cocoa" + seed_name = "cacao" + display_name = "cacao tree" + kitchen_tag = "cocoa" + chems = list("nutriment" = list(1,10), "coco" = list(4,5)) + +/datum/seed/cocoa/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"treefruit") + set_trait(TRAIT_PRODUCT_COLOUR,"#CCA935") + set_trait(TRAIT_PLANT_ICON,"tree2") + set_trait(TRAIT_IDEAL_HEAT, 298) + set_trait(TRAIT_WATER_CONSUMPTION, 6) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/corn.dm b/code/modules/hydroponics/seedtypes/corn.dm new file mode 100644 index 0000000000..2a4b2824f8 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/corn.dm @@ -0,0 +1,21 @@ +/datum/seed/corn + name = "corn" + seed_name = "corn" + display_name = "ears of corn" + kitchen_tag = "corn" + chems = list("nutriment" = list(1,10), "cornoil" = list(3,15)) + trash_type = /obj/item/weapon/corncob + +/datum/seed/corn/New() + ..() + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_PRODUCT_ICON,"corn") + set_trait(TRAIT_PRODUCT_COLOUR,"#FFF23B") + set_trait(TRAIT_PLANT_COLOUR,"#87C969") + set_trait(TRAIT_PLANT_ICON,"corn") + set_trait(TRAIT_IDEAL_HEAT, 298) + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_WATER_CONSUMPTION, 6) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/diona.dm b/code/modules/hydroponics/seedtypes/diona.dm new file mode 100644 index 0000000000..be3b80b6bf --- /dev/null +++ b/code/modules/hydroponics/seedtypes/diona.dm @@ -0,0 +1,21 @@ +/datum/seed/diona + name = "diona" + seed_name = "diona" + seed_noun = "nodes" + display_name = "replicant pods" + can_self_harvest = 1 + apply_color_to_mob = FALSE + has_mob_product = /mob/living/carbon/alien/diona + +/datum/seed/diona/New() + ..() + set_trait(TRAIT_IMMUTABLE,1) + set_trait(TRAIT_ENDURANCE,8) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,10) + set_trait(TRAIT_YIELD,1) + set_trait(TRAIT_POTENCY,30) + set_trait(TRAIT_PRODUCT_ICON,"diona") + set_trait(TRAIT_PRODUCT_COLOUR,"#799957") + set_trait(TRAIT_PLANT_COLOUR,"#66804B") + set_trait(TRAIT_PLANT_ICON,"alien4") \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/durian.dm b/code/modules/hydroponics/seedtypes/durian.dm new file mode 100644 index 0000000000..8963f4c9ec --- /dev/null +++ b/code/modules/hydroponics/seedtypes/durian.dm @@ -0,0 +1,21 @@ +/datum/seed/durian + name = "durian" + seed_name = "durian" + seed_noun = "pits" + display_name = "durian" + kitchen_tag = "durian" + chems = list("nutriment" = list(1,5), "durianpaste" = list(1, 20)) + +/datum/seed/durian/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"spinefruit") + set_trait(TRAIT_PRODUCT_COLOUR,"#757631") + set_trait(TRAIT_PLANT_COLOUR,"#87C969") + set_trait(TRAIT_PLANT_ICON,"tree") + set_trait(TRAIT_IDEAL_LIGHT, 8) + set_trait(TRAIT_WATER_CONSUMPTION, 8) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/eggplant.dm b/code/modules/hydroponics/seedtypes/eggplant.dm new file mode 100644 index 0000000000..c856f0d382 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/eggplant.dm @@ -0,0 +1,31 @@ +//Eggplants/varieties. +/datum/seed/eggplant + name = "eggplant" + seed_name = "eggplant" + display_name = "eggplants" + kitchen_tag = "eggplant" + mutants = list("egg-plant") + chems = list("nutriment" = list(1,10)) + +/datum/seed/eggplant/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_PRODUCT_ICON,"eggplant") + set_trait(TRAIT_PRODUCT_COLOUR,"#892694") + set_trait(TRAIT_PLANT_ICON,"bush4") + set_trait(TRAIT_IDEAL_HEAT, 298) + set_trait(TRAIT_IDEAL_LIGHT, 7) + +// Return of Eggy. Just makes purple eggs. If the reagents are separated from the egg production by xenobotany or RNG, it's still an Egg plant. +/datum/seed/eggplant/egg + name = "egg-plant" + seed_name = "egg-plant" + display_name = "egg-plants" + kitchen_tag = "egg-plant" + mutants = null + chems = list("nutriment" = list(1,5), "egg" = list(3,12)) + has_item_product = /obj/item/weapon/reagent_containers/food/snacks/egg/purple \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/flowers.dm b/code/modules/hydroponics/seedtypes/flowers.dm new file mode 100644 index 0000000000..2c2ffe13ec --- /dev/null +++ b/code/modules/hydroponics/seedtypes/flowers.dm @@ -0,0 +1,108 @@ +//Flowers/varieties +/datum/seed/flower + name = "harebells" + seed_name = "harebell" + display_name = "harebells" + kitchen_tag = "harebell" + chems = list("nutriment" = list(1,20)) + +/datum/seed/flower/New() + ..() + set_trait(TRAIT_MATURATION,7) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_PRODUCT_ICON,"flower5") + set_trait(TRAIT_PRODUCT_COLOUR,"#C492D6") + set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E") + set_trait(TRAIT_PLANT_ICON,"flower") + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + +/datum/seed/flower/poppy + name = "poppies" + seed_name = "poppy" + display_name = "poppies" + kitchen_tag = "poppy" + chems = list("nutriment" = list(1,20), "bicaridine" = list(1,10)) + +/datum/seed/flower/poppy/New() + ..() + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_PRODUCT_ICON,"flower3") + set_trait(TRAIT_PRODUCT_COLOUR,"#B33715") + set_trait(TRAIT_PLANT_ICON,"flower3") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_WATER_CONSUMPTION, 0.5) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + +/datum/seed/flower/sunflower + name = "sunflowers" + seed_name = "sunflower" + display_name = "sunflowers" + kitchen_tag = "sunflower" + +/datum/seed/flower/sunflower/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCT_ICON,"flower2") + set_trait(TRAIT_PRODUCT_COLOUR,"#FFF700") + set_trait(TRAIT_PLANT_ICON,"flower2") + set_trait(TRAIT_IDEAL_LIGHT, 7) + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + +/datum/seed/flower/lavender + name = "lavender" + seed_name = "lavender" + display_name = "lavender" + kitchen_tag = "lavender" + chems = list("nutriment" = list(1,20), "bicaridine" = list(1,10)) + +/datum/seed/flower/lavender/New() + ..() + set_trait(TRAIT_MATURATION,7) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_PRODUCT_ICON,"flower6") + set_trait(TRAIT_PRODUCT_COLOUR,"#B57EDC") + set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E") + set_trait(TRAIT_PLANT_ICON,"flower4") + set_trait(TRAIT_IDEAL_LIGHT, 7) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.05) + set_trait(TRAIT_WATER_CONSUMPTION, 0.5) + +/datum/seed/flower/rose + name = "rose" + seed_name = "rose" + display_name = "rose" + kitchen_tag = "rose" + mutants = list("bloodrose") + chems = list("nutriment" = list(1,5), "stoxin" = list(0,2)) + +/datum/seed/flower/rose/New() + ..() + set_trait(TRAIT_MATURATION,7) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_PRODUCT_ICON,"flowers") + set_trait(TRAIT_PRODUCT_COLOUR,"#ce0e0e") + set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E") + set_trait(TRAIT_PLANT_ICON,"bush5") + set_trait(TRAIT_IDEAL_LIGHT, 7) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.1) + set_trait(TRAIT_WATER_CONSUMPTION, 0.5) + set_trait(TRAIT_STINGS,1) + +/datum/seed/flower/rose/blood + name = "bloodrose" + display_name = "bleeding rose" + mutants = null + chems = list("nutriment" = list(1,5), "stoxin" = list(1,5), "blood" = list(0,2)) + +/datum/seed/flower/rose/blood/New() + ..() + set_trait(TRAIT_IDEAL_LIGHT, 1) + set_trait(TRAIT_PLANT_COLOUR,"#5e0303") + set_trait(TRAIT_CARNIVOROUS,1) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/gelthi.dm b/code/modules/hydroponics/seedtypes/gelthi.dm new file mode 100644 index 0000000000..1fa365c875 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/gelthi.dm @@ -0,0 +1,15 @@ +/datum/seed/gelthi + name = "gelthi" + seed_name = "gelthi" + display_name = "gelthi plant" + kitchen_tag = "gelthi" + chems = list("stoxin" = list(1,5),"capsaicin" = list(1,5),"nutriment" = list(1,5)) + +/datum/seed/gelthi/New() + ..() + set_trait(TRAIT_PLANT_ICON,"mushroom3") + set_trait(TRAIT_ENDURANCE,15) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,1) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/gnomes.dm b/code/modules/hydroponics/seedtypes/gnomes.dm new file mode 100644 index 0000000000..2ee0901926 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/gnomes.dm @@ -0,0 +1,25 @@ +// Gnomes +/datum/seed/gnomes + name = "gnomes" + seed_name = "gnomes" + display_name = "gnomes" + force_layer = 3 + chems = list("magicdust" = list(5,20)) + +/datum/seed/gnomes/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_PLANT_ICON,"gnomes") + set_trait(TRAIT_PRODUCT_ICON,"gnomes") + set_trait(TRAIT_PRODUCT_COLOUR,"") + set_trait(TRAIT_FLESH_COLOUR,"") + set_trait(TRAIT_PLANT_COLOUR,"") + set_trait(TRAIT_BIOLUM_COLOUR,"#fff200") + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_BIOLUM,1) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_SPREAD,1) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_REQUIRES_NUTRIENTS,0) + set_trait(TRAIT_REQUIRES_WATER,0) diff --git a/code/modules/hydroponics/seedtypes/grapes.dm b/code/modules/hydroponics/seedtypes/grapes.dm new file mode 100644 index 0000000000..e61978e5f0 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/grapes.dm @@ -0,0 +1,33 @@ +//Grapes/varieties +/datum/seed/grapes + name = "grapes" + seed_name = "grape" + display_name = "grapevines" + kitchen_tag = "grapes" + mutants = list("greengrapes") + chems = list("nutriment" = list(1,10), "sugar" = list(1,5), "grapejuice" = list(10,10)) + +/datum/seed/grapes/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"grapes") + set_trait(TRAIT_PRODUCT_COLOUR,"#BB6AC4") + set_trait(TRAIT_PLANT_COLOUR,"#378F2E") + set_trait(TRAIT_PLANT_ICON,"vine") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) + +/datum/seed/grapes/green + name = "greengrapes" + seed_name = "green grape" + display_name = "green grapevines" + mutants = null + chems = list("nutriment" = list(1,10), "kelotane" = list(3,5), "grapejuice" = list(10,10)) + +/datum/seed/grapes/green/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"42ed2f") \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/grass.dm b/code/modules/hydroponics/seedtypes/grass.dm new file mode 100644 index 0000000000..0a94f9707f --- /dev/null +++ b/code/modules/hydroponics/seedtypes/grass.dm @@ -0,0 +1,19 @@ +/datum/seed/grass + name = "grass" + seed_name = "grass" + display_name = "grass" + kitchen_tag = "grass" + chems = list("nutriment" = list(1,20)) + +/datum/seed/grass/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,2) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_PRODUCT_ICON,"grass") + set_trait(TRAIT_PRODUCT_COLOUR,"#09FF00") + set_trait(TRAIT_PLANT_COLOUR,"#07D900") + set_trait(TRAIT_PLANT_ICON,"grass") + set_trait(TRAIT_WATER_CONSUMPTION, 0.5) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/jurlmah.dm b/code/modules/hydroponics/seedtypes/jurlmah.dm new file mode 100644 index 0000000000..61e810b9da --- /dev/null +++ b/code/modules/hydroponics/seedtypes/jurlmah.dm @@ -0,0 +1,15 @@ +/datum/seed/jurlmah + name = "jurlmah" + seed_name = "jurl'mah" + display_name = "jurl'mah reeds" + kitchen_tag = "jurlmah" + chems = list("serotrotium" = list(1,5),"nutriment" = list(1,5)) + +/datum/seed/jurlmah/New() + ..() + set_trait(TRAIT_PLANT_ICON,"mushroom9") + set_trait(TRAIT_ENDURANCE,12) + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,9) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,10) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/kudzu.dm b/code/modules/hydroponics/seedtypes/kudzu.dm new file mode 100644 index 0000000000..336c205b25 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/kudzu.dm @@ -0,0 +1,19 @@ +/datum/seed/kudzu + name = "kudzu" + seed_name = "kudzu" + display_name = "kudzu vines" + kitchen_tag = "kudzu" + chems = list("nutriment" = list(1,50), "anti_toxin" = list(1,25)) + +/datum/seed/kudzu/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_SPREAD,2) + set_trait(TRAIT_PRODUCT_ICON,"treefruit") + set_trait(TRAIT_PRODUCT_COLOUR,"#96D278") + set_trait(TRAIT_PLANT_COLOUR,"#6F7A63") + set_trait(TRAIT_PLANT_ICON,"vine2") + set_trait(TRAIT_WATER_CONSUMPTION, 0.5) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/lettuce.dm b/code/modules/hydroponics/seedtypes/lettuce.dm new file mode 100644 index 0000000000..ae2830f88a --- /dev/null +++ b/code/modules/hydroponics/seedtypes/lettuce.dm @@ -0,0 +1,34 @@ +// Lettuce/varieties. +/datum/seed/lettuce + name = "lettuce" + seed_name = "lettuce" + display_name = "lettuce" + kitchen_tag = "cabbage" + chems = list("nutriment" = list(1,15)) + +/datum/seed/lettuce/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,4) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,8) + set_trait(TRAIT_PRODUCT_ICON,"lettuce") + set_trait(TRAIT_PRODUCT_COLOUR,"#A8D0A7") + set_trait(TRAIT_PLANT_COLOUR,"#6D9C6B") + set_trait(TRAIT_PLANT_ICON,"vine2") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_WATER_CONSUMPTION, 8) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.13) + +/datum/seed/lettuce/ice + name = "siflettuce" + seed_name = "glacial lettuce" + display_name = "glacial lettuce" + kitchen_tag = "icelettuce" + chems = list("nutriment" = list(1,5), "paracetamol" = list(0,2)) + +/datum/seed/lettuce/ice/New() + ..() + set_trait(TRAIT_ALTER_TEMP, -5) + set_trait(TRAIT_PRODUCT_COLOUR,"#9ABCC9") \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/malanitear.dm b/code/modules/hydroponics/seedtypes/malanitear.dm new file mode 100644 index 0000000000..15b62d23d4 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/malanitear.dm @@ -0,0 +1,19 @@ +/datum/seed/mtear + name = "mtear" + seed_name = "Malani's tear" + display_name = "Malani's tear leaves" + kitchen_tag = "mtear" + chems = list("honey" = list(1,10), "kelotane" = list(3,5)) + +/datum/seed/mtear/New() + ..() + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"alien4") + set_trait(TRAIT_PRODUCT_COLOUR,"#4CC5C7") + set_trait(TRAIT_PLANT_COLOUR,"#4CC789") + set_trait(TRAIT_PLANT_ICON,"bush7") + set_trait(TRAIT_IDEAL_HEAT, 283) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/mushrooms.dm b/code/modules/hydroponics/seedtypes/mushrooms.dm new file mode 100644 index 0000000000..ceb6b0a33b --- /dev/null +++ b/code/modules/hydroponics/seedtypes/mushrooms.dm @@ -0,0 +1,200 @@ +//Mushrooms/varieties. +/datum/seed/mushroom + name = "mushrooms" + seed_name = "chanterelle" + seed_noun = "spores" + display_name = "chanterelle mushrooms" + mutants = list("reishi","amanita","plumphelmet") + chems = list("nutriment" = list(1,25)) + splat_type = /obj/effect/plant + kitchen_tag = "mushroom" + +/datum/seed/mushroom/New() + ..() + set_trait(TRAIT_MATURATION,7) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_POTENCY,1) + set_trait(TRAIT_PRODUCT_ICON,"mushroom4") + set_trait(TRAIT_PRODUCT_COLOUR,"#DBDA72") + set_trait(TRAIT_PLANT_COLOUR,"#D9C94E") + set_trait(TRAIT_PLANT_ICON,"mushroom") + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_IDEAL_HEAT, 288) + set_trait(TRAIT_LIGHT_TOLERANCE, 6) + +/datum/seed/mushroom/mold + name = "mold" + seed_name = "brown mold" + display_name = "brown mold" + mutants = null + +/datum/seed/mushroom/mold/New() + ..() + set_trait(TRAIT_SPREAD,1) + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_YIELD,-1) + set_trait(TRAIT_PRODUCT_ICON,"mushroom5") + set_trait(TRAIT_PRODUCT_COLOUR,"#7A5F20") + set_trait(TRAIT_PLANT_COLOUR,"#7A5F20") + set_trait(TRAIT_PLANT_ICON,"mushroom9") + +/datum/seed/mushroom/plump + name = "plumphelmet" + seed_name = "plump helmet" + display_name = "plump helmet mushrooms" + mutants = list("walkingmushroom","towercap") + chems = list("nutriment" = list(2,10)) + kitchen_tag = "plumphelmet" + +/datum/seed/mushroom/plump/New() + ..() + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,0) + set_trait(TRAIT_PRODUCT_ICON,"mushroom10") + set_trait(TRAIT_PRODUCT_COLOUR,"#B57BB0") + set_trait(TRAIT_PLANT_COLOUR,"#9E4F9D") + set_trait(TRAIT_PLANT_ICON,"mushroom2") + +/datum/seed/mushroom/hallucinogenic + name = "reishi" + seed_name = "reishi" + display_name = "reishi" + mutants = list("libertycap","glowshroom") + chems = list("nutriment" = list(1,50), "psilocybin" = list(3,5)) + +/datum/seed/mushroom/hallucinogenic/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,15) + set_trait(TRAIT_PRODUCT_ICON,"mushroom11") + set_trait(TRAIT_PRODUCT_COLOUR,"#FFB70F") + set_trait(TRAIT_PLANT_COLOUR,"#F58A18") + set_trait(TRAIT_PLANT_ICON,"mushroom6") + +/datum/seed/mushroom/hallucinogenic/strong + name = "libertycap" + seed_name = "liberty cap" + display_name = "liberty cap mushrooms" + mutants = null + chems = list("nutriment" = list(1), "stoxin" = list(3,3), "space_drugs" = list(1,25)) + +/datum/seed/mushroom/hallucinogenic/strong/New() + ..() + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_POTENCY,15) + set_trait(TRAIT_PRODUCT_ICON,"mushroom8") + set_trait(TRAIT_PRODUCT_COLOUR,"#F2E550") + set_trait(TRAIT_PLANT_COLOUR,"#D1CA82") + set_trait(TRAIT_PLANT_ICON,"mushroom3") + +/datum/seed/mushroom/poison + name = "amanita" + seed_name = "fly amanita" + display_name = "fly amanita mushrooms" + mutants = list("destroyingangel","plastic") + chems = list("nutriment" = list(1), "amatoxin" = list(3,3), "psilocybin" = list(1,25)) + +/datum/seed/mushroom/poison/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"mushroom") + set_trait(TRAIT_PRODUCT_COLOUR,"#FF4545") + set_trait(TRAIT_PLANT_COLOUR,"#E0DDBA") + set_trait(TRAIT_PLANT_ICON,"mushroom4") + +/datum/seed/mushroom/poison/death + name = "destroyingangel" + seed_name = "destroying angel" + display_name = "destroying angel mushrooms" + mutants = null + chems = list("nutriment" = list(1,50), "amatoxin" = list(13,3), "psilocybin" = list(1,25)) + +/datum/seed/mushroom/poison/death/New() + ..() + set_trait(TRAIT_MATURATION,12) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,35) + set_trait(TRAIT_PRODUCT_ICON,"mushroom3") + set_trait(TRAIT_PRODUCT_COLOUR,"#EDE8EA") + set_trait(TRAIT_PLANT_COLOUR,"#E6D8DD") + set_trait(TRAIT_PLANT_ICON,"mushroom5") + +/datum/seed/mushroom/towercap + name = "towercap" + seed_name = "tower cap" + display_name = "tower caps" + chems = list("woodpulp" = list(10,1)) + mutants = null + has_item_product = /obj/item/stack/material/log + +/datum/seed/mushroom/towercap/New() + ..() + set_trait(TRAIT_MATURATION,15) + set_trait(TRAIT_PRODUCT_ICON,"mushroom7") + set_trait(TRAIT_PRODUCT_COLOUR,"#79A36D") + set_trait(TRAIT_PLANT_COLOUR,"#857F41") + set_trait(TRAIT_PLANT_ICON,"mushroom8") + +/datum/seed/mushroom/glowshroom + name = "glowshroom" + seed_name = "glowshroom" + display_name = "glowshrooms" + mutants = null + chems = list("radium" = list(1,20)) + +/datum/seed/mushroom/glowshroom/New() + ..() + set_trait(TRAIT_SPREAD,1) + set_trait(TRAIT_MATURATION,15) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,30) + set_trait(TRAIT_BIOLUM,1) + set_trait(TRAIT_BIOLUM_COLOUR,"#006622") + set_trait(TRAIT_PRODUCT_ICON,"mushroom2") + set_trait(TRAIT_PRODUCT_COLOUR,"#DDFAB6") + set_trait(TRAIT_PLANT_COLOUR,"#EFFF8A") + set_trait(TRAIT_PLANT_ICON,"mushroom7") + +/datum/seed/mushroom/plastic + name = "plastic" + seed_name = "plastellium" + display_name = "plastellium" + mutants = null + chems = list("plasticide" = list(1,10)) + +/datum/seed/mushroom/plastic/New() + ..() + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_PRODUCT_ICON,"mushroom6") + set_trait(TRAIT_PRODUCT_COLOUR,"#E6E6E6") + set_trait(TRAIT_PLANT_COLOUR,"#E6E6E6") + set_trait(TRAIT_PLANT_ICON,"mushroom10") + +/datum/seed/mushroom/spore + name = "sporeshroom" + seed_name = "corpellian" + display_name = "corpellian" + mutants = null + chems = list("serotrotium" = list(5,10), "mold" = list(1,10)) + +/datum/seed/mushroom/spore/New() + ..() + set_trait(TRAIT_MATURATION,15) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,20) + set_trait(TRAIT_PRODUCT_ICON,"mushroom5") + set_trait(TRAIT_PRODUCT_COLOUR,"#e29cd2") + set_trait(TRAIT_PLANT_COLOUR,"#f8e6f4") + set_trait(TRAIT_PLANT_ICON,"mushroom9") + set_trait(TRAIT_SPORING, TRUE) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/nettles.dm b/code/modules/hydroponics/seedtypes/nettles.dm new file mode 100644 index 0000000000..5a1073c6fc --- /dev/null +++ b/code/modules/hydroponics/seedtypes/nettles.dm @@ -0,0 +1,35 @@ +// Nettles/variants. +/datum/seed/nettle + name = "nettle" + seed_name = "nettle" + display_name = "nettles" + mutants = list("deathnettle") + chems = list("nutriment" = list(1,50), "sacid" = list(0,1)) + kitchen_tag = "nettle" + +/datum/seed/nettle/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_STINGS,1) + set_trait(TRAIT_PLANT_ICON,"bush5") + set_trait(TRAIT_PRODUCT_ICON,"nettles") + set_trait(TRAIT_PRODUCT_COLOUR,"#728A54") + +/datum/seed/nettle/death + name = "deathnettle" + seed_name = "death nettle" + display_name = "death nettles" + kitchen_tag = "deathnettle" + mutants = null + chems = list("nutriment" = list(1,50), "pacid" = list(0,1)) + +/datum/seed/nettle/death/New() + ..() + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_PRODUCT_COLOUR,"#8C5030") + set_trait(TRAIT_PLANT_COLOUR,"#634941") diff --git a/code/modules/hydroponics/seedtypes/onion.dm b/code/modules/hydroponics/seedtypes/onion.dm new file mode 100644 index 0000000000..2123ad2b38 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/onion.dm @@ -0,0 +1,17 @@ +/datum/seed/onion + name = "onion" + seed_name = "onion" + display_name = "onions" + kitchen_tag = "onion" + chems = list("nutriment" = list(1,10)) + +/datum/seed/onion/New() + ..() + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"onion") + set_trait(TRAIT_PRODUCT_COLOUR,"#E0C367") + set_trait(TRAIT_PLANT_ICON,"carrot") + set_trait(TRAIT_WATER_CONSUMPTION, 6) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/peanuts.dm b/code/modules/hydroponics/seedtypes/peanuts.dm new file mode 100644 index 0000000000..cc710d25ca --- /dev/null +++ b/code/modules/hydroponics/seedtypes/peanuts.dm @@ -0,0 +1,19 @@ +//Everything else +/datum/seed/peanuts + name = "peanut" + seed_name = "peanut" + display_name = "peanut vines" + kitchen_tag = "peanut" + chems = list("nutriment" = list(1,10), "peanutoil" = list(3,10)) + +/datum/seed/peanuts/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"nuts") + set_trait(TRAIT_PRODUCT_COLOUR,"#C4AE7A") + set_trait(TRAIT_PLANT_ICON,"bush2") + set_trait(TRAIT_IDEAL_LIGHT, 6) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/potato.dm b/code/modules/hydroponics/seedtypes/potato.dm new file mode 100644 index 0000000000..8aad55afc6 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/potato.dm @@ -0,0 +1,18 @@ +/datum/seed/potato + name = "potato" + seed_name = "potato" + display_name = "potatoes" + kitchen_tag = "potato" + chems = list("nutriment" = list(1,10), "potatojuice" = list(10,10)) + +/datum/seed/potato/New() + ..() + set_trait(TRAIT_PRODUCES_POWER,1) + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"potato") + set_trait(TRAIT_PRODUCT_COLOUR,"#D4CAB4") + set_trait(TRAIT_PLANT_ICON,"bush2") + set_trait(TRAIT_WATER_CONSUMPTION, 6) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/pumpkin.dm b/code/modules/hydroponics/seedtypes/pumpkin.dm new file mode 100644 index 0000000000..916d44e58b --- /dev/null +++ b/code/modules/hydroponics/seedtypes/pumpkin.dm @@ -0,0 +1,19 @@ +/datum/seed/pumpkin + name = "pumpkin" + seed_name = "pumpkin" + display_name = "pumpkin vine" + kitchen_tag = "pumpkin" + chems = list("nutriment" = list(1,6)) + +/datum/seed/pumpkin/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"vine2") + set_trait(TRAIT_PRODUCT_COLOUR,"#DBAC02") + set_trait(TRAIT_PLANT_COLOUR,"#21661E") + set_trait(TRAIT_PLANT_ICON,"vine2") + set_trait(TRAIT_WATER_CONSUMPTION, 6) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/rhubarb.dm b/code/modules/hydroponics/seedtypes/rhubarb.dm new file mode 100644 index 0000000000..f3ee13ce41 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/rhubarb.dm @@ -0,0 +1,17 @@ +/datum/seed/rhubarb + name = "rhubarb" + seed_name = "rhubarb" + display_name = "rhubarb" + kitchen_tag = "rhubarb" + chems = list("nutriment" = list(1,15)) + +/datum/seed/rhubarb/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,5) + set_trait(TRAIT_POTENCY,6) + set_trait(TRAIT_PRODUCT_ICON,"stalk") + set_trait(TRAIT_PRODUCT_COLOUR,"#FD5656") + set_trait(TRAIT_PLANT_ICON,"stalk3") \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/rice.dm b/code/modules/hydroponics/seedtypes/rice.dm new file mode 100644 index 0000000000..413c43b9fc --- /dev/null +++ b/code/modules/hydroponics/seedtypes/rice.dm @@ -0,0 +1,19 @@ +/datum/seed/rice + name = "rice" + seed_name = "rice" + display_name = "rice stalks" + kitchen_tag = "rice" + chems = list("nutriment" = list(1,25), "rice" = list(10,15)) + +/datum/seed/rice/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,5) + set_trait(TRAIT_PRODUCT_ICON,"rice") + set_trait(TRAIT_PRODUCT_COLOUR,"#D5E6D1") + set_trait(TRAIT_PLANT_COLOUR,"#8ED17D") + set_trait(TRAIT_PLANT_ICON,"stalk2") + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/selemhand.dm b/code/modules/hydroponics/seedtypes/selemhand.dm new file mode 100644 index 0000000000..5b49728c61 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/selemhand.dm @@ -0,0 +1,19 @@ +/datum/seed/shand + name = "shand" + seed_name = "Selem's hand" + display_name = "Selem's hand leaves" + kitchen_tag = "shand" + chems = list("bicaridine" = list(0,10)) + +/datum/seed/shand/New() + ..() + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"alien3") + set_trait(TRAIT_PRODUCT_COLOUR,"#378C61") + set_trait(TRAIT_PLANT_COLOUR,"#378C61") + set_trait(TRAIT_PLANT_ICON,"tree5") + set_trait(TRAIT_IDEAL_HEAT, 283) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/soybean.dm b/code/modules/hydroponics/seedtypes/soybean.dm new file mode 100644 index 0000000000..22329be263 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/soybean.dm @@ -0,0 +1,17 @@ +/datum/seed/soybean + name = "soybean" + seed_name = "soybean" + display_name = "soybeans" + kitchen_tag = "soybeans" + chems = list("nutriment" = list(1,20), "soymilk" = list(10,20)) + +/datum/seed/soybean/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,4) + set_trait(TRAIT_PRODUCTION,4) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,5) + set_trait(TRAIT_PRODUCT_ICON,"bean") + set_trait(TRAIT_PRODUCT_COLOUR,"#EBE7C0") + set_trait(TRAIT_PLANT_ICON,"stalk") \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/spineapple.dm b/code/modules/hydroponics/seedtypes/spineapple.dm new file mode 100644 index 0000000000..b8ff58f597 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/spineapple.dm @@ -0,0 +1,22 @@ +/datum/seed/spineapple + name = "spineapple" + seed_name = "spineapple" + display_name = "spineapple" + kitchen_tag = "pineapple" + chems = list("nutriment" = list(1,5), "enzyme" = list(1,5), "pineapplejuice" = list(1, 20)) + +/datum/seed/spineapple/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,10) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,1) + set_trait(TRAIT_POTENCY,13) + set_trait(TRAIT_PRODUCT_ICON,"pineapple") + set_trait(TRAIT_PRODUCT_COLOUR,"#FFF23B") + set_trait(TRAIT_PLANT_COLOUR,"#87C969") + set_trait(TRAIT_PLANT_ICON,"corn") + set_trait(TRAIT_IDEAL_HEAT, 298) + set_trait(TRAIT_IDEAL_LIGHT, 4) + set_trait(TRAIT_WATER_CONSUMPTION, 8) + set_trait(TRAIT_STINGS,1) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/sugarcane.dm b/code/modules/hydroponics/seedtypes/sugarcane.dm new file mode 100644 index 0000000000..c670500a1d --- /dev/null +++ b/code/modules/hydroponics/seedtypes/sugarcane.dm @@ -0,0 +1,19 @@ +/datum/seed/sugarcane + name = "sugarcane" + seed_name = "sugarcane" + display_name = "sugarcanes" + kitchen_tag = "sugarcanes" + chems = list("sugar" = list(4,5)) + +/datum/seed/sugarcane/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,3) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"stalk") + set_trait(TRAIT_PRODUCT_COLOUR,"#B4D6BD") + set_trait(TRAIT_PLANT_COLOUR,"#6BBD68") + set_trait(TRAIT_PLANT_ICON,"stalk3") + set_trait(TRAIT_IDEAL_HEAT, 298) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/surik.dm b/code/modules/hydroponics/seedtypes/surik.dm new file mode 100644 index 0000000000..8ea521995c --- /dev/null +++ b/code/modules/hydroponics/seedtypes/surik.dm @@ -0,0 +1,15 @@ +/datum/seed/surik + name = "surik" + seed_name = "surik" + display_name = "surik vine" + kitchen_tag = "surik" + chems = list("impedrezene" = list(1,3),"synaptizine" = list(1,2),"nutriment" = list(1,5)) + +/datum/seed/surik/New() + ..() + set_trait(TRAIT_PLANT_ICON,"bush6") + set_trait(TRAIT_ENDURANCE,18) + set_trait(TRAIT_MATURATION,7) + set_trait(TRAIT_PRODUCTION,7) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,3) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/telriis.dm b/code/modules/hydroponics/seedtypes/telriis.dm new file mode 100644 index 0000000000..47c577b787 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/telriis.dm @@ -0,0 +1,16 @@ +/datum/seed/telriis + name = "telriis" + seed_name = "telriis" + display_name = "telriis grass" + kitchen_tag = "telriis" + chems = list("pwine" = list(1,5), "nutriment" = list(1,6)) + +/datum/seed/telriis/New() + ..() + set_trait(TRAIT_PLANT_ICON,"ambrosia") + set_trait(TRAIT_PRODUCT_ICON,"ambrosia") + set_trait(TRAIT_ENDURANCE,50) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,5) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/thaadra.dm b/code/modules/hydroponics/seedtypes/thaadra.dm new file mode 100644 index 0000000000..209b495c82 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/thaadra.dm @@ -0,0 +1,16 @@ +/datum/seed/thaadra + name = "thaadra" + seed_name = "thaa'dra" + display_name = "thaa'dra lichen" + kitchen_tag = "thaadra" + chems = list("frostoil" = list(1,5),"nutriment" = list(1,5)) + +/datum/seed/thaadra/New() + ..() + set_trait(TRAIT_PLANT_ICON,"grass") + set_trait(TRAIT_PLANT_COLOUR,"#ABC7D2") + set_trait(TRAIT_ENDURANCE,10) + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,9) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,5) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/tomatoes.dm b/code/modules/hydroponics/seedtypes/tomatoes.dm new file mode 100644 index 0000000000..3454d69952 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/tomatoes.dm @@ -0,0 +1,75 @@ +//Tomatoes/variants. +/datum/seed/tomato + name = "tomato" + seed_name = "tomato" + display_name = "tomato plant" + mutants = list("bluetomato","bloodtomato") + chems = list("nutriment" = list(1,10), "tomatojuice" = list(10,10)) + kitchen_tag = "tomato" + +/datum/seed/tomato/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"tomato") + set_trait(TRAIT_PRODUCT_COLOUR,"#D10000") + set_trait(TRAIT_PLANT_ICON,"bush3") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_WATER_CONSUMPTION, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25) + +/datum/seed/tomato/blood + name = "bloodtomato" + seed_name = "blood tomato" + display_name = "blood tomato plant" + mutants = list("killertomato") + chems = list("nutriment" = list(1,10), "blood" = list(1,5)) + splat_type = /obj/effect/decal/cleanable/blood/splatter + +/datum/seed/tomato/blood/New() + ..() + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_PRODUCT_COLOUR,"#FF0000") + +/datum/seed/tomato/killer + name = "killertomato" + seed_name = "killer tomato" + display_name = "killer tomato plant" + mutants = null + can_self_harvest = 1 + has_mob_product = /mob/living/simple_mob/tomato + +/datum/seed/tomato/killer/New() + ..() + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_PRODUCT_COLOUR,"#A86747") + +/datum/seed/tomato/blue + name = "bluetomato" + seed_name = "blue tomato" + display_name = "blue tomato plant" + mutants = list("bluespacetomato") + chems = list("nutriment" = list(1,20), "lube" = list(1,5)) + +/datum/seed/tomato/blue/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#4D86E8") + set_trait(TRAIT_PLANT_COLOUR,"#070AAD") + +/datum/seed/tomato/blue/teleport + name = "bluespacetomato" + seed_name = "bluespace tomato" + display_name = "bluespace tomato plant" + mutants = null + chems = list("nutriment" = list(1,20), "singulo" = list(10,5)) + +/datum/seed/tomato/blue/teleport/New() + ..() + set_trait(TRAIT_TELEPORTING,1) + set_trait(TRAIT_PRODUCT_COLOUR,"#00E5FF") + set_trait(TRAIT_BIOLUM,1) + set_trait(TRAIT_BIOLUM_COLOUR,"#4DA4A8") \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/vale.dm b/code/modules/hydroponics/seedtypes/vale.dm new file mode 100644 index 0000000000..166fafcf97 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/vale.dm @@ -0,0 +1,15 @@ +/datum/seed/vale + name = "vale" + seed_name = "vale" + display_name = "vale bush" + kitchen_tag = "vale" + chems = list("paracetamol" = list(1,5),"dexalin" = list(1,2),"nutriment"= list(1,5)) + +/datum/seed/vale/New() + ..() + set_trait(TRAIT_PLANT_ICON,"flower4") + set_trait(TRAIT_ENDURANCE,15) + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,10) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,3) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/vanilla.dm b/code/modules/hydroponics/seedtypes/vanilla.dm new file mode 100644 index 0000000000..a2bc5c8dcf --- /dev/null +++ b/code/modules/hydroponics/seedtypes/vanilla.dm @@ -0,0 +1,19 @@ +/datum/seed/vanilla + name = "vanilla" + seed_name = "vanilla" + display_name = "vanilla" + kitchen_tag = "vanilla" + chems = list("nutriment" = list(1,10), "vanilla" = list(2,8), "sugar" = list(1, 4)) + +/datum/seed/vanilla/New() + ..() + set_trait(TRAIT_MATURATION,7) + set_trait(TRAIT_PRODUCTION,5) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_PRODUCT_ICON,"chili") + set_trait(TRAIT_PRODUCT_COLOUR,"#B57EDC") + set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E") + set_trait(TRAIT_PLANT_ICON,"bush5") + set_trait(TRAIT_IDEAL_LIGHT, 8) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.3) + set_trait(TRAIT_WATER_CONSUMPTION, 0.5) diff --git a/code/modules/hydroponics/seedtypes/wabback.dm b/code/modules/hydroponics/seedtypes/wabback.dm new file mode 100644 index 0000000000..8c1e9411f0 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/wabback.dm @@ -0,0 +1,54 @@ +//Wabback / varieties. +/datum/seed/wabback + name = "whitewabback" + seed_name = "white wabback" + seed_noun = "nodes" + display_name = "white wabback" + chems = list("nutriment" = list(1,10), "protein" = list(1,5), "enzyme" = list(0,3)) + kitchen_tag = "wabback" + mutants = list("blackwabback","wildwabback") + has_item_product = /obj/item/stack/material/cloth + +/datum/seed/wabback/New() + ..() + set_trait(TRAIT_IDEAL_LIGHT, 5) + set_trait(TRAIT_MATURATION,8) + set_trait(TRAIT_PRODUCTION,3) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,5) + set_trait(TRAIT_PRODUCT_ICON,"carrot2") + set_trait(TRAIT_PRODUCT_COLOUR,"#E6EDFA") + set_trait(TRAIT_PLANT_ICON,"chute") + set_trait(TRAIT_PLANT_COLOUR, "#0650ce") + set_trait(TRAIT_WATER_CONSUMPTION, 10) + set_trait(TRAIT_ALTER_TEMP, -1) + set_trait(TRAIT_CARNIVOROUS,1) + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_SPREAD,1) + +/datum/seed/wabback/vine + name = "blackwabback" + seed_name = "black wabback" + display_name = "black wabback" + mutants = null + chems = list("nutriment" = list(1,3), "protein" = list(1,10), "serotrotium_v" = list(0,1)) + +/datum/seed/wabback/vine/New() + ..() + set_trait(TRAIT_PRODUCT_COLOUR,"#2E2F32") + set_trait(TRAIT_CARNIVOROUS,2) + +/datum/seed/wabback/wild + name = "wildwabback" + seed_name = "wild wabback" + display_name = "wild wabback" + mutants = list("whitewabback") + has_item_product = null + chems = list("nutriment" = list(1,15), "protein" = list(0,2), "enzyme" = list(0,1)) + +/datum/seed/wabback/wild/New() + ..() + set_trait(TRAIT_IDEAL_LIGHT, 3) + set_trait(TRAIT_WATER_CONSUMPTION, 7) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.1) + set_trait(TRAIT_YIELD,5) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/watermelon.dm b/code/modules/hydroponics/seedtypes/watermelon.dm new file mode 100644 index 0000000000..79ae157295 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/watermelon.dm @@ -0,0 +1,23 @@ +/datum/seed/watermelon + name = "watermelon" + seed_name = "watermelon" + display_name = "watermelon vine" + kitchen_tag = "watermelon" + chems = list("nutriment" = list(1,6), "watermelonjuice" = list(10,6)) + +/datum/seed/watermelon/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_JUICY,1) + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,3) + set_trait(TRAIT_POTENCY,1) + set_trait(TRAIT_PRODUCT_ICON,"vine") + set_trait(TRAIT_PRODUCT_COLOUR,"#3D8C3A") + set_trait(TRAIT_PLANT_COLOUR,"#257522") + set_trait(TRAIT_PLANT_ICON,"vine2") + set_trait(TRAIT_FLESH_COLOUR,"#F22C2C") + set_trait(TRAIT_IDEAL_HEAT, 298) + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_WATER_CONSUMPTION, 6) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/weeds.dm b/code/modules/hydroponics/seedtypes/weeds.dm new file mode 100644 index 0000000000..9a867174b8 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/weeds.dm @@ -0,0 +1,16 @@ +/datum/seed/weeds + name = "weeds" + seed_name = "weed" + display_name = "weeds" + +/datum/seed/weeds/New() + ..() + set_trait(TRAIT_MATURATION,5) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,-1) + set_trait(TRAIT_POTENCY,-1) + set_trait(TRAIT_IMMUTABLE,-1) + set_trait(TRAIT_PRODUCT_ICON,"flower4") + set_trait(TRAIT_PRODUCT_COLOUR,"#FCEB2B") + set_trait(TRAIT_PLANT_COLOUR,"#59945A") + set_trait(TRAIT_PLANT_ICON,"bush6") \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/wheat.dm b/code/modules/hydroponics/seedtypes/wheat.dm new file mode 100644 index 0000000000..a657490c15 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/wheat.dm @@ -0,0 +1,19 @@ +/datum/seed/wheat + name = "wheat" + seed_name = "wheat" + display_name = "wheat stalks" + kitchen_tag = "wheat" + chems = list("nutriment" = list(1,25), "flour" = list(10,30)) + +/datum/seed/wheat/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,4) + set_trait(TRAIT_POTENCY,5) + set_trait(TRAIT_PRODUCT_ICON,"wheat") + set_trait(TRAIT_PRODUCT_COLOUR,"#DBD37D") + set_trait(TRAIT_PLANT_COLOUR,"#BFAF82") + set_trait(TRAIT_PLANT_ICON,"stalk2") + set_trait(TRAIT_IDEAL_LIGHT, 6) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/whitebeets.dm b/code/modules/hydroponics/seedtypes/whitebeets.dm new file mode 100644 index 0000000000..3534fcc7ff --- /dev/null +++ b/code/modules/hydroponics/seedtypes/whitebeets.dm @@ -0,0 +1,18 @@ +/datum/seed/whitebeets + name = "whitebeet" + seed_name = "white-beet" + display_name = "white-beets" + kitchen_tag = "whitebeet" + chems = list("nutriment" = list(0,20), "sugar" = list(1,5)) + +/datum/seed/whitebeets/New() + ..() + set_trait(TRAIT_MATURATION,6) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,6) + set_trait(TRAIT_POTENCY,10) + set_trait(TRAIT_PRODUCT_ICON,"carrot2") + set_trait(TRAIT_PRODUCT_COLOUR,"#EEF5B0") + set_trait(TRAIT_PLANT_COLOUR,"#4D8F53") + set_trait(TRAIT_PLANT_ICON,"carrot2") + set_trait(TRAIT_WATER_CONSUMPTION, 6) \ No newline at end of file diff --git a/code/modules/hydroponics/seedtypes/wurmwoad.dm b/code/modules/hydroponics/seedtypes/wurmwoad.dm new file mode 100644 index 0000000000..bb4df620a2 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/wurmwoad.dm @@ -0,0 +1,23 @@ +// Wurmwoad, the Space Spice maker. Totally is actually, 100% literal worms. + +/datum/seed/wurmwoad + name = "wurmwoad" + seed_name = "wurmwoad" + display_name = "wurmwoad growth" + chems = list("nutriment" = list(1,10), "spacespice" = list(5,15)) + kitchen_tag = "wurmwoad" + +/datum/seed/wurmwoad/New() + ..() + set_trait(TRAIT_HARVEST_REPEAT,1) + set_trait(TRAIT_MATURATION,7) + set_trait(TRAIT_PRODUCTION,6) + set_trait(TRAIT_YIELD,2) + set_trait(TRAIT_POTENCY,8) + set_trait(TRAIT_PRODUCT_ICON,"eyepod") + set_trait(TRAIT_PRODUCT_COLOUR,"#e08702") + set_trait(TRAIT_PLANT_COLOUR,"#f1d1d2") + set_trait(TRAIT_PLANT_ICON,"worm") + set_trait(TRAIT_IDEAL_LIGHT, 1) + set_trait(TRAIT_WATER_CONSUMPTION, 8) + set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25) diff --git a/code/modules/hydroponics/seedtypes/xeno.dm b/code/modules/hydroponics/seedtypes/xeno.dm new file mode 100644 index 0000000000..2b1acd76b0 --- /dev/null +++ b/code/modules/hydroponics/seedtypes/xeno.dm @@ -0,0 +1,19 @@ +// Alien weeds. +/datum/seed/xenomorph + name = "xenomorph" + seed_name = "alien weed" + display_name = "alien weeds" + force_layer = 3 + chems = list("phoron" = list(1,3)) + +/datum/seed/xenomorph/New() + ..() + set_trait(TRAIT_PLANT_ICON,"vine2") + set_trait(TRAIT_IMMUTABLE,1) + set_trait(TRAIT_PRODUCT_COLOUR,"#3D1934") + set_trait(TRAIT_FLESH_COLOUR,"#3D1934") + set_trait(TRAIT_PLANT_COLOUR,"#3D1934") + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,-1) + set_trait(TRAIT_SPREAD,2) + set_trait(TRAIT_POTENCY,50) \ No newline at end of file diff --git a/code/modules/hydroponics/trays/tray_tools.dm b/code/modules/hydroponics/trays/tray_tools.dm index d05922b2f9..cedcc3f8b9 100644 --- a/code/modules/hydroponics/trays/tray_tools.dm +++ b/code/modules/hydroponics/trays/tray_tools.dm @@ -19,6 +19,10 @@ var/datum/seed/last_seed var/list/last_reagents +/obj/item/device/analyzer/plant_analyzer/Destroy() + . = ..() + QDEL_NULL(last_seed) + /obj/item/device/analyzer/plant_analyzer/attack_self(mob/user) tgui_interact(user) @@ -34,7 +38,7 @@ /obj/item/device/analyzer/plant_analyzer/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) var/list/data = ..() - var/datum/seed/grown_seed = locate(last_seed) + var/datum/seed/grown_seed = last_seed if(!istype(grown_seed)) return list("no_seed" = TRUE) @@ -95,7 +99,9 @@ to_chat(user, "[src] can tell you nothing about \the [target].") return - last_seed = REF(grown_seed) + last_seed = grown_seed.diverge() + if(!istype(last_seed)) + last_seed = grown_seed // TRAIT_IMMUTABLE makes diverge() return null user.visible_message("[user] runs the scanner over \the [target].") @@ -119,7 +125,7 @@ print_report(usr) /obj/item/device/analyzer/plant_analyzer/proc/print_report(var/mob/living/user) - var/datum/seed/grown_seed = locate(last_seed) + var/datum/seed/grown_seed = last_seed if(!istype(grown_seed)) to_chat(user, "There is no scan data to print.") return diff --git a/code/modules/integrated_electronics/core/assemblies/device.dm b/code/modules/integrated_electronics/core/assemblies/device.dm index 3170393fc3..8500f4dafc 100644 --- a/code/modules/integrated_electronics/core/assemblies/device.dm +++ b/code/modules/integrated_electronics/core/assemblies/device.dm @@ -78,7 +78,7 @@ output.assembly = src /obj/item/device/electronic_assembly/device/check_interactivity(mob/user) - if(!CanInteract(user, state = deep_inventory_state)) + if(!CanInteract(user, state = GLOB.tgui_deep_inventory_state)) return 0 return 1 diff --git a/code/modules/integrated_electronics/core/pins.dm b/code/modules/integrated_electronics/core/pins.dm index ddc0b06f8a..c194b4a8a2 100644 --- a/code/modules/integrated_electronics/core/pins.dm +++ b/code/modules/integrated_electronics/core/pins.dm @@ -40,8 +40,8 @@ D [1]/ || holder = null . = ..() -/datum/integrated_io/nano_host() - return holder.nano_host() +/datum/integrated_io/tgui_host() + return holder.tgui_host() /datum/integrated_io/proc/data_as_type(var/as_type) diff --git a/code/modules/integrated_electronics/core/special_pins/list_pin.dm b/code/modules/integrated_electronics/core/special_pins/list_pin.dm index 77d83f82b5..4eeb756cd0 100644 --- a/code/modules/integrated_electronics/core/special_pins/list_pin.dm +++ b/code/modules/integrated_electronics/core/special_pins/list_pin.dm @@ -117,7 +117,7 @@ /datum/integrated_io/list/display_pin_type() return IC_FORMAT_LIST -/datum/integrated_io/list/Topic(href, href_list, state = interactive_state) +/datum/integrated_io/list/Topic(href, href_list, state = GLOB.tgui_always_state) if(!holder.check_interactivity(usr)) return if(..()) diff --git a/code/modules/integrated_electronics/core/tools.dm b/code/modules/integrated_electronics/core/tools.dm index a8f714d44a..8823007967 100644 --- a/code/modules/integrated_electronics/core/tools.dm +++ b/code/modules/integrated_electronics/core/tools.dm @@ -115,7 +115,7 @@ /obj/item/device/integrated_electronics/debugger/attack_self(mob/user) var/type_to_use = input("Please choose a type to use.","[src] type setting") as null|anything in list("string","number","ref", "null") - if(!CanInteract(user, physical_state)) + if(!CanInteract(user, GLOB.tgui_physical_state)) return var/new_data = null @@ -124,13 +124,13 @@ accepting_refs = 0 new_data = input("Now type in a string.","[src] string writing") as null|text new_data = sanitizeSafe(new_data, MAX_MESSAGE_LEN, 0, 0) - if(istext(new_data) && CanInteract(user, physical_state)) + if(istext(new_data) && CanInteract(user, GLOB.tgui_physical_state)) data_to_write = new_data to_chat(user, "You set \the [src]'s memory to \"[new_data]\".") if("number") accepting_refs = 0 new_data = input("Now type in a number.","[src] number writing") as null|num - if(isnum(new_data) && CanInteract(user, physical_state)) + if(isnum(new_data) && CanInteract(user, GLOB.tgui_physical_state)) data_to_write = new_data to_chat(user, "You set \the [src]'s memory to [new_data].") if("ref") diff --git a/code/modules/integrated_electronics/subtypes/input.dm b/code/modules/integrated_electronics/subtypes/input.dm index a084633642..9c140cedae 100644 --- a/code/modules/integrated_electronics/subtypes/input.dm +++ b/code/modules/integrated_electronics/subtypes/input.dm @@ -54,7 +54,7 @@ /obj/item/integrated_circuit/input/numberpad/ask_for_input(mob/user) var/new_input = input(user, "Enter a number, please.","Number pad", get_pin_data(IC_OUTPUT, 1)) as null|num - if(isnum(new_input) && CanInteract(user, physical_state)) + if(isnum(new_input) && CanInteract(user, GLOB.tgui_physical_state)) set_pin_data(IC_OUTPUT, 1, new_input) push_data() activate_pin(1) @@ -73,7 +73,7 @@ /obj/item/integrated_circuit/input/textpad/ask_for_input(mob/user) var/new_input = input(user, "Enter some words, please.","Number pad", get_pin_data(IC_OUTPUT, 1)) as null|text - if(istext(new_input) && CanInteract(user, physical_state)) + if(istext(new_input) && CanInteract(user, GLOB.tgui_physical_state)) set_pin_data(IC_OUTPUT, 1, new_input) push_data() activate_pin(1) @@ -92,7 +92,7 @@ /obj/item/integrated_circuit/input/colorpad/ask_for_input(mob/user) var/new_color = input(user, "Enter a color, please.", "Color pad", get_pin_data(IC_OUTPUT, 1)) as color|null - if(new_color && CanInteract(user, physical_state)) + if(new_color && CanInteract(user, GLOB.tgui_physical_state)) set_pin_data(IC_OUTPUT, 1, new_color) push_data() activate_pin(1) diff --git a/code/modules/integrated_electronics/subtypes/memory.dm b/code/modules/integrated_electronics/subtypes/memory.dm index 630136e7d0..90cb23de35 100644 --- a/code/modules/integrated_electronics/subtypes/memory.dm +++ b/code/modules/integrated_electronics/subtypes/memory.dm @@ -89,7 +89,7 @@ /obj/item/integrated_circuit/memory/constant/attack_self(mob/user) var/datum/integrated_io/O = outputs[1] var/type_to_use = input("Please choose a type to use.","[src] type setting") as null|anything in list("string","number","ref", "null") - if(!CanInteract(user, physical_state)) + if(!CanInteract(user, GLOB.tgui_physical_state)) return var/new_data = null @@ -97,13 +97,13 @@ if("string") accepting_refs = 0 new_data = input("Now type in a string.","[src] string writing") as null|text - if(istext(new_data) && CanInteract(user, physical_state)) + if(istext(new_data) && CanInteract(user, GLOB.tgui_physical_state)) O.data = new_data to_chat(user, "You set \the [src]'s memory to [O.display_data(O.data)].") if("number") accepting_refs = 0 new_data = input("Now type in a number.","[src] number writing") as null|num - if(isnum(new_data) && CanInteract(user, physical_state)) + if(isnum(new_data) && CanInteract(user, GLOB.tgui_physical_state)) O.data = new_data to_chat(user, "You set \the [src]'s memory to [O.display_data(O.data)].") if("ref") diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm index 1caf83608b..9a226b836d 100644 --- a/code/modules/library/lib_machines.dm +++ b/code/modules/library/lib_machines.dm @@ -173,14 +173,14 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f var/dat = "Book Inventory Management\n" // switch(screenstate) if(0) - // Main Menu + // Main Menu //VOREStation Edit start dat += {"
1. View General Inventory
2. View Checked Out Inventory
3. Check out a Book
- 4. Connect to Internal Archive
//VOREStation Edit + 4. Connect to Internal Archive
5. Upload New Title to Archive
6. Print a Bible
- 8. Access External Archive
"} //VOREStation Edit + 8. Access External Archive
"} //VOREStation Edit end if(src.emagged) dat += "7. Access the Forbidden Lore Vault
" if(src.arcanecheckout) @@ -338,11 +338,11 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f if(!bibledelay) var/obj/item/weapon/storage/bible/B = new /obj/item/weapon/storage/bible(src.loc) - if(ticker && ( ticker.Bible_icon_state && ticker.Bible_item_state) ) - B.icon_state = ticker.Bible_icon_state - B.item_state = ticker.Bible_item_state - B.name = ticker.Bible_name - B.deity_name = ticker.Bible_deity_name + if(GLOB.religion) + B.icon_state = GLOB.bible_icon_state + B.item_state = GLOB.bible_item_state + B.name = GLOB.bible_name + B.deity_name = GLOB.deity bibledelay = 1 spawn(60) diff --git a/code/modules/looking_glass/lg_console.dm b/code/modules/looking_glass/lg_console.dm index 60b51a325a..b46ea9c5fb 100644 --- a/code/modules/looking_glass/lg_console.dm +++ b/code/modules/looking_glass/lg_console.dm @@ -50,27 +50,30 @@ return ..() /obj/machinery/computer/looking_glass/attack_ai(var/mob/user as mob) - return src.attack_hand(user) + return attack_hand(user) /obj/machinery/computer/looking_glass/attack_hand(var/mob/user as mob) if(..()) return - user.set_machine(src) - ui_interact(user) + tgui_interact(user) -/obj/machinery/computer/looking_glass/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) - - var/list/data = list() - var/program_list[0] +/obj/machinery/computer/looking_glass/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "LookingGlass", name) + ui.open() +/obj/machinery/computer/looking_glass/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + var/list/program_list = list() for(var/P in supported_programs) - program_list[++program_list.len] = P + program_list.Add(P) if(emagged) for(var/P in secret_programs) - program_list[++program_list.len] = P + program_list.Add(P) data["supportedPrograms"] = program_list data["currentProgram"] = current_program @@ -78,24 +81,18 @@ if(my_area?.has_gravity) data["gravity"] = 1 else - data["gravity"] = null + data["gravity"] = 0 - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "lookingglass.tmpl", src.name, 400, 550) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(20) + return data -/obj/machinery/computer/looking_glass/Topic(href, href_list) +/obj/machinery/computer/looking_glass/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return 1 - if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) - - if(href_list["program"]) + return TRUE + + switch(action) + if("program") if(ready) - var/prog = href_list["program"] + var/prog = params["program"] if(prog == "Off") current_program = "Off" unload_program() @@ -104,17 +101,18 @@ load_program(prog) else visible_message("ERROR. Recalibrating displays.") + return TRUE - else if(href_list["gravity"]) + if("gravity") toggle_gravity(my_area) + return TRUE - else if(href_list["immersion"]) + if("immersion") immersion = !immersion my_area.toggle_optional(immersion) + return TRUE - src.add_fingerprint(usr) - - SSnanoui.update_uis(src) + add_fingerprint(usr) /obj/machinery/computer/looking_glass/emag_act(var/remaining_charges, var/mob/user as mob) if (!emagged) diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm index b852e10383..ff567c55f4 100644 --- a/code/modules/materials/material_recipes.dm +++ b/code/modules/materials/material_recipes.dm @@ -1,9 +1,9 @@ -/material/proc/get_recipes() +/datum/material/proc/get_recipes() if(!recipes) generate_recipes() return recipes -/material/proc/generate_recipes() +/datum/material/proc/generate_recipes() recipes = list() // If is_brittle() returns true, these are only good for a single strike. @@ -29,7 +29,7 @@ recipes += new/datum/stack_recipe("[display_name] knife", /obj/item/weapon/material/knife/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) recipes += new/datum/stack_recipe("[display_name] blade", /obj/item/weapon/material/butterflyblade, 6, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) -/material/steel/generate_recipes() +/datum/material/steel/generate_recipes() ..() recipes += new/datum/stack_recipe_list("office chairs",list( \ new/datum/stack_recipe("dark office chair", /obj/structure/bed/chair/office/dark, 5, one_per_turf = 1, on_floor = 1), \ @@ -105,7 +105,7 @@ )) recipes += new/datum/stack_recipe("desk bell", /obj/item/weapon/deskbell, 1, on_floor = 1, supplied_material = "[name]") -/material/plasteel/generate_recipes() +/datum/material/plasteel/generate_recipes() ..() recipes += new/datum/stack_recipe("AI core", /obj/structure/AIcore, 4, time = 50, one_per_turf = 1) recipes += new/datum/stack_recipe("Metal crate", /obj/structure/closet/crate, 10, time = 50, one_per_turf = 1) @@ -114,16 +114,16 @@ recipes += new/datum/stack_recipe("roller bed", /obj/item/roller, 5, time = 30, on_floor = 1) recipes += new/datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 10) -/material/stone/generate_recipes() +/datum/material/stone/generate_recipes() ..() recipes += new/datum/stack_recipe("planting bed", /obj/machinery/portable_atmospherics/hydroponics/soil, 3, time = 10, one_per_turf = 1, on_floor = 1) -/material/stone/marble/generate_recipes() +/datum/material/stone/marble/generate_recipes() ..() recipes += new/datum/stack_recipe("light marble floor tile", /obj/item/stack/tile/wmarble, 1, 4, 20) recipes += new/datum/stack_recipe("dark marble floor tile", /obj/item/stack/tile/bmarble, 1, 4, 20) -/material/plastic/generate_recipes() +/datum/material/plastic/generate_recipes() ..() recipes += new/datum/stack_recipe("plastic crate", /obj/structure/closet/crate/plastic, 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE) recipes += new/datum/stack_recipe("plastic bag", /obj/item/weapon/storage/bag/plasticbag, 3, on_floor = 1, pass_stack_color = TRUE) @@ -141,7 +141,7 @@ recipes += new/datum/stack_recipe("plastic fishtank", /obj/item/glass_jar/fish/plastic, 2, time = 30 SECONDS) recipes += new/datum/stack_recipe("reagent tubing", /obj/item/stack/hose, 1, 4, 20, pass_stack_color = TRUE) -/material/wood/generate_recipes() +/datum/material/wood/generate_recipes() ..() recipes += new/datum/stack_recipe("oar", /obj/item/weapon/oar, 2, time = 30, supplied_material = "[name]", pass_stack_color = TRUE) recipes += new/datum/stack_recipe("boat", /obj/vehicle/boat, 20, time = 10 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE) @@ -163,11 +163,11 @@ recipes += new/datum/stack_recipe("wooden standup figure", /obj/structure/barricade/cutout, 5, time = 10 SECONDS, pass_stack_color = TRUE) //VOREStation Add recipes += new/datum/stack_recipe("noticeboard", /obj/structure/noticeboard, 1) -/material/wood/log/generate_recipes() +/datum/material/wood/log/generate_recipes() recipes = list() recipes += new/datum/stack_recipe("bonfire", /obj/structure/bonfire, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE) -/material/cardboard/generate_recipes() +/datum/material/cardboard/generate_recipes() ..() recipes += new/datum/stack_recipe("box", /obj/item/weapon/storage/box, pass_stack_color = TRUE) recipes += new/datum/stack_recipe("donut box", /obj/item/weapon/storage/box/donut/empty, pass_stack_color = TRUE) @@ -186,7 +186,7 @@ new/datum/stack_recipe("yellow folder", /obj/item/weapon/folder/yellow), \ )) -/material/snow/generate_recipes() +/datum/material/snow/generate_recipes() recipes = list() recipes += new/datum/stack_recipe("snowball", /obj/item/weapon/material/snow/snowball, 1, time = 10) recipes += new/datum/stack_recipe("snow brick", /obj/item/stack/material/snowbrick, 2, time = 10) @@ -194,7 +194,7 @@ recipes += new/datum/stack_recipe("snow robot", /obj/structure/snowman/borg, 2, time = 10) recipes += new/datum/stack_recipe("snow spider", /obj/structure/snowman/spider, 3, time = 20) -/material/snowbrick/generate_recipes() +/datum/material/snowbrick/generate_recipes() recipes = list() recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") recipes += new/datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") @@ -205,7 +205,7 @@ recipes += new/datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") recipes += new/datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") -/material/wood/sif/generate_recipes() +/datum/material/wood/sif/generate_recipes() ..() recipes += new/datum/stack_recipe("alien wood floor tile", /obj/item/stack/tile/wood/sif, 1, 4, 20, pass_stack_color = TRUE) for(var/datum/stack_recipe/r_recipe in recipes) @@ -216,11 +216,11 @@ recipes -= r_recipe continue -/material/supermatter/generate_recipes() +/datum/material/supermatter/generate_recipes() recipes = list() recipes += new/datum/stack_recipe("supermatter shard", /obj/machinery/power/supermatter/shard, 30 , one_per_turf = 1, time = 600, on_floor = 1) -/material/cloth/generate_recipes() +/datum/material/cloth/generate_recipes() recipes = list() recipes += new/datum/stack_recipe("woven net", /obj/item/weapon/material/fishing_net, 10, time = 30 SECONDS, pass_stack_color = TRUE) recipes += new/datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE) @@ -238,7 +238,7 @@ recipes += new/datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE) recipes += new/datum/stack_recipe("crude bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE) -/material/resin/generate_recipes() +/datum/material/resin/generate_recipes() recipes = list() recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door/resin, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) recipes += new/datum/stack_recipe("[display_name] barricade", /obj/effect/alien/resin/wall, 5, time = 5 SECONDS, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE) diff --git a/code/modules/materials/material_recipes_ch.dm b/code/modules/materials/material_recipes_ch.dm index e4a0016c05..009ac2b9fb 100644 --- a/code/modules/materials/material_recipes_ch.dm +++ b/code/modules/materials/material_recipes_ch.dm @@ -1,6 +1,6 @@ //In future consider cleaning up often used recipes by adding them to the general recipe list with material criteria -/material/plasteel/generate_recipes() +/datum/material/plasteel/generate_recipes() . = ..() // recipes += new/datum/stack_recipe("Hammer Head", /obj/item/weapon/hammer_head, 2) //CHOMPEdit - Disabled because I had to disable code/game/objects/items/weapons/material/sledgehammer_construction_ch.dm due to lots of errors recipes += new/datum/stack_recipe_list("sofas", list( \ @@ -10,7 +10,7 @@ new/datum/stack_recipe("sofa corner", /obj/structure/bed/chair/sofa/corner, 1, one_per_turf = 1, on_floor = 1), \ )) -/material/plastic/generate_recipes() +/datum/material/plastic/generate_recipes() . = ..() recipes += new/datum/stack_recipe_list("sofas", list( \ new/datum/stack_recipe("sofa middle", /obj/structure/bed/chair/sofa, 1, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"), \ @@ -19,7 +19,7 @@ new/datum/stack_recipe("sofa corner", /obj/structure/bed/chair/sofa/corner, 1, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"), \ )) -/material/wood/generate_recipes() //Is a little sad we cant have lovely wooden sofa +/datum/material/wood/generate_recipes() //Is a little sad we cant have lovely wooden sofa . = ..() recipes += new/datum/stack_recipe_list("sofas", list( \ new/datum/stack_recipe("sofa middle", /obj/structure/bed/chair/sofa, 1, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"), \ diff --git a/code/modules/materials/material_recipes_vr.dm b/code/modules/materials/material_recipes_vr.dm index ba2a95250a..3dc6975a04 100644 --- a/code/modules/materials/material_recipes_vr.dm +++ b/code/modules/materials/material_recipes_vr.dm @@ -1,5 +1,5 @@ -/material/steel/generate_recipes() +/datum/material/steel/generate_recipes() . = ..() recipes += new/datum/stack_recipe_list("mounted chairs", list( new/datum/stack_recipe("mounted chair", /obj/structure/bed/chair/bay/chair, 2, one_per_turf = 1, on_floor = 1, time = 10), @@ -80,11 +80,11 @@ new/datum/stack_recipe("orange sofa corner", /obj/structure/bed/chair/sofa/orange/corner, 1, one_per_turf = 1, on_floor = 1), \ )) -/material/durasteel/generate_recipes() +/datum/material/durasteel/generate_recipes() . = ..() recipes += new/datum/stack_recipe("durasteel fishing rod", /obj/item/weapon/material/fishing_rod/modern/strong, 2) recipes += new/datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 30) -/material/plastitanium/generate_recipes() +/datum/material/plastitanium/generate_recipes() . = ..() recipes += new/datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 20) diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm index 153e023ad0..6eb7b990e8 100644 --- a/code/modules/materials/material_sheets.dm +++ b/code/modules/materials/material_sheets.dm @@ -14,7 +14,7 @@ ) var/default_type = DEFAULT_WALL_MATERIAL - var/material/material + var/datum/material/material var/perunit = SHEET_MATERIAL_AMOUNT var/apply_colour //temp pending icon rewrite drop_sound = 'sound/items/drop/axe.ogg' @@ -403,8 +403,8 @@ no_variants = FALSE pass_color = TRUE strict_color_stacking = TRUE - drop_sound = 'sound/items/drop/cloth.ogg' - pickup_sound = 'sound/items/pickup/cloth.ogg' + drop_sound = 'sound/items/drop/clothing.ogg' + pickup_sound = 'sound/items/pickup/clothing.ogg' /obj/item/stack/material/cloth/diyaab color = "#c6ccf0" diff --git a/code/modules/materials/material_sheets_vr.dm b/code/modules/materials/material_sheets_vr.dm index fa8676d92d..e198d6d3c0 100644 --- a/code/modules/materials/material_sheets_vr.dm +++ b/code/modules/materials/material_sheets_vr.dm @@ -21,7 +21,7 @@ type_to_spawn = /obj/item/stack/material/glass/titanium /obj/item/stack/material/plastitanium - name = "plas-tanium sheets" + name = "plastitanium sheets" icon = 'icons/obj/stacks_vr.dmi' icon_state = "sheet-plastitanium" item_state = "sheet-silver" @@ -32,8 +32,20 @@ name = "stack of plastitanium" type_to_spawn = /obj/item/stack/material/plastitanium +/obj/item/stack/material/plastitanium/hull + name = "plastitanium hull sheets" + icon = 'icons/obj/stacks_vr.dmi' + icon_state = "sheet-plastitanium" + item_state = "sheet-silver" + no_variants = FALSE + default_type = MAT_PLASTITANIUMHULL + +/obj/fiftyspawner/plastitanium_hull + name = "stack of plastitanium" + type_to_spawn = /obj/item/stack/material/plastitanium/hull + /obj/item/stack/material/glass/plastitanium - name = "plas-tanium glass sheets" + name = "plastitanium glass sheets" icon = 'icons/obj/stacks_vr.dmi' icon_state = "sheet-plastitaniumglass" item_state = "sheet-silver" diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm index af39896432..211ebcfe80 100644 --- a/code/modules/materials/materials.dm +++ b/code/modules/materials/materials.dm @@ -45,7 +45,7 @@ var/list/name_to_material //mostly for convenience /obj/proc/get_material_name() - var/material/material = get_material() + var/datum/material/material = get_material() if(material) return material.name @@ -53,8 +53,8 @@ var/list/name_to_material /proc/populate_material_list(force_remake=0) if(name_to_material && !force_remake) return // Already set up! name_to_material = list() - for(var/type in typesof(/material) - /material) - var/material/new_mineral = new type + for(var/type in typesof(/datum/material) - /datum/material) + var/datum/material/new_mineral = new type if(!new_mineral.name) continue name_to_material[lowertext(new_mineral.name)] = new_mineral @@ -67,13 +67,13 @@ var/list/name_to_material return name_to_material[name] /proc/material_display_name(name) - var/material/material = get_material_by_name(name) + var/datum/material/material = get_material_by_name(name) if(material) return material.display_name return null // Material definition and procs follow. -/material +/datum/material var/name // Unique name for use in indexing the list. var/display_name // Prettier name for display. var/use_name @@ -137,7 +137,7 @@ var/list/name_to_material var/rotting_touch_message = "crumbles under your touch" // Placeholders for light tiles and rglass. -/material/proc/build_rod_product(var/mob/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack) +/datum/material/proc/build_rod_product(var/mob/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack) if(!rod_product) to_chat(user, "You cannot make anything out of \the [target_stack]") return @@ -150,7 +150,7 @@ var/list/name_to_material S.add_fingerprint(user) S.add_to_stacks(user) -/material/proc/build_wired_product(var/mob/living/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack) +/datum/material/proc/build_wired_product(var/mob/living/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack) if(!wire_product) to_chat(user, "You cannot make anything out of \the [target_stack]") return @@ -165,7 +165,7 @@ var/list/name_to_material user.put_in_hands(product) // Make sure we have a display name and shard icon even if they aren't explicitly set. -/material/New() +/datum/material/New() ..() if(!display_name) display_name = name @@ -175,15 +175,15 @@ var/list/name_to_material shard_icon = shard_type // This is a placeholder for proper integration of windows/windoors into the system. -/material/proc/build_windows(var/mob/living/user, var/obj/item/stack/used_stack) +/datum/material/proc/build_windows(var/mob/living/user, var/obj/item/stack/used_stack) return 0 // Weapons handle applying a divisor for this value locally. -/material/proc/get_blunt_damage() +/datum/material/proc/get_blunt_damage() return weight //todo // Return the matter comprising this material. -/material/proc/get_matter() +/datum/material/proc/get_matter() var/list/temp_matter = list() if(islist(composite_material)) for(var/material_string in composite_material) @@ -193,61 +193,61 @@ var/list/name_to_material return temp_matter // As above. -/material/proc/get_edge_damage() +/datum/material/proc/get_edge_damage() return hardness //todo // Snowflakey, only checked for alien doors at the moment. -/material/proc/can_open_material_door(var/mob/living/user) +/datum/material/proc/can_open_material_door(var/mob/living/user) return 1 // Currently used for weapons and objects made of uranium to irradiate things. -/material/proc/products_need_process() +/datum/material/proc/products_need_process() return (radioactivity>0) //todo // Used by walls when qdel()ing to avoid neighbor merging. -/material/placeholder +/datum/material/placeholder name = "placeholder" // Places a girder object when a wall is dismantled, also applies reinforced material. -/material/proc/place_dismantled_girder(var/turf/target, var/material/reinf_material, var/material/girder_material) +/datum/material/proc/place_dismantled_girder(var/turf/target, var/datum/material/reinf_material, var/datum/material/girder_material) var/obj/structure/girder/G = new(target) if(reinf_material) G.reinf_material = reinf_material G.reinforce_girder() if(girder_material) - if(istype(girder_material, /material)) + if(istype(girder_material, /datum/material)) girder_material = girder_material.name G.set_material(girder_material) // General wall debris product placement. // Not particularly necessary aside from snowflakey cult girders. -/material/proc/place_dismantled_product(var/turf/target) +/datum/material/proc/place_dismantled_product(var/turf/target) place_sheet(target) // Debris product. Used ALL THE TIME. -/material/proc/place_sheet(var/turf/target) +/datum/material/proc/place_sheet(var/turf/target) if(stack_type) return new stack_type(target) // As above. -/material/proc/place_shard(var/turf/target) +/datum/material/proc/place_shard(var/turf/target) if(shard_type) return new /obj/item/weapon/material/shard(target, src.name) // Used by walls and weapons to determine if they break or not. -/material/proc/is_brittle() +/datum/material/proc/is_brittle() return !!(flags & MATERIAL_BRITTLE) -/material/proc/combustion_effect(var/turf/T, var/temperature) +/datum/material/proc/combustion_effect(var/turf/T, var/temperature) return // Used by walls to do on-touch things, after checking for crumbling and open-ability. -/material/proc/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L) +/datum/material/proc/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L) return // Datum definitions follow. -/material/uranium +/datum/material/uranium name = "uranium" stack_type = /obj/item/stack/material/uranium radioactivity = 12 @@ -259,7 +259,7 @@ var/list/name_to_material door_icon_base = "stone" supply_conversion_value = 2 -/material/diamond +/datum/material/diamond name = "diamond" stack_type = /obj/item/stack/material/diamond flags = MATERIAL_UNMELTABLE @@ -275,7 +275,7 @@ var/list/name_to_material stack_origin_tech = list(TECH_MATERIAL = 6) supply_conversion_value = 8 -/material/gold +/datum/material/gold name = "gold" stack_type = /obj/item/stack/material/gold icon_colour = "#EDD12F" @@ -287,11 +287,11 @@ var/list/name_to_material sheet_plural_name = "ingots" supply_conversion_value = 2 -/material/gold/bronze //placeholder for ashtrays +/datum/material/gold/bronze //placeholder for ashtrays name = "bronze" icon_colour = "#EDD12F" -/material/silver +/datum/material/silver name = "silver" stack_type = /obj/item/stack/material/silver icon_colour = "#D1E6E3" @@ -304,7 +304,7 @@ var/list/name_to_material supply_conversion_value = 2 //R-UST port -/material/supermatter +/datum/material/supermatter name = "supermatter" icon_colour = "#FFFF00" stack_type = /obj/item/stack/material/supermatter @@ -322,7 +322,7 @@ var/list/name_to_material is_fusion_fuel = 1 stack_origin_tech = list(TECH_MATERIAL = 8, TECH_PHORON = 5, TECH_BLUESPACE = 4) -/material/phoron +/datum/material/phoron name = "phoron" stack_type = /obj/item/stack/material/phoron ignition_point = PHORON_MINIMUM_BURN_TEMPERATURE @@ -338,7 +338,7 @@ var/list/name_to_material /* // Commenting this out while fires are so spectacularly lethal, as I can't seem to get this balanced appropriately. -/material/phoron/combustion_effect(var/turf/T, var/temperature, var/effect_multiplier) +/datum/material/phoron/combustion_effect(var/turf/T, var/temperature, var/effect_multiplier) if(isnull(ignition_point)) return 0 if(temperature < ignition_point) @@ -353,7 +353,7 @@ var/list/name_to_material return round(totalPhoron/100) */ -/material/stone +/datum/material/stone name = "sandstone" stack_type = /obj/item/stack/material/sandstone icon_base = "stone" @@ -369,7 +369,7 @@ var/list/name_to_material sheet_singular_name = "brick" sheet_plural_name = "bricks" -/material/stone/marble +/datum/material/stone/marble name = "marble" icon_colour = "#AAAAAA" weight = 26 @@ -378,7 +378,7 @@ var/list/name_to_material stack_type = /obj/item/stack/material/marble supply_conversion_value = 2 -/material/steel +/datum/material/steel name = DEFAULT_WALL_MATERIAL stack_type = /obj/item/stack/material/steel integrity = 150 @@ -388,7 +388,7 @@ var/list/name_to_material icon_reinf = "reinf_over" icon_colour = "#666666" -/material/steel/hull +/datum/material/steel/hull name = MAT_STEELHULL stack_type = /obj/item/stack/material/steel/hull integrity = 250 @@ -397,10 +397,10 @@ var/list/name_to_material icon_reinf = "reinf_mesh" icon_colour = "#666677" -/material/steel/hull/place_sheet(var/turf/target) //Deconstructed into normal steel sheets. +/datum/material/steel/hull/place_sheet(var/turf/target) //Deconstructed into normal steel sheets. new /obj/item/stack/material/steel(target) -/material/diona +/datum/material/diona name = "biomass" icon_colour = null stack_type = null @@ -408,19 +408,19 @@ var/list/name_to_material icon_base = "diona" icon_reinf = "noreinf" -/material/diona/place_dismantled_product() +/datum/material/diona/place_dismantled_product() return -/material/diona/place_dismantled_girder(var/turf/target) +/datum/material/diona/place_dismantled_girder(var/turf/target) spawn_diona_nymph(target) -/material/steel/holographic +/datum/material/steel/holographic name = "holo" + DEFAULT_WALL_MATERIAL display_name = DEFAULT_WALL_MATERIAL stack_type = null shard_type = SHARD_NONE -/material/plasteel +/datum/material/plasteel name = "plasteel" stack_type = /obj/item/stack/material/plasteel integrity = 400 @@ -437,7 +437,7 @@ var/list/name_to_material composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT, "platinum" = SHEET_MATERIAL_AMOUNT) //todo supply_conversion_value = 6 -/material/plasteel/hull +/datum/material/plasteel/hull name = MAT_PLASTEELHULL stack_type = /obj/item/stack/material/plasteel/hull integrity = 600 @@ -446,11 +446,11 @@ var/list/name_to_material icon_colour = "#777788" explosion_resistance = 40 -/material/plasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets. +/datum/material/plasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets. new /obj/item/stack/material/plasteel(target) // Very rare alloy that is reflective, should be used sparingly. -/material/durasteel +/datum/material/durasteel name = "durasteel" stack_type = /obj/item/stack/material/durasteel/hull integrity = 600 @@ -467,7 +467,7 @@ var/list/name_to_material composite_material = list("plasteel" = SHEET_MATERIAL_AMOUNT, "diamond" = SHEET_MATERIAL_AMOUNT) //shrug supply_conversion_value = 9 -/material/durasteel/hull //The 'Hardball' of starship hulls. +/datum/material/durasteel/hull //The 'Hardball' of starship hulls. name = MAT_DURASTEELHULL icon_base = "hull" icon_reinf = "reinf_mesh" @@ -475,10 +475,10 @@ var/list/name_to_material explosion_resistance = 90 reflectivity = 0.9 -/material/durasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal durasteel sheets. +/datum/material/durasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal durasteel sheets. new /obj/item/stack/material/durasteel(target) -/material/plasteel/titanium +/datum/material/plasteel/titanium name = MAT_TITANIUM stack_type = /obj/item/stack/material/titanium conductivity = 2.38 @@ -487,16 +487,16 @@ var/list/name_to_material icon_colour = "#D1E6E3" icon_reinf = "reinf_metal" -/material/plasteel/titanium/hull +/datum/material/plasteel/titanium/hull name = MAT_TITANIUMHULL stack_type = /obj/item/stack/material/titanium/hull icon_base = "hull" icon_reinf = "reinf_mesh" -/material/plasteel/titanium/hull/place_sheet(var/turf/target) //Deconstructed into normal titanium sheets. +/datum/material/plasteel/titanium/hull/place_sheet(var/turf/target) //Deconstructed into normal titanium sheets. new /obj/item/stack/material/titanium(target) -/material/glass +/datum/material/glass name = "glass" stack_type = /obj/item/stack/material/glass flags = MATERIAL_BRITTLE @@ -517,7 +517,7 @@ var/list/name_to_material created_fulltile_window = /obj/structure/window/basic/full rod_product = /obj/item/stack/material/glass/reinforced -/material/glass/build_windows(var/mob/living/user, var/obj/item/stack/used_stack) +/datum/material/glass/build_windows(var/mob/living/user, var/obj/item/stack/used_stack) if(!user || !used_stack || !created_window || !created_fulltile_window || !window_options.len) return 0 @@ -588,10 +588,10 @@ var/list/name_to_material new build_path(T, build_dir, 1) return 1 -/material/glass/proc/is_reinforced() +/datum/material/glass/proc/is_reinforced() return (hardness > 35) //todo -/material/glass/reinforced +/datum/material/glass/reinforced name = "rglass" display_name = "reinforced glass" stack_type = /obj/item/stack/material/glass/reinforced @@ -611,7 +611,7 @@ var/list/name_to_material wire_product = null rod_product = null -/material/glass/phoron +/datum/material/glass/phoron name = "borosilicate glass" display_name = "borosilicate glass" stack_type = /obj/item/stack/material/glass/phoronglass @@ -625,7 +625,7 @@ var/list/name_to_material wire_product = null rod_product = /obj/item/stack/material/glass/phoronrglass -/material/glass/phoron/reinforced +/datum/material/glass/phoron/reinforced name = "reinforced borosilicate glass" display_name = "reinforced borosilicate glass" stack_type = /obj/item/stack/material/glass/phoronrglass @@ -640,7 +640,7 @@ var/list/name_to_material composite_material = list() //todo rod_product = null -/material/plastic +/datum/material/plastic name = "plastic" stack_type = /obj/item/stack/material/plastic flags = MATERIAL_BRITTLE @@ -655,13 +655,13 @@ var/list/name_to_material melting_point = T0C+371 //assuming heat resistant plastic stack_origin_tech = list(TECH_MATERIAL = 3) -/material/plastic/holographic +/datum/material/plastic/holographic name = "holoplastic" display_name = "plastic" stack_type = null shard_type = SHARD_NONE -/material/graphite +/datum/material/graphite name = MAT_GRAPHITE stack_type = /obj/item/stack/material/graphite flags = MATERIAL_BRITTLE @@ -677,7 +677,7 @@ var/list/name_to_material radiation_resistance = 15 stack_origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 2) -/material/osmium +/datum/material/osmium name = "osmium" stack_type = /obj/item/stack/material/osmium icon_colour = "#9999FF" @@ -687,7 +687,7 @@ var/list/name_to_material conductivity = 100 supply_conversion_value = 6 -/material/tritium +/datum/material/tritium name = "tritium" stack_type = /obj/item/stack/material/tritium icon_colour = "#777777" @@ -697,7 +697,7 @@ var/list/name_to_material is_fusion_fuel = 1 conductive = 0 -/material/deuterium +/datum/material/deuterium name = "deuterium" stack_type = /obj/item/stack/material/deuterium icon_colour = "#999999" @@ -707,7 +707,7 @@ var/list/name_to_material is_fusion_fuel = 1 conductive = 0 -/material/mhydrogen +/datum/material/mhydrogen name = "mhydrogen" stack_type = /obj/item/stack/material/mhydrogen icon_colour = "#E6C5DE" @@ -716,7 +716,7 @@ var/list/name_to_material is_fusion_fuel = 1 supply_conversion_value = 6 -/material/platinum +/datum/material/platinum name = "platinum" stack_type = /obj/item/stack/material/platinum icon_colour = "#9999FF" @@ -727,7 +727,7 @@ var/list/name_to_material sheet_plural_name = "ingots" supply_conversion_value = 5 -/material/iron +/datum/material/iron name = "iron" stack_type = /obj/item/stack/material/iron icon_colour = "#5C5454" @@ -736,7 +736,7 @@ var/list/name_to_material sheet_singular_name = "ingot" sheet_plural_name = "ingots" -/material/lead +/datum/material/lead name = MAT_LEAD stack_type = /obj/item/stack/material/lead icon_colour = "#273956" @@ -749,7 +749,7 @@ var/list/name_to_material // Particle Smasher and other exotic materials. -/material/verdantium +/datum/material/verdantium name = MAT_VERDANTIUM stack_type = /obj/item/stack/material/verdantium icon_base = "metal" @@ -770,7 +770,7 @@ var/list/name_to_material sheet_plural_name = "sheets" supply_conversion_value = 8 -/material/morphium +/datum/material/morphium name = MAT_MORPHIUM stack_type = /obj/item/stack/material/morphium icon_base = "metal" @@ -791,13 +791,13 @@ var/list/name_to_material stack_origin_tech = list(TECH_MATERIAL = 8, TECH_ILLEGAL = 1, TECH_PHORON = 4, TECH_BLUESPACE = 4, TECH_ARCANE = 1) supply_conversion_value = 13 -/material/morphium/hull +/datum/material/morphium/hull name = MAT_MORPHIUMHULL stack_type = /obj/item/stack/material/morphium/hull icon_base = "hull" icon_reinf = "reinf_mesh" -/material/valhollide +/datum/material/valhollide name = MAT_VALHOLLIDE stack_type = /obj/item/stack/material/valhollide icon_base = "stone" @@ -820,7 +820,7 @@ var/list/name_to_material // Adminspawn only, do not let anyone get this. -/material/alienalloy +/datum/material/alienalloy name = "alienalloy" display_name = "durable alloy" stack_type = null @@ -834,31 +834,31 @@ var/list/name_to_material protectiveness = 80 // 80% // Likewise. -/material/alienalloy/elevatorium +/datum/material/alienalloy/elevatorium name = "elevatorium" display_name = "elevator panelling" icon_colour = "#666666" // Ditto. -/material/alienalloy/dungeonium +/datum/material/alienalloy/dungeonium name = "dungeonium" display_name = "ultra-durable" icon_base = "dungeon" icon_colour = "#FFFFFF" -/material/alienalloy/bedrock +/datum/material/alienalloy/bedrock name = "bedrock" display_name = "impassable rock" icon_base = "rock" icon_colour = "#FFFFFF" -/material/alienalloy/alium +/datum/material/alienalloy/alium name = "alium" display_name = "alien" icon_base = "alien" icon_colour = "#FFFFFF" -/material/resin +/datum/material/resin name = "resin" icon_colour = "#35343a" icon_base = "resin" @@ -874,13 +874,13 @@ var/list/name_to_material stack_origin_tech = list(TECH_MATERIAL = 8, TECH_PHORON = 4, TECH_BLUESPACE = 4, TECH_BIO = 7) stack_type = /obj/item/stack/material/resin -/material/resin/can_open_material_door(var/mob/living/user) +/datum/material/resin/can_open_material_door(var/mob/living/user) var/mob/living/carbon/M = user if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs) return 1 return 0 -/material/resin/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L) +/datum/material/resin/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L) var/mob/living/carbon/M = L if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs) to_chat(M, "\The [W] shudders under your touch, starting to become porous.") @@ -892,7 +892,7 @@ var/list/name_to_material return 1 return 0 -/material/wood +/datum/material/wood name = MAT_WOOD stack_type = /obj/item/stack/material/wood icon_colour = "#9c5930" @@ -915,7 +915,7 @@ var/list/name_to_material sheet_singular_name = "plank" sheet_plural_name = "planks" -/material/wood/log +/datum/material/wood/log name = MAT_LOG icon_base = "log" stack_type = /obj/item/stack/material/log @@ -924,25 +924,25 @@ var/list/name_to_material pass_stack_colors = TRUE supply_conversion_value = 3 //YW Adds: logs worth points -/material/wood/log/sif +/datum/material/wood/log/sif name = MAT_SIFLOG icon_colour = "#0099cc" // Cyan-ish stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) stack_type = /obj/item/stack/material/log/sif -/material/wood/holographic +/datum/material/wood/holographic name = "holowood" display_name = "wood" stack_type = null shard_type = SHARD_NONE -/material/wood/sif +/datum/material/wood/sif name = MAT_SIFWOOD stack_type = /obj/item/stack/material/wood/sif icon_colour = "#0099cc" // Cyan-ish stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) // Alien wood would presumably be more interesting to the analyzer. -/material/cardboard +/datum/material/cardboard name = "cardboard" stack_type = /obj/item/stack/material/cardboard flags = MATERIAL_BRITTLE @@ -962,7 +962,7 @@ var/list/name_to_material radiation_resistance = 1 pass_stack_colors = TRUE -/material/snow +/datum/material/snow name = MAT_SNOW stack_type = /obj/item/stack/material/snow flags = MATERIAL_BRITTLE @@ -980,7 +980,7 @@ var/list/name_to_material sheet_plural_name = "pile" //Just a bigger pile radiation_resistance = 1 -/material/snowbrick //only slightly stronger than snow, used to make igloos mostly +/datum/material/snowbrick //only slightly stronger than snow, used to make igloos mostly name = "packed snow" flags = MATERIAL_BRITTLE stack_type = /obj/item/stack/material/snowbrick @@ -998,7 +998,7 @@ var/list/name_to_material sheet_plural_name = "bricks" radiation_resistance = 1 -/material/cloth //todo +/datum/material/cloth //todo name = "cloth" stack_origin_tech = list(TECH_MATERIAL = 2) door_icon_base = "wood" @@ -1009,7 +1009,7 @@ var/list/name_to_material conductive = 0 pass_stack_colors = TRUE -/material/cult +/datum/material/cult name = "cult" display_name = "disturbing stone" icon_base = "cult" @@ -1020,21 +1020,21 @@ var/list/name_to_material sheet_plural_name = "bricks" conductive = 0 -/material/cult/place_dismantled_girder(var/turf/target) +/datum/material/cult/place_dismantled_girder(var/turf/target) new /obj/structure/girder/cult(target, "cult") -/material/cult/place_dismantled_product(var/turf/target) +/datum/material/cult/place_dismantled_product(var/turf/target) new /obj/effect/decal/cleanable/blood(target) -/material/cult/reinf +/datum/material/cult/reinf name = "cult2" display_name = "human remains" -/material/cult/reinf/place_dismantled_product(var/turf/target) +/datum/material/cult/reinf/place_dismantled_product(var/turf/target) new /obj/effect/decal/remains/human(target) //TODO PLACEHOLDERS: -/material/leather +/datum/material/leather name = "leather" icon_colour = "#5C4831" stack_origin_tech = list(TECH_MATERIAL = 2) @@ -1061,7 +1061,7 @@ var/list/name_to_material */ //CHOMPstation Removal End -/material/cotton +/datum/material/cotton name = "cotton" display_name ="cotton" icon_colour = "#FFFFFF" @@ -1072,7 +1072,7 @@ var/list/name_to_material conductive = 0 // This all needs to be OOP'd and use inheritence if its ever used in the future. -/material/cloth_teal +/datum/material/cloth_teal name = "teal" display_name ="teal" use_name = "teal cloth" @@ -1083,7 +1083,7 @@ var/list/name_to_material protectiveness = 1 // 4% conductive = 0 -/material/cloth_black +/datum/material/cloth_black name = "black" display_name = "black" use_name = "black cloth" @@ -1094,7 +1094,7 @@ var/list/name_to_material protectiveness = 1 // 4% conductive = 0 -/material/cloth_green +/datum/material/cloth_green name = "green" display_name = "green" use_name = "green cloth" @@ -1105,7 +1105,7 @@ var/list/name_to_material protectiveness = 1 // 4% conductive = 0 -/material/cloth_puple +/datum/material/cloth_puple name = "purple" display_name = "purple" use_name = "purple cloth" @@ -1116,7 +1116,7 @@ var/list/name_to_material protectiveness = 1 // 4% conductive = 0 -/material/cloth_blue +/datum/material/cloth_blue name = "blue" display_name = "blue" use_name = "blue cloth" @@ -1127,7 +1127,7 @@ var/list/name_to_material protectiveness = 1 // 4% conductive = 0 -/material/cloth_beige +/datum/material/cloth_beige name = "beige" display_name = "beige" use_name = "beige cloth" @@ -1138,7 +1138,7 @@ var/list/name_to_material protectiveness = 1 // 4% conductive = 0 -/material/cloth_lime +/datum/material/cloth_lime name = "lime" display_name = "lime" use_name = "lime cloth" @@ -1149,7 +1149,7 @@ var/list/name_to_material protectiveness = 1 // 4% conductive = 0 -/material/cloth_yellow +/datum/material/cloth_yellow name = "yellow" display_name = "yellow" use_name = "yellow cloth" @@ -1160,7 +1160,7 @@ var/list/name_to_material protectiveness = 1 // 4% conductive = 0 -/material/cloth_orange +/datum/material/cloth_orange name = "orange" display_name = "orange" use_name = "orange cloth" @@ -1171,7 +1171,7 @@ var/list/name_to_material protectiveness = 1 // 4% conductive = 0 -/material/toy_foam +/datum/material/toy_foam name = "foam" display_name = "foam" use_name = "foam" diff --git a/code/modules/materials/materials_ch.dm b/code/modules/materials/materials_ch.dm index 94a1516f38..efad561c7a 100644 --- a/code/modules/materials/materials_ch.dm +++ b/code/modules/materials/materials_ch.dm @@ -1,6 +1,6 @@ //CARPET materials -/material/carpet +/datum/material/carpet name = MAT_CARPET display_name = "comfy" use_name = "upholstery" @@ -14,42 +14,42 @@ protectiveness = 1 // 4% conductive = 0 -/material/carpet/teal +/datum/material/carpet/teal name = MAT_CARPET_TEAL icon_colour = "#007575" stack_type = /obj/item/stack/tile/carpet/teal -/material/carpet/bcarpet +/datum/material/carpet/bcarpet name = MAT_CARPET_BLACK icon_colour = "#1B171E" stack_type = /obj/item/stack/tile/carpet/bcarpet -/material/carpet/blucarpet +/datum/material/carpet/blucarpet name = MAT_CARPET_BLUE icon_colour = "#122CDF" stack_type = /obj/item/stack/tile/carpet/blucarpet -/material/carpet/turcarpet +/datum/material/carpet/turcarpet name = MAT_CARPET_TURQUOISE icon_colour = "#41A997" stack_type = /obj/item/stack/tile/carpet/turcarpet -/material/carpet/sblucarpet +/datum/material/carpet/sblucarpet name = MAT_CARPET_SILVERBLUE icon_colour = "#547EC6" stack_type = /obj/item/stack/tile/carpet/sblucarpet -/material/carpet/gaycarpet +/datum/material/carpet/gaycarpet name = MAT_CARPET_PINK icon_colour = "#E12C87" stack_type = /obj/item/stack/tile/carpet/gaycarpet -/material/carpet/purcarpet +/datum/material/carpet/purcarpet name = MAT_CARPET_PURPLE icon_colour = "#B500A6" stack_type = /obj/item/stack/tile/carpet/purcarpet -/material/carpet/oracarpet +/datum/material/carpet/oracarpet name = MAT_CARPET_ORANGE icon_colour = "#D1D000" stack_type = /obj/item/stack/tile/carpet/oracarpet \ No newline at end of file diff --git a/code/modules/materials/materials_vr.dm b/code/modules/materials/materials_vr.dm index c341a15496..460869d32f 100644 --- a/code/modules/materials/materials_vr.dm +++ b/code/modules/materials/materials_vr.dm @@ -1,4 +1,4 @@ -/material/flesh +/datum/material/flesh name = "flesh" display_name = "chunk of flesh" icon_colour = "#dd90aa" @@ -10,7 +10,7 @@ hardness = 500 weight = 500 -/material/fluff //This is to allow for 2 handed weapons that don't want to have a prefix. +/datum/material/fluff //This is to allow for 2 handed weapons that don't want to have a prefix. name = " " display_name = "" icon_colour = "#000000" @@ -19,19 +19,19 @@ hardness = 60 weight = 20 //Strong as iron. -/material/darkglass +/datum/material/darkglass name = "darkglass" display_name = "darkglass" icon_base = "darkglass" icon_colour = "#FFFFFF" -/material/fancyblack +/datum/material/fancyblack name = "fancyblack" display_name = "fancyblack" icon_base = "fancyblack" icon_colour = "#FFFFFF" -/material/glass/titaniumglass +/datum/material/glass/titaniumglass name = MAT_TITANIUMGLASS display_name = "titanium glass" stack_type = /obj/item/stack/material/glass/titanium @@ -48,7 +48,7 @@ rod_product = /obj/item/stack/material/glass/titanium composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, "glass" = SHEET_MATERIAL_AMOUNT) -/material/plastitanium +/datum/material/plastitanium name = MAT_PLASTITANIUM stack_type = /obj/item/stack/material/plastitanium integrity = 600 @@ -65,7 +65,18 @@ composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, MAT_PLASTEEL = SHEET_MATERIAL_AMOUNT) supply_conversion_value = 8 -/material/glass/plastaniumglass +/datum/material/plastitanium/hull + name = MAT_PLASTITANIUMHULL + stack_type = /obj/item/stack/material/plastitanium/hull + icon_base = "hull" + icon_reinf = "reinf_mesh" + icon_colour = "#585658" + explosion_resistance = 50 + +/datum/material/plastitanium/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets. + new /obj/item/stack/material/plastitanium(target) + +/datum/material/glass/plastaniumglass name = MAT_PLASTITANIUMGLASS display_name = "plas-titanium glass" stack_type = /obj/item/stack/material/glass/plastitanium diff --git a/code/modules/media/media_tracks.dm b/code/modules/media/media_tracks.dm index e84e4911a6..31a1dc6035 100644 --- a/code/modules/media/media_tracks.dm +++ b/code/modules/media/media_tracks.dm @@ -27,7 +27,7 @@ str += " by [artist]" return str -/datum/track/proc/toNanoList() +/datum/track/proc/toTguiList() return list("ref" = "\ref[src]", "title" = title, "artist" = artist, "duration" = duration) diff --git a/code/modules/mining/drilling/scanner.dm b/code/modules/mining/drilling/scanner.dm index 31da4a9753..50bf8bdd35 100644 --- a/code/modules/mining/drilling/scanner.dm +++ b/code/modules/mining/drilling/scanner.dm @@ -6,7 +6,7 @@ item_state = "electronic" origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1) matter = list(DEFAULT_WALL_MATERIAL = 150) - var/scan_time = 5 SECONDS + var/scan_time = 2 SECONDS /obj/item/weapon/mining_scanner/attack_self(mob/user as mob) to_chat(user, "You begin sweeping \the [src] about, scanning for metal deposits.") diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm index 93c711b6be..32d47681c3 100644 --- a/code/modules/mining/machine_processing.dm +++ b/code/modules/mining/machine_processing.dm @@ -275,7 +275,7 @@ var/can_make = CLAMP(ores_stored[metal],0,sheets_per_tick-sheets) if(can_make%2>0) can_make-- - var/material/M = get_material_by_name(O.compresses_to) + var/datum/material/M = get_material_by_name(O.compresses_to) if(!istype(M) || !can_make || ores_stored[metal] < 1) continue @@ -289,7 +289,7 @@ var/can_make = CLAMP(ores_stored[metal],0,sheets_per_tick-sheets) - var/material/M = get_material_by_name(O.smelts_to) + var/datum/material/M = get_material_by_name(O.smelts_to) if(!istype(M) || !can_make || ores_stored[metal] < 1) continue diff --git a/code/modules/mining/ore_redemption_machine/equipment_vendor.dm b/code/modules/mining/ore_redemption_machine/equipment_vendor.dm index 2f388e2ba5..0ab8381002 100644 --- a/code/modules/mining/ore_redemption_machine/equipment_vendor.dm +++ b/code/modules/mining/ore_redemption_machine/equipment_vendor.dm @@ -91,8 +91,9 @@ EQUIPMENT("Fine Excavation Kit - Measuring Tape", /obj/item/device/measuring_tape, 125), EQUIPMENT("Fine Excavation Kit - Hand Pick", /obj/item/weapon/pickaxe/hand, 375), EQUIPMENT("Explosive Excavation Kit - Plastic Charge",/obj/item/weapon/plastique/seismic/locked, 1500), - EQUIPMENT("Industrial Equipment - Phoron Bore", /obj/item/weapon/gun/magnetic/matfed, 3000), - EQUIPMENT("Industrial Equipment - Sheet-Snatcher",/obj/item/weapon/storage/bag/sheetsnatcher, 500), + EQUIPMENT("Industrial Equipment - Phoron Bore", /obj/item/weapon/gun/magnetic/matfed, 3000), + EQUIPMENT("Industrial Equipment - Inducer", /obj/item/weapon/inducer, 900), + EQUIPMENT("Industrial Equipment - Sheet-Snatcher", /obj/item/weapon/storage/bag/sheetsnatcher, 500), ) prize_list["Hardsuit"] = list( EQUIPMENT("Hardsuit - Control Module", /obj/item/weapon/rig/industrial/vendor, 2000), diff --git a/code/modules/mining/ore_redemption_machine/survey_vendor.dm b/code/modules/mining/ore_redemption_machine/survey_vendor.dm index 1eb8672ef6..eaf5667094 100644 --- a/code/modules/mining/ore_redemption_machine/survey_vendor.dm +++ b/code/modules/mining/ore_redemption_machine/survey_vendor.dm @@ -55,6 +55,7 @@ EQUIPMENT("Digital Tablet - Standard", /obj/item/modular_computer/tablet/preset/custom_loadout/standard, 50), EQUIPMENT("Digital Tablet - Advanced", /obj/item/modular_computer/tablet/preset/custom_loadout/advanced, 100), EQUIPMENT("Industrial Equipment - Phoron Bore", /obj/item/weapon/gun/magnetic/matfed, 300), + EQUIPMENT("Industrial Equipment - Inducer", /obj/item/weapon/inducer, 90), EQUIPMENT("Laser Pointer", /obj/item/device/laser_pointer, 90), EQUIPMENT("Luxury Shelter Capsule", /obj/item/device/survivalcapsule/luxury, 310), EQUIPMENT("Bar Shelter Capsule", /obj/item/device/survivalcapsule/luxurybar, 1000), diff --git a/code/modules/mob/living/bot/cleanbot.dm b/code/modules/mob/living/bot/cleanbot.dm index 6594126b1d..8071c184ee 100644 --- a/code/modules/mob/living/bot/cleanbot.dm +++ b/code/modules/mob/living/bot/cleanbot.dm @@ -221,6 +221,7 @@ target_types += /obj/effect/decal/cleanable/liquid_fuel target_types += /obj/effect/decal/cleanable/mucus target_types += /obj/effect/decal/cleanable/dirt + target_types += /obj/effect/decal/cleanable/filth if(blood) target_types += /obj/effect/decal/cleanable/blood diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 3f0cab7f9d..c4480cf5ae 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -210,7 +210,7 @@ return spread_fire(AM) - + ..() // call parent because we moved behavior to parent // Get rank from ID, ID inside PDA, PDA, ID in wallet, etc. @@ -220,7 +220,7 @@ if (pda.id) return pda.id.rank ? pda.id.rank : if_no_job else - return pda.ownrank + return pda.ownrank ? pda.ownrank : if_no_job else var/obj/item/weapon/card/id/id = get_idcard() if(id) @@ -236,7 +236,7 @@ if (pda.id) return pda.id.assignment else - return pda.ownjob + return pda.ownjob ? pda.ownjob : if_no_job else var/obj/item/weapon/card/id/id = get_idcard() if(id) @@ -252,7 +252,7 @@ if (pda.id) return pda.id.registered_name else - return pda.owner + return pda.owner ? pda.owner : if_no_id else var/obj/item/weapon/card/id/id = get_idcard() if(id) @@ -285,7 +285,7 @@ . = if_no_id if(istype(wear_id,/obj/item/device/pda)) var/obj/item/device/pda/P = wear_id - return P.owner + return P.owner ? P.owner : if_no_id if(wear_id) var/obj/item/weapon/card/id/I = wear_id.GetID() if(I) diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 2bda9a55d4..a7678647d8 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -183,31 +183,32 @@ // VOREstation Edit End. #undef HUMAN_LOWEST_SLOWDOWN +/mob/living/carbon/human/get_jetpack() + if(back) + var/obj/item/weapon/rig/rig = get_rig() + if(istype(back, /obj/item/weapon/tank/jetpack)) + return back + else if(istype(rig)) + for(var/obj/item/rig_module/maneuvering_jets.module in rig.installed_modules) + return module.jets + /mob/living/carbon/human/Process_Spacemove(var/check_drift = 0) //Can we act? if(restrained()) return 0 + if(..()) //Can move due to other reasons, don't use jetpack fuel + return 1 + //Do we have a working jetpack? - var/obj/item/weapon/tank/jetpack/thrust - if(back) - if(istype(back,/obj/item/weapon/tank/jetpack)) - thrust = back - else if(istype(get_rig(),/obj/item/weapon/rig)) - var/obj/item/weapon/rig/rig = get_rig() - for(var/obj/item/rig_module/maneuvering_jets/module in rig.installed_modules) - thrust = module.jets - break + var/obj/item/weapon/tank/jetpack/thrust = get_jetpack() if(thrust) - if(((!check_drift) || (check_drift && thrust.stabilization_on)) && (!lying) && (thrust.allow_thrust(0.01, src))) + if(((!check_drift) || (check_drift && thrust.stabilization_on)) && (!lying) && (thrust.do_thrust(0.01, src))) inertia_dir = 0 return 1 if(flying) //VOREStation Edit. If you're flying, you glide around! return 0 //VOREStation Edit. - //If no working jetpack then use the other checks - if(..()) - return 1 return 0 @@ -215,7 +216,11 @@ //If knocked out we might just hit it and stop. This makes it possible to get dead bodies and such. if(species.flags & NO_SLIP) - return + return 0 + + var/obj/item/weapon/tank/jetpack/thrust = get_jetpack() + if(thrust?.can_thrust(0.01)) + return 0 if(stat) prob_slip = 0 // Changing this to zero to make it line up with the comment, and also, make more sense. diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 39ad53458b..fbf1b76b90 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -1290,13 +1290,19 @@ clear_fullscreen("blind") clear_alert("blind") - if(disabilities & NEARSIGHTED) //this looks meh but saves a lot of memory by not requiring to add var/prescription - if(glasses) //to every /obj/item + var/apply_nearsighted_overlay = FALSE + if(disabilities & NEARSIGHTED) + apply_nearsighted_overlay = TRUE + + if(glasses) var/obj/item/clothing/glasses/G = glasses - if(!G.prescription) - set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1) - else if (!nif || !nif.flag_check(NIF_V_CORRECTIVE,NIF_FLAGS_VISION)) //VOREStation Edit - NIF - set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1) + if(G.prescription) + apply_nearsighted_overlay = FALSE + + if(nif && nif.flag_check(NIF_V_CORRECTIVE, NIF_FLAGS_VISION)) // VOREStation Edit - NIF + apply_nearsighted_overlay = FALSE + + set_fullscreen(apply_nearsighted_overlay, "nearsighted", /obj/screen/fullscreen/impaired, 1) set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry) set_fullscreen(druggy, "high", /obj/screen/fullscreen/high) diff --git a/code/modules/mob/living/carbon/human/species/station/alraune.dm b/code/modules/mob/living/carbon/human/species/station/alraune.dm index fe7410c774..8353d36cba 100644 --- a/code/modules/mob/living/carbon/human/species/station/alraune.dm +++ b/code/modules/mob/living/carbon/human/species/station/alraune.dm @@ -111,19 +111,19 @@ //This is mostly normal breath code with some tweaks that apply to their particular biology. var/datum/gas_mixture/breath = null - var/fullysealed = FALSE //if they're wearing a fully sealed suit, their internals take priority. - var/environmentalair = FALSE //if no sealed suit, internals take priority in low pressure environements + var/fullysealed = FALSE //are they covered in a sealed suit or not - if(H.wear_suit && (H.wear_suit.min_pressure_protection = 0) && H.head && (H.head.min_pressure_protection = 0)) + if(H.wear_suit && (H.wear_suit.min_pressure_protection < hazard_low_pressure) && H.head && (H.head.min_pressure_protection < hazard_low_pressure)) + //if they're wearing a fully sealed suit, their internals take priority. + breath = H.get_breath_from_internal() fullysealed = TRUE - else // find out if local gas mixture is enough to override use of internals + else + // find out if local gas mixture is enough to override use of internals + // if pressure is low enough, they can still breathe from internals without a suit var/datum/gas_mixture/environment = H.loc.return_air() var/envpressure = environment.return_pressure() - if(envpressure >= hazard_low_pressure) - environmentalair = TRUE - - if(fullysealed || !environmentalair) - breath = H.get_breath_from_internal() + if(envpressure < hazard_low_pressure) + breath = H.get_breath_from_internal() if(!breath) //No breath from internals so let's try to get air from our location // cut-down version of get_breath_from_environment - notably, gas masks provide no benefit diff --git a/code/modules/mob/living/carbon/human/stripping.dm b/code/modules/mob/living/carbon/human/stripping.dm index 736109794a..7aa08accbb 100644 --- a/code/modules/mob/living/carbon/human/stripping.dm +++ b/code/modules/mob/living/carbon/human/stripping.dm @@ -58,14 +58,22 @@ var/stripping var/obj/item/held = user.get_active_hand() if(!istype(held) || is_robot_module(held)) + stripping = TRUE + else + var/obj/item/weapon/holder/holder = held + if(istype(holder) && src == holder.held_mob) + stripping = TRUE + else + var/obj/item/weapon/grab/grab = held + if(istype(grab) && grab.affecting == src) + stripping = TRUE + + if(stripping) if(!istype(target_slot)) // They aren't holding anything valid and there's nothing to remove, why are we even here? return if(!target_slot.canremove) to_chat(user, "You cannot remove \the [src]'s [target_slot.name].") return - stripping = 1 - - if(stripping) visible_message("\The [user] is trying to remove \the [src]'s [target_slot.name]!") else if(slot_to_strip == slot_wear_mask && istype(held, /obj/item/weapon/grenade)) diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 063b4fe188..a88a434d96 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -10,9 +10,6 @@ if(!loc) return - if(machine && !CanMouseDrop(machine, src)) - machine = null - var/datum/gas_mixture/environment = loc.return_air() //handle_modifiers() // Do this early since it might affect other things later. //VOREStation Edit diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 1864ee5d01..05990e8de9 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -132,16 +132,25 @@ default behaviour is: if((tmob.mob_always_swap || (tmob.a_intent == I_HELP || tmob.restrained()) && (a_intent == I_HELP || src.restrained())) && tmob.canmove && canmove && !tmob.buckled && !buckled && can_swap && can_move_mob(tmob, 1, 0)) // mutual brohugs all around! var/turf/oldloc = loc + //VOREstation Edit - Begin + + //check bumpnom chance, if it's a simplemob that's doing the bumping + var/mob/living/simple_mob/srcsimp = src + if(istype(srcsimp)) + if(srcsimp.tryBumpNom(tmob)) + now_pushing = 0 + return + + //if it's a simplemob being bumped, and the above didn't make them start getting bumpnommed, they get a chance to bumpnom + var/mob/living/simple_mob/tmobsimp = tmob + if(istype(tmobsimp)) + if(tmobsimp.tryBumpNom(src)) + now_pushing = 0 + return + + //VOREstation Edit - End forceMove(tmob.loc) //VOREstation Edit - Begin - if (istype(tmob, /mob/living/simple_mob)) //check bumpnom chance, if it's a simplemob that's bumped - tmob.Bumped(src) - else if(istype(src, /mob/living/simple_mob)) //otherwise, if it's a simplemob doing the bumping. Simplemob on simplemob doesn't seem to trigger but that's fine. - Bumped(tmob) - if (tmob.loc == src) //check if they got ate, and if so skip the forcemove - now_pushing = 0 - return - // In case of micros, we don't swap positions; instead occupying the same square! if (handle_micro_bump_helping(tmob)) now_pushing = 0 diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 60966f6da2..0c20f6bf31 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -20,7 +20,6 @@ var/list/ai_verbs_default = list( /mob/living/silicon/ai/proc/ai_call_shuttle, /mob/living/silicon/ai/proc/ai_camera_track, /mob/living/silicon/ai/proc/ai_camera_list, - /mob/living/silicon/ai/proc/ai_roster, /mob/living/silicon/ai/proc/ai_checklaws, /mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/take_image, @@ -48,7 +47,7 @@ var/list/ai_verbs_default = list( anchored = 1 // -- TLE density = 1 status_flags = CANSTUN|CANPARALYSE|CANPUSH - shouldnt_see = list(/obj/effect/rune) + shouldnt_see = list(/mob/observer/eye, /obj/effect/rune) var/list/network = list(NETWORK_DEFAULT) var/obj/machinery/camera/camera = null var/aiRestorePowerRoutine = 0 @@ -355,12 +354,6 @@ var/list/ai_verbs_default = list( if(new_sprite) selected_sprite = new_sprite updateicon() -// this verb lets the ai see the stations manifest -/mob/living/silicon/ai/proc/ai_roster() - set category = "AI Commands" - set name = "Show Crew Manifest" - show_station_manifest() - /mob/living/silicon/ai/var/message_cooldown = 0 /mob/living/silicon/ai/proc/ai_announcement() set category = "AI Commands" @@ -399,9 +392,7 @@ var/list/ai_verbs_default = list( // hack to display shuttle timer if(emergency_shuttle.online()) - var/obj/machinery/computer/communications/C = locate() in machines - if(C) - C.post_status("shuttle") + post_status(src, "shuttle", user = src) /mob/living/silicon/ai/proc/ai_recall_shuttle() set category = "AI Commands" diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 3a995ba19d..cf135f9d55 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -122,7 +122,10 @@ pda.ownjob = "Personal Assistant" pda.owner = text("[]", src) pda.name = pda.owner + " (" + pda.ownjob + ")" - pda.toff = 1 + + var/datum/data/pda/app/messenger/M = pda.find_program(/datum/data/pda/app/messenger) + if(M) + M.toff = TRUE ..() /mob/living/silicon/pai/Login() @@ -210,7 +213,7 @@ medicalActive1 = null medicalActive2 = null medical_cannotfind = 0 - SSnanoui.update_uis(src) + SStgui.update_uis(src) to_chat(usr, "You reset your record-viewing software.") /mob/living/silicon/pai/cancel_camera() diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm index bbb038dead..cad5229097 100644 --- a/code/modules/mob/living/silicon/pai/software.dm +++ b/code/modules/mob/living/silicon/pai/software.dm @@ -41,27 +41,24 @@ var/global/list/default_pai_software = list() set category = "pAI Commands" set name = "Software Interface" - ui_interact(src) + tgui_interact(src) -/mob/living/silicon/pai/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1) - if(user != src) - if(ui) ui.set_status(STATUS_CLOSE, 0) - return +/mob/living/silicon/pai/tgui_state(mob/user) + return GLOB.tgui_self_state - if(ui_key != "main") - var/datum/pai_software/S = software[ui_key] - if(S && !S.toggle) - S.on_ui_interact(src, ui, force_open) - else - if(ui) ui.set_status(STATUS_CLOSE, 0) - return - - var/data[0] +/mob/living/silicon/pai/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "pAIInterface", "pAI Software Interface") + ui.open() +/mob/living/silicon/pai/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + // Software we have bought - var/bought_software[0] + var/list/bought_software = list() // Software we have not bought - var/not_bought_software[0] + var/list/not_bought_software = list() for(var/key in pai_software_by_key) var/datum/pai_software/S = pai_software_by_key[key] @@ -70,62 +67,52 @@ var/global/list/default_pai_software = list() software_data["id"] = S.id if(key in software) software_data["on"] = S.is_active(src) - bought_software[++bought_software.len] = software_data + bought_software.Add(list(software_data)) else software_data["ram"] = S.ram_cost - not_bought_software[++not_bought_software.len] = software_data + not_bought_software.Add(list(software_data)) data["bought"] = bought_software data["not_bought"] = not_bought_software data["available_ram"] = ram // Emotions - var/emotions[0] + var/list/emotions = list() for(var/name in pai_emotions) - var/emote[0] + var/list/emote = list() emote["name"] = name emote["id"] = pai_emotions[name] - emotions[++emotions.len] = emote + emotions.Add(list(emote)) data["emotions"] = emotions data["current_emotion"] = card.current_emotion - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "pai_interface.tmpl", "pAI Software Interface", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data -/mob/living/silicon/pai/Topic(href, href_list) - . = ..() - if(.) return +/mob/living/silicon/pai/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE - if(href_list["software"]) - var/soft = href_list["software"] - var/datum/pai_software/S = software[soft] - if(S.toggle) - S.toggle(src) - else - ui_interact(src, ui_key = soft) - return 1 + switch(action) + if("software") + var/soft = params["software"] + var/datum/pai_software/S = software[soft] + if(S.toggle) + S.toggle(src) + else + S.tgui_interact(src, parent_ui = ui) + return TRUE - else if(href_list["stopic"]) - var/soft = href_list["stopic"] - var/datum/pai_software/S = software[soft] - if(S) - return S.Topic(href, href_list) + if("purchase") + var/soft = params["purchase"] + var/datum/pai_software/S = pai_software_by_key[soft] + if(S && (ram >= S.ram_cost)) + ram -= S.ram_cost + software[S.id] = S + return TRUE - else if(href_list["purchase"]) - var/soft = href_list["purchase"] - var/datum/pai_software/S = pai_software_by_key[soft] - if(S && (ram >= S.ram_cost)) - ram -= S.ram_cost - software[S.id] = S - return 1 - - else if(href_list["image"]) - var/img = text2num(href_list["image"]) - if(1 <= img && img <= (pai_emotions.len)) - card.setEmotion(img) - return 1 + if("image") + var/img = text2num(params["image"]) + if(1 <= img && img <= (pai_emotions.len)) + card.setEmotion(img) + return TRUE diff --git a/code/modules/mob/living/silicon/pai/software_modules.dm b/code/modules/mob/living/silicon/pai/software_modules.dm index 8f7e8462de..e518e74a4a 100644 --- a/code/modules/mob/living/silicon/pai/software_modules.dm +++ b/code/modules/mob/living/silicon/pai/software_modules.dm @@ -12,14 +12,19 @@ // Whether pAIs should automatically receive this module at no cost var/default = 0 - proc/on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - return +/datum/pai_software/proc/toggle(mob/living/silicon/pai/user) + return - proc/toggle(mob/living/silicon/pai/user) - return +/datum/pai_software/proc/is_active(mob/living/silicon/pai/user) + return 0 - proc/is_active(mob/living/silicon/pai/user) - return 0 +/datum/pai_software/tgui_state(mob/user) + return GLOB.tgui_always_state + +/datum/pai_software/tgui_status(mob/user) + if(!istype(user, /mob/living/silicon/pai)) + return STATUS_CLOSE + return ..() /datum/pai_software/directives name = "Directives" @@ -28,55 +33,58 @@ toggle = 0 default = 1 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] +/datum/pai_software/directives/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "pAIDirectives", name, parent_ui) + ui.open() - data["master"] = user.master - data["dna"] = user.master_dna - data["prime"] = user.pai_law0 - data["supplemental"] = user.pai_laws +/datum/pai_software/directives/tgui_data(mob/living/silicon/pai/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = list() - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_directives.tmpl", "pAI Directives", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + data["master"] = user.master + data["dna"] = user.master_dna + data["prime"] = user.pai_law0 + data["supplemental"] = user.pai_laws - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return + return data - if(href_list["getdna"]) - var/mob/living/M = P.loc - var/count = 0 +/datum/pai_software/directives/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + var/mob/living/silicon/pai/P = usr + if(!istype(P)) + return TRUE + if(..()) + return TRUE - // Find the carrier - while(!istype(M, /mob/living)) - if(!M || !M.loc || count > 6) - //For a runtime where M ends up in nullspace (similar to bluespace but less colourful) - to_chat(src, "You are not being carried by anyone!") - return 0 - M = M.loc - count++ + if(action == "getdna") + var/mob/living/M = P.loc - // Check the carrier - var/datum/gender/TM = gender_datums[M.get_visible_gender()] - var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No") - if(answer == "Yes") - var/turf/T = get_turf_or_move(P.loc) - for (var/mob/v in viewers(T)) - v.show_message("[M] presses [TM.his] thumb against [P].", 3, "[P] makes a sharp clicking sound as it extracts DNA material from [M].", 2) - var/datum/dna/dna = M.dna - to_chat(P, "

[M]'s UE string : [dna.unique_enzymes]

") - if(dna.unique_enzymes == P.master_dna) - to_chat(P, "DNA is a match to stored Master DNA.") - else - to_chat(P, "DNA does not match stored Master DNA.") + var/count = 0 + // Find the carrier + while(!istype(M, /mob/living)) + if(!M || !M.loc || count > 6) + //For a runtime where M ends up in nullspace (similar to bluespace but less colourful) + to_chat(src, "You are not being carried by anyone!") + return 0 + M = M.loc + count++ + + // Check the carrier + var/datum/gender/TM = gender_datums[M.get_visible_gender()] + var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No") + if(answer == "Yes") + var/turf/T = get_turf(P.loc) + for (var/mob/v in viewers(T)) + v.show_message("[M] presses [TM.his] thumb against [P].", 3, "[P] makes a sharp clicking sound as it extracts DNA material from [M].", 2) + var/datum/dna/dna = M.dna + to_chat(P, "

[M]'s UE string : [dna.unique_enzymes]

") + if(dna.unique_enzymes == P.master_dna) + to_chat(P, "DNA is a match to stored Master DNA.") else - to_chat(P, "[M] does not seem like [TM.he] is going to provide a DNA sample willingly.") - return 1 + to_chat(P, "DNA does not match stored Master DNA.") + else + to_chat(P, "[M] does not seem like [TM.he] is going to provide a DNA sample willingly.") + return TRUE /datum/pai_software/radio_config name = "Radio Configuration" @@ -85,35 +93,8 @@ toggle = 0 default = 1 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui = null, force_open = 1) - var/data[0] - - data["listening"] = user.radio.broadcasting - data["frequency"] = format_frequency(user.radio.frequency) - - var/channels[0] - for(var/ch_name in user.radio.channels) - var/ch_stat = user.radio.channels[ch_name] - var/ch_dat[0] - ch_dat["name"] = ch_name - // FREQ_LISTENING is const in /obj/item/device/radio - ch_dat["listening"] = !!(ch_stat & user.radio.FREQ_LISTENING) - channels[++channels.len] = ch_dat - - data["channels"] = channels - - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - ui = new(user, user, id, "pai_radio.tmpl", "Radio Configuration", 300, 150) - ui.set_initial_data(data) - ui.open() - - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return - - P.radio.Topic(href, href_list) - return 1 +/datum/pai_software/radio_config/tgui_interact(mob/living/silicon/pai/user, datum/tgui/ui, datum/tgui/parent_ui) + return user.radio.tgui_interact(user, parent_ui = parent_ui) /datum/pai_software/crew_manifest name = "Crew Manifest" @@ -121,20 +102,18 @@ id = "manifest" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) +/datum/pai_software/crew_manifest/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "CrewManifest", name, parent_ui) + ui.open() + +/datum/pai_software/crew_manifest/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + if(data_core) data_core.get_manifest_list() - - var/data[0] - // This is dumb, but NanoUI breaks if it has no data to send - data["manifest"] = PDA_Manifest - - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "crew_manifest.tmpl", "Crew Manifest", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + data["manifest"] = PDA_Manifest + return data /datum/pai_software/messenger name = "Digital Messenger" @@ -142,75 +121,8 @@ id = "messenger" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] - - data["receiver_off"] = user.pda.toff - data["ringer_off"] = user.pda.message_silent - data["current_ref"] = null - data["current_name"] = user.current_pda_messaging - - var/pdas[0] - if(!user.pda.toff) - for(var/obj/item/device/pda/P in sortAtom(PDAs)) - if(!P.owner || P.toff || P == user.pda || P.hidden) continue - var/pda[0] - pda["name"] = "[P]" - pda["owner"] = "[P.owner]" - pda["ref"] = "\ref[P]" - if(P.owner == user.current_pda_messaging) - data["current_ref"] = "\ref[P]" - pdas[++pdas.len] = pda - - data["pdas"] = pdas - - var/messages[0] - if(user.current_pda_messaging) - for(var/index in user.pda.tnote) - if(index["owner"] != user.current_pda_messaging) - continue - var/msg[0] - var/sent = index["sent"] - msg["sent"] = sent ? 1 : 0 - msg["target"] = index["owner"] - msg["message"] = index["message"] - messages[++messages.len] = msg - - data["messages"] = messages - - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_messenger.tmpl", "Digital Messenger", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return - - if(!isnull(P.pda)) - if(href_list["toggler"]) - P.pda.toff = href_list["toggler"] != "1" - return 1 - else if(href_list["ringer"]) - P.pda.message_silent = href_list["ringer"] != "1" - return 1 - else if(href_list["select"]) - var/s = href_list["select"] - if(s == "*NONE*") - P.current_pda_messaging = null - else - P.current_pda_messaging = s - return 1 - else if(href_list["target"]) - if(P.silence_time) - return alert("Communications circuits remain uninitialized.") - - var/target = locate(href_list["target"]) - P.pda.create_message(P, target, 1) - return 1 +/datum/pai_software/messenger/tgui_interact(mob/living/silicon/pai/user, datum/tgui/ui, datum/tgui/parent_ui) + return user.pda.tgui_interact(user, parent_ui = parent_ui) /datum/pai_software/med_records name = "Medical Records" @@ -218,53 +130,55 @@ id = "med_records" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] +/datum/pai_software/med_records/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "pAIMedrecords", name, parent_ui) + ui.open() - var/records[0] - for(var/datum/data/record/general in sortRecord(data_core.general)) - var/record[0] - record["name"] = general.fields["name"] - record["ref"] = "\ref[general]" - records[++records.len] = record +/datum/pai_software/med_records/tgui_data(mob/living/silicon/pai/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + var/list/records = list() + for(var/datum/data/record/general in sortRecord(data_core.general)) + var/list/record = list() + record["name"] = general.fields["name"] + record["ref"] = "\ref[general]" + records.Add(list(record)) - data["records"] = records + data["records"] = records - var/datum/data/record/G = user.medicalActive1 - var/datum/data/record/M = user.medicalActive2 - data["general"] = G ? G.fields : null - data["medical"] = M ? M.fields : null - data["could_not_find"] = user.medical_cannotfind + var/datum/data/record/G = user.medicalActive1 + var/datum/data/record/M = user.medicalActive2 + data["general"] = G ? G.fields : null + data["medical"] = M ? M.fields : null + data["could_not_find"] = user.medical_cannotfind - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_medrecords.tmpl", "Medical Records", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return +/datum/pai_software/med_records/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + . = ..() + var/mob/living/silicon/pai/P = usr + if(!istype(P)) + return - if(href_list["select"]) - var/datum/data/record/record = locate(href_list["select"]) - if(record) - var/datum/data/record/R = record - var/datum/data/record/M = null - if (!( data_core.general.Find(R) )) - P.medical_cannotfind = 1 - else - P.medical_cannotfind = 0 - for(var/datum/data/record/E in data_core.medical) - if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - M = E - P.medicalActive1 = R - P.medicalActive2 = M - else + if(action == "select") + var/datum/data/record/record = locate(params["select"]) + if(record) + var/datum/data/record/R = record + var/datum/data/record/M = null + if (!( data_core.general.Find(R) )) P.medical_cannotfind = 1 - return 1 + else + P.medical_cannotfind = 0 + for(var/datum/data/record/E in data_core.medical) + if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + M = E + P.medicalActive1 = R + P.medicalActive2 = M + else + P.medical_cannotfind = 1 + return 1 /datum/pai_software/sec_records name = "Security Records" @@ -272,57 +186,59 @@ id = "sec_records" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] +/datum/pai_software/sec_records/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "pAISecrecords", name, parent_ui) + ui.open() - var/records[0] - for(var/datum/data/record/general in sortRecord(data_core.general)) - var/record[0] - record["name"] = general.fields["name"] - record["ref"] = "\ref[general]" - records[++records.len] = record +/datum/pai_software/sec_records/tgui_data(mob/living/silicon/pai/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + var/list/records = list() + for(var/datum/data/record/general in sortRecord(data_core.general)) + var/list/record = list() + record["name"] = general.fields["name"] + record["ref"] = "\ref[general]" + records.Add(list(record)) - data["records"] = records + data["records"] = records - var/datum/data/record/G = user.securityActive1 - var/datum/data/record/S = user.securityActive2 - data["general"] = G ? G.fields : null - data["security"] = S ? S.fields : null - data["could_not_find"] = user.security_cannotfind + var/datum/data/record/G = user.securityActive1 + var/datum/data/record/S = user.securityActive2 + data["general"] = G ? G.fields : null + data["security"] = S ? S.fields : null + data["could_not_find"] = user.security_cannotfind - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_secrecords.tmpl", "Security Records", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return +/datum/pai_software/sec_records/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + . = ..() + var/mob/living/silicon/pai/P = usr + if(!istype(P)) + return - if(href_list["select"]) - var/datum/data/record/record = locate(href_list["select"]) - if(record) - var/datum/data/record/R = record - var/datum/data/record/S = null - if (!( data_core.general.Find(R) )) - P.securityActive1 = null - P.securityActive2 = null - P.security_cannotfind = 1 - else - P.security_cannotfind = 0 - for(var/datum/data/record/E in data_core.security) - if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - S = E - P.securityActive1 = R - P.securityActive2 = S - else + if(action == "select") + var/datum/data/record/record = locate(params["select"]) + if(record) + var/datum/data/record/R = record + var/datum/data/record/S = null + if (!( data_core.general.Find(R) )) P.securityActive1 = null P.securityActive2 = null P.security_cannotfind = 1 - return 1 + else + P.security_cannotfind = 0 + for(var/datum/data/record/E in data_core.security) + if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + S = E + P.securityActive1 = R + P.securityActive2 = S + else + P.securityActive1 = null + P.securityActive2 = null + P.security_cannotfind = 1 + return TRUE /datum/pai_software/door_jack name = "Door Jack" @@ -330,47 +246,49 @@ id = "door_jack" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] +/datum/pai_software/door_jack/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "pAIDoorjack", "Door Jack", parent_ui) + ui.open() - data["cable"] = user.cable != null - data["machine"] = user.cable && (user.cable.machine != null) - data["inprogress"] = user.hackdoor != null - data["progress_a"] = round(user.hackprogress / 10) - data["progress_b"] = user.hackprogress % 10 - data["aborted"] = user.hack_aborted +/datum/pai_software/door_jack/tgui_data(mob/living/silicon/pai/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_doorjack.tmpl", "Door Jack", 300, 150) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + data["cable"] = user.cable != null + data["machine"] = user.cable && (user.cable.machine != null) + data["inprogress"] = user.hackdoor != null + data["progress_a"] = round(user.hackprogress / 10) + data["progress_b"] = user.hackprogress % 10 + data["aborted"] = user.hack_aborted - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return + return data - if(href_list["jack"]) +/datum/pai_software/door_jack/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + var/mob/living/silicon/pai/P = usr + if(!istype(P) || ..()) + return TRUE + + switch(action) + if("jack") if(P.cable && P.cable.machine) P.hackdoor = P.cable.machine P.hackloop() return 1 - else if(href_list["cancel"]) + if("cancel") P.hackdoor = null return 1 - else if(href_list["cable"]) - var/turf/T = get_turf_or_move(P.loc) + if("cable") + var/turf/T = get_turf(P) P.hack_aborted = 0 P.cable = new /obj/item/weapon/pai_cable(T) for(var/mob/M in viewers(T)) M.show_message("A port on [P] opens to reveal [P.cable], which promptly falls to the floor.", 3, - "You hear the soft click of something light and hard falling to the ground.", 2) + "You hear the soft click of something light and hard falling to the ground.", 2) return 1 /mob/living/silicon/pai/proc/hackloop() - var/turf/T = get_turf_or_move(src.loc) + var/turf/T = get_turf(src) for(var/mob/living/silicon/ai/AI in player_list) if(T.loc) to_chat(AI, "Network Alert: Brute-force encryption crack in progress in [T.loc].") @@ -404,134 +322,155 @@ id = "atmos_sense" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] +/datum/pai_software/atmosphere_sensor/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "pAIAtmos", name, parent_ui) + ui.open() - var/turf/T = get_turf_or_move(user.loc) - if(!T) - data["reading"] = 0 - data["pressure"] = 0 - data["temperature"] = 0 - data["temperatureC"] = 0 - data["gas"] = list() - else - var/datum/gas_mixture/env = T.return_air() - data["reading"] = 1 - var/pres = env.return_pressure() * 10 - data["pressure"] = "[round(pres/10)].[pres%10]" - data["temperature"] = round(env.temperature) - data["temperatureC"] = round(env.temperature-T0C) +/datum/pai_software/atmosphere_sensor/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() - var/t_moles = env.total_moles - var/gases[0] - for(var/g in env.gas) - var/gas[0] - gas["name"] = gas_data.name[g] - gas["percent"] = round((env.gas[g] / t_moles) * 100) - gases[++gases.len] = gas - data["gas"] = gases + var/list/results = list() + var/turf/T = get_turf(user) + if(!isnull(T)) + var/datum/gas_mixture/environment = T.return_air() + var/pressure = environment.return_pressure() + var/total_moles = environment.total_moles + if (total_moles) + var/o2_level = environment.gas["oxygen"]/total_moles + var/n2_level = environment.gas["nitrogen"]/total_moles + var/co2_level = environment.gas["carbon_dioxide"]/total_moles + var/phoron_level = environment.gas["phoron"]/total_moles + var/unknown_level = 1-(o2_level+n2_level+co2_level+phoron_level) - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_atmosphere.tmpl", "Atmosphere Sensor", 350, 300) - ui.set_initial_data(data) - ui.open() + // entry is what the element is describing + // Type identifies which unit or other special characters to use + // Val is the information reported + // Bad_high/_low are the values outside of which the entry reports as dangerous + // Poor_high/_low are the values outside of which the entry reports as unideal + // Values were extracted from the template itself + results = list( + list("entry" = "Pressure", "units" = "kPa", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80), + list("entry" = "Temperature", "units" = "°C", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5), + list("entry" = "Oxygen", "units" = "kPa", "val" = "[round(o2_level*100,0.1)]", "bad_high" = 140, "poor_high" = 135, "poor_low" = 19, "bad_low" = 17), + list("entry" = "Nitrogen", "units" = "kPa", "val" = "[round(n2_level*100,0.1)]", "bad_high" = 105, "poor_high" = 85, "poor_low" = 50, "bad_low" = 40), + list("entry" = "Carbon Dioxide", "units" = "kPa", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0), + list("entry" = "Phoron", "units" = "kPa", "val" = "[round(phoron_level*100,0.01)]", "bad_high" = 0.5, "poor_high" = 0, "poor_low" = 0, "bad_low" = 0), + list("entry" = "Other", "units" = "kPa", "val" = "[round(unknown_level, 0.01)]", "bad_high" = 1, "poor_high" = 0.5, "poor_low" = 0, "bad_low" = 0) + ) + + if(isnull(results)) + results = list(list("entry" = "pressure", "units" = "kPa", "val" = "0", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80)) + + data["aircontents"] = results + + return data /datum/pai_software/sec_hud name = "Security HUD" ram_cost = 20 id = "sec_hud" - toggle(mob/living/silicon/pai/user) - user.secHUD = !user.secHUD - user.plane_holder.set_vis(VIS_CH_ID, user.secHUD) - user.plane_holder.set_vis(VIS_CH_WANTED, user.secHUD) - user.plane_holder.set_vis(VIS_CH_IMPTRACK, user.secHUD) - user.plane_holder.set_vis(VIS_CH_IMPLOYAL, user.secHUD) - user.plane_holder.set_vis(VIS_CH_IMPCHEM, user.secHUD) +/datum/pai_software/sec_hud/toggle(mob/living/silicon/pai/user) + user.secHUD = !user.secHUD + user.plane_holder.set_vis(VIS_CH_ID, user.secHUD) + user.plane_holder.set_vis(VIS_CH_WANTED, user.secHUD) + user.plane_holder.set_vis(VIS_CH_IMPTRACK, user.secHUD) + user.plane_holder.set_vis(VIS_CH_IMPLOYAL, user.secHUD) + user.plane_holder.set_vis(VIS_CH_IMPCHEM, user.secHUD) - is_active(mob/living/silicon/pai/user) - return user.secHUD +/datum/pai_software/sec_hud/is_active(mob/living/silicon/pai/user) + return user.secHUD /datum/pai_software/med_hud name = "Medical HUD" ram_cost = 20 id = "med_hud" - toggle(mob/living/silicon/pai/user) - user.medHUD = !user.medHUD - user.plane_holder.set_vis(VIS_CH_STATUS, user.medHUD) - user.plane_holder.set_vis(VIS_CH_HEALTH, user.medHUD) +/datum/pai_software/med_hud/toggle(mob/living/silicon/pai/user) + user.medHUD = !user.medHUD + user.plane_holder.set_vis(VIS_CH_STATUS, user.medHUD) + user.plane_holder.set_vis(VIS_CH_HEALTH, user.medHUD) - is_active(mob/living/silicon/pai/user) - return user.medHUD +/datum/pai_software/med_hud/is_active(mob/living/silicon/pai/user) + return user.medHUD /datum/pai_software/translator name = "Universal Translator" ram_cost = 35 id = "translator" - toggle(mob/living/silicon/pai/user) - // Sol Common, Tradeband, Terminus and Gutter are added with New() and are therefore the current default, always active languages - user.translator_on = !user.translator_on - if(user.translator_on) - user.add_language(LANGUAGE_UNATHI) - user.add_language(LANGUAGE_SIIK) - user.add_language(LANGUAGE_AKHANI) - user.add_language(LANGUAGE_SKRELLIAN) - user.add_language(LANGUAGE_ZADDAT) - user.add_language(LANGUAGE_SCHECHI) - else - user.remove_language(LANGUAGE_UNATHI) - user.remove_language(LANGUAGE_SIIK) - user.remove_language(LANGUAGE_AKHANI) - user.remove_language(LANGUAGE_SKRELLIAN) - user.remove_language(LANGUAGE_ZADDAT) - user.remove_language(LANGUAGE_SCHECHI) +/datum/pai_software/translator/toggle(mob/living/silicon/pai/user) + // Sol Common, Tradeband, Terminus and Gutter are added with New() and are therefore the current default, always active languages + user.translator_on = !user.translator_on + if(user.translator_on) + user.add_language(LANGUAGE_UNATHI) + user.add_language(LANGUAGE_SIIK) + user.add_language(LANGUAGE_AKHANI) + user.add_language(LANGUAGE_SKRELLIAN) + user.add_language(LANGUAGE_ZADDAT) + user.add_language(LANGUAGE_SCHECHI) + else + user.remove_language(LANGUAGE_UNATHI) + user.remove_language(LANGUAGE_SIIK) + user.remove_language(LANGUAGE_AKHANI) + user.remove_language(LANGUAGE_SKRELLIAN) + user.remove_language(LANGUAGE_ZADDAT) + user.remove_language(LANGUAGE_SCHECHI) - is_active(mob/living/silicon/pai/user) - return user.translator_on +/datum/pai_software/translator/is_active(mob/living/silicon/pai/user) + return user.translator_on /datum/pai_software/signaller - name = "Remote Signaller" + name = "Remote Signaler" ram_cost = 5 id = "signaller" toggle = 0 - on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) - var/data[0] +/datum/pai_software/signaller/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Signaler", "Signaler", parent_ui) + ui.open() - data["frequency"] = format_frequency(user.sradio.frequency) - data["code"] = user.sradio.code +/datum/pai_software/signaller/tgui_data(mob/living/silicon/pai/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + var/obj/item/radio/integrated/signal/R = user.sradio - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_signaller.tmpl", "Signaller", 320, 150) - ui.set_initial_data(data) - ui.open() + data["frequency"] = R.frequency + data["minFrequency"] = RADIO_LOW_FREQ + data["maxFrequency"] = RADIO_HIGH_FREQ + data["code"] = R.code - Topic(href, href_list) - var/mob/living/silicon/pai/P = usr - if(!istype(P)) return + return data - if(href_list["send"]) - P.sradio.send_signal("ACTIVATE") - for(var/mob/O in hearers(1, P.loc)) - O.show_message("[bicon(P)] *beep* *beep*", 3, "*beep* *beep*", 2) - return 1 +/datum/pai_software/signaller/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE - else if(href_list["freq"]) - var/new_frequency = (P.sradio.frequency + text2num(href_list["freq"])) - if(new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ) - new_frequency = sanitize_frequency(new_frequency) - P.sradio.set_frequency(new_frequency) - return 1 + var/mob/living/silicon/pai/user = usr + if(istype(user)) + var/obj/item/radio/integrated/signal/R = user.sradio - else if(href_list["code"]) - P.sradio.code += text2num(href_list["code"]) - P.sradio.code = round(P.sradio.code) - P.sradio.code = min(100, P.sradio.code) - P.sradio.code = max(1, P.sradio.code) - return 1 + switch(action) + if("signal") + spawn(0) + R.send_signal("ACTIVATE") + for(var/mob/O in hearers(1, R.loc)) + O.show_message("[bicon(R)] *beep* *beep*", 3, "*beep* *beep*", 2) + if("freq") + var/frequency = unformat_frequency(params["freq"]) + frequency = sanitize_frequency(frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) + R.set_frequency(frequency) + . = TRUE + if("code") + R.code = clamp(round(text2num(params["code"])), 1, 100) + . = TRUE + if("reset") + if(params["reset"] == "freq") + R.set_frequency(initial(R.frequency)) + else + R.code = initial(R.code) + . = TRUE diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index adc9b66a89..bb4bfc90fb 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -350,12 +350,6 @@ updatename() updateicon() -// this verb lets cyborgs see the stations manifest -/mob/living/silicon/robot/verb/cmd_station_manifest() - set category = "Robot Commands" - set name = "Show Crew Manifest" - show_station_manifest() - /mob/living/silicon/robot/proc/self_diagnosis() if(!is_component_functioning("diagnosis unit")) return null diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm b/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm index d4a6a5d9aa..58a5027402 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm @@ -172,7 +172,8 @@ pto_type = PTO_SCIENCE vr_sprites = list( "Acheron" = "mechoid-Science", - "ZOOM-BA" = "zoomba-research" + "ZOOM-BA" = "zoomba-research", + "XI-GUS" = "spiderscience" ) /obj/item/weapon/robot_module/robot/security/combat diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm index fe05775c51..bc9b7367f2 100644 --- a/code/modules/mob/living/silicon/robot/robot_movement.dm +++ b/code/modules/mob/living/silicon/robot/robot_movement.dm @@ -1,16 +1,28 @@ +/mob/living/silicon/robot/get_jetpack() + if(module) + for(var/obj/item/weapon/tank/jetpack/J in module.modules) + return J + +/mob/living/silicon/robot/Check_Shoegrip() + return module && module.no_slip + /mob/living/silicon/robot/Process_Spaceslipping(var/prob_slip) + var/obj/item/weapon/tank/jetpack/thrust = get_jetpack() + if(thrust?.can_thrust(0.01)) + return 0 if(module && module.no_slip) return 0 ..(prob_slip) -/mob/living/silicon/robot/Process_Spacemove() - if(module) - for(var/obj/item/weapon/tank/jetpack/J in module.modules) - if(istype(J, /obj/item/weapon/tank/jetpack)) - if(J.allow_thrust(0.01)) - return 1 - if(..()) +/mob/living/silicon/robot/Process_Spacemove(var/check_drift = 0) + if(..())//Can move due to other reasons, don't use jetpack fuel return 1 + + var/obj/item/weapon/tank/jetpack/thrust = get_jetpack() + if(thrust && (!check_drift || (check_drift && thrust.stabilization_on)) && thrust.do_thrust(0.01)) + inertia_dir = 0 + return 1 + return 0 //No longer needed, but I'll leave it here incase we plan to re-use it. diff --git a/code/modules/mob/living/silicon/robot/robot_vr.dm b/code/modules/mob/living/silicon/robot/robot_vr.dm index 840026946f..21011e84c7 100644 --- a/code/modules/mob/living/silicon/robot/robot_vr.dm +++ b/code/modules/mob/living/silicon/robot/robot_vr.dm @@ -53,7 +53,8 @@ "zoomba-service", "zoomba-combat", "zoomba-combat-roll", - "zoomba-combat-shield" + "zoomba-combat-shield", + "spiderscience" ) //List of all used sprites that are in robots_vr.dmi diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index b6cf748fb8..b9c2c60c47 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -153,18 +153,6 @@ show_malf_ai() ..() -// this function displays the stations manifest in a separate window -/mob/living/silicon/proc/show_station_manifest() - var/dat = "
" - if(!data_core) - to_chat(src, "There is no data to form a manifest with. Contact your Nanotrasen administrator.") - return - dat += data_core.get_manifest(1) //The 1 makes it monochrome. - - var/datum/browser/popup = new(src, "Crew Manifest", "Crew Manifest", 370, 420, src) - popup.set_content(dat) - popup.open() - //can't inject synths /mob/living/silicon/can_inject(var/mob/user, var/error_msg) if(error_msg) diff --git a/code/modules/mob/living/silicon/subystems.dm b/code/modules/mob/living/silicon/subystems.dm index be6a68591d..890f1a8b37 100644 --- a/code/modules/mob/living/silicon/subystems.dm +++ b/code/modules/mob/living/silicon/subystems.dm @@ -2,6 +2,7 @@ var/register_alarms = 1 var/datum/tgui_module/alarm_monitor/all/robot/alarm_monitor var/datum/tgui_module/atmos_control/robot/atmos_control + var/datum/tgui_module/crew_manifest/robot/crew_manifest var/datum/tgui_module/crew_monitor/robot/crew_monitor var/datum/tgui_module/law_manager/robot/law_manager var/datum/tgui_module/power_monitor/robot/power_monitor @@ -10,6 +11,7 @@ /mob/living/silicon var/list/silicon_subsystems = list( /mob/living/silicon/proc/subsystem_alarm_monitor, + /mob/living/silicon/proc/subsystem_crew_manifest, /mob/living/silicon/proc/subsystem_law_manager ) @@ -17,6 +19,7 @@ silicon_subsystems = list( /mob/living/silicon/proc/subsystem_alarm_monitor, /mob/living/silicon/proc/subsystem_atmos_control, + /mob/living/silicon/proc/subsystem_crew_manifest, /mob/living/silicon/proc/subsystem_crew_monitor, /mob/living/silicon/proc/subsystem_law_manager, /mob/living/silicon/proc/subsystem_power_monitor, @@ -30,6 +33,7 @@ /mob/living/silicon/proc/init_subsystems() alarm_monitor = new(src) atmos_control = new(src) + crew_manifest = new(src) crew_monitor = new(src) law_manager = new(src) power_monitor = new(src) @@ -60,6 +64,15 @@ atmos_control.tgui_interact(usr) +/******************** +* Crew Manifest * +********************/ +/mob/living/silicon/proc/subsystem_crew_manifest() + set category = "Subystems" + set name = "Crew Manifest" + + crew_manifest.tgui_interact(usr) + /******************** * Crew Monitor * ********************/ diff --git a/code/modules/mob/living/simple_mob/simple_mob.dm b/code/modules/mob/living/simple_mob/simple_mob.dm index 3a27d98d01..f3bf4543db 100644 --- a/code/modules/mob/living/simple_mob/simple_mob.dm +++ b/code/modules/mob/living/simple_mob/simple_mob.dm @@ -271,18 +271,22 @@ // Harvest an animal's delicious byproducts -/mob/living/simple_mob/proc/harvest(var/mob/user) +/mob/living/simple_mob/proc/harvest(var/mob/user, var/invisible) var/actual_meat_amount = max(1,(meat_amount/2)) + var/attacker_name = user.name + if(invisible) + attacker_name = "someone" + if(meat_type && actual_meat_amount>0 && (stat == DEAD)) for(var/i=0;i[user] chops up \the [src]!") + user.visible_message("[attacker_name] chops up \the [src]!") new/obj/effect/decal/cleanable/blood/splatter(get_turf(src)) qdel(src) else - user.visible_message("[user] butchers \the [src] messily!") + user.visible_message("[attacker_name] butchers \the [src] messily!") gib() diff --git a/code/modules/mob/living/simple_mob/simple_mob_vr.dm b/code/modules/mob/living/simple_mob/simple_mob_vr.dm index 6b2d4bb6fe..ef631fa897 100644 --- a/code/modules/mob/living/simple_mob/simple_mob_vr.dm +++ b/code/modules/mob/living/simple_mob/simple_mob_vr.dm @@ -244,17 +244,23 @@ "The stomach glorps and gurgles as it tries to work you into slop.") /mob/living/simple_mob/Bumped(var/atom/movable/AM, yes) - if(ismob(AM)) - var/mob/tmob = AM - if(will_eat(tmob) && !istype(tmob, type) && prob(vore_bump_chance) && !ckey) //check if they decide to eat. Includes sanity check to prevent cannibalism. - if(tmob.canmove && prob(vore_pounce_chance)) //if they'd pounce for other noms, pounce for these too, otherwise still try and eat them if they hold still - tmob.Weaken(5) - tmob.visible_message("\the [src] [vore_bump_emote] \the [tmob]!!") - set_AI_busy(TRUE) + if(tryBumpNom(AM)) + return + ..() + +/mob/living/simple_mob/proc/tryBumpNom(var/mob/tmob) + //returns TRUE if we actually start an attempt to bumpnom, FALSE if checks fail or the random bump nom chance fails + if(istype(tmob) && will_eat(tmob) && !istype(tmob, type) && prob(vore_bump_chance) && !ckey) //check if they decide to eat. Includes sanity check to prevent cannibalism. + if(tmob.canmove && prob(vore_pounce_chance)) //if they'd pounce for other noms, pounce for these too, otherwise still try and eat them if they hold still + tmob.Weaken(5) + tmob.visible_message("\the [src] [vore_bump_emote] \the [tmob]!!") + set_AI_busy(TRUE) + spawn() animal_nom(tmob) update_icon() set_AI_busy(FALSE) - ..() + return TRUE + return FALSE // Checks to see if mob doesn't like this kind of turf /mob/living/simple_mob/IMove(newloc) diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/farm animals/chicken.dm b/code/modules/mob/living/simple_mob/subtypes/animal/farm animals/chicken.dm index dbedc27aa0..d713ade614 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/farm animals/chicken.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/farm animals/chicken.dm @@ -25,7 +25,7 @@ GLOBAL_VAR_INIT(chicken_count, 0) // How mant chickens DO we have? say_list_type = /datum/say_list/chicken meat_amount = 2 - meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/chicken var/eggsleft = 0 var/body_color @@ -125,7 +125,7 @@ GLOBAL_VAR_INIT(chicken_count, 0) // How mant chickens DO we have? say_list_type = /datum/say_list/chick meat_amount = 1 - meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat + meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/chicken var/amount_grown = 0 diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/thermic.dm b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/thermic.dm index 7abb7156d5..d51f6422fe 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/thermic.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/thermic.dm @@ -28,6 +28,7 @@ melee_damage_lower = 10 melee_damage_upper = 25 + attack_armor_pen = 15 heat_resist = 0.75 cold_resist = -0.50 diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/pets/parrot.dm b/code/modules/mob/living/simple_mob/subtypes/animal/pets/parrot.dm index 8d09b18fea..848fb7fafa 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/pets/parrot.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/pets/parrot.dm @@ -1,252 +1,253 @@ -// Parrots can talk, and may repeat things it hears. -/mob/living/simple_mob/animal/passive/bird/parrot - name = "parrot" - description_info = "You can give it a headset by clicking on it with a headset. \ - To remove it, click the bird while on grab intent." - has_langs = list("Galactic Common", "Bird") - - ai_holder_type = /datum/ai_holder/simple_mob/passive/parrot - - // A headset, so that talking parrots can yell at the crew over comms. - // If set to a type, on initialize it will be instantiated into that type. - var/obj/item/device/radio/headset/my_headset = null - -// Say list -/datum/say_list/bird/poly - speak = list( - "Poly wanna cracker!", - "Check the singulo, you chucklefucks!", - "Wire the solars, you lazy bums!", - "WHO TOOK THE DAMN HARDSUITS?", - "OH GOD ITS FREE CALL THE SHUTTLE", - "Danger! Crystal hyperstructure instability!", - "CRYSTAL DELAMINATION IMMINENT.", - "Tweet tweet, I'm a Teshari.", - "Chitters.", - "Meteors have been detected on a collision course with the station!" - ) - -// Lets the AI use headsets. -// Player-controlled parrots will need to do it manually. -/mob/living/simple_mob/animal/passive/bird/parrot/ISay(message) - if(my_headset && prob(50)) - var/list/keys = list() - for(var/channel in my_headset.channels) - var/key = get_radio_key_from_channel(channel) - if(key) - keys += key - if(keys.len) - var/key_used = pick(keys) - return say("[key_used] [message]") - return say(message) - -// Ugly saycode so parrots can use their headsets. -/mob/living/simple_mob/animal/passive/bird/parrot/handle_message_mode(message_mode, message, verb, speaking, used_radios) - ..() - if(message_mode) - if(my_headset && istype(my_headset, /obj/item/device/radio)) - my_headset.talk_into(src, message, message_mode, verb, speaking) - used_radios += my_headset - -// Clicked on while holding an object. -/mob/living/simple_mob/animal/passive/bird/parrot/attackby(obj/item/I, mob/user) - if(istype(I, /obj/item/device/radio/headset)) - give_headset(I, user) - return - return ..() - -// Clicked on by empty hand. -/mob/living/simple_mob/animal/passive/bird/parrot/attack_hand(mob/living/L) - if(L.a_intent == I_GRAB && my_headset) - remove_headset(L) - else - ..() - - -/mob/living/simple_mob/animal/passive/bird/parrot/proc/give_headset(obj/item/device/radio/headset/new_headset, mob/living/user) - if(!istype(new_headset)) - to_chat(user, span("warning", "\The [new_headset] isn't a headset.")) - return - if(my_headset) - to_chat(user, span("warning", "\The [src] is already wearing \a [my_headset].")) - return - else - user.drop_item(new_headset) - my_headset = new_headset - new_headset.forceMove(src) - to_chat(user, span("warning", "You place \a [new_headset] on \the [src]. You monster.")) - to_chat(src, span("notice", "\The [user] gives you \a [new_headset]. You should put it to good use immediately.")) - return - -/mob/living/simple_mob/animal/passive/bird/parrot/proc/remove_headset(mob/living/user) - if(!my_headset) - to_chat(user, "\The [src] doesn't have a headset to remove, thankfully.") - else - ISay("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") - my_headset.forceMove(get_turf(src)) - user.put_in_hands(my_headset) - to_chat(user, span("notice", "You take away \the [src]'s [my_headset.name]. Finally.")) - to_chat(src, span("warning", "\The [user] takes your [my_headset.name] away! How cruel!")) - my_headset = null - -/mob/living/simple_mob/animal/passive/bird/parrot/examine(mob/user) - . = ..() - if(my_headset) - . += "It is wearing \a [my_headset]." - -/mob/living/simple_mob/animal/passive/bird/parrot/Initialize() - if(my_headset) - my_headset = new my_headset(src) - return ..() - -// Subtypes. - -// Best Bird -/mob/living/simple_mob/animal/passive/bird/parrot/poly - name = "Poly" - desc = "It's a parrot. An expert on quantum cracker theory." - icon_state = "poly" - icon_rest = "poly-held" - icon_dead = "poly-dead" - tt_desc = "E Ara macao" - //my_headset = /obj/item/device/radio/headset/headset_eng //VOREStation Removal - say_list_type = /datum/say_list/bird/poly - -// Best Bird with best headset. -/mob/living/simple_mob/animal/passive/bird/parrot/poly/ultimate - my_headset = /obj/item/device/radio/headset/omni - -/mob/living/simple_mob/animal/passive/bird/parrot/kea - name = "kea" - desc = "A species of parrot. On Earth, they are unique among other parrots for residing in alpine climates. \ - They are known to be intelligent and curious, which has made some consider them a pest." - icon_state = "kea" - icon_rest = "kea-held" - icon_dead = "kea-dead" - tt_desc = "E Nestor notabilis" - -/mob/living/simple_mob/animal/passive/bird/parrot/eclectus - name = "eclectus" - desc = "A species of parrot, this species features extreme sexual dimorphism in their plumage's colors. \ - A male eclectus has emerald green plumage, where as a female eclectus has red and purple plumage." - icon_state = "eclectus" - icon_rest = "eclectus-held" - icon_dead = "eclectus-dead" - tt_desc = "E Eclectus roratus" - -/mob/living/simple_mob/animal/passive/bird/parrot/eclectus/Initialize() - gender = pick(MALE, FEMALE) - if(gender == FEMALE) - icon_state = "eclectusf" - icon_rest = "eclectusf-held" - icon_dead = "eclectusf-dead" - return ..() - -/mob/living/simple_mob/animal/passive/bird/parrot/grey_parrot - name = "grey parrot" - desc = "A species of parrot. This one is predominantly grey, but has red tail feathers." - icon_state = "agrey" - icon_rest = "agrey-held" - icon_dead = "agrey-dead" - tt_desc = "E Psittacus erithacus" - -/mob/living/simple_mob/animal/passive/bird/parrot/black_headed_caique - name = "black-headed caique" - desc = "A species of parrot, these birds have a distinct black color on their heads, distinguishing them from their relative Caiques." - icon_state = "bcaique" - icon_rest = "bcaique-held" - icon_dead = "bcaique-dead" - tt_desc = "E Pionites melanocephalus" - -/mob/living/simple_mob/animal/passive/bird/parrot/white_caique - name = "white-bellied caique" - desc = "A species of parrot, they are also known as the Green-Thighed Parrot." - icon_state = "wcaique" - icon_rest = "wcaique-held" - icon_dead = "wcaique-dead" - tt_desc = "E Pionites leucogaster" - -/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar - name = "budgerigar" - desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \ - This one is has its natural colors of green and yellow." - icon_state = "gbudge" - icon_rest = "gbudge-held" - icon_dead = "gbudge-dead" - tt_desc = "E Melopsittacus undulatus" - -/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/blue - icon_state = "bbudge" - icon_rest = "bbudge-held" - icon_dead = "bbudge-dead" - desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \ - This one has a mutation which altered its color to be blue instead of green and yellow." - -/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/bluegreen - icon_state = "bgbudge" - icon_rest = "bgbudge-held" - icon_dead = "bgbudge-dead" - desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \ - This one has a mutation which altered its color to be a mix of blue and green." - -/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel - name = "cockatiel" - desc = "A species of parrot. This one has a highly visible crest." - icon_state = "tiel" - icon_rest = "tiel-held" - icon_dead = "tiel-dead" - tt_desc = "E Nymphicus hollandicus" - -/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/white - icon_state = "wtiel" - icon_rest = "wtiel-held" - icon_dead = "wtiel-dead" - -/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/yellowish - icon_state = "luttiel" - icon_rest = "luttiel-held" - icon_dead = "luttiel-dead" - -/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/grey - icon_state = "blutiel" // idk why this is blu. - icon_rest = "blutiel-held" - icon_dead = "blutiel-dead" - -// This actually might be the yellow-crested cockatoo but idk. -/mob/living/simple_mob/animal/passive/bird/parrot/sulphur_cockatoo - name = "sulphur-crested cockatoo" - desc = "A species of parrot. This one has an expressive yellow crest. Their underwing and tail feathers are also yellow." - icon_state = "too" - icon_rest = "too-held" - icon_dead = "too-dead" - tt_desc = "E Cacatua galerita" - -// This was originally called 'hooded_too', which might not mean the unbrella cockatoo but idk. -/mob/living/simple_mob/animal/passive/bird/parrot/white_cockatoo - name = "white cockatoo" - desc = "A species of parrot. This one is also known as the Umbrella Cockatoo, due to the semicircular shape of its crest." - icon_state = "utoo" - icon_rest = "utoo-held" - icon_dead = "utoo-dead" - tt_desc = "E Cacatua alba" - -/mob/living/simple_mob/animal/passive/bird/parrot/pink_cockatoo - name = "pink cockatoo" - desc = "A species of parrot. This one is also known as Major Mitchell's cockatoo, \ - in honor of a human surveyor and explorer who existed before humans fully explored their home planet." - icon_state = "mtoo" - icon_rest = "mtoo-held" - icon_dead = "mtoo-dead" - tt_desc = "E Lophochroa leadbeateri" - - -// AI -/datum/ai_holder/simple_mob/passive/parrot - speak_chance = 2 - base_wander_delay = 8 - -/datum/ai_holder/simple_mob/passive/parrot/on_hear_say(mob/living/speaker, message) - if(holder.stat || !holder.say_list || !message || speaker == holder) - return - var/datum/say_list/S = holder.say_list - S.speak |= message \ No newline at end of file +// Parrots can talk, and may repeat things it hears. +/mob/living/simple_mob/animal/passive/bird/parrot + name = "parrot" + description_info = "You can give it a headset by clicking on it with a headset. \ + To remove it, click the bird while on grab intent." + has_langs = list("Galactic Common", "Bird") + + ai_holder_type = /datum/ai_holder/simple_mob/passive/parrot + + // A headset, so that talking parrots can yell at the crew over comms. + // If set to a type, on initialize it will be instantiated into that type. + var/obj/item/device/radio/headset/my_headset = null + +// Say list +/datum/say_list/bird/poly + speak = list( + "Poly wanna cracker!", + "Check the singulo, you chucklefucks!", + "Wire the solars, you lazy bums!", + "WHO TOOK THE DAMN HARDSUITS?", + "OH GOD ITS FREE CALL THE SHUTTLE", + "Danger! Crystal hyperstructure instability!", + "CRYSTAL DELAMINATION IMMINENT.", + "Tweet tweet, I'm a Teshari.", + "Chitters.", + "Meteors have been detected on a collision course with the station!" + ) + +// Lets the AI use headsets. +// Player-controlled parrots will need to do it manually. +/mob/living/simple_mob/animal/passive/bird/parrot/ISay(message) + if(my_headset && prob(50)) + var/list/keys = list() + for(var/channel in my_headset.channels) + var/key = get_radio_key_from_channel(channel) + if(key) + keys += key + if(keys.len) + var/key_used = pick(keys) + return say("[key_used] [message]") + return say(message) + +// Ugly saycode so parrots can use their headsets. +/mob/living/simple_mob/animal/passive/bird/parrot/handle_message_mode(message_mode, message, verb, speaking, used_radios) + ..() + if(message_mode) + if(my_headset && istype(my_headset, /obj/item/device/radio)) + my_headset.talk_into(src, message, message_mode, verb, speaking) + used_radios += my_headset + +// Clicked on while holding an object. +/mob/living/simple_mob/animal/passive/bird/parrot/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/device/radio/headset)) + give_headset(I, user) + return + return ..() + +// Clicked on by empty hand. +/mob/living/simple_mob/animal/passive/bird/parrot/attack_hand(mob/living/L) + if(L.a_intent == I_GRAB && my_headset) + remove_headset(L) + else + ..() + + +/mob/living/simple_mob/animal/passive/bird/parrot/proc/give_headset(obj/item/device/radio/headset/new_headset, mob/living/user) + if(!istype(new_headset)) + to_chat(user, span("warning", "\The [new_headset] isn't a headset.")) + return + if(my_headset) + to_chat(user, span("warning", "\The [src] is already wearing \a [my_headset].")) + return + else + user.drop_item(new_headset) + my_headset = new_headset + new_headset.forceMove(src) + to_chat(user, span("warning", "You place \a [new_headset] on \the [src]. You monster.")) + to_chat(src, span("notice", "\The [user] gives you \a [new_headset]. You should put it to good use immediately.")) + return + +/mob/living/simple_mob/animal/passive/bird/parrot/proc/remove_headset(mob/living/user) + if(!my_headset) + to_chat(user, "\The [src] doesn't have a headset to remove, thankfully.") + else + ISay("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") + my_headset.forceMove(get_turf(src)) + user.put_in_hands(my_headset) + to_chat(user, span("notice", "You take away \the [src]'s [my_headset.name]. Finally.")) + to_chat(src, span("warning", "\The [user] takes your [my_headset.name] away! How cruel!")) + my_headset = null + +/mob/living/simple_mob/animal/passive/bird/parrot/examine(mob/user) + . = ..() + if(my_headset) + . += "It is wearing \a [my_headset]." + +/mob/living/simple_mob/animal/passive/bird/parrot/Initialize() + if(my_headset) + my_headset = new my_headset(src) + return ..() + +// Subtypes. + +// Best Bird +/mob/living/simple_mob/animal/passive/bird/parrot/poly + name = "Poly" + desc = "It's a parrot. An expert on quantum cracker theory." + icon_state = "poly" + icon_rest = "poly-held" + icon_dead = "poly-dead" + tt_desc = "E Ara macao" + attack_armor_pen = 20 //HE HAS THE B E A K + my_headset = /obj/item/device/radio/headset/headset_eng + say_list_type = /datum/say_list/bird/poly + +// Best Bird with best headset. +/mob/living/simple_mob/animal/passive/bird/parrot/poly/ultimate + my_headset = /obj/item/device/radio/headset/omni + +/mob/living/simple_mob/animal/passive/bird/parrot/kea + name = "kea" + desc = "A species of parrot. On Earth, they are unique among other parrots for residing in alpine climates. \ + They are known to be intelligent and curious, which has made some consider them a pest." + icon_state = "kea" + icon_rest = "kea-held" + icon_dead = "kea-dead" + tt_desc = "E Nestor notabilis" + +/mob/living/simple_mob/animal/passive/bird/parrot/eclectus + name = "eclectus" + desc = "A species of parrot, this species features extreme sexual dimorphism in their plumage's colors. \ + A male eclectus has emerald green plumage, where as a female eclectus has red and purple plumage." + icon_state = "eclectus" + icon_rest = "eclectus-held" + icon_dead = "eclectus-dead" + tt_desc = "E Eclectus roratus" + +/mob/living/simple_mob/animal/passive/bird/parrot/eclectus/Initialize() + gender = pick(MALE, FEMALE) + if(gender == FEMALE) + icon_state = "eclectusf" + icon_rest = "eclectusf-held" + icon_dead = "eclectusf-dead" + return ..() + +/mob/living/simple_mob/animal/passive/bird/parrot/grey_parrot + name = "grey parrot" + desc = "A species of parrot. This one is predominantly grey, but has red tail feathers." + icon_state = "agrey" + icon_rest = "agrey-held" + icon_dead = "agrey-dead" + tt_desc = "E Psittacus erithacus" + +/mob/living/simple_mob/animal/passive/bird/parrot/black_headed_caique + name = "black-headed caique" + desc = "A species of parrot, these birds have a distinct black color on their heads, distinguishing them from their relative Caiques." + icon_state = "bcaique" + icon_rest = "bcaique-held" + icon_dead = "bcaique-dead" + tt_desc = "E Pionites melanocephalus" + +/mob/living/simple_mob/animal/passive/bird/parrot/white_caique + name = "white-bellied caique" + desc = "A species of parrot, they are also known as the Green-Thighed Parrot." + icon_state = "wcaique" + icon_rest = "wcaique-held" + icon_dead = "wcaique-dead" + tt_desc = "E Pionites leucogaster" + +/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar + name = "budgerigar" + desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \ + This one is has its natural colors of green and yellow." + icon_state = "gbudge" + icon_rest = "gbudge-held" + icon_dead = "gbudge-dead" + tt_desc = "E Melopsittacus undulatus" + +/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/blue + icon_state = "bbudge" + icon_rest = "bbudge-held" + icon_dead = "bbudge-dead" + desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \ + This one has a mutation which altered its color to be blue instead of green and yellow." + +/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/bluegreen + icon_state = "bgbudge" + icon_rest = "bgbudge-held" + icon_dead = "bgbudge-dead" + desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \ + This one has a mutation which altered its color to be a mix of blue and green." + +/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel + name = "cockatiel" + desc = "A species of parrot. This one has a highly visible crest." + icon_state = "tiel" + icon_rest = "tiel-held" + icon_dead = "tiel-dead" + tt_desc = "E Nymphicus hollandicus" + +/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/white + icon_state = "wtiel" + icon_rest = "wtiel-held" + icon_dead = "wtiel-dead" + +/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/yellowish + icon_state = "luttiel" + icon_rest = "luttiel-held" + icon_dead = "luttiel-dead" + +/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/grey + icon_state = "blutiel" // idk why this is blu. + icon_rest = "blutiel-held" + icon_dead = "blutiel-dead" + +// This actually might be the yellow-crested cockatoo but idk. +/mob/living/simple_mob/animal/passive/bird/parrot/sulphur_cockatoo + name = "sulphur-crested cockatoo" + desc = "A species of parrot. This one has an expressive yellow crest. Their underwing and tail feathers are also yellow." + icon_state = "too" + icon_rest = "too-held" + icon_dead = "too-dead" + tt_desc = "E Cacatua galerita" + +// This was originally called 'hooded_too', which might not mean the unbrella cockatoo but idk. +/mob/living/simple_mob/animal/passive/bird/parrot/white_cockatoo + name = "white cockatoo" + desc = "A species of parrot. This one is also known as the Umbrella Cockatoo, due to the semicircular shape of its crest." + icon_state = "utoo" + icon_rest = "utoo-held" + icon_dead = "utoo-dead" + tt_desc = "E Cacatua alba" + +/mob/living/simple_mob/animal/passive/bird/parrot/pink_cockatoo + name = "pink cockatoo" + desc = "A species of parrot. This one is also known as Major Mitchell's cockatoo, \ + in honor of a human surveyor and explorer who existed before humans fully explored their home planet." + icon_state = "mtoo" + icon_rest = "mtoo-held" + icon_dead = "mtoo-dead" + tt_desc = "E Lophochroa leadbeateri" + + +// AI +/datum/ai_holder/simple_mob/passive/parrot + speak_chance = 2 + base_wander_delay = 8 + +/datum/ai_holder/simple_mob/passive/parrot/on_hear_say(mob/living/speaker, message) + if(holder.stat || !holder.say_list || !message || speaker == holder) + return + var/datum/say_list/S = holder.say_list + S.speak |= message diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/alien.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/alien.dm index 9502940343..d3cda1f22b 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/space/alien.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/alien.dm @@ -18,10 +18,12 @@ maxHealth = 100 health = 100 + see_in_dark = 7 harm_intent_damage = 5 melee_damage_lower = 25 melee_damage_upper = 25 + attack_armor_pen = 15 //It's a freaking alien. attack_sharp = TRUE attack_edge = TRUE @@ -121,4 +123,4 @@ /mob/living/simple_mob/animal/space/alien/death() ..() visible_message("[src] lets out a waning guttural screech, green blood bubbling from its maw...") - playsound(src, 'sound/voice/hiss6.ogg', 100, 1) \ No newline at end of file + playsound(src, 'sound/voice/hiss6.ogg', 100, 1) diff --git a/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs.dm index 59a4d1c8c8..2770d6ff98 100644 --- a/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs.dm +++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs.dm @@ -24,6 +24,7 @@ harm_intent_damage = 5 melee_damage_lower = 15 //Tac Knife damage melee_damage_upper = 15 + attack_armor_pen = 20 attack_sharp = 1 attack_edge = 1 attacktext = list("slashed", "stabbed") diff --git a/code/modules/mob/living/simple_mob/subtypes/humanoid/pirates.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/pirates.dm index cc16cebedc..3927b1dcf1 100644 --- a/code/modules/mob/living/simple_mob/subtypes/humanoid/pirates.dm +++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/pirates.dm @@ -15,7 +15,7 @@ harm_intent_damage = 5 melee_damage_lower = 30 melee_damage_upper = 30 - attack_armor_pen = 50 + attack_armor_pen = 30 attack_sharp = 1 attack_edge = 1 diff --git a/code/modules/mob/living/simple_mob/subtypes/humanoid/russian.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/russian.dm index ce679f90de..121e112a7a 100644 --- a/code/modules/mob/living/simple_mob/subtypes/humanoid/russian.dm +++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/russian.dm @@ -14,6 +14,7 @@ response_harm = "hits" harm_intent_damage = 5 + attack_armor_pen = 15 melee_damage_lower = 15 melee_damage_upper = 15 attacktext = list("punched") diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/drones/combat_drone.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/drones/combat_drone.dm index 7c35258a7f..6766cd67d3 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/drones/combat_drone.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/drones/combat_drone.dm @@ -34,9 +34,6 @@ desc = "An automated combat drone armed with state of the art weaponry and shielding." catalogue_data = list(/datum/category_item/catalogue/technology/drone/combat_drone) - icon = 'icons/mob/animal_vr64x64.dmi' //VOREStation Add - pixel_x = -16 //VOREStation Add - pixel_y = -16 //VOREStation Add icon_state = "drone" icon_living = "drone" icon_dead = "drone_dead" diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/drones/combat_drone_vr.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/drones/combat_drone_vr.dm new file mode 100644 index 0000000000..09956c1579 --- /dev/null +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/drones/combat_drone_vr.dm @@ -0,0 +1,8 @@ +/mob/living/simple_mob/mechanical/combat_drone + icon = 'icons/mob/animal_vr64x64.dmi' + + pixel_x = -16 + default_pixel_x = -16 + pixel_y = -16 + default_pixel_y = -16 + diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/golem.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/golem.dm index 808e5c6c38..5071f10b34 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/golem.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/golem.dm @@ -1,152 +1,153 @@ -// The GOLEM is a spell-flinging synthetic. - -/mob/living/simple_mob/mechanical/technomancer_golem - name = "unknown synthetic" - desc = "A rather unusual looking synthetic." - icon = 'icons/mob/mob.dmi' - icon_state = "golem" - health = 300 - maxHealth = 300 - - faction = "golem" - - response_help = "pets" - response_disarm = "pushes away" - response_harm = "punches" - harm_intent_damage = 3 - friendly = "hugs" - - melee_damage_lower = 30 // It has a built in esword. - melee_damage_upper = 30 - attack_sound = 'sound/weapons/blade1.ogg' - attacktext = list("slashed") - melee_attack_delay = 0.5 SECONDS // Even has custom attack animations. - ranged_attack_delay = 0.5 SECONDS - special_attack_delay = 1 SECOND - - special_attack_min_range = 0 - special_attack_max_range = 7 - - ai_holder_type = /datum/ai_holder/simple_mob/melee - - var/obj/item/weapon/technomancer_core/golem/core = null - var/obj/item/weapon/spell/active_spell = null // Shield and ranged spells - var/mob/living/master = null - var/casting = FALSE // Used to ensure the correct animation is played. Testing if a spell exists won't always work as some spells delete themselves upon use. - - var/list/known_spells = list( - "beam" = /obj/item/weapon/spell/projectile/beam, - "chain lightning" = /obj/item/weapon/spell/projectile/chain_lightning, - "force missile" = /obj/item/weapon/spell/projectile/force_missile, - "ionic bolt" = /obj/item/weapon/spell/projectile/ionic_bolt, - "lightning" = /obj/item/weapon/spell/projectile/lightning, - "blink" = /obj/item/weapon/spell/blink, - "dispel" = /obj/item/weapon/spell/dispel, - "oxygenate" = /obj/item/weapon/spell/oxygenate, - "mend life" = /obj/item/weapon/spell/modifier/mend_life, - "mend synthetic" = /obj/item/weapon/spell/modifier/mend_synthetic, - "mend organs" = /obj/item/weapon/spell/mend_organs, - "purify" = /obj/item/weapon/spell/modifier/purify, - "resurrect" = /obj/item/weapon/spell/resurrect, - "passwall" = /obj/item/weapon/spell/passwall, - "repel missiles" = /obj/item/weapon/spell/modifier/repel_missiles, - "corona" = /obj/item/weapon/spell/modifier/corona, - "haste" = /obj/item/weapon/spell/modifier/haste - ) - -/mob/living/simple_mob/mechanical/technomancer_golem/Initialize() - core = new(src) - return ..() - -/mob/living/simple_mob/mechanical/technomancer_golem/Destroy() - qdel(core) - return ..() - -/mob/living/simple_mob/mechanical/technomancer_golem/unref_spell() - active_spell = null - return ..() - -/mob/living/simple_mob/mechanical/technomancer_golem/death() - ..() - visible_message("\The [src] disintegrates!") - new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc) - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - qdel(src) - -/mob/living/simple_mob/mechanical/technomancer_golem/place_spell_in_hand(var/path) - if(!path || !ispath(path)) - return FALSE - if(active_spell) - qdel(active_spell) - - active_spell = new path(src) - -/mob/living/simple_mob/mechanical/technomancer_golem/verb/test_giving_spells() - var/choice = input(usr, "What spell?", "Give spell") as null|anything in known_spells - if(choice) - place_spell_in_hand(known_spells[choice]) - else - qdel(active_spell) - -/mob/living/simple_mob/mechanical/technomancer_golem/get_technomancer_core() - return core - -/mob/living/simple_mob/mechanical/technomancer_golem/can_special_attack(atom/A) - if(active_spell) // Don't bother checking everything else if no spell is ready. - return ..() - return FALSE - -/mob/living/simple_mob/mechanical/technomancer_golem/should_special_attack(atom/A) - return instability < 50 // Don't kill ourselves by casting everything. - - -/mob/living/simple_mob/mechanical/technomancer_golem/do_special_attack(atom/A) - var/proximity = Adjacent(A) - if(active_spell) - if(proximity && active_spell.cast_methods & CAST_MELEE) // Use melee method if available and close enough. - return active_spell.on_melee_cast(A, src) - else if(active_spell.cast_methods & CAST_RANGED) // Otherwise use ranged if possible. Will also work for point-blank range. - return active_spell.on_ranged_cast(A, src) - return ..() - -/mob/living/simple_mob/mechanical/technomancer_golem/melee_pre_animation(atom/A) - if(active_spell && active_spell.cast_methods & CAST_MELEE|CAST_RANGED) // If they're trying to melee-cast a spell, use the special animation instead. - special_pre_animation(A) - return - - flick("golem_pre_melee", src) // To force the animation to restart. - icon_living = "golem_pre_melee" // The animation will hold after this point until melee_post_animation() gets called. - icon_state = "golem_pre_melee" - setClickCooldown(2) - -/mob/living/simple_mob/mechanical/technomancer_golem/melee_post_animation(atom/A) - if(casting) // Some spells delete themselves when used, so we use a different variable set earlier instead. - special_post_animation(A) - return - - flick("golem_post_melee", src) - icon_living = "golem" - icon_state = "golem" - setClickCooldown(6) - -/mob/living/simple_mob/mechanical/technomancer_golem/ranged_pre_animation(atom/A) - flick("golem_pre_ranged", src) - icon_living = "golem_pre_ranged" - icon_state = "golem_pre_ranged" - setClickCooldown(5) - -/mob/living/simple_mob/mechanical/technomancer_golem/ranged_post_animation(atom/A) - flick("golem_post_ranged", src) - icon_living = "golem" - icon_state = "golem" - setClickCooldown(5) - -/mob/living/simple_mob/mechanical/technomancer_golem/special_pre_animation(atom/A) - casting = TRUE - ranged_pre_animation(A) // Both have the same animation. - -/mob/living/simple_mob/mechanical/technomancer_golem/special_post_animation(atom/A) - casting = FALSE - ranged_post_animation(A) +// The GOLEM is a spell-flinging synthetic. + +/mob/living/simple_mob/mechanical/technomancer_golem + name = "unknown synthetic" + desc = "A rather unusual looking synthetic." + icon = 'icons/mob/mob.dmi' + icon_state = "golem" + health = 300 + maxHealth = 300 + + faction = "golem" + + response_help = "pets" + response_disarm = "pushes away" + response_harm = "punches" + harm_intent_damage = 3 + friendly = "hugs" + + melee_damage_lower = 30 // It has a built in esword. + melee_damage_upper = 30 + attack_armor_pen = 20 + attack_sound = 'sound/weapons/blade1.ogg' + attacktext = list("slashed") + melee_attack_delay = 0.5 SECONDS // Even has custom attack animations. + ranged_attack_delay = 0.5 SECONDS + special_attack_delay = 1 SECOND + + special_attack_min_range = 0 + special_attack_max_range = 7 + + ai_holder_type = /datum/ai_holder/simple_mob/melee + + var/obj/item/weapon/technomancer_core/golem/core = null + var/obj/item/weapon/spell/active_spell = null // Shield and ranged spells + var/mob/living/master = null + var/casting = FALSE // Used to ensure the correct animation is played. Testing if a spell exists won't always work as some spells delete themselves upon use. + + var/list/known_spells = list( + "beam" = /obj/item/weapon/spell/projectile/beam, + "chain lightning" = /obj/item/weapon/spell/projectile/chain_lightning, + "force missile" = /obj/item/weapon/spell/projectile/force_missile, + "ionic bolt" = /obj/item/weapon/spell/projectile/ionic_bolt, + "lightning" = /obj/item/weapon/spell/projectile/lightning, + "blink" = /obj/item/weapon/spell/blink, + "dispel" = /obj/item/weapon/spell/dispel, + "oxygenate" = /obj/item/weapon/spell/oxygenate, + "mend life" = /obj/item/weapon/spell/modifier/mend_life, + "mend synthetic" = /obj/item/weapon/spell/modifier/mend_synthetic, + "mend organs" = /obj/item/weapon/spell/mend_organs, + "purify" = /obj/item/weapon/spell/modifier/purify, + "resurrect" = /obj/item/weapon/spell/resurrect, + "passwall" = /obj/item/weapon/spell/passwall, + "repel missiles" = /obj/item/weapon/spell/modifier/repel_missiles, + "corona" = /obj/item/weapon/spell/modifier/corona, + "haste" = /obj/item/weapon/spell/modifier/haste + ) + +/mob/living/simple_mob/mechanical/technomancer_golem/Initialize() + core = new(src) + return ..() + +/mob/living/simple_mob/mechanical/technomancer_golem/Destroy() + qdel(core) + return ..() + +/mob/living/simple_mob/mechanical/technomancer_golem/unref_spell() + active_spell = null + return ..() + +/mob/living/simple_mob/mechanical/technomancer_golem/death() + ..() + visible_message("\The [src] disintegrates!") + new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc) + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + qdel(src) + +/mob/living/simple_mob/mechanical/technomancer_golem/place_spell_in_hand(var/path) + if(!path || !ispath(path)) + return FALSE + if(active_spell) + qdel(active_spell) + + active_spell = new path(src) + +/mob/living/simple_mob/mechanical/technomancer_golem/verb/test_giving_spells() + var/choice = input(usr, "What spell?", "Give spell") as null|anything in known_spells + if(choice) + place_spell_in_hand(known_spells[choice]) + else + qdel(active_spell) + +/mob/living/simple_mob/mechanical/technomancer_golem/get_technomancer_core() + return core + +/mob/living/simple_mob/mechanical/technomancer_golem/can_special_attack(atom/A) + if(active_spell) // Don't bother checking everything else if no spell is ready. + return ..() + return FALSE + +/mob/living/simple_mob/mechanical/technomancer_golem/should_special_attack(atom/A) + return instability < 50 // Don't kill ourselves by casting everything. + + +/mob/living/simple_mob/mechanical/technomancer_golem/do_special_attack(atom/A) + var/proximity = Adjacent(A) + if(active_spell) + if(proximity && active_spell.cast_methods & CAST_MELEE) // Use melee method if available and close enough. + return active_spell.on_melee_cast(A, src) + else if(active_spell.cast_methods & CAST_RANGED) // Otherwise use ranged if possible. Will also work for point-blank range. + return active_spell.on_ranged_cast(A, src) + return ..() + +/mob/living/simple_mob/mechanical/technomancer_golem/melee_pre_animation(atom/A) + if(active_spell && active_spell.cast_methods & CAST_MELEE|CAST_RANGED) // If they're trying to melee-cast a spell, use the special animation instead. + special_pre_animation(A) + return + + flick("golem_pre_melee", src) // To force the animation to restart. + icon_living = "golem_pre_melee" // The animation will hold after this point until melee_post_animation() gets called. + icon_state = "golem_pre_melee" + setClickCooldown(2) + +/mob/living/simple_mob/mechanical/technomancer_golem/melee_post_animation(atom/A) + if(casting) // Some spells delete themselves when used, so we use a different variable set earlier instead. + special_post_animation(A) + return + + flick("golem_post_melee", src) + icon_living = "golem" + icon_state = "golem" + setClickCooldown(6) + +/mob/living/simple_mob/mechanical/technomancer_golem/ranged_pre_animation(atom/A) + flick("golem_pre_ranged", src) + icon_living = "golem_pre_ranged" + icon_state = "golem_pre_ranged" + setClickCooldown(5) + +/mob/living/simple_mob/mechanical/technomancer_golem/ranged_post_animation(atom/A) + flick("golem_post_ranged", src) + icon_living = "golem" + icon_state = "golem" + setClickCooldown(5) + +/mob/living/simple_mob/mechanical/technomancer_golem/special_pre_animation(atom/A) + casting = TRUE + ranged_pre_animation(A) // Both have the same animation. + +/mob/living/simple_mob/mechanical/technomancer_golem/special_post_animation(atom/A) + casting = FALSE + ranged_post_animation(A) diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/hivebot.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/hivebot.dm index c90d0413be..667c514f0b 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/hivebot.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/hivebot.dm @@ -46,6 +46,7 @@ health = 1 LASERS_TO_KILL melee_damage_lower = 8 melee_damage_upper = 8 + attack_armor_pen = 5 /datum/ai_holder/simple_mob/hivebot pointblank = TRUE diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/ranged_damage_vr.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/ranged_damage_vr.dm index 3ac368a7ee..31c9cdf10f 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/ranged_damage_vr.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/ranged_damage_vr.dm @@ -1,4 +1,4 @@ -/datum/category_item/catalogue/technology/drone/hivebot/laser // Hivebot Scanner Data - This is for Laser Hivebots +/datum/category_item/catalogue/technology/drone/hivebot/rapidfire // Hivebot Scanner Data - This is for Rapidfire Hivebots name = "Drone - Rapidfire Hivebot" desc = "A drone that walks on several legs, with yellow/gold armor plating. It appears to have some sort of \ rifle, built for high-rate fire. Other than that, it has similar yellowish color \ diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/support_vr.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/support_vr.dm index 0003b78124..434ce659e8 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/support_vr.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/support_vr.dm @@ -5,7 +5,7 @@ to the other hivebots. Other than that, it has similar yellowish color to regular hivebots." value = CATALOGUER_REWARD_HARD -/datum/category_item/catalogue/technology/drone/hivebot/logistics // Hivebot Scanner Data - This is for Commander Hivebots +/datum/category_item/catalogue/technology/drone/hivebot/logistics // Hivebot Scanner Data - This is for Logistics Hivebots name = "Drone - Logistics Hivebot" desc = "A drone that walks on several legs, with yellow/gold armor plating. It appears to have some sort of \ ballistic weapon. It also appears to have supply deploying bays, and internal fabs to repair and buff their allies' special capabilities. \ diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/viscerator.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/viscerator.dm index 89281bf4fc..4545057bc6 100644 --- a/code/modules/mob/living/simple_mob/subtypes/mechanical/viscerator.dm +++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/viscerator.dm @@ -87,3 +87,9 @@ if(istype(L, /mob/living/simple_mob/mechanical/ward/monitor/crew)) // Also ignore friendly monitor wards return TRUE return L.assess_perp(src, FALSE, FALSE, TRUE, FALSE) <= 3 + +// Variant that has high armor pen. Slightly slower attack speed and movement. Meant to be dispersed in groups with other ones +/mob/living/simple_mob/mechanical/viscerator/piercing + attack_armor_pen = 20 + base_attack_cooldown = 10 // One attack a second or so. + movement_cooldown = 0.5 diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm b/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm index f5004db3c1..7b2da46008 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm @@ -89,6 +89,10 @@ ..() /mob/living/simple_mob/vore/hostile/morph/proc/assume(atom/movable/target) + var/mob/living/carbon/human/humantarget = target + if(istype(humantarget) && humantarget.resleeve_lock && ckey != humantarget.resleeve_lock) + to_chat(src, "[target] cannot be impersonated!") + return if(morphed) to_chat(src, "You must restore to your original form first!") return diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/oregrub.dm b/code/modules/mob/living/simple_mob/subtypes/vore/oregrub.dm new file mode 100644 index 0000000000..c4163733bd --- /dev/null +++ b/code/modules/mob/living/simple_mob/subtypes/vore/oregrub.dm @@ -0,0 +1,173 @@ +/datum/category_item/catalogue/fauna/oregrub + name = "Oregrub" + desc = "Some form of mutated space larva, they seem to feed on minerals. This makes them the natural enemy of miners. \ + To make matters worse, these creatures will flee when threatened. More than a few foolhardy miners have met their end chasing down oregrubs after some other hostile creature attacked them. \ + Their guts tend to contain undigested minerals, so miners who are quick (and not afraid to get their hands dirty) can reap some rewards from these leathery lithovores." + value = CATALOGUER_REWARD_EASY + +/datum/category_item/catalogue/fauna/lavagrub + name = "Lavagrub" + desc = "Some form of mutated space larva, they seem to feed on minerals. This makes them the natural enemy of miners. \ + To make matters worse, these creatures will flee when threatened. More than a few foolhardy miners have met their end chasing down oregrubs after some other hostile creature attacked them. \ + This particular variant seems to be even tougher and faster than its common brown kin, and its hide is laced with silicates that make it more durable. \ + On the plus side, it's sure to contain even more valuable minerals within its bowels, if you can catch up with it to crack it open..." + value = CATALOGUER_REWARD_MEDIUM + +/datum/ai_holder/simple_mob/oregrub + hostile = FALSE //docile, unless you hit them + retaliate = TRUE //they *may* bite you... + can_flee = TRUE //but they'd rather run away + dying_threshold = 1 //and ideally, we flee as soon as possible + flee_when_outmatched = TRUE //especially when outmatched + outmatched_threshold = 25 //and we're outmatched by... basically everything! + +/datum/ai_holder/simple_mob/oregrub/lava + outmatched_threshold = 15 + +/mob/living/simple_mob/vore/oregrub + name = "juvenile oregrub" + desc = "A young, leathery oregrub." + catalogue_data = list(/datum/category_item/catalogue/fauna/oregrub) + icon = 'icons/mob/vore.dmi' //all of these are placeholders + icon_state = "oregrub" + icon_living = "oregrub" + icon_dead = "oregrub-dead" + + faction = "grubs" + maxHealth = 50 //oregrubs are quite hardy + health = 50 + + melee_damage_lower = 1 + melee_damage_upper = 3 //low damage, they prefer to flee + + movement_cooldown = 8 + + meat_type = /obj/item/weapon/ore/coal + + response_help = "pokes" + response_disarm = "pushes" + response_harm = "roughly pushes" + + ai_holder_type = /datum/ai_holder/simple_mob/oregrub + say_list_type = /datum/say_list/oregrub + + var/poison_per_bite = 2.5 + var/poison_type = "thermite_v" //burn baby burn + var/poison_chance = 50 + + var/min_ore = 4 + var/max_ore = 7 + + vore_bump_chance = 0 //disabled for now + vore_bump_emote = "applies minimal effort to try and slurp up" + vore_active = 0 //disabled for now + vore_capacity = 1 + vore_pounce_chance = 0 //grubs only eat incapacitated targets + vore_default_mode = DM_DIGEST + + min_oxy = 0 + max_oxy = 0 + min_tox = 0 + max_tox = 0 + min_co2 = 0 + max_co2 = 0 + min_n2 = 0 + max_n2 = 0 + minbodytemp = 0 + maxbodytemp = 1000 + poison_resist = 1.0 + + //these things are resilient, on account of being infused with all the minerals they eat + armor = list( + "melee" = 25, + "bullet" = 15, + "laser" = 15, + "energy" = 0, + "bomb" = 25, + "bio" = 100, + "rad" = 100 + ) + +/mob/living/simple_mob/vore/oregrub/lava + name = "mature lavagrub" + desc = "A mature, rocky lavagrub" + catalogue_data = list(/datum/category_item/catalogue/fauna/lavagrub) + icon_state = "lavagrub" + icon_living = "lavagrub" + icon_dead = "lavagrub-dead" + + movement_cooldown = 5 + maxHealth = 75 //lavagrubs are really hardy + health = 75 + ai_holder_type = /datum/ai_holder/simple_mob/oregrub/lava + //lavagrubs have even more armor than oregrubs + armor = list( + "melee" = 50, + "bullet" = 25, + "laser" = 25, + "energy" = 0, + "bomb" = 50, + "bio" = 100, + "rad" = 100 + ) + + var/lava_min_ore = 6 + var/lava_max_ore = 10 + + poison_per_bite = 5 + poison_chance = 66 + +/datum/say_list/oregrub + emote_see = list("burbles", "chitters", "snuffles around for fresh ore") + +/mob/living/simple_mob/vore/oregrub/apply_melee_effects(var/atom/A) + if(isliving(A)) + var/mob/living/L = A + var/target_zone = pick(BP_TORSO,BP_TORSO,BP_TORSO,BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_HEAD) + if(L.can_inject(src, null, target_zone)) + inject_poison(L, target_zone) + +/mob/living/simple_mob/vore/oregrub/death() + visible_message("\The [src] shudders and collapses, expelling the ores it had devoured!") + var/i = rand(min_ore,max_ore) + while(i>1) + var/ore = pick(/obj/item/weapon/ore/glass,/obj/item/weapon/ore/coal,/obj/item/weapon/ore/iron,/obj/item/weapon/ore/lead,/obj/item/weapon/ore/marble,/obj/item/weapon/ore/phoron,/obj/item/weapon/ore/silver,/obj/item/weapon/ore/gold) + new ore(src.loc) + i-- + ..() + +/mob/living/simple_mob/vore/oregrub/lava/handle_light() + . = ..() + if(. == 0 && !is_dead()) + set_light(2.5, 1, COLOR_ORANGE) + return 1 + +/mob/living/simple_mob/vore/oregrub/lava/death() + set_light(0) + var/p = rand(lava_min_ore,lava_max_ore) + while(p>1) + var/ore = pick(/obj/item/weapon/ore/osmium,/obj/item/weapon/ore/uranium,/obj/item/weapon/ore/hydrogen,/obj/item/weapon/ore/diamond,/obj/item/weapon/ore/verdantium) + new ore(src.loc) + p-- + ..() + +// Does actual poison injection, after all checks passed. +/mob/living/simple_mob/vore/oregrub/proc/inject_poison(mob/living/L, target_zone) + if(prob(poison_chance)) + to_chat(L, "You feel fire running through your veins!") + L.reagents.add_reagent(poison_type, poison_per_bite) + +//I'm no good at writing this stuff, so I've just left it as placeholders and disabled the chances of them eating you. +/* +/mob/living/simple_mob/vore/oregrub/init_vore() + ..() + var/obj/belly/B = vore_selected + B.name = "stomach" + B.desc = "PLACEHOLDER!" + + B.emote_lists[DM_HOLD] = list( + "PLACEHOLDER!") + + B.emote_lists[DM_DIGEST] = list( + "PLACEHOLDER!") +*/ \ No newline at end of file diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm index ffaeef3c09..d965956dfe 100644 --- a/code/modules/mob/logout.dm +++ b/code/modules/mob/logout.dm @@ -1,5 +1,4 @@ /mob/Logout() - SSnanoui.user_logout(src) // this is used to clean up (remove) this user's Nano UIs SStgui.on_logout(src) // Cleanup any TGUIs the user has open player_list -= src disconnect_time = world.realtime //VOREStation Addition: logging when we disappear. diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 680021de9f..4d9a2e774a 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -84,7 +84,7 @@ else exclude_mobs = list(src) src.show_message(self_message, 1, blind_message, 2) - . = ..() + . = ..(message, blind_message, exclude_mobs) // Returns an amount of power drawn from the object (-1 if it's not viable). // If drain_check is set it will not actually drain power, just return a value. diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 7be3255cbd..c5066adb7c 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -202,7 +202,7 @@ var/mob/teleop = null var/turf/listed_turf = null //the current turf being examined in the stat panel - var/list/shouldnt_see = list() //list of objects that this mob shouldn't see in the stat panel. this silliness is needed because of AI alt+click and cult blood runes + var/list/shouldnt_see = list(/mob/observer/eye) //list of objects that this mob shouldn't see in the stat panel. this silliness is needed because of AI alt+click and cult blood runes var/list/active_genes=list() var/mob_size = MOB_MEDIUM diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 92856d72c8..75b2ccd07f 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -390,6 +390,9 @@ /mob/proc/Post_Incorpmove() return +/mob/proc/get_jetpack() + return + ///Process_Spacemove ///Called by /client/Move() ///For moving in space diff --git a/code/modules/mob/new_player/sprite_accessories_vr.dm b/code/modules/mob/new_player/sprite_accessories_vr.dm index 959e25505d..233c5a14f1 100644 --- a/code/modules/mob/new_player/sprite_accessories_vr.dm +++ b/code/modules/mob/new_player/sprite_accessories_vr.dm @@ -240,13 +240,6 @@ icon_state = "hair_fingerwave" species_allowed = list(SPECIES_VULPKANIN, SPECIES_XENOCHIMERA, SPECIES_TAJ, SPECIES_SERGAL, SPECIES_FENNEC, SPECIES_ZORREN_HIGH, SPECIES_PROTEAN) - teshari_fluffymohawk - name = "Teshari Fluffy Mohawk" - icon = 'icons/mob/human_face_vr.dmi' - icon_add = 'icons/mob/human_face_vr_add.dmi' - icon_state = "teshari_fluffymohawk" - species_allowed = list(SPECIES_TESHARI) - //Teshari things teshari icon_add = 'icons/mob/human_face_vr_add.dmi' @@ -290,6 +283,22 @@ teshari_mushroom icon_add = 'icons/mob/human_face_vr_add.dmi' + teshari_twies + icon_add = 'icons/mob/human_face_vr_add.dmi' + + teshari_backstrafe + icon_add = 'icons/mob/human_face_vr_add.dmi' + + teshari_longway + icon_add = 'icons/mob/human_face_vr_add.dmi' + + teshari_tree + icon_add = 'icons/mob/human_face_vr_add.dmi' + + teshari_fluffymohawk + icon = 'icons/mob/human_face_vr.dmi' + icon_add = 'icons/mob/human_face_vr_add.dmi' + //Skrell 'hairstyles' - these were requested for a chimera and screw it, if one wants to eat seafood, go nuts skr_tentacle_veryshort name = "Skrell Very Short Tentacles" @@ -1166,3 +1175,8 @@ icon_state = "dnose" color_blend_mode = ICON_MULTIPLY body_parts = list(BP_HEAD) + + bee_stripes + name = "bee stripes" + icon_state = "beestripes" + body_parts = list(BP_TORSO,BP_GROIN) \ No newline at end of file diff --git a/code/modules/modular_computers/NTNet/NTNet.dm b/code/modules/modular_computers/NTNet/NTNet.dm index 8370683522..6479f92a21 100644 --- a/code/modules/modular_computers/NTNet/NTNet.dm +++ b/code/modules/modular_computers/NTNet/NTNet.dm @@ -181,5 +181,8 @@ var/global/datum/ntnet/ntnet_global = new() return 1 return 0 - +/datum/ntnet/proc/get_chat_channel_by_id(id) + for(var/datum/ntnet_conversation/chan in chat_channels) + if(chan.id == id) + return chan diff --git a/code/modules/modular_computers/computers/modular_computer/core.dm b/code/modules/modular_computers/computers/modular_computer/core.dm index 97b4cfe851..d4b311e8e2 100644 --- a/code/modules/modular_computers/computers/modular_computer/core.dm +++ b/code/modules/modular_computers/computers/modular_computer/core.dm @@ -42,6 +42,8 @@ return 1 /obj/item/modular_computer/Initialize() + if(!overlay_icon) + overlay_icon = icon START_PROCESSING(SSobj, src) install_default_hardware() if(hard_drive) @@ -72,20 +74,20 @@ overlays.Cut() if(bsod) - overlays.Add("bsod") + overlays += image(icon = overlay_icon, icon_state = "bsod") return if(!enabled) if(icon_state_screensaver) - overlays.Add(icon_state_screensaver) + overlays += image(icon = overlay_icon, icon_state = icon_state_screensaver) set_light(0) return set_light(light_strength) if(active_program) - overlays.Add(active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu) + overlays += image(icon = overlay_icon, icon_state = active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu) if(active_program.program_key_state) - overlays.Add(active_program.program_key_state) + overlays += image(icon = overlay_icon, icon_state = active_program.program_key_state) else - overlays.Add(icon_state_menu) + overlays += image(icon = overlay_icon, icon_state = icon_state_menu) /obj/item/modular_computer/proc/turn_on(var/mob/user) if(bsod) @@ -119,7 +121,7 @@ active_program = null var/mob/user = usr if(user && istype(user)) - ui_interact(user) // Re-open the UI on this computer. It should show the main screen now. + tgui_interact(user) // Re-open the UI on this computer. It should show the main screen now. update_icon() // Returns 0 for No Signal, 1 for Low Signal and 2 for Good Signal. 3 is for wired connection (always-on) @@ -154,7 +156,7 @@ run_program(autorun.stored_data) if(user) - ui_interact(user) + tgui_interact(user) /obj/item/modular_computer/proc/minimize_program(mob/user) if(!active_program || !processor_unit) @@ -162,12 +164,11 @@ idle_threads.Add(active_program) active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs - SSnanoui.close_uis(active_program.NM ? active_program.NM : active_program) SStgui.close_uis(active_program.TM ? active_program.TM : active_program) active_program = null update_icon() if(istype(user)) - ui_interact(user) // Re-open the UI on this computer. It should show the main screen now. + tgui_interact(user) // Re-open the UI on this computer. It should show the main screen now. /obj/item/modular_computer/proc/run_program(prog) @@ -207,12 +208,12 @@ return 1 /obj/item/modular_computer/proc/update_uis() - if(active_program) //Should we update program ui or computer ui? - SSnanoui.update_uis(active_program) - if(active_program.NM) - SSnanoui.update_uis(active_program.NM) + if(active_program) + SStgui.update_uis(active_program) + if(active_program.TM) + SStgui.update_uis(active_program.TM) else - SSnanoui.update_uis(src) + SStgui.update_uis(src) /obj/item/modular_computer/proc/check_update_ui_need() var/ui_update_needed = 0 diff --git a/code/modules/modular_computers/computers/modular_computer/interaction.dm b/code/modules/modular_computers/computers/modular_computer/interaction.dm index c9ee11a77e..24c02c1add 100644 --- a/code/modules/modular_computers/computers/modular_computer/interaction.dm +++ b/code/modules/modular_computers/computers/modular_computer/interaction.dm @@ -99,7 +99,7 @@ /obj/item/modular_computer/attack_ghost(var/mob/observer/ghost/user) if(enabled) - ui_interact(user) + tgui_interact(user) else if(check_rights(R_ADMIN|R_EVENT, 0, user)) var/response = alert(user, "This computer is turned off. Would you like to turn it on?", "Admin Override", "Yes", "No") if(response == "Yes") @@ -116,7 +116,7 @@ // On-click handling. Turns on the computer if it's off and opens the GUI. /obj/item/modular_computer/attack_self(var/mob/user) if(enabled && screen_on) - ui_interact(user) + tgui_interact(user) else if(!enabled && screen_on) turn_on(user) diff --git a/code/modules/modular_computers/computers/modular_computer/ui.dm b/code/modules/modular_computers/computers/modular_computer/ui.dm index 81081c0cb1..5166d0d777 100644 --- a/code/modules/modular_computers/computers/modular_computer/ui.dm +++ b/code/modules/modular_computers/computers/modular_computer/ui.dm @@ -1,5 +1,10 @@ -// Operates NanoUI -/obj/item/modular_computer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +// Operates TGUI +/obj/item/modular_computer/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/simple/headers) + ) + +/obj/item/modular_computer/tgui_interact(mob/user, datum/tgui/ui) if(!screen_on || !enabled) if(ui) ui.close() @@ -13,7 +18,7 @@ if(active_program) if(ui) // This is the main laptop screen. Since we are switching to program's UI close it for now. ui.close() - active_program.ui_interact(user) + active_program.tgui_interact(user) return // We are still here, that means there is no program loaded. Load the BIOS/ROM/OS/whatever you want to call it. @@ -22,80 +27,100 @@ visible_message("\The [src] beeps three times, it's screen displaying \"DISK ERROR\" warning.") return // No HDD, No HDD files list or no stored files. Something is very broken. - var/datum/computer_file/data/autorun = hard_drive.find_file_by_name("autorun") - - var/list/data = get_header_data() - - var/list/programs = list() - for(var/datum/computer_file/program/P in hard_drive.stored_files) - var/list/program = list() - program["name"] = P.filename - program["desc"] = P.filedesc - program["icon"] = P.program_menu_icon - program["autorun"] = (istype(autorun) && (autorun.stored_data == P.filename)) ? 1 : 0 - if(P in idle_threads) - program["running"] = 1 - programs.Add(list(program)) - - data["programs"] = programs - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "laptop_mainscreen.tmpl", "NTOS Main Menu", 400, 500) - ui.auto_update_layout = 1 - ui.set_initial_data(data) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "NtosMain") + ui.set_autoupdate(TRUE) ui.open() - ui.set_auto_update(1) + +/obj/item/modular_computer/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = get_header_data() + data["device_theme"] = device_theme + + data["login"] = list() + var/obj/item/weapon/computer_hardware/card_slot/cardholder = card_slot + if(cardholder) + var/obj/item/weapon/card/id/stored_card = cardholder.stored_card + if(stored_card) + var/stored_name = stored_card.registered_name + var/stored_title = stored_card.assignment + if(!stored_name) + stored_name = "Unknown" + if(!stored_title) + stored_title = "Unknown" + data["login"] = list( + IDName = stored_name, + IDJob = stored_title, + ) + + data["removable_media"] = list() + + var/datum/computer_file/data/autorun = hard_drive.find_file_by_name("autorun") + data["programs"] = list() + for(var/datum/computer_file/program/P in hard_drive.stored_files) + var/running = FALSE + if(P in idle_threads) + running = TRUE + + data["programs"] += list(list( + "name" = P.filename, + "desc" = P.filedesc, + "icon" = P.program_menu_icon, + "running" = running, + "autorun" = (istype(autorun) && (autorun.stored_data == P.filename)) ? 1 : 0 + )) + + data["has_light"] = FALSE // has_light + data["light_on"] = FALSE // light_on + data["comp_light_color"] = null // comp_light_color + + return data // Handles user's GUI input -/obj/item/modular_computer/Topic(href, href_list) +/obj/item/modular_computer/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return 1 - if( href_list["PC_exit"] ) - kill_program() - return 1 - if( href_list["PC_enable_component"] ) - var/obj/item/weapon/computer_hardware/H = find_hardware_by_name(href_list["PC_enable_component"]) - if(H && istype(H) && !H.enabled) - H.enabled = 1 - . = 1 - if( href_list["PC_disable_component"] ) - var/obj/item/weapon/computer_hardware/H = find_hardware_by_name(href_list["PC_disable_component"]) - if(H && istype(H) && H.enabled) - H.enabled = 0 - . = 1 - if( href_list["PC_shutdown"] ) - shutdown_computer() - return 1 - if( href_list["PC_minimize"] ) - var/mob/user = usr - minimize_program(user) + return TRUE + + switch(action) + if("PC_exit") + kill_program() + return TRUE + if("PC_shutdown") + shutdown_computer() + return TRUE + if("PC_minimize") + var/mob/user = usr + minimize_program(user) + if("PC_killprogram") + var/prog = params["name"] + var/datum/computer_file/program/P = null + var/mob/user = usr + if(hard_drive) + P = hard_drive.find_file_by_name(prog) - if( href_list["PC_killprogram"] ) - var/prog = href_list["PC_killprogram"] - var/datum/computer_file/program/P = null - var/mob/user = usr - if(hard_drive) - P = hard_drive.find_file_by_name(prog) + if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED) + return - if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED) + P.kill_program(1) + to_chat(user, "Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.") + return TRUE + if("PC_runprogram") + return run_program(params["name"]) + if("PC_setautorun") + if(!hard_drive) + return + set_autorun(params["name"]) + return TRUE + if("PC_Eject_Disk") + var/param = params["name"] + switch(param) + if("ID") + proc_eject_id(usr) + return TRUE + else return - P.kill_program(1) - update_uis() - to_chat(user, "Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.") - - if( href_list["PC_runprogram"] ) - return run_program(href_list["PC_runprogram"]) - - if( href_list["PC_setautorun"] ) - if(!hard_drive) - return - set_autorun(href_list["PC_setautorun"]) - - if(.) - update_uis() - -// Function used by NanoUI's to obtain data for header. All relevant entries begin with "PC_" +// Function used by TGUI's to obtain data for header. All relevant entries begin with "PC_" /obj/item/modular_computer/proc/get_header_data() var/list/data = list() @@ -152,4 +177,4 @@ data["PC_stationtime"] = stationtime2text() data["PC_hasheader"] = 1 data["PC_showexitprogram"] = active_program ? 1 : 0 // Hides "Exit Program" button on mainscreen - return data \ No newline at end of file + return data diff --git a/code/modules/modular_computers/computers/modular_computer/variables.dm b/code/modules/modular_computers/computers/modular_computer/variables.dm index 8a1641a125..373d2ad3e1 100644 --- a/code/modules/modular_computers/computers/modular_computer/variables.dm +++ b/code/modules/modular_computers/computers/modular_computer/variables.dm @@ -6,6 +6,7 @@ var/enabled = 0 // Whether the computer is turned on. var/screen_on = 1 // Whether the computer is active/opened/it's screen is on. + var/device_theme = "ntos" // Sets the theme for the main menu, hardware config, and file browser apps. Overridden by certain non-NT devices. var/datum/computer_file/program/active_program = null // A currently active program running on the computer. var/hardware_flag = 0 // A flag that describes this device type var/last_power_usage = 0 // Last tick power usage of this computer @@ -23,6 +24,7 @@ // If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example. icon = null // This thing isn't meant to be used on it's own. Subtypes should supply their own icon. + var/overlay_icon = null // Icon file used for overlays icon_state = null center_of_mass = null // No pixelshifting by placing on tables, etc. randpixel = 0 // And no random pixelshifting on-creation either. diff --git a/code/modules/modular_computers/file_system/news_article.dm b/code/modules/modular_computers/file_system/news_article.dm index 88497ee706..0b327f8218 100644 --- a/code/modules/modular_computers/file_system/news_article.dm +++ b/code/modules/modular_computers/file_system/news_article.dm @@ -17,7 +17,7 @@ // NEWS DEFINITIONS BELOW THIS LINE -/* KEPT HERE AS AN EXAMPLE +/* /datum/computer_file/data/news_article/space/vol_one filename = "SPACE Magazine vol. 1" server_file_path = 'news_articles/space_magazine_1.html' diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm index 08589fb13c..d5e55940d0 100644 --- a/code/modules/modular_computers/file_system/program.dm +++ b/code/modules/modular_computers/file_system/program.dm @@ -5,9 +5,6 @@ var/required_access = null // List of required accesses to run/download the program. var/requires_access_to_run = 1 // Whether the program checks for required_access when run. var/requires_access_to_download = 1 // Whether the program checks for required_access when downloading. - // NanoModule - var/datum/nano_module/NM = null // If the program uses NanoModule, put it here and it will be automagically opened. Otherwise implement ui_interact. - var/nanomodule_path = null // Path to nanomodule, make sure to set this if implementing new program. // TGUIModule var/datum/tgui_module/TM = null // If the program uses TGUIModule, put it here and it will be automagically opened. Otherwise implement tgui_interact. var/tguimodule_path = null // Path to tguimodule, make sure to set this if implementing new program. @@ -29,6 +26,8 @@ var/computer_emagged = 0 // Set to 1 if computer that's running us was emagged. Computer updates this every Process() tick var/ui_header = null // Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /nano/images/status_icons. Be careful not to use too large images! var/ntnet_speed = 0 // GQ/s - current network connectivity transfer rate + /// Name of the tgui interface + var/tgui_id /datum/computer_file/program/New(var/obj/item/modular_computer/comp = null) ..() @@ -39,16 +38,12 @@ computer = null . = ..() -/datum/computer_file/program/nano_host() - return computer.nano_host() - /datum/computer_file/program/tgui_host() return computer.tgui_host() /datum/computer_file/program/clone() var/datum/computer_file/program/temp = ..() temp.required_access = required_access - temp.nanomodule_path = nanomodule_path temp.filedesc = filedesc temp.program_icon_state = program_icon_state temp.requires_ntnet = requires_ntnet @@ -134,13 +129,9 @@ /datum/computer_file/program/proc/run_program(var/mob/living/user) if(can_run(user, 1) || !requires_access_to_run) computer.active_program = src - if(nanomodule_path) - NM = new nanomodule_path(src, new /datum/topic_manager/program(src), src) - NM.using_access = user.GetAccess() if(tguimodule_path) TM = new tguimodule_path(src) TM.using_access = user.GetAccess() - TM.tgui_interact(user) if(requires_ntnet && network_destination) generate_network_log("Connection opened to [network_destination].") program_state = PROGRAM_STATE_ACTIVE @@ -152,26 +143,28 @@ program_state = PROGRAM_STATE_KILLED if(network_destination) generate_network_log("Connection to [network_destination] closed.") - QDEL_NULL(NM) if(TM) SStgui.close_uis(TM) - qdel(TM) - TM = null + QDEL_NULL(TM) return 1 -// This is called every tick when the program is enabled. Ensure you do parent call if you override it. If parent returns 1 continue with UI initialisation. -// It returns 0 if it can't run or if NanoModule was used instead. I suggest using NanoModules where applicable. -/datum/computer_file/program/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - if(program_state != PROGRAM_STATE_ACTIVE) // Our program was closed. Close the ui if it exists. +/datum/computer_file/program/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/simple/headers) + ) + +/datum/computer_file/program/tgui_interact(mob/user, datum/tgui/ui) + if(program_state != PROGRAM_STATE_ACTIVE) if(ui) ui.close() - return computer.ui_interact(user) - if(istype(NM)) - NM.ui_interact(user, ui_key, null, force_open) - return 0 + return computer.tgui_interact(user) if(istype(TM)) TM.tgui_interact(user) return 0 + ui = SStgui.try_update_ui(user, src, ui) + if(!ui && tgui_id) + ui = new(user, src, tgui_id, filedesc) + ui.open() return 1 // CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC: @@ -185,49 +178,56 @@ if(computer) return computer.Topic(href, href_list) +// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC: +// Topic calls are automagically forwarded from NanoModule this program contains. +// Calls beginning with "PRG_" are reserved for programs handling. +// Calls beginning with "PC_" are reserved for computer handling (by whatever runs the program) +// ALWAYS INCLUDE PARENT CALL ..() OR DIE IN FIRE. +/datum/computer_file/program/tgui_act(action,list/params, datum/tgui/ui) + if(..()) + return 1 + if(computer) + switch(action) + if("PC_exit") + computer.kill_program() + ui.close() + return 1 + if("PC_shutdown") + computer.shutdown_computer() + ui.close() + return 1 + if("PC_minimize") + var/mob/user = usr + if(!computer.active_program) + return + + computer.idle_threads.Add(computer.active_program) + program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs + + computer.active_program = null + computer.update_icon() + ui.close() + + if(user && istype(user)) + computer.tgui_interact(user) // Re-open the UI on this computer. It should show the main screen now. + + + // Relays the call to nano module, if we have one /datum/computer_file/program/proc/check_eye(var/mob/user) - if(NM) - return NM.check_eye(user) if(TM) return TM.check_eye(user) else return -1 -/obj/item/modular_computer/initial_data() - return get_header_data() - -/obj/item/modular_computer/update_layout() - return TRUE - -/datum/nano_module/program - //available_to_ai = FALSE - var/datum/computer_file/program/program = null // Program-Based computer program that runs this nano module. Defaults to null. - -/datum/nano_module/program/New(var/host, var/topic_manager, var/program) - ..() - src.program = program - -/datum/topic_manager/program - var/datum/program - -/datum/topic_manager/program/New(var/datum/program) - ..() - src.program = program - -// Calls forwarded to PROGRAM itself should begin with "PRG_" -// Calls forwarded to COMPUTER running the program should begin with "PC_" -/datum/topic_manager/program/Topic(href, href_list) - return program && program.Topic(href, href_list) - /datum/computer_file/program/apply_visual(mob/M) - if(NM) - return NM.apply_visual(M) + if(TM) + return TM.apply_visual(M) /datum/computer_file/program/remove_visual(mob/M) - if(NM) - return NM.remove_visual(M) + if(TM) + return TM.remove_visual(M) /datum/computer_file/program/proc/relaymove(var/mob/M, direction) - if(NM) - return NM.relaymove(M, direction) \ No newline at end of file + if(TM) + return TM.relaymove(M, direction) \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm b/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm index 04bf931593..11547e3426 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm @@ -6,15 +6,17 @@ program_menu_icon = "unlocked" extended_desc = "This highly advanced script can very slowly decrypt operational codes used in almost any network. These codes can be downloaded to an ID card to expand the available access. The system administrator will probably notice this." size = 34 - requires_ntnet = 1 - available_on_ntnet = 0 - available_on_syndinet = 1 - nanomodule_path = /datum/nano_module/program/access_decrypter/ + requires_ntnet = TRUE + available_on_ntnet = FALSE + available_on_syndinet = TRUE + tgui_id = "NtosAccessDecrypter" + var/message = "" var/running = FALSE var/progress = 0 var/target_progress = 300 var/datum/access/target_access = null + var/list/restricted_access_codes = list(access_change_ids, access_network) // access codes that are not hackable due to balance reasons /datum/computer_file/program/access_decrypter/kill_program(var/forced) reset() @@ -48,82 +50,63 @@ message = "Successfully decrypted and saved operational key codes. Downloaded access codes for: [target_access.desc]" target_access = null -/datum/computer_file/program/access_decrypter/Topic(href, href_list) +/datum/computer_file/program/access_decrypter/tgui_act(action, list/params, datum/tgui/ui) if(..()) - return 1 - if(href_list["PRG_reset"]) - reset() - return 1 - if(href_list["PRG_execute"]) - if(running) - return 1 - if(text2num(href_list["allowed"])) - return 1 - var/obj/item/weapon/computer_hardware/processor_unit/CPU = computer.processor_unit - var/obj/item/weapon/computer_hardware/card_slot/RFID = computer.card_slot - if(!istype(CPU) || !CPU.check_functionality() || !istype(RFID) || !RFID.check_functionality()) - message = "A fatal hardware error has been detected." - return - if(!istype(RFID.stored_card)) - message = "RFID card is not present in the device. Operation aborted." - return - running = TRUE - target_access = get_access_by_id(href_list["PRG_execute"]) - if(ntnet_global.intrusion_detection_enabled) - ntnet_global.add_log("IDS WARNING - Unauthorised access attempt to primary keycode database from device: [computer.network_card.get_network_tag()]") - ntnet_global.intrusion_detection_alarm = 1 - return 1 + return TRUE + switch(action) + if("PRG_reset") + reset() + return TRUE + if("PRG_execute") + if(running) + return TRUE + if(text2num(params["allowed"])) + return TRUE + var/obj/item/weapon/computer_hardware/processor_unit/CPU = computer.processor_unit + var/obj/item/weapon/computer_hardware/card_slot/RFID = computer.card_slot + if(!istype(CPU) || !CPU.check_functionality() || !istype(RFID) || !RFID.check_functionality()) + message = "A fatal hardware error has been detected." + return + if(!istype(RFID.stored_card)) + message = "RFID card is not present in the device. Operation aborted." + return + running = TRUE + target_access = get_access_by_id("[params["access_target"]]") + if(ntnet_global.intrusion_detection_enabled) + ntnet_global.add_log("IDS WARNING - Unauthorised access attempt to primary keycode database from device: [computer.network_card.get_network_tag()]") + ntnet_global.intrusion_detection_alarm = TRUE + return TRUE -/datum/nano_module/program/access_decrypter - name = "NTNet Access Decrypter" - var/list/restricted_access_codes = list(access_change_ids, access_network) // access codes that are not hackable due to balance reasons - -/datum/nano_module/program/access_decrypter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) +/datum/computer_file/program/access_decrypter/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) if(!ntnet_global) return - var/datum/computer_file/program/access_decrypter/PRG = program - var/list/data = list() - if(!istype(PRG)) - return - data = PRG.get_header_data() + var/list/data = get_header_data() - if(PRG.message) - data["message"] = PRG.message - else if(PRG.running) + var/list/regions = list() + data["message"] = null + data["running"] = running + if(message) + data["message"] = message + else if(running) data["running"] = 1 - data["rate"] = PRG.computer.processor_unit.max_idle_programs - - // Stolen from DOS traffic generator, generates strings of 1s and 0s - var/percentage = (PRG.progress / PRG.target_progress) * 100 - var/list/strings[0] - for(var/j, j<10, j++) - var/string = "" - for(var/i, i<20, i++) - string = "[string][prob(percentage)]" - strings.Add(string) - data["dos_strings"] = strings - else if(program.computer.card_slot && program.computer.card_slot.stored_card) - var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card - var/list/regions = list() + data["rate"] = computer.processor_unit.max_idle_programs + data["factor"] = (progress / target_progress) + else if(computer?.card_slot?.stored_card) + var/obj/item/weapon/card/id/id_card = computer.card_slot.stored_card for(var/i = 1; i <= 7; i++) var/list/accesses = list() for(var/access in get_region_accesses(i)) - if (get_access_desc(access)) + if(get_access_desc(access) && !(access in restricted_access_codes)) accesses.Add(list(list( - "desc" = replacetext(get_access_desc(access), " ", " "), + "desc" = replacetext(get_access_desc(access), " ", " "), "ref" = access, - "allowed" = (access in id_card.access) ? 1 : 0, - "blocked" = (access in restricted_access_codes) ? 1 : 0))) + "allowed" = (access in id_card.access) ? 1 : 0 + ))) regions.Add(list(list( "name" = get_region_accesses_name(i), - "accesses" = accesses))) - data["regions"] = regions + "accesses" = accesses + ))) + data["regions"] = regions - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "access_decrypter.tmpl", "NTNet Access Decrypter", 550, 400, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) \ No newline at end of file + return data \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm index 0e0a1381bd..e1fa0cfa8a 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm @@ -6,10 +6,11 @@ program_menu_icon = "arrow-4-diag" extended_desc = "This advanced script can perform denial of service attacks against NTNet quantum relays. The system administrator will probably notice this. Multiple devices can run this program together against same relay for increased effect" size = 20 - requires_ntnet = 1 - available_on_ntnet = 0 - available_on_syndinet = 1 - nanomodule_path = /datum/nano_module/program/computer_dos/ + requires_ntnet = TRUE + available_on_ntnet = FALSE + available_on_syndinet = TRUE + tgui_id = "NtosNetDos" + var/obj/machinery/ntnet_relay/target = null var/dos_speed = 0 var/error = "" @@ -39,70 +40,51 @@ ..(forced) -/datum/nano_module/program/computer_dos - name = "DoS Traffic Generator" - -/datum/nano_module/program/computer_dos/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) +/datum/computer_file/program/ntnet_dos/tgui_data(mob/user) if(!ntnet_global) return - var/datum/computer_file/program/ntnet_dos/PRG = program - var/list/data = list() - if(!istype(PRG)) - return - data = PRG.get_header_data() - if(PRG.error) - data["error"] = PRG.error - else if(PRG.target && PRG.executed) - data["target"] = 1 - data["speed"] = PRG.dos_speed + var/list/data = get_header_data() - // This is mostly visual, generate some strings of 1s and 0s - // Probability of 1 is equal of completion percentage of DoS attack on this relay. - // Combined with UI updates this adds quite nice effect to the UI - var/percentage = PRG.target.dos_overload * 100 / PRG.target.dos_capacity - var/list/strings[0] - for(var/j, j<10, j++) - var/string = "" - for(var/i, i<20, i++) - string = "[string][prob(percentage)]" - strings.Add(string) - data["dos_strings"] = strings + data["error"] = error + if(target && executed) + data["target"] = TRUE + data["speed"] = dos_speed + + data["overload"] = target.dos_overload + data["capacity"] = target.dos_capacity else - var/list/relays[0] + data["target"] = FALSE + data["relays"] = list() for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays) - relays.Add(R.uid) - data["relays"] = relays - data["focus"] = PRG.target ? PRG.target.uid : null + data["relays"] += list(list("id" = R.uid)) + data["focus"] = target ? target.uid : null - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "ntnet_dos.tmpl", "DoS Traffic Generator", 400, 250, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data -/datum/computer_file/program/ntnet_dos/Topic(href, href_list) +/datum/computer_file/program/ntnet_dos/tgui_act(action, params) if(..()) - return 1 - if(href_list["PRG_target_relay"]) - for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays) - if("[R.uid]" == href_list["PRG_target_relay"]) - target = R - return 1 - if(href_list["PRG_reset"]) - if(target) - target.dos_sources.Remove(src) - target = null - executed = 0 - error = "" - return 1 - if(href_list["PRG_execute"]) - if(target) - executed = 1 - target.dos_sources.Add(src) - if(ntnet_global.intrusion_detection_enabled) - ntnet_global.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [computer.network_card.get_network_tag()]") - ntnet_global.intrusion_detection_alarm = 1 - return 1 + return TRUE + switch(action) + if("PRG_target_relay") + for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays) + if(R.uid == text2num(params["targid"])) + target = R + break + return TRUE + if("PRG_reset") + if(target) + target.dos_sources.Remove(src) + target = null + executed = FALSE + error = "" + return TRUE + if("PRG_execute") + if(target) + executed = TRUE + target.dos_sources.Add(src) + if(ntnet_global.intrusion_detection_enabled) + var/obj/item/weapon/computer_hardware/network_card/network_card = computer.network_card + ntnet_global.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [network_card.get_network_tag()]") + ntnet_global.intrusion_detection_alarm = TRUE + return TRUE diff --git a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm index 17199c3b18..5d0e291336 100644 --- a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm +++ b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm @@ -6,10 +6,10 @@ program_menu_icon = "home" extended_desc = "This virus can destroy hard drive of system it is executed on. It may be obfuscated to look like another non-malicious program. Once armed, it will destroy the system upon next execution." size = 13 - requires_ntnet = 0 - available_on_ntnet = 0 - available_on_syndinet = 1 - nanomodule_path = /datum/nano_module/program/revelation/ + requires_ntnet = FALSE + available_on_ntnet = FALSE + available_on_syndinet = TRUE + tgui_id = "NtosRevelation" var/armed = 0 /datum/computer_file/program/revelation/run_program(var/mob/living/user) @@ -37,48 +37,31 @@ if(computer.tesla_link && prob(50)) qdel(computer.tesla_link) -/datum/computer_file/program/revelation/Topic(href, href_list) +/datum/computer_file/program/revelation/tgui_act(action, params) if(..()) - return 1 - else if(href_list["PRG_arm"]) - armed = !armed - else if(href_list["PRG_activate"]) - activate() - else if(href_list["PRG_obfuscate"]) - var/mob/living/user = usr - var/newname = sanitize(input(user, "Enter new program name: ")) - if(!newname) - return - filedesc = newname - for(var/datum/computer_file/program/P in ntnet_global.available_station_software) - if(filedesc == P.filedesc) - program_menu_icon = P.program_menu_icon - break - return 1 + return + switch(action) + if("PRG_arm") + armed = !armed + return TRUE + if("PRG_activate") + activate() + return TRUE + if("PRG_obfuscate") + var/newname = params["new_name"] + if(!newname) + return + filedesc = newname + return TRUE /datum/computer_file/program/revelation/clone() var/datum/computer_file/program/revelation/temp = ..() temp.armed = armed return temp -/datum/nano_module/program/revelation - name = "Revelation Virus" +/datum/computer_file/program/revelation/tgui_data(mob/user) + var/list/data = get_header_data() -/datum/nano_module/program/revelation/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = list() - var/datum/computer_file/program/revelation/PRG = program - if(!istype(PRG)) - return - - data = PRG.get_header_data() - - data["armed"] = PRG.armed - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "revelation.tmpl", "Revelation Virus", 400, 250, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + data["armed"] = armed + return data \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/command/card.dm b/code/modules/modular_computers/file_system/programs/command/card.dm index aa122c0abf..47fe4ea2b3 100644 --- a/code/modules/modular_computers/file_system/programs/command/card.dm +++ b/code/modules/modular_computers/file_system/programs/command/card.dm @@ -1,7 +1,7 @@ /datum/computer_file/program/card_mod filename = "cardmod" filedesc = "ID card modification program" - nanomodule_path = /datum/nano_module/program/card_mod + tguimodule_path = /datum/tgui_module/cardmod program_icon_state = "id" program_key_state = "id_key" program_menu_icon = "key" @@ -9,220 +9,3 @@ required_access = access_change_ids requires_ntnet = 0 size = 8 - -/datum/nano_module/program/card_mod - name = "ID card modification program" - var/mod_mode = 1 - var/is_centcom = 0 - var/show_assignments = 0 - -/datum/nano_module/program/card_mod/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - - data["src"] = "\ref[src]" - data["station_name"] = station_name() - data["manifest"] = data_core ? data_core.get_manifest(0) : null - data["assignments"] = show_assignments - if(program && program.computer) - data["have_id_slot"] = !!program.computer.card_slot - data["have_printer"] = !!program.computer.nano_printer - data["authenticated"] = program.can_run(user) - if(!program.computer.card_slot) - mod_mode = 0 //We can't modify IDs when there is no card reader - else - data["have_id_slot"] = 0 - data["have_printer"] = 0 - data["authenticated"] = 0 - data["mmode"] = mod_mode - data["centcom_access"] = is_centcom - - if(program && program.computer && program.computer.card_slot) - var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card - data["has_id"] = !!id_card - data["id_account_number"] = id_card ? id_card.associated_account_number : null - data["id_rank"] = id_card && id_card.assignment ? id_card.assignment : "Unassigned" - data["id_owner"] = id_card && id_card.registered_name ? id_card.registered_name : "-----" - data["id_name"] = id_card ? id_card.name : "-----" - - var/list/departments = list() - for(var/D in SSjob.get_all_department_datums()) - var/datum/department/dept = D - if(!dept.assignable) // No AI ID cards for you. - continue - if(dept.centcom_only && !is_centcom) - continue - departments[++departments.len] = list("department_name" = dept.name, "jobs" = format_jobs(SSjob.get_job_titles_in_department(dept.name)) ) - - data["departments"] = departments - - data["all_centcom_access"] = is_centcom ? get_accesses(1) : null - data["regions"] = get_accesses() - - if(program.computer.card_slot && program.computer.card_slot.stored_card) - var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card - if(is_centcom) - var/list/all_centcom_access = list() - for(var/access in get_all_centcom_access()) - all_centcom_access.Add(list(list( - "desc" = replacetext(get_centcom_access_desc(access), " ", " "), - "ref" = access, - "allowed" = (access in id_card.access) ? 1 : 0))) - data["all_centcom_access"] = all_centcom_access - else - var/list/regions = list() - for(var/i = 1; i <= 7; i++) - var/list/accesses = list() - for(var/access in get_region_accesses(i)) - if (get_access_desc(access)) - accesses.Add(list(list( - "desc" = replacetext(get_access_desc(access), " ", " "), - "ref" = access, - "allowed" = (access in id_card.access) ? 1 : 0))) - - regions.Add(list(list( - "name" = get_region_accesses_name(i), - "accesses" = accesses))) - data["regions"] = regions - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "mod_identification_computer.tmpl", name, 600, 700, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - -/datum/nano_module/program/card_mod/proc/format_jobs(list/jobs) - var/obj/item/weapon/card/id/id_card = program.computer.card_slot ? program.computer.card_slot.stored_card : null - var/list/formatted = list() - for(var/job in jobs) - formatted.Add(list(list( - "display_name" = replacetext(job, " ", " "), - "target_rank" = id_card && id_card.assignment ? id_card.assignment : "Unassigned", - "job" = job))) - - return formatted - -/datum/nano_module/program/card_mod/proc/get_accesses(var/is_centcom = 0) - return null - - -/datum/computer_file/program/card_mod/Topic(href, href_list) - if(..()) - return 1 - - var/mob/user = usr - var/obj/item/weapon/card/id/user_id_card = user.GetIdCard() - var/obj/item/weapon/card/id/id_card - if (computer.card_slot) - id_card = computer.card_slot.stored_card - - var/datum/nano_module/program/card_mod/module = NM - switch(href_list["action"]) - if("switchm") - if(href_list["target"] == "mod") - module.mod_mode = 1 - else if (href_list["target"] == "manifest") - module.mod_mode = 0 - if("togglea") - if(module.show_assignments) - module.show_assignments = 0 - else - module.show_assignments = 1 - if("print") - if(computer && computer.nano_printer) //This option should never be called if there is no printer - if(module.mod_mode) - if(can_run(user, 1)) - var/contents = {"

Access Report

- Prepared By: [user_id_card.registered_name ? user_id_card.registered_name : "Unknown"]
- For: [id_card.registered_name ? id_card.registered_name : "Unregistered"]
-
- Assignment: [id_card.assignment]
- Account Number: #[id_card.associated_account_number]
- Blood Type: [id_card.blood_type]

- Access:
- "} - - var/known_access_rights = get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM) - for(var/A in id_card.access) - if(A in known_access_rights) - contents += " [get_access_desc(A)]" - - if(!computer.nano_printer.print_text(contents,"access report")) - to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") - return - else - computer.visible_message("\The [computer] prints out paper.") - else - var/contents = {"

Crew Manifest

-
- [data_core ? data_core.get_manifest(0) : ""] - "} - if(!computer.nano_printer.print_text(contents,text("crew manifest ([])", stationtime2text()))) - to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") - return - else - computer.visible_message("\The [computer] prints out paper.") - if("eject") - if(computer && computer.card_slot) - if(id_card) - data_core.manifest_modify(id_card.registered_name, id_card.assignment) - computer.proc_eject_id(user) - if("terminate") - if(computer && can_run(user, 1)) - id_card.assignment = "Dismissed" //VOREStation Edit: setting adjustment - id_card.access = list() - callHook("terminate_employee", list(id_card)) - if("edit") - if(computer && can_run(user, 1)) - if(href_list["name"]) - var/temp_name = sanitizeName(input("Enter name.", "Name", id_card.registered_name),allow_numbers=TRUE) - if(temp_name) - id_card.registered_name = temp_name - else - computer.visible_message("[computer] buzzes rudely.") - else if(href_list["account"]) - var/account_num = text2num(input("Enter account number.", "Account", id_card.associated_account_number)) - id_card.associated_account_number = account_num - if("assign") - if(computer && can_run(user, 1) && id_card) - var/t1 = href_list["assign_target"] - if(t1 == "Custom") - var/temp_t = sanitize(input("Enter a custom job assignment.","Assignment", id_card.assignment), 45) - //let custom jobs function as an impromptu alt title, mainly for sechuds - if(temp_t) - id_card.assignment = temp_t - else - var/list/access = list() - if(module.is_centcom) - access = get_centcom_access(t1) - else - var/datum/job/jobdatum - for(var/jobtype in typesof(/datum/job)) - var/datum/job/J = new jobtype - if(ckey(J.title) == ckey(t1)) - jobdatum = J - break - if(!jobdatum) - to_chat(usr, "No log exists for this job: [t1]") - return - - access = jobdatum.get_access() - - id_card.access = access - id_card.assignment = t1 - id_card.rank = t1 - - callHook("reassign_employee", list(id_card)) - if("access") - if(href_list["allowed"] && computer && can_run(user, 1)) - var/access_type = text2num(href_list["access_target"]) - var/access_allowed = text2num(href_list["allowed"]) - if(access_type in get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM)) - id_card.access -= access_type - if(!access_allowed) - id_card.access += access_type - if(id_card) - id_card.name = text("[id_card.registered_name]'s ID Card ([id_card.assignment])") - - SSnanoui.update_uis(NM) - return 1 diff --git a/code/modules/modular_computers/file_system/programs/command/comm.dm b/code/modules/modular_computers/file_system/programs/command/comm.dm index fc2efa8820..a2079ad494 100644 --- a/code/modules/modular_computers/file_system/programs/command/comm.dm +++ b/code/modules/modular_computers/file_system/programs/command/comm.dm @@ -9,7 +9,7 @@ program_icon_state = "comm" program_key_state = "med_key" program_menu_icon = "flag" - nanomodule_path = /datum/nano_module/program/comm + tguimodule_path = /datum/tgui_module/communications/ntos extended_desc = "Used to command and control. Can relay long-range communications. This program can not be run on tablet computers." required_access = access_heads requires_ntnet = 1 @@ -24,269 +24,6 @@ temp.message_core.messages = message_core.messages.Copy() return temp -/datum/nano_module/program/comm - name = "Command and Communications Program" - //available_to_ai = TRUE - var/current_status = STATE_DEFAULT - var/msg_line1 = "" - var/msg_line2 = "" - var/centcomm_message_cooldown = 0 - var/announcment_cooldown = 0 - var/datum/announcement/priority/crew_announcement = new - var/current_viewing_message_id = 0 - var/current_viewing_message = null - -/datum/nano_module/program/comm/New() - ..() - crew_announcement.newscast = 1 - -/datum/nano_module/program/comm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - - if(program) - data["emagged"] = program.computer_emagged - data["net_comms"] = !!program.get_signal(NTNET_COMMUNICATION) //Double !! is needed to get 1 or 0 answer - data["net_syscont"] = !!program.get_signal(NTNET_SYSTEMCONTROL) - if(program.computer) - data["have_printer"] = !!program.computer.nano_printer - else - data["have_printer"] = 0 - else - data["emagged"] = 0 - data["net_comms"] = 1 - data["net_syscont"] = 1 - data["have_printer"] = 0 - - data["message_line1"] = msg_line1 - data["message_line2"] = msg_line2 - data["state"] = current_status - data["isAI"] = issilicon(usr) - data["authenticated"] = get_authentication_level(user) - data["current_security_level"] = security_level - data["current_security_level_title"] = num2seclevel(security_level) - - data["def_SEC_LEVEL_DELTA"] = SEC_LEVEL_DELTA - data["def_SEC_LEVEL_YELLOW"] = SEC_LEVEL_YELLOW - data["def_SEC_LEVEL_ORANGE"] = SEC_LEVEL_ORANGE - data["def_SEC_LEVEL_VIOLET"] = SEC_LEVEL_VIOLET - data["def_SEC_LEVEL_BLUE"] = SEC_LEVEL_BLUE - data["def_SEC_LEVEL_GREEN"] = SEC_LEVEL_GREEN - - var/datum/comm_message_listener/l = obtain_message_listener() - data["messages"] = l.messages - data["message_deletion_allowed"] = l != global_message_listener - data["message_current_id"] = current_viewing_message_id - if(current_viewing_message) - data["message_current"] = current_viewing_message - - if(emergency_shuttle.location()) - data["have_shuttle"] = 1 - if(emergency_shuttle.online()) - data["have_shuttle_called"] = 1 - else - data["have_shuttle_called"] = 0 - else - data["have_shuttle"] = 0 - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "mod_communication.tmpl", name, 550, 420, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - -/datum/nano_module/program/comm/proc/get_authentication_level(var/mob/user) - if(program) - if(program.can_run(user, 0, access_captain)) - return 2 - else - return program.can_run(user) - return 1 - -/datum/nano_module/program/comm/proc/obtain_message_listener() - if(program) - var/datum/computer_file/program/comm/P = program - return P.message_core - return global_message_listener - -/datum/nano_module/program/comm/Topic(href, href_list) - if(..()) - return 1 - var/mob/user = usr - var/ntn_comm = program ? !!program.get_signal(NTNET_COMMUNICATION) : 1 - var/ntn_cont = program ? !!program.get_signal(NTNET_SYSTEMCONTROL) : 1 - var/datum/comm_message_listener/l = obtain_message_listener() - switch(href_list["action"]) - if("sw_menu") - . = 1 - current_status = text2num(href_list["target"]) - if("announce") - . = 1 - if(get_authentication_level(user) == 2 && !issilicon(usr) && ntn_comm) - if(user) - var/obj/item/weapon/card/id/id_card = user.GetIdCard() - crew_announcement.announcer = GetNameAndAssignmentFromId(id_card) - else - crew_announcement.announcer = "Unknown" - if(announcment_cooldown) - to_chat(usr, "Please allow at least one minute to pass between announcements") - return TRUE - var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement") as null|message - if(!input || !can_still_topic()) - return 1 - crew_announcement.Announce(input) - announcment_cooldown = 1 - spawn(600)//One minute cooldown - announcment_cooldown = 0 - if("message") - . = 1 - if(href_list["target"] == "emagged") - if(program) - if(get_authentication_level(user) == 2 && program.computer_emagged && !issilicon(usr) && ntn_comm) - if(centcomm_message_cooldown) - to_chat(usr, "Arrays recycling. Please stand by.") - SSnanoui.update_uis(src) - return - var/input = sanitize(input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "") as null|text) - if(!input || !can_still_topic()) - return 1 - Syndicate_announce(input, usr) - to_chat(usr, "Message transmitted.") - log_say("[key_name(usr)] has made an illegal announcement: [input]") - centcomm_message_cooldown = 1 - spawn(300)//30 second cooldown - centcomm_message_cooldown = 0 - else if(href_list["target"] == "regular") - if(get_authentication_level(user) == 2 && !issilicon(usr) && ntn_comm) - if(centcomm_message_cooldown) - to_chat(usr, "Arrays recycling. Please stand by.") - SSnanoui.update_uis(src) - return - if(!is_relay_online())//Contact Centcom has a check, Syndie doesn't to allow for Traitor funs. - to_chat(usr, "No Emergency Bluespace Relay detected. Unable to transmit message.") - return 1 - var/input = sanitize(input("Please choose a message to transmit to Centcomm via quantum entanglement. \ - Please be aware that this process is very expensive, and abuse will lead to... termination. \ - Transmission does not guarantee a response. There is a 30 second delay before you may send another message, \ - be clear, full and concise.", "Central Command Quantum Messaging") as null|message) - if(!input || !can_still_topic()) - return 1 - CentCom_announce(input, usr) - to_chat(usr, "Message transmitted.") - log_say("[key_name(usr)] has made an IA Centcomm announcement: [input]") - centcomm_message_cooldown = 1 - spawn(300) //30 second cooldown - centcomm_message_cooldown = 0 - if("shuttle") - . = 1 - if(get_authentication_level(user) && ntn_cont) - if(href_list["target"] == "call") - var/confirm = alert("Are you sure you want to call the shuttle?", name, "No", "Yes") - if(confirm == "Yes" && can_still_topic()) - call_shuttle_proc(usr) - - if(href_list["target"] == "cancel" && !issilicon(usr)) - var/confirm = alert("Are you sure you want to cancel the shuttle?", name, "No", "Yes") - if(confirm == "Yes" && can_still_topic()) - cancel_call_proc(usr) - if("setstatus") - . = 1 - if(get_authentication_level(user) && ntn_cont) - switch(href_list["target"]) - if("line1") - var/linput = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", msg_line1) as text|null, 40), 40) - if(can_still_topic()) - msg_line1 = linput - if("line2") - var/linput = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", msg_line2) as text|null, 40), 40) - if(can_still_topic()) - msg_line2 = linput - if("message") - post_status("message", msg_line1, msg_line2) - if("alert") - post_status("alert", href_list["alert"]) - else - post_status(href_list["target"]) - if("setalert") - . = 1 - if(get_authentication_level(user) && !issilicon(usr) && ntn_cont && ntn_comm) - var/current_level = text2num(href_list["target"]) - var/confirm = alert("Are you sure you want to change alert level to [num2seclevel(current_level)]?", name, "No", "Yes") - if(confirm == "Yes" && can_still_topic()) - var/old_level = security_level - if(!current_level) current_level = SEC_LEVEL_GREEN - if(current_level < SEC_LEVEL_GREEN) current_level = SEC_LEVEL_GREEN - if(current_level > SEC_LEVEL_BLUE) current_level = SEC_LEVEL_BLUE //Cannot engage delta with this - set_security_level(current_level) - if(security_level != old_level) - log_game("[key_name(usr)] has changed the security level to [get_security_level()].") - message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].") - switch(security_level) - if(SEC_LEVEL_GREEN) - feedback_inc("alert_comms_green",1) - if(SEC_LEVEL_YELLOW) - feedback_inc("alert_comms_yellow",1) - if(SEC_LEVEL_ORANGE) - feedback_inc("alert_comms_orange",1) - if(SEC_LEVEL_VIOLET) - feedback_inc("alert_comms_violet",1) - if(SEC_LEVEL_BLUE) - feedback_inc("alert_comms_blue",1) - else - to_chat(usr, "You press button, but red light flashes and nothing happens.")//This should never happen - - current_status = STATE_DEFAULT - if("viewmessage") - . = 1 - if(get_authentication_level(user) && ntn_comm) - current_viewing_message_id = text2num(href_list["target"]) - for(var/list/m in l.messages) - if(m["id"] == current_viewing_message_id) - current_viewing_message = m - current_status = STATE_VIEWMESSAGE - if("delmessage") - . = 1 - if(get_authentication_level(user) && ntn_comm && l != global_message_listener) - l.Remove(current_viewing_message) - current_status = STATE_MESSAGELIST - if("printmessage") - . = 1 - if(get_authentication_level(user) && ntn_comm) - if(program && program.computer && program.computer.nano_printer) - if(!program.computer.nano_printer.print_text(current_viewing_message["contents"],current_viewing_message["title"])) - to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") - else - program.computer.visible_message("\The [program.computer] prints out paper.") - - -/datum/nano_module/program/comm/proc/post_status(var/command, var/data1, var/data2) - - var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) - - if(!frequency) return - - - var/datum/signal/status_signal = new - status_signal.source = src - status_signal.transmission_method = TRANSMISSION_RADIO - status_signal.data["command"] = command - - switch(command) - if("message") - status_signal.data["msg1"] = data1 - status_signal.data["msg2"] = data2 - log_admin("STATUS: [key_name(usr)] set status screen message with [src]: [data1] [data2]") - if("alert") - status_signal.data["picture_state"] = data1 - - frequency.post_signal(src, status_signal) - -#undef STATE_DEFAULT -#undef STATE_MESSAGELIST -#undef STATE_VIEWMESSAGE -#undef STATE_STATUSDISPLAY -#undef STATE_ALERT_LEVEL - /* General message handling stuff */ @@ -304,19 +41,9 @@ proc/post_comm_message(var/message_title, var/message_text) message["title"] = message_title message["contents"] = message_text - for (var/datum/comm_message_listener/l in comm_message_listeners) + for(var/datum/comm_message_listener/l in comm_message_listeners) l.Add(message) - //Old console support - for (var/obj/machinery/computer/communications/comm in machines) - if (!(comm.stat & (BROKEN | NOPOWER)) && comm.prints_intercept) - var/obj/item/weapon/paper/intercept = new /obj/item/weapon/paper( comm.loc ) - intercept.name = message_title - intercept.info = message_text - - comm.messagetitle.Add(message_title) - comm.messagetext.Add(message_text) - /datum/comm_message_listener var/list/messages diff --git a/code/modules/modular_computers/file_system/programs/generic/configurator.dm b/code/modules/modular_computers/file_system/programs/generic/configurator.dm index c3ce1e358a..2d660c8b7e 100644 --- a/code/modules/modular_computers/file_system/programs/generic/configurator.dm +++ b/code/modules/modular_computers/file_system/programs/generic/configurator.dm @@ -14,51 +14,4 @@ size = 4 available_on_ntnet = 0 requires_ntnet = 0 - nanomodule_path = /datum/nano_module/program/computer_configurator/ - -/datum/nano_module/program/computer_configurator - name = "NTOS Computer Configuration Tool" - var/obj/item/modular_computer/movable = null - -/datum/nano_module/program/computer_configurator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - if(program) - movable = program.computer - if(!istype(movable)) - movable = null - - // No computer connection, we can't get data from that. - if(!movable) - return 0 - - var/list/data = list() - - if(program) - data = program.get_header_data() - - var/list/hardware = movable.get_all_components() - - data["disk_size"] = movable.hard_drive.max_capacity - data["disk_used"] = movable.hard_drive.used_capacity - data["power_usage"] = movable.last_power_usage - data["battery_exists"] = movable.battery_module ? 1 : 0 - if(movable.battery_module) - data["battery_rating"] = movable.battery_module.battery.maxcharge - data["battery_percent"] = round(movable.battery_module.battery.percent()) - - var/list/all_entries[0] - for(var/obj/item/weapon/computer_hardware/H in hardware) - all_entries.Add(list(list( - "name" = H.name, - "desc" = H.desc, - "enabled" = H.enabled, - "critical" = H.critical, - "powerusage" = H.power_usage - ))) - - data["hardware"] = all_entries - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "laptop_configuration.tmpl", "NTOS Configuration Utility", 575, 700, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() \ No newline at end of file + tguimodule_path = /datum/tgui_module/computer_configurator diff --git a/code/modules/modular_computers/file_system/programs/generic/email_client.dm b/code/modules/modular_computers/file_system/programs/generic/email_client.dm index 3e2f979bb5..32d635fef4 100644 --- a/code/modules/modular_computers/file_system/programs/generic/email_client.dm +++ b/code/modules/modular_computers/file_system/programs/generic/email_client.dm @@ -11,15 +11,15 @@ var/stored_login = "" var/stored_password = "" - nanomodule_path = /datum/nano_module/email_client + tguimodule_path = /datum/tgui_module/email_client // Persistency. Unless you log out, or unless your password changes, this will pre-fill the login data when restarting the program /datum/computer_file/program/email_client/kill_program() - if(NM) - var/datum/nano_module/email_client/NME = NM - if(NME.current_account) - stored_login = NME.stored_login - stored_password = NME.stored_password + if(TM) + var/datum/tgui_module/email_client/TME = TM + if(TME.current_account) + stored_login = TME.stored_login + stored_password = TME.stored_password else stored_login = "" stored_password = "" @@ -27,473 +27,31 @@ /datum/computer_file/program/email_client/run_program() . = ..() - if(NM) - var/datum/nano_module/email_client/NME = NM - NME.stored_login = stored_login - NME.stored_password = stored_password - NME.log_in() - NME.error = "" - NME.check_for_new_messages(1) + if(TM) + var/datum/tgui_module/email_client/TME = TM + TME.stored_login = stored_login + TME.stored_password = stored_password + TME.log_in() + TME.error = "" + TME.check_for_new_messages(1) /datum/computer_file/program/email_client/proc/new_mail_notify() - computer.visible_message("\The [computer] beeps softly, indicating a new email has been received.", 1) + var/turf/T = get_turf(computer) // Because visible_message is being a butt + if(T) + T.visible_message("[computer] beeps softly, indicating a new email has been received.") + playsound(computer, 'sound/misc/server-ready.ogg', 100, 0) /datum/computer_file/program/email_client/process_tick() ..() - var/datum/nano_module/email_client/NME = NM - if(!istype(NME)) + var/datum/tgui_module/email_client/TME = TM + if(!istype(TME)) return - NME.relayed_process(ntnet_speed) + TME.relayed_process(ntnet_speed) - var/check_count = NME.check_for_new_messages() + var/check_count = TME.check_for_new_messages() if(check_count) if(check_count == 2) new_mail_notify() ui_header = "ntnrc_new.gif" else ui_header = "ntnrc_idle.gif" - -/datum/nano_module/email_client/ - name = "Email Client" - var/stored_login = "" - var/stored_password = "" - var/error = "" - - var/msg_title = "" - var/msg_body = "" - var/msg_recipient = "" - var/datum/computer_file/msg_attachment = null - var/folder = "Inbox" - var/addressbook = FALSE - var/new_message = FALSE - - var/last_message_count = 0 // How many messages were there during last check. - var/read_message_count = 0 // How many messages were there when user has last accessed the UI. - - var/datum/computer_file/downloading = null - var/download_progress = 0 - var/download_speed = 0 - - var/datum/computer_file/data/email_account/current_account = null - var/datum/computer_file/data/email_message/current_message = null - -/datum/nano_module/email_client/proc/log_in() - for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts) - if(!account.can_login) - continue - if(account.login == stored_login) - if(account.password == stored_password) - if(account.suspended) - error = "This account has been suspended. Please contact the system administrator for assistance." - return 0 - current_account = account - return 1 - else - error = "Invalid Password" - return 0 - error = "Invalid Login" - return 0 - -// Returns 0 if no new messages were received, 1 if there is an unread message but notification has already been sent. -// and 2 if there is a new message that appeared in this tick (and therefore notification should be sent by the program). -/datum/nano_module/email_client/proc/check_for_new_messages(var/messages_read = FALSE) - if(!current_account) - return 0 - - var/list/allmails = current_account.all_emails() - - if(allmails.len > last_message_count) - . = 2 - else if(allmails.len > read_message_count) - . = 1 - else - . = 0 - - last_message_count = allmails.len - if(messages_read) - read_message_count = allmails.len - - -/datum/nano_module/email_client/proc/log_out() - current_account = null - downloading = null - download_progress = 0 - last_message_count = 0 - read_message_count = 0 - -/datum/nano_module/email_client/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - - // Password has been changed by other client connected to this email account - if(current_account) - if(current_account.password != stored_password) - log_out() - error = "Invalid Password" - // Banned. - if(current_account.suspended) - log_out() - error = "This account has been suspended. Please contact the system administrator for assistance." - - if(error) - data["error"] = error - else if(downloading) - data["downloading"] = 1 - data["down_filename"] = "[downloading.filename].[downloading.filetype]" - data["down_progress"] = download_progress - data["down_size"] = downloading.size - data["down_speed"] = download_speed - - else if(istype(current_account)) - data["current_account"] = current_account.login - if(addressbook) - var/list/all_accounts = list() - for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts) - if(!account.can_login) - continue - all_accounts.Add(list(list( - "login" = account.login - ))) - data["addressbook"] = 1 - data["accounts"] = all_accounts - else if(new_message) - data["new_message"] = 1 - data["msg_title"] = msg_title - data["msg_body"] = pencode2html(msg_body) - data["msg_recipient"] = msg_recipient - if(msg_attachment) - data["msg_hasattachment"] = 1 - data["msg_attachment_filename"] = "[msg_attachment.filename].[msg_attachment.filetype]" - data["msg_attachment_size"] = msg_attachment.size - else if (current_message) - data["cur_title"] = current_message.title - data["cur_body"] = pencode2html(current_message.stored_data) - data["cur_timestamp"] = current_message.timestamp - data["cur_source"] = current_message.source - data["cur_uid"] = current_message.uid - if(istype(current_message.attachment)) - data["cur_hasattachment"] = 1 - data["cur_attachment_filename"] = "[current_message.attachment.filename].[current_message.attachment.filetype]" - data["cur_attachment_size"] = current_message.attachment.size - else - data["label_inbox"] = "Inbox ([current_account.inbox.len])" - data["label_spam"] = "Spam ([current_account.spam.len])" - data["label_deleted"] = "Deleted ([current_account.deleted.len])" - var/list/message_source - if(folder == "Inbox") - message_source = current_account.inbox - else if(folder == "Spam") - message_source = current_account.spam - else if(folder == "Deleted") - message_source = current_account.deleted - - if(message_source) - data["folder"] = folder - var/list/all_messages = list() - for(var/datum/computer_file/data/email_message/message in message_source) - all_messages.Add(list(list( - "title" = message.title, - "body" = pencode2html(message.stored_data), - "source" = message.source, - "timestamp" = message.timestamp, - "uid" = message.uid - ))) - data["messages"] = all_messages - data["messagecount"] = all_messages.len - else - data["stored_login"] = stored_login - data["stored_password"] = stars(stored_password, 0) - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "email_client.tmpl", "Email Client", 600, 450, state = state) - if(host.update_layout()) - ui.auto_update_layout = 1 - ui.set_auto_update(1) - ui.set_initial_data(data) - ui.open() - -/datum/nano_module/email_client/proc/find_message_by_fuid(var/fuid) - if(!istype(current_account)) - return - - // href_list works with strings, so this makes it a bit easier for us - if(istext(fuid)) - fuid = text2num(fuid) - - for(var/datum/computer_file/data/email_message/message in current_account.all_emails()) - if(message.uid == fuid) - return message - -/datum/nano_module/email_client/proc/clear_message() - new_message = FALSE - msg_title = "" - msg_body = "" - msg_recipient = "" - msg_attachment = null - current_message = null - -/datum/nano_module/email_client/proc/relayed_process(var/netspeed) - download_speed = netspeed - if(!downloading) - return - download_progress = min(download_progress + netspeed, downloading.size) - if(download_progress >= downloading.size) - var/obj/item/modular_computer/MC = nano_host() - if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) - error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?" - downloading = null - download_progress = 0 - return 1 - - if(MC.hard_drive.store_file(downloading)) - error = "File successfully downloaded to local device." - else - error = "Error saving file: I/O Error: The hard drive may be full or nonfunctional." - downloading = null - download_progress = 0 - return 1 - - -/datum/nano_module/email_client/Topic(href, href_list) - if(..()) - return 1 - var/mob/living/user = usr - check_for_new_messages(1) // Any actual interaction (button pressing) is considered as acknowledging received message, for the purpose of notification icons. - if(href_list["login"]) - log_in() - return 1 - - if(href_list["logout"]) - log_out() - return 1 - - if(href_list["reset"]) - error = "" - return 1 - - if(href_list["new_message"]) - new_message = TRUE - return 1 - - if(href_list["cancel"]) - if(addressbook) - addressbook = FALSE - else - clear_message() - return 1 - - if(href_list["addressbook"]) - addressbook = TRUE - return 1 - - if(href_list["set_recipient"]) - msg_recipient = sanitize(href_list["set_recipient"]) - addressbook = FALSE - return 1 - - if(href_list["edit_title"]) - var/newtitle = sanitize(input(user,"Enter title for your message:", "Message title", msg_title), 100) - if(newtitle) - msg_title = newtitle - return 1 - - // This uses similar editing mechanism as the FileManager program, therefore it supports various paper tags and remembers formatting. - if(href_list["edit_body"]) - var/oldtext = html_decode(msg_body) - oldtext = replacetext(oldtext, "\[editorbr\]", "\n") - - var/newtext = sanitize(replacetext(input(usr, "Enter your message. You may use most tags from paper formatting", "Message Editor", oldtext) as message|null, "\n", "\[editorbr\]"), 20000) - if(newtext) - msg_body = newtext - return 1 - - if(href_list["edit_recipient"]) - var/newrecipient = sanitize(input(user,"Enter recipient's email address:", "Recipient", msg_recipient), 100) - if(newrecipient) - msg_recipient = newrecipient - return 1 - - if(href_list["edit_login"]) - var/newlogin = sanitize(input(user,"Enter login", "Login", stored_login), 100) - if(newlogin) - stored_login = newlogin - return 1 - - if(href_list["edit_password"]) - var/newpass = sanitize(input(user,"Enter password", "Password"), 100) - if(newpass) - stored_password = newpass - return 1 - - if(href_list["delete"]) - if(!istype(current_account)) - return 1 - var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["delete"]) - if(!istype(M)) - return 1 - if(folder == "Deleted") - current_account.deleted.Remove(M) - qdel(M) - else - current_account.deleted.Add(M) - current_account.inbox.Remove(M) - current_account.spam.Remove(M) - if(current_message == M) - current_message = null - return 1 - - if(href_list["send"]) - if(!current_account) - return 1 - if((msg_title == "") || (msg_body == "") || (msg_recipient == "")) - error = "Error sending mail: Title or message body is empty!" - return 1 - - var/datum/computer_file/data/email_message/message = new() - message.title = msg_title - message.stored_data = msg_body - message.source = current_account.login - message.attachment = msg_attachment - if(!current_account.send_mail(msg_recipient, message)) - error = "Error sending email: this address doesn't exist." - return 1 - else - error = "Email successfully sent." - clear_message() - return 1 - - if(href_list["set_folder"]) - folder = href_list["set_folder"] - return 1 - - if(href_list["reply"]) - var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["reply"]) - if(!istype(M)) - return 1 - - new_message = TRUE - msg_recipient = M.source - msg_title = "Re: [M.title]" - msg_body = "\[editorbr\]\[editorbr\]\[editorbr\]\[br\]==============================\[br\]\[editorbr\]" - msg_body += "Received by [current_account.login] at [M.timestamp]\[br\]\[editorbr\][M.stored_data]" - return 1 - - if(href_list["view"]) - var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["view"]) - if(istype(M)) - current_message = M - return 1 - - if(href_list["changepassword"]) - var/oldpassword = sanitize(input(user,"Please enter your old password:", "Password Change"), 100) - if(!oldpassword) - return 1 - var/newpassword1 = sanitize(input(user,"Please enter your new password:", "Password Change"), 100) - if(!newpassword1) - return 1 - var/newpassword2 = sanitize(input(user,"Please re-enter your new password:", "Password Change"), 100) - if(!newpassword2) - return 1 - - if(!istype(current_account)) - error = "Please log in before proceeding." - return 1 - - if(current_account.password != oldpassword) - error = "Incorrect original password" - return 1 - - if(newpassword1 != newpassword2) - error = "The entered passwords do not match." - return 1 - - current_account.password = newpassword1 - stored_password = newpassword1 - error = "Your password has been successfully changed!" - return 1 - - // The following entries are Modular Computer framework only, and therefore won't do anything in other cases (like AI View) - - if(href_list["save"]) - // Fully dependant on modular computers here. - var/obj/item/modular_computer/MC = nano_host() - - if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) - error = "Error exporting file. Are you using a functional and NTOS-compliant device?" - return 1 - - var/filename = sanitize(input(user,"Please specify file name:", "Message export"), 100) - if(!filename) - return 1 - - var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["save"]) - var/datum/computer_file/data/mail = istype(M) ? M.export() : null - if(!istype(mail)) - return 1 - mail.filename = filename - if(!MC.hard_drive || !MC.hard_drive.store_file(mail)) - error = "Internal I/O error when writing file, the hard drive may be full." - else - error = "Email exported successfully" - return 1 - - if(href_list["addattachment"]) - var/obj/item/modular_computer/MC = nano_host() - msg_attachment = null - - if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) - error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?" - return 1 - - var/list/filenames = list() - for(var/datum/computer_file/CF in MC.hard_drive.stored_files) - if(CF.unsendable) - continue - filenames.Add(CF.filename) - var/picked_file = input(user, "Please pick a file to send as attachment (max 32GQ)") as null|anything in filenames - - if(!picked_file) - return 1 - - if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) - error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?" - return 1 - - for(var/datum/computer_file/CF in MC.hard_drive.stored_files) - if(CF.unsendable) - continue - if(CF.filename == picked_file) - msg_attachment = CF.clone() - break - if(!istype(msg_attachment)) - msg_attachment = null - error = "Unknown error when uploading attachment." - return 1 - - if(msg_attachment.size > 32) - error = "Error uploading attachment: File exceeds maximal permitted file size of 32GQ." - msg_attachment = null - else - error = "File [msg_attachment.filename].[msg_attachment.filetype] has been successfully uploaded." - return 1 - - if(href_list["downloadattachment"]) - if(!current_account || !current_message || !current_message.attachment) - return 1 - var/obj/item/modular_computer/MC = nano_host() - if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) - error = "Error downloading file. Are you using a functional and NTOSv2-compliant device?" - return 1 - - downloading = current_message.attachment.clone() - download_progress = 0 - return 1 - - if(href_list["canceldownload"]) - downloading = null - download_progress = 0 - return 1 - - if(href_list["remove_attachment"]) - msg_attachment = null - return 1 \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/generic/file_browser.dm b/code/modules/modular_computers/file_system/programs/generic/file_browser.dm index 42dfdd622d..13a137993e 100644 --- a/code/modules/modular_computers/file_system/programs/generic/file_browser.dm +++ b/code/modules/modular_computers/file_system/programs/generic/file_browser.dm @@ -6,202 +6,190 @@ program_key_state = "generic_key" program_menu_icon = "folder-collapsed" size = 8 - requires_ntnet = 0 - available_on_ntnet = 0 - undeletable = 1 - nanomodule_path = /datum/nano_module/program/computer_filemanager/ + requires_ntnet = FALSE + available_on_ntnet = FALSE + undeletable = TRUE + tgui_id = "NtosFileManager" + var/open_file var/error -/datum/computer_file/program/filemanager/Topic(href, href_list) +/datum/computer_file/program/filemanager/tgui_act(action, list/params, datum/tgui/ui) if(..()) - return 1 + return TRUE - if(href_list["PRG_openfile"]) - . = 1 - open_file = href_list["PRG_openfile"] - if(href_list["PRG_newtextfile"]) - . = 1 - var/newname = sanitize(input(usr, "Enter file name or leave blank to cancel:", "File rename")) - if(!newname) - return 1 - var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive - if(!HDD) - return 1 - var/datum/computer_file/data/F = new/datum/computer_file/data() - F.filename = newname - F.filetype = "TXT" - HDD.store_file(F) - if(href_list["PRG_deletefile"]) - . = 1 - var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive - if(!HDD) - return 1 - var/datum/computer_file/file = HDD.find_file_by_name(href_list["PRG_deletefile"]) - if(!file || file.undeletable) - return 1 - HDD.remove_file(file) - if(href_list["PRG_usbdeletefile"]) - . = 1 - var/obj/item/weapon/computer_hardware/hard_drive/RHDD = computer.portable_drive - if(!RHDD) - return 1 - var/datum/computer_file/file = RHDD.find_file_by_name(href_list["PRG_usbdeletefile"]) - if(!file || file.undeletable) - return 1 - RHDD.remove_file(file) - if(href_list["PRG_closefile"]) - . = 1 - open_file = null - error = null - if(href_list["PRG_clone"]) - . = 1 - var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive - if(!HDD) - return 1 - var/datum/computer_file/F = HDD.find_file_by_name(href_list["PRG_clone"]) - if(!F || !istype(F)) - return 1 - var/datum/computer_file/C = F.clone(1) - HDD.store_file(C) - if(href_list["PRG_rename"]) - . = 1 - var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive - if(!HDD) - return 1 - var/datum/computer_file/file = HDD.find_file_by_name(href_list["PRG_rename"]) - if(!file || !istype(file)) - return 1 - var/newname = sanitize(input(usr, "Enter new file name:", "File rename", file.filename)) - if(file && newname) + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + var/obj/item/weapon/computer_hardware/hard_drive/RHDD = computer.portable_drive + + switch(action) + if("PRG_openfile") + open_file = params["name"] + return TRUE + if("PRG_newtextfile") + if(!HDD) + return + var/newname = sanitize(input(usr, "Enter file name or leave blank to cancel:", "File rename")) + if(!newname) + return + var/datum/computer_file/data/F = new/datum/computer_file/data() + F.filename = newname + F.filetype = "TXT" + HDD.store_file(F) + return TRUE + if("PRG_closefile") + open_file = null + error = null + return TRUE + if("PRG_clone") + if(!HDD) + return + var/datum/computer_file/F = HDD.find_file_by_name(params["name"]) + if(!F || !istype(F)) + return + var/datum/computer_file/C = F.clone(1) + HDD.store_file(C) + return TRUE + if("PRG_edit") + if(!HDD) + return + if(!open_file) + return + var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) + if(!F || !istype(F)) + return + if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No")) + return + + var/oldtext = html_decode(F.stored_data) + oldtext = replacetext(oldtext, "\[br\]", "\n") + + var/newtext = sanitize(replacetext(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH) + if(!newtext) + return + + if(F) + var/datum/computer_file/data/backup = F.clone() + HDD.remove_file(F) + F.stored_data = newtext + F.calculate_size() + // We can't store the updated file, it's probably too large. Print an error and restore backed up version. + // This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space. + // They will be able to copy-paste the text from error screen and store it in notepad or something. + if(!HDD.store_file(F)) + error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:

[html_decode(F.stored_data)]

" + HDD.store_file(backup) + return TRUE + if("PRG_printfile") + if(!HDD) + return + if(!open_file) + return + var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) + if(!F || !istype(F)) + return + if(!computer.nano_printer) + error = "Missing Hardware: Your computer does not have required hardware to complete this operation." + return + if(!computer.nano_printer.print_text(pencode2html(F.stored_data))) + error = "Hardware error: Printer was unable to print the file. It may be out of paper." + return + return TRUE + if("PRG_deletefile") + if(!HDD) + return + var/datum/computer_file/file = HDD.find_file_by_name(params["name"]) + if(!file || file.undeletable) + return + HDD.remove_file(file) + return TRUE + if("PRG_usbdeletefile") + if(!RHDD) + return + var/datum/computer_file/file = RHDD.find_file_by_name(params["name"]) + if(!file || file.undeletable) + return + RHDD.remove_file(file) + return TRUE + if("PRG_rename") + if(!HDD) + return + var/datum/computer_file/file = HDD.find_file_by_name(params["name"]) + if(!file) + return + var/newname = params["new_name"] + if(!newname) + return file.filename = newname - if(href_list["PRG_edit"]) - . = 1 - if(!open_file) - return 1 - var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive - if(!HDD) - return 1 - var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) - if(!F || !istype(F)) - return 1 - if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No")) - return 1 + return TRUE + if("PRG_copytousb") + if(!HDD || !RHDD) + return + var/datum/computer_file/F = HDD.find_file_by_name(params["name"]) + if(!F) + return + var/datum/computer_file/C = F.clone(FALSE) + RHDD.store_file(C) + return TRUE + if("PRG_copyfromusb") + if(!HDD || !RHDD) + return + var/datum/computer_file/F = RHDD.find_file_by_name(params["name"]) + if(!F || !istype(F)) + return + var/datum/computer_file/C = F.clone(FALSE) + HDD.store_file(C) + return TRUE - var/oldtext = html_decode(F.stored_data) - oldtext = replacetext(oldtext, "\[br\]", "\n") +/datum/computer_file/program/filemanager/tgui_data(mob/user) + var/list/data = get_header_data() - var/newtext = sanitize(replacetext(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH) - if(!newtext) - return + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive - if(F) - var/datum/computer_file/data/backup = F.clone() - HDD.remove_file(F) - F.stored_data = newtext - F.calculate_size() - // We can't store the updated file, it's probably too large. Print an error and restore backed up version. - // This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space. - // They will be able to copy-paste the text from error screen and store it in notepad or something. - if(!HDD.store_file(F)) - error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:

[html_decode(F.stored_data)]

" - HDD.store_file(backup) - if(href_list["PRG_printfile"]) - . = 1 - if(!open_file) - return 1 - var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive - if(!HDD) - return 1 - var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) - if(!F || !istype(F)) - return 1 - if(!computer.nano_printer) - error = "Missing Hardware: Your computer does not have required hardware to complete this operation." - return 1 - if(!computer.nano_printer.print_text(pencode2html(F.stored_data))) - error = "Hardware error: Printer was unable to print the file. It may be out of paper." - return 1 - if(href_list["PRG_copytousb"]) - . = 1 - var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive - var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive - if(!HDD || !RHDD) - return 1 - var/datum/computer_file/F = HDD.find_file_by_name(href_list["PRG_copytousb"]) - if(!F || !istype(F)) - return 1 - var/datum/computer_file/C = F.clone(0) - RHDD.store_file(C) - if(href_list["PRG_copyfromusb"]) - . = 1 - var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive - var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive - if(!HDD || !RHDD) - return 1 - var/datum/computer_file/F = RHDD.find_file_by_name(href_list["PRG_copyfromusb"]) - if(!F || !istype(F)) - return 1 - var/datum/computer_file/C = F.clone(0) - HDD.store_file(C) - if(.) - SSnanoui.update_uis(NM) + data["error"] = null + if(error) + data["error"] = error + if(!computer || !HDD) + data["error"] = "I/O ERROR: Unable to access hard drive." + + data["filedata"] = null + data["filename"] = null + data["files"] = list() + data["usbconnected"] = FALSE + data["usbfiles"] = list() -/datum/nano_module/program/computer_filemanager - name = "NTOS File Manager" - -/datum/nano_module/program/computer_filemanager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - var/datum/computer_file/program/filemanager/PRG - PRG = program - - var/obj/item/weapon/computer_hardware/hard_drive/HDD - var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD - if(PRG.error) - data["error"] = PRG.error - if(PRG.open_file) + if(open_file) var/datum/computer_file/data/file - if(!PRG.computer || !PRG.computer.hard_drive) + if(!computer || !computer.hard_drive) data["error"] = "I/O ERROR: Unable to access hard drive." else - HDD = PRG.computer.hard_drive - file = HDD.find_file_by_name(PRG.open_file) + file = HDD.find_file_by_name(open_file) if(!istype(file)) data["error"] = "I/O ERROR: Unable to open file." else data["filedata"] = pencode2html(file.stored_data) data["filename"] = "[file.filename].[file.filetype]" else - if(!PRG.computer || !PRG.computer.hard_drive) - data["error"] = "I/O ERROR: Unable to access hard drive." - else - HDD = PRG.computer.hard_drive - RHDD = PRG.computer.portable_drive - var/list/files[0] - for(var/datum/computer_file/F in HDD.stored_files) - files.Add(list(list( + var/list/files = list() + for(var/datum/computer_file/F in HDD.stored_files) + files += list(list( + "name" = F.filename, + "type" = F.filetype, + "size" = F.size, + "undeletable" = F.undeletable + )) + data["files"] = files + if(RHDD) + data["usbconnected"] = TRUE + var/list/usbfiles = list() + for(var/datum/computer_file/F in RHDD.stored_files) + usbfiles += list(list( "name" = F.filename, "type" = F.filetype, "size" = F.size, "undeletable" = F.undeletable - ))) - data["files"] = files - if(RHDD) - data["usbconnected"] = 1 - var/list/usbfiles[0] - for(var/datum/computer_file/F in RHDD.stored_files) - usbfiles.Add(list(list( - "name" = F.filename, - "type" = F.filetype, - "size" = F.size, - "undeletable" = F.undeletable - ))) - data["usbfiles"] = usbfiles + )) + data["usbfiles"] = usbfiles - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "file_manager.tmpl", "NTOS File Manager", 575, 700, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() \ No newline at end of file + return data diff --git a/code/modules/modular_computers/file_system/programs/generic/game.dm b/code/modules/modular_computers/file_system/programs/generic/game.dm index b4c0688c29..4d21095f9d 100644 --- a/code/modules/modular_computers/file_system/programs/generic/game.dm +++ b/code/modules/modular_computers/file_system/programs/generic/game.dm @@ -1,152 +1,188 @@ // This file is used as a reference for Modular Computers Development guide on the wiki. It contains a lot of excess comments, as it is intended as explanation // for someone who may not be as experienced in coding. When making changes, please try to keep it this way. -// An actual program definition. /datum/computer_file/program/game - filename = "arcadec" // File name, as shown in the file browser program. - filedesc = "Unknown Game" // User-Friendly name. In this case, we will generate a random name in constructor. - program_icon_state = "game" // Icon state of this program's screen. - program_menu_icon = "script" - extended_desc = "Fun for the whole family! Probably not an AAA title, but at least you can download it on the corporate network.." // A nice description. - size = 5 // Size in GQ. Integers only. Smaller sizes should be used for utility/low use programs (like this one), while large sizes are for important programs. - requires_ntnet = 0 // This particular program does not require NTNet network conectivity... - available_on_ntnet = 1 // ... but we want it to be available for download. - nanomodule_path = /datum/nano_module/arcade_classic/ // Path of relevant nano module. The nano module is defined further in the file. - var/picked_enemy_name + filename = "dsarcade" // File name, as shown in the file browser program. + filedesc = "Donksoft Micro Arcade" // User-Friendly name. + program_icon_state = "arcade" // Icon state of this program's screen. + extended_desc = "This is a port of the classic game 'Outbomb Cuban Pete', redesigned to run on tablets; Now with thrilling graphics and chilling storytelling." // A nice description. + size = 6 // Size in GQ. Integers only. Smaller sizes should be used for utility/low use programs (like this one), while large sizes are for important programs. + requires_ntnet = FALSE // This particular program does not require NTNet network conectivity... + available_on_ntnet = TRUE // ... but we want it to be available for download. + tgui_id = "NtosArcade" // Path of relevant tgui template.js file. -// Blatantly stolen and shortened version from arcade machines. Generates a random enemy name -/datum/computer_file/program/game/proc/random_enemy_name() - var/name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Cuban ", "the Evil ", "the Dread King ", "the Space ", "Lord ", "the Great ", "Duke ", "General ") - var/name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon", "Uhangoid", "Vhakoid", "Peteoid", "Slime", "Lizard Man", "Unicorn") - return "[name_part1] [name_part2]" + ///Returns TRUE if the game is being played. + var/game_active = TRUE + ///This disables buttom actions from having any impact if TRUE. Resets to FALSE when the player is allowed to make an action again. + var/pause_state = FALSE + var/boss_hp = 45 + var/boss_mp = 15 + var/player_hp = 30 + var/player_mp = 10 + var/ticket_count = 0 + ///Shows what text is shown on the app, usually showing the log of combat actions taken by the player. + var/heads_up = "Nanotrasen says, winners make us money." + var/boss_name = "Cuban Pete's Minion" + ///Determines which boss image to use on the UI. + var/boss_id = 1 -// When the program is first created, we generate a new enemy name and name ourselves accordingly. -/datum/computer_file/program/game/New() - ..() - picked_enemy_name = random_enemy_name() - filedesc = "Defeat [picked_enemy_name]" +// This is the primary game loop, which handles the logic of being defeated or winning. +/datum/computer_file/program/game/proc/game_check(mob/user) + sleep(5) + if(boss_hp <= 0) + heads_up = "You have crushed [boss_name]! Rejoice!" + playsound(computer.loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3, falloff = 10) + game_active = FALSE + program_icon_state = "arcade_off" + if(istype(computer)) + computer.update_icon() + ticket_count += 1 + // user?.mind?.adjust_experience(/datum/skill/gaming, 50) + sleep(10) + else if(player_hp <= 0 || player_mp <= 0) + heads_up = "You have been defeated... how will the station survive?" + playsound(computer.loc, 'sound/arcade/lose.ogg', 50, TRUE, extrarange = -3, falloff = 10) + game_active = FALSE + program_icon_state = "arcade_off" + if(istype(computer)) + computer.update_icon() + // user?.mind?.adjust_experience(/datum/skill/gaming, 10) + sleep(10) -// Important in order to ensure that copied versions will have the same enemy name. -/datum/computer_file/program/game/clone() - var/datum/computer_file/program/game/G = ..() - G.picked_enemy_name = picked_enemy_name - return G - -// When running the program, we also want to pass our enemy name to the nano module. -/datum/computer_file/program/game/run_program() - . = ..() - if(. && NM) - var/datum/nano_module/arcade_classic/NMC = NM - NMC.enemy_name = picked_enemy_name - - -// Nano module the program uses. -// This can be either /datum/nano_module/ or /datum/nano_module/program. The latter is intended for nano modules that are suposed to be exclusively used with modular computers, -// and should generally not be used, as such nano modules are hard to use on other places. -/datum/nano_module/arcade_classic/ - name = "Classic Arcade" - var/player_mana // Various variables specific to the nano module. In this case, the nano module is a simple arcade game, so the variables store health and other stats. - var/player_health - var/enemy_mana - var/enemy_health - var/enemy_name = "Greytide Horde" - var/gameover - var/information - -/datum/nano_module/arcade_classic/New() - ..() - new_game() - -// ui_interact handles transfer of data to NanoUI. Keep in mind that data you pass from here is actually sent to the client. In other words, don't send anything you don't want a client -// to see, and don't send unnecessarily large amounts of data (due to laginess). -/datum/nano_module/arcade_classic/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - - data["player_health"] = player_health - data["player_mana"] = player_mana - data["enemy_health"] = enemy_health - data["enemy_mana"] = enemy_mana - data["enemy_name"] = enemy_name - data["gameover"] = gameover - data["information"] = information - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "arcade_classic.tmpl", "Defeat [enemy_name]", 500, 350, state = state) - if(host.update_layout()) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - -// Three helper procs i've created. These are unique to this particular nano module. If you are creating your own nano module, you'll most likely create similar procs too. -/datum/nano_module/arcade_classic/proc/enemy_play() - if((enemy_mana < 5) && prob(60)) - var/steal = rand(2, 3) - player_mana -= steal - enemy_mana += steal - information += "[enemy_name] steals [steal] of your power!" - else if((enemy_health < 15) && (enemy_mana > 3) && prob(80)) - var/healamt = min(rand(3, 5), enemy_mana) - enemy_mana -= healamt - enemy_health += healamt - information += "[enemy_name] heals for [healamt] health!" +// This handles the boss "AI". +/datum/computer_file/program/game/proc/enemy_check(mob/user) + var/boss_attackamt = 0 //Spam protection from boss attacks as well. + var/boss_mpamt = 0 + var/bossheal = 0 + if(pause_state == TRUE) + boss_attackamt = rand(3,6) + boss_mpamt = rand (2,4) + bossheal = rand (4,6) + if(game_active == FALSE) + return + if(boss_mp <= 5) + heads_up = "[boss_mpamt] magic power has been stolen from you!" + playsound(computer.loc, 'sound/arcade/steal.ogg', 50, TRUE, extrarange = -3, falloff = 10) + player_mp -= boss_mpamt + boss_mp += boss_mpamt + else if(boss_mp > 5 && boss_hp <12) + heads_up = "[boss_name] heals for [bossheal] health!" + playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3, falloff = 10) + boss_hp += bossheal + boss_mp -= boss_mpamt else - var/dam = rand(3,6) - player_health -= dam - information += "[enemy_name] attacks for [dam] damage!" + heads_up = "[boss_name] attacks you for [boss_attackamt] damage!" + playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 10) + player_hp -= boss_attackamt -/datum/nano_module/arcade_classic/proc/check_gameover() - if((player_health <= 0) || player_mana <= 0) - if(enemy_health <= 0) - information += "You have defeated [enemy_name], but you have died in the fight!" - else - information += "You have been defeated by [enemy_name]!" - gameover = 1 + pause_state = FALSE + game_check() + +/** + * UI assets define a list of asset datums to be sent with the UI. + * In this case, it's a bunch of cute enemy sprites. + */ +/datum/computer_file/program/game/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/simple/arcade), + ) + +/** + * This provides all of the relevant data to the UI in a list(). + */ +/datum/computer_file/program/game/tgui_data(mob/user) + var/list/data = get_header_data() + data["Hitpoints"] = boss_hp + data["PlayerHitpoints"] = player_hp + data["PlayerMP"] = player_mp + data["TicketCount"] = ticket_count + data["GameActive"] = game_active + data["PauseState"] = pause_state + data["Status"] = heads_up + data["BossID"] = "boss[boss_id].gif" + return data + +/** + * This is tgui's replacement for Topic(). It handles any user input from the UI. + */ +/datum/computer_file/program/game/tgui_act(action, list/params) + if(..()) // Always call parent in tgui_act, it handles making sure the user is allowed to interact with the UI. return TRUE - else if(enemy_health <= 0) - gameover = 1 - information += "Congratulations! You have defeated [enemy_name]!" - return TRUE - return FALSE -/datum/nano_module/arcade_classic/proc/new_game() - player_mana = 10 - player_health = 30 - enemy_mana = 20 - enemy_health = 45 - gameover = FALSE - information = "A new game has started!" + var/obj/item/weapon/computer_hardware/nano_printer/printer + if(computer) + printer = computer.nano_printer - - -/datum/nano_module/arcade_classic/Topic(href, href_list) - if(..()) // Always begin your Topic() calls with a parent call! - return 1 - if(href_list["new_game"]) - new_game() - return 1 // Returning 1 (TRUE) in Topic automatically handles UI updates. - if(gameover) // If the game has already ended, we don't want the following three topic calls to be processed at all. - return 1 // Instead of adding checks into each of those three, we can easily add this one check here to reduce on code copy-paste. - if(href_list["attack"]) - var/damage = rand(2, 6) - information = "You attack for [damage] damage." - enemy_health -= damage - enemy_play() - check_gameover() - return 1 - if(href_list["heal"]) - var/healfor = rand(6, 8) - var/cost = rand(1, 3) - information = "You heal yourself for [healfor] damage, using [cost] energy in the process." - player_health += healfor - player_mana -= cost - enemy_play() - check_gameover() - return 1 - if(href_list["regain_mana"]) - var/regen = rand(4, 7) - information = "You rest of a while, regaining [regen] energy." - player_mana += regen - enemy_play() - check_gameover() - return 1 \ No newline at end of file + // var/gamerSkillLevel = usr.mind?.get_skill_level(/datum/skill/gaming) + // var/gamerSkill = usr.mind?.get_skill_modifier(/datum/skill/gaming, SKILL_RANDS_MODIFIER) + switch(action) + if("Attack") + var/attackamt = 0 //Spam prevention. + if(pause_state == FALSE) + attackamt = rand(2,6) // + rand(0, gamerSkill) + pause_state = TRUE + heads_up = "You attack for [attackamt] damage." + playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 10) + boss_hp -= attackamt + sleep(10) + game_check() + enemy_check() + return TRUE + if("Heal") + var/healamt = 0 //More Spam Prevention. + var/healcost = 0 + if(pause_state == FALSE) + healamt = rand(6,8) // + rand(0, gamerSkill) + var/maxPointCost = 3 + // if(gamerSkillLevel >= SKILL_LEVEL_JOURNEYMAN) + // maxPointCost = 2 + healcost = rand(1, maxPointCost) + pause_state = TRUE + heads_up = "You heal for [healamt] damage." + playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3, falloff = 10) + player_hp += healamt + player_mp -= healcost + sleep(10) + game_check() + enemy_check() + return TRUE + if("Recharge_Power") + var/rechargeamt = 0 //As above. + if(pause_state == FALSE) + rechargeamt = rand(4,7) // + rand(0, gamerSkill) + pause_state = TRUE + heads_up = "You regain [rechargeamt] magic power." + playsound(computer.loc, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3, falloff = 10) + player_mp += rechargeamt + sleep(10) + game_check() + enemy_check() + return TRUE + if("Dispense_Tickets") + if(!printer) + to_chat(usr, "Hardware error: A printer is required to redeem tickets.") + return + if(printer.stored_paper <= 0) + to_chat(usr, "Hardware error: Printer is out of paper.") + return + else + computer.visible_message("\The [computer] prints out paper.") + if(ticket_count >= 1) + new /obj/item/stack/arcadeticket((get_turf(computer)), 1) + to_chat(usr, "[src] dispenses a ticket!") + ticket_count -= 1 + printer.stored_paper -= 1 + else + to_chat(usr, "You don't have any stored tickets!") + return TRUE + if("Start_Game") + game_active = TRUE + boss_hp = 45 + player_hp = 30 + player_mp = 10 + heads_up = "You stand before [boss_name]! Prepare for battle!" + program_icon_state = "arcade" + boss_id = rand(1,6) + pause_state = FALSE + if(istype(computer)) + computer.update_icon() diff --git a/code/modules/modular_computers/file_system/programs/generic/news_browser.dm b/code/modules/modular_computers/file_system/programs/generic/news_browser.dm index 1d4da6d4d5..e72e30fd38 100644 --- a/code/modules/modular_computers/file_system/programs/generic/news_browser.dm +++ b/code/modules/modular_computers/file_system/programs/generic/news_browser.dm @@ -6,16 +6,17 @@ program_key_state = "generic_key" program_menu_icon = "contact" size = 4 - requires_ntnet = 1 - available_on_ntnet = 1 + requires_ntnet = TRUE + available_on_ntnet = TRUE + + tgui_id = "NtosNewsBrowser" - nanomodule_path = /datum/nano_module/program/computer_newsbrowser/ var/datum/computer_file/data/news_article/loaded_article var/download_progress = 0 var/download_netspeed = 0 - var/downloading = 0 + var/downloading = FALSE var/message = "" - var/show_archived = 0 + var/show_archived = FALSE /datum/computer_file/program/newsbrowser/process_tick() if(!downloading) @@ -33,86 +34,31 @@ if(download_progress >= loaded_article.size) downloading = 0 requires_ntnet = 0 // Turn off NTNet requirement as we already loaded the file into local memory. - SSnanoui.update_uis(NM) + SStgui.update_uis(src) -/datum/computer_file/program/newsbrowser/kill_program() - ..() - requires_ntnet = 1 - loaded_article = null - download_progress = 0 - downloading = 0 - show_archived = 0 +/datum/computer_file/program/newsbrowser/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = get_header_data() -/datum/computer_file/program/newsbrowser/Topic(href, href_list) - if(..()) - return 1 - if(href_list["PRG_openarticle"]) - . = 1 - if(downloading || loaded_article) - return 1 - - for(var/datum/computer_file/data/news_article/N in ntnet_global.available_news) - if(N.uid == text2num(href_list["PRG_openarticle"])) - loaded_article = N.clone() - downloading = 1 - break - if(href_list["PRG_reset"]) - . = 1 - downloading = 0 - download_progress = 0 - requires_ntnet = 1 - loaded_article = null - if(href_list["PRG_clearmessage"]) - . = 1 - message = "" - if(href_list["PRG_savearticle"]) - . = 1 - if(downloading || !loaded_article) - return - - var/savename = sanitize(input(usr, "Enter file name or leave blank to cancel:", "Save article", loaded_article.filename)) - if(!savename) - return 1 - var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive - if(!HDD) - return 1 - var/datum/computer_file/data/news_article/N = loaded_article.clone() - N.filename = savename - HDD.store_file(N) - if(href_list["PRG_toggle_archived"]) - . = 1 - show_archived = !show_archived - if(.) - SSnanoui.update_uis(NM) - - -/datum/nano_module/program/computer_newsbrowser - name = "NTNet/ExoNet News Browser" - -/datum/nano_module/program/computer_newsbrowser/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - - var/datum/computer_file/program/newsbrowser/PRG - var/list/data = list() - if(program) - data = program.get_header_data() - PRG = program - else - return - - data["message"] = PRG.message - if(PRG.loaded_article && !PRG.downloading) // Viewing an article. - data["title"] = PRG.loaded_article.filename - data["cover"] = PRG.loaded_article.cover - data["article"] = PRG.loaded_article.stored_data - else if(PRG.downloading) // Downloading an article. - data["download_running"] = 1 - data["download_progress"] = PRG.download_progress - data["download_maxprogress"] = PRG.loaded_article.size - data["download_rate"] = PRG.download_netspeed + var/list/all_articles = list() + data["message"] = message + data["showing_archived"] = show_archived + data["download"] = null + data["article"] = null + if(loaded_article && !downloading) // Viewing an article. + data["article"] = list( + "title" = loaded_article.filename, + "cover" = loaded_article.cover, + "content" = loaded_article.stored_data, + ) + else if(downloading) // Downloading an article. + data["download"] = list( + "download_progress" = download_progress, + "download_maxprogress" = loaded_article.size, + "download_rate" = download_netspeed + ) else // Viewing list of articles - var/list/all_articles[0] for(var/datum/computer_file/data/news_article/F in ntnet_global.available_news) - if(!PRG.show_archived && F.archived) + if(!show_archived && F.archived) continue all_articles.Add(list(list( "name" = F.filename, @@ -120,12 +66,56 @@ "uid" = F.uid, "archived" = F.archived ))) - data["all_articles"] = all_articles - data["showing_archived"] = PRG.show_archived + data["all_articles"] = all_articles + + return data + +/datum/computer_file/program/newsbrowser/kill_program() + ..() + requires_ntnet = TRUE + loaded_article = null + download_progress = 0 + downloading = FALSE + show_archived = FALSE + +/datum/computer_file/program/newsbrowser/tgui_act(action, list/params, datum/tgui/ui) + if(..()) + return TRUE + switch(action) + if("PRG_openarticle") + . = TRUE + if(downloading || loaded_article) + return TRUE + + for(var/datum/computer_file/data/news_article/N in ntnet_global.available_news) + if(N.uid == text2num(params["uid"])) + loaded_article = N.clone() + downloading = 1 + break + if("PRG_reset") + . = TRUE + downloading = 0 + download_progress = 0 + requires_ntnet = 1 + loaded_article = null + if("PRG_clearmessage") + . = TRUE + message = "" + if("PRG_savearticle") + . = TRUE + if(downloading || !loaded_article) + return + + var/savename = sanitize(input(usr, "Enter file name or leave blank to cancel:", "Save article", loaded_article.filename)) + if(!savename) + return TRUE + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + if(!HDD) + return TRUE + var/datum/computer_file/data/news_article/N = loaded_article.clone() + N.filename = savename + HDD.store_file(N) + if("PRG_toggle_archived") + . = TRUE + show_archived = !show_archived - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "news_browser.tmpl", "NTNet/ExoNet News Browser", 575, 750, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() diff --git a/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm b/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm index a0b2194168..14e2343e66 100644 --- a/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm +++ b/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm @@ -5,29 +5,26 @@ program_key_state = "generic_key" program_menu_icon = "arrowthickstop-1-s" extended_desc = "This program allows downloads of software from official NT repositories" - unsendable = 1 - undeletable = 1 + unsendable = TRUE + undeletable = TRUE size = 4 - requires_ntnet = 1 + requires_ntnet = TRUE requires_ntnet_feature = NTNET_SOFTWAREDOWNLOAD - available_on_ntnet = 0 - nanomodule_path = /datum/nano_module/program/computer_ntnetdownload/ + available_on_ntnet = FALSE ui_header = "downloader_finished.gif" + tgui_id = "NtosNetDownloader" + var/datum/computer_file/program/downloaded_file = null var/hacked_download = 0 var/download_completion = 0 //GQ of downloaded data. var/download_netspeed = 0 var/downloaderror = "" + var/obj/item/modular_computer/my_computer = null var/list/downloads_queue[0] /datum/computer_file/program/ntnetdownload/kill_program() ..() - downloaded_file = null - download_completion = 0 - download_netspeed = 0 - downloaderror = "" - ui_header = "downloader_finished.gif" - + abort_file_download() /datum/computer_file/program/ntnetdownload/proc/begin_file_download(var/filename) if(downloaded_file) @@ -108,93 +105,85 @@ download_netspeed = NTNETSPEED_ETHERNET download_completion += download_netspeed -/datum/computer_file/program/ntnetdownload/Topic(href, href_list) +/datum/computer_file/program/ntnetdownload/tgui_act(action, params) if(..()) - return 1 - if(href_list["PRG_downloadfile"]) - if(!downloaded_file) - begin_file_download(href_list["PRG_downloadfile"]) - else if(check_file_download(href_list["PRG_downloadfile"]) && !downloads_queue.Find(href_list["PRG_downloadfile"]) && downloaded_file.filename != href_list["PRG_downloadfile"]) - downloads_queue += href_list["PRG_downloadfile"] - return 1 - if(href_list["PRG_removequeued"]) - downloads_queue.Remove(href_list["PRG_removequeued"]) - return 1 - if(href_list["PRG_reseterror"]) - if(downloaderror) - download_completion = 0 - download_netspeed = 0 - downloaded_file = null - downloaderror = "" - return 1 - return 0 - -/datum/nano_module/program/computer_ntnetdownload - name = "Network Downloader" - var/obj/item/modular_computer/my_computer = null - -/datum/nano_module/program/computer_ntnetdownload/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - if(program) - my_computer = program.computer + return TRUE + switch(action) + if("PRG_downloadfile") + if(!downloaded_file) + begin_file_download(params["filename"]) + else if(check_file_download(params["filename"]) && !downloads_queue.Find(params["filename"]) && downloaded_file.filename != params["filename"]) + downloads_queue += params["filename"] + return TRUE + if("PRG_removequeued") + downloads_queue.Remove(params["filename"]) + return TRUE + if("PRG_reseterror") + if(downloaderror) + download_completion = 0 + download_netspeed = 0 + downloaded_file = null + downloaderror = "" + return TRUE + return FALSE +/datum/computer_file/program/ntnetdownload/tgui_data(mob/user) + my_computer = computer if(!istype(my_computer)) return - var/list/data = list() - var/datum/computer_file/program/ntnetdownload/prog = program - // For now limited to execution by the downloader program - if(!prog || !istype(prog)) - return - if(program) - data = program.get_header_data() + var/list/data = get_header_data() - // This IF cuts on data transferred to client, so i guess it's worth it. - if(prog.downloaderror) // Download errored. Wait until user resets the program. - data["error"] = prog.downloaderror - if(prog.downloaded_file) // Download running. Wait please.. - data["downloadname"] = prog.downloaded_file.filename - data["downloaddesc"] = prog.downloaded_file.filedesc - data["downloadsize"] = prog.downloaded_file.size - data["downloadspeed"] = prog.download_netspeed - data["downloadcompletion"] = round(prog.download_completion, 0.1) + data["downloading"] = !!downloaded_file + data["error"] = downloaderror || FALSE + + if(downloaded_file) // Download running. Wait please.. + data["downloadname"] = downloaded_file.filename + data["downloaddesc"] = downloaded_file.filedesc + data["downloadsize"] = downloaded_file.size + data["downloadspeed"] = download_netspeed + data["downloadcompletion"] = round(download_completion, 0.1) data["disk_size"] = my_computer.hard_drive.max_capacity data["disk_used"] = my_computer.hard_drive.used_capacity var/list/all_entries[0] for(var/datum/computer_file/program/P in ntnet_global.available_station_software) // Only those programs our user can run will show in the list - if(!P.can_run(user) && P.requires_access_to_download) + if(!P.can_run(user) && P.requires_access_to_download || my_computer.hard_drive.find_file_by_name(P.filename)) continue all_entries.Add(list(list( - "filename" = P.filename, - "filedesc" = P.filedesc, - "fileinfo" = P.extended_desc, - "size" = P.size, - "icon" = P.program_menu_icon - ))) - data["hackedavailable"] = 0 - if(prog.computer_emagged) // If we are running on emagged computer we have access to some "bonus" software - var/list/hacked_programs[0] - for(var/datum/computer_file/program/P in ntnet_global.available_antag_software) - data["hackedavailable"] = 1 - hacked_programs.Add(list(list( "filename" = P.filename, "filedesc" = P.filedesc, "fileinfo" = P.extended_desc, + "compatibility" = check_compatibility(P), "size" = P.size, "icon" = P.program_menu_icon + ))) + data["hackedavailable"] = FALSE + if(computer_emagged) // If we are running on emagged computer we have access to some "bonus" software + var/list/hacked_programs[0] + for(var/datum/computer_file/program/P in ntnet_global.available_antag_software) + if(my_computer.hard_drive.find_file_by_name(P.filename)) + continue + data["hackedavailable"] = TRUE + hacked_programs.Add(list(list( + "filename" = P.filename, + "filedesc" = P.filedesc, + "fileinfo" = P.extended_desc, + "compatibility" = check_compatibility(P), + "size" = P.size, + "icon" = P.program_menu_icon ))) data["hacked_programs"] = hacked_programs data["downloadable_programs"] = all_entries + data["downloads_queue"] = downloads_queue - if(prog.downloads_queue.len > 0) - data["downloads_queue"] = prog.downloads_queue + return data - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "ntnet_downloader.tmpl", "NTNet Download Program", 575, 700, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) +/datum/computer_file/program/ntnetdownload/proc/check_compatibility(datum/computer_file/program/P) + var/hardflag = computer.hardware_flag + + if(P && P.is_supported_by_hardware(hardflag,0)) + return "Compatible" + return "Incompatible!" diff --git a/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm b/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm index 6c67c02c0d..f2466213f3 100644 --- a/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm +++ b/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm @@ -11,222 +11,220 @@ network_destination = "NTNRC server" ui_header = "ntnrc_idle.gif" available_on_ntnet = 1 - nanomodule_path = /datum/nano_module/program/computer_chatclient/ - var/last_message = null // Used to generate the toolbar icon + tgui_id = "NtosNetChat" + var/last_message // Used to generate the toolbar icon var/username - var/datum/ntnet_conversation/channel = null - var/operator_mode = 0 // Channel operator mode - var/netadmin_mode = 0 // Administrator mode (invisible to other users + bypasses passwords) + var/active_channel + var/list/channel_history = list() + var/operator_mode = FALSE // Channel operator mode + var/netadmin_mode = FALSE // Administrator mode (invisible to other users + bypasses passwords) /datum/computer_file/program/chatclient/New() username = "DefaultUser[rand(100, 999)]" -/datum/computer_file/program/chatclient/Topic(href, href_list) +/datum/computer_file/program/chatclient/tgui_act(action, params) if(..()) - return 1 + return - if(href_list["PRG_speak"]) - . = 1 - if(!channel) - return 1 - var/mob/living/user = usr - var/message = sanitize(input(user, "Enter message or leave blank to cancel: "), 512) - if(!message || !channel) - return - channel.add_message(message, username) + var/datum/ntnet_conversation/channel = ntnet_global.get_chat_channel_by_id(active_channel) + var/authed = FALSE + if(channel && ((channel.operator == src) || netadmin_mode)) + authed = TRUE + switch(action) + if("PRG_speak") + if(!channel || isnull(active_channel)) + return + var/message = reject_bad_text(params["message"]) + if(!message) + return + if(channel.password && !(src in channel.clients)) + if(channel.password == message) + channel.add_client(src) + return TRUE - if(href_list["PRG_joinchannel"]) - . = 1 - var/datum/ntnet_conversation/C - for(var/datum/ntnet_conversation/chan in ntnet_global.chat_channels) - if(chan.id == text2num(href_list["PRG_joinchannel"])) - C = chan - break + channel.add_message(message, username) + // var/mob/living/user = usr + // user.log_talk(message, LOG_CHAT, tag="as [username] to channel [channel.title]") + return TRUE + if("PRG_joinchannel") + var/new_target = text2num(params["id"]) + if(isnull(new_target) || new_target == active_channel) + return - if(!C) - return 1 + if(netadmin_mode) + active_channel = new_target // Bypasses normal leave/join and passwords. Technically makes the user invisible to others. + return TRUE - if(netadmin_mode) - channel = C // Bypasses normal leave/join and passwords. Technically makes the user invisible to others. - return 1 - - if(C.password) + active_channel = new_target + channel = ntnet_global.get_chat_channel_by_id(new_target) + if(!(src in channel.clients) && !channel.password) + channel.add_client(src) + return TRUE + if("PRG_leavechannel") + if(channel) + channel.remove_client(src) + active_channel = null + return TRUE + if("PRG_newchannel") + var/channel_title = reject_bad_text(params["new_channel_name"]) + if(!channel_title) + return + var/datum/ntnet_conversation/C = new /datum/ntnet_conversation() + C.add_client(src) + C.operator = src + C.title = channel_title + active_channel = C.id + return TRUE + if("PRG_toggleadmin") + if(netadmin_mode) + netadmin_mode = FALSE + if(channel) + channel.remove_client(src) // We shouldn't be in channel's user list, but just in case... + return TRUE var/mob/living/user = usr - var/password = sanitize(input(user,"Access Denied. Enter password:")) - if(C && (password == C.password)) - C.add_client(src) - channel = C - return 1 - C.add_client(src) - channel = C - if(href_list["PRG_leavechannel"]) - . = 1 - if(channel) - channel.remove_client(src) - channel = null - if(href_list["PRG_newchannel"]) - . = 1 - var/mob/living/user = usr - var/channel_title = sanitizeSafe(input(user,"Enter channel name or leave blank to cancel:"), 64) - if(!channel_title) - return - var/datum/ntnet_conversation/C = new/datum/ntnet_conversation() - C.add_client(src) - C.operator = src - channel = C - C.title = channel_title - if(href_list["PRG_toggleadmin"]) - . = 1 - if(netadmin_mode) - netadmin_mode = 0 - if(channel) - channel.remove_client(src) // We shouldn't be in channel's user list, but just in case... - channel = null - return 1 - var/mob/living/user = usr - if(can_run(usr, 1, access_network)) - if(channel) - var/response = alert(user, "Really engage admin-mode? You will be disconnected from your current channel!", "NTNRC Admin mode", "Yes", "No") - if(response == "Yes") - if(channel) - channel.remove_client(src) - channel = null - else - return - netadmin_mode = 1 - if(href_list["PRG_changename"]) - . = 1 - var/mob/living/user = usr - var/newname = sanitize(input(user,"Enter new nickname or leave blank to cancel:"), 20) - if(!newname) - return 1 - if(channel) - channel.add_status_message("[username] is now known as [newname].") - username = newname + if(can_run(user, TRUE, access_network)) + for(var/C in ntnet_global.chat_channels) + var/datum/ntnet_conversation/chan = C + chan.remove_client(src) + netadmin_mode = TRUE + return TRUE + if("PRG_changename") + var/newname = sanitize(params["new_name"]) + if(!newname) + return + for(var/C in ntnet_global.chat_channels) + var/datum/ntnet_conversation/chan = C + if(src in chan.clients) + chan.add_status_message("[username] is now known as [newname].") + username = newname + return TRUE + if("PRG_savelog") + if(!channel) + return + var/logname = stripped_input(params["log_name"]) + if(!logname) + return + var/datum/computer_file/data/logfile = new /datum/computer_file/data/logfile() + // Now we will generate HTML-compliant file that can actually be viewed/printed. + logfile.filename = logname + logfile.stored_data = "\[b\]Logfile dump from NTNRC channel [channel.title]\[/b\]\[BR\]" + for(var/logstring in channel.messages) + logfile.stored_data = "[logfile.stored_data][logstring]\[BR\]" + logfile.stored_data = "[logfile.stored_data]\[b\]Logfile dump completed.\[/b\]" + logfile.calculate_size() + if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(logfile)) + if(!computer) + // This program shouldn't even be runnable without computer. + CRASH("Var computer is null!") + if(!computer.hard_drive) + computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive connection error\" warning.") + else // In 99.9% cases this will mean our HDD is full + computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive may be full. Please free some space and try again. Required space: [logfile.size]GQ\" warning.") + return TRUE + if("PRG_renamechannel") + if(!authed) + return + var/newname = reject_bad_text(params["new_name"]) + if(!newname || !channel) + return + channel.add_status_message("Channel renamed from [channel.title] to [newname] by operator.") + channel.title = newname + return TRUE + if("PRG_deletechannel") + if(authed) + qdel(channel) + active_channel = null + return TRUE + if("PRG_setpassword") + if(!authed) + return - if(href_list["PRG_savelog"]) - . = 1 - if(!channel) - return - var/mob/living/user = usr - var/logname = input(user,"Enter desired logfile name (.log) or leave blank to cancel:") - if(!logname || !channel) - return 1 - var/datum/computer_file/data/logfile = new/datum/computer_file/data/logfile() - // Now we will generate HTML-compliant file that can actually be viewed/printed. - logfile.filename = logname - logfile.stored_data = "\[b\]Logfile dump from NTNRC channel [channel.title]\[/b\]\[BR\]" - for(var/logstring in channel.messages) - logfile.stored_data += "[logstring]\[BR\]" - logfile.stored_data += "\[b\]Logfile dump completed.\[/b\]" - logfile.calculate_size() - if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(logfile)) - if(!computer) - // This program shouldn't even be runnable without computer. - CRASH("Var computer is null!") - return 1 - if(!computer.hard_drive) - computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive connection error\" warning.") - else // In 99.9% cases this will mean our HDD is full - computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive may be full. Please free some space and try again. Required space: [logfile.size]GQ\" warning.") - if(href_list["PRG_renamechannel"]) - . = 1 - if(!operator_mode || !channel) - return 1 - var/mob/living/user = usr - var/newname = sanitize(input(user, "Enter new channel name or leave blank to cancel:"), 64) - if(!newname || !channel) - return - channel.add_status_message("Channel renamed from [channel.title] to [newname] by operator.") - channel.title = newname - if(href_list["PRG_deletechannel"]) - . = 1 - if(channel && ((channel.operator == src) || netadmin_mode)) - qdel(channel) - channel = null - if(href_list["PRG_setpassword"]) - . = 1 - if(!channel || ((channel.operator != src) && !netadmin_mode)) - return 1 + var/new_password = sanitize(params["new_password"]) + if(!authed) + return - var/mob/living/user = usr - var/newpassword = sanitize(input(user, "Enter new password for this channel. Leave blank to cancel, enter 'nopassword' to remove password completely:")) - if(!channel || !newpassword || ((channel.operator != src) && !netadmin_mode)) - return 1 - - if(newpassword == "nopassword") - channel.password = "" - else - channel.password = newpassword + channel.password = new_password + return TRUE /datum/computer_file/program/chatclient/process_tick() ..() + var/datum/ntnet_conversation/channel = ntnet_global.get_chat_channel_by_id(active_channel) if(program_state != PROGRAM_STATE_KILLED) ui_header = "ntnrc_idle.gif" if(channel) // Remember the last message. If there is no message in the channel remember null. - last_message = channel.messages.len ? channel.messages[channel.messages.len - 1] : null + last_message = length(channel.messages) ? channel.messages[channel.messages.len - 1] : null else last_message = null return 1 - if(channel && channel.messages && channel.messages.len) + if(channel?.messages?.len) ui_header = last_message == channel.messages[channel.messages.len - 1] ? "ntnrc_idle.gif" : "ntnrc_new.gif" else ui_header = "ntnrc_idle.gif" -/datum/computer_file/program/chatclient/kill_program(var/forced = 0) - if(channel) +/datum/computer_file/program/chatclient/kill_program(forced = FALSE) + for(var/C in ntnet_global.chat_channels) + var/datum/ntnet_conversation/channel = C channel.remove_client(src) - channel = null - ..(forced) - -/datum/nano_module/program/computer_chatclient - name = "NTNet Relay Chat Client" - -/datum/nano_module/program/computer_chatclient/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - if(!ntnet_global || !ntnet_global.chat_channels) - return + ..() +/datum/computer_file/program/chatclient/tgui_static_data(mob/user) var/list/data = list() - if(program) - data = program.get_header_data() + data["can_admin"] = can_run(user, FALSE, access_network) + return data + +/datum/computer_file/program/chatclient/tgui_data(mob/user) + if(!ntnet_global || !ntnet_global.chat_channels) + return list() - var/datum/computer_file/program/chatclient/C = program - if(!istype(C)) - return + var/list/data = get_header_data() - data["adminmode"] = C.netadmin_mode - if(C.channel) - data["title"] = C.channel.title - var/list/messages[0] - for(var/M in C.channel.messages) - messages.Add(list(list( - "msg" = M + var/list/all_channels = list() + for(var/C in ntnet_global.chat_channels) + var/datum/ntnet_conversation/conv = C + if(conv && conv.title) + all_channels.Add(list(list( + "chan" = conv.title, + "id" = conv.id ))) - data["messages"] = messages - var/list/clients[0] - for(var/datum/computer_file/program/chatclient/cl in C.channel.clients) + data["all_channels"] = all_channels + + data["active_channel"] = active_channel + data["username"] = username + data["adminmode"] = netadmin_mode + var/datum/ntnet_conversation/channel = ntnet_global.get_chat_channel_by_id(active_channel) + if(channel) + data["title"] = channel.title + var/authed = FALSE + if(!channel.password) + authed = TRUE + if(netadmin_mode) + authed = TRUE + var/list/clients = list() + for(var/C in channel.clients) + if(C == src) + authed = TRUE + var/datum/computer_file/program/chatclient/cl = C clients.Add(list(list( "name" = cl.username ))) - data["clients"] = clients - C.operator_mode = (C.channel.operator == C) ? 1 : 0 - data["is_operator"] = C.operator_mode || C.netadmin_mode - - else // Channel selection screen - var/list/all_channels[0] - for(var/datum/ntnet_conversation/conv in ntnet_global.chat_channels) - if(conv && conv.title) - all_channels.Add(list(list( - "chan" = conv.title, - "id" = conv.id + data["authed"] = authed + //no fishing for ui data allowed + if(authed) + data["clients"] = clients + var/list/messages = list() + for(var/M in channel.messages) + messages.Add(list(list( + "msg" = M ))) - data["all_channels"] = all_channels + data["messages"] = messages + data["is_operator"] = (channel.operator == src) || netadmin_mode + else + data["clients"] = list() + data["messages"] = list() + else + data["clients"] = list() + data["authed"] = FALSE + data["messages"] = list() - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "ntnet_chat.tmpl", "NTNet Relay Chat Client", 575, 700, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm b/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm index 0efed986ae..ea88d3597e 100644 --- a/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm +++ b/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm @@ -12,7 +12,7 @@ var/global/nttransfer_uid = 0 requires_ntnet_feature = NTNET_PEERTOPEER network_destination = "other device via P2P tunnel" available_on_ntnet = 1 - nanomodule_path = /datum/nano_module/program/computer_nttransfer/ + tgui_id = "NtosNetTransfer" var/error = "" // Error screen var/server_password = "" // Optional password to download the file. @@ -75,111 +75,101 @@ var/global/nttransfer_uid = 0 remote = null download_completion = 0 +/datum/computer_file/program/nttransfer/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = get_header_data() -/datum/nano_module/program/computer_nttransfer - name = "NTNet P2P Transfer Client" + data["error"] = error -/datum/nano_module/program/computer_nttransfer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - if(!program) - return - var/datum/computer_file/program/nttransfer/PRG = program - if(!istype(PRG)) - return - - var/list/data = program.get_header_data() - - if(PRG.error) - data["error"] = PRG.error - else if(PRG.downloaded_file) - data["downloading"] = 1 - data["download_size"] = PRG.downloaded_file.size - data["download_progress"] = PRG.download_completion - data["download_netspeed"] = PRG.actual_netspeed - data["download_name"] = "[PRG.downloaded_file.filename].[PRG.downloaded_file.filetype]" - else if (PRG.provided_file) - data["uploading"] = 1 - data["upload_uid"] = PRG.unique_token - data["upload_clients"] = PRG.connected_clients.len - data["upload_haspassword"] = PRG.server_password ? 1 : 0 - data["upload_filename"] = "[PRG.provided_file.filename].[PRG.provided_file.filetype]" - else if (PRG.upload_menu) - var/list/all_files[0] - for(var/datum/computer_file/F in PRG.computer.hard_drive.stored_files) + data["downloading"] = !!downloaded_file + if(downloaded_file) + data["download_size"] = downloaded_file.size + data["download_progress"] = download_completion + data["download_netspeed"] = actual_netspeed + data["download_name"] = "[downloaded_file.filename].[downloaded_file.filetype]" + + data["uploading"] = !!provided_file + if(provided_file) + data["upload_uid"] = unique_token + data["upload_clients"] = connected_clients.len + data["upload_haspassword"] = server_password ? 1 : 0 + data["upload_filename"] = "[provided_file.filename].[provided_file.filetype]" + + data["upload_filelist"] = list() + if(upload_menu) + var/list/all_files = list() + for(var/datum/computer_file/F in computer.hard_drive.stored_files) all_files.Add(list(list( "uid" = F.uid, "filename" = "[F.filename].[F.filetype]", "size" = F.size ))) data["upload_filelist"] = all_files - else - var/list/all_servers[0] + + data["servers"] = list() + if(!(downloaded_file || provided_file || upload_menu)) + var/list/all_servers = list() for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers) if(!P.provided_file) continue all_servers.Add(list(list( - "uid" = P.unique_token, - "filename" = "[P.provided_file.filename].[P.provided_file.filetype]", - "size" = P.provided_file.size, - "haspassword" = P.server_password ? 1 : 0 + "uid" = P.unique_token, + "filename" = "[P.provided_file.filename].[P.provided_file.filetype]", + "size" = P.provided_file.size, + "haspassword" = P.server_password ? 1 : 0 ))) data["servers"] = all_servers - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "ntnet_transfer.tmpl", "NTNet P2P Transfer Client", 575, 700, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data -/datum/computer_file/program/nttransfer/Topic(href, href_list) +/datum/computer_file/program/nttransfer/tgui_act(action, list/params, datum/tgui/ui) if(..()) - return 1 - if(href_list["PRG_downloadfile"]) - for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers) - if("[P.unique_token]" == href_list["PRG_downloadfile"]) - remote = P - break - if(!remote || !remote.provided_file) - return - if(remote.server_password) - var/pass = sanitize(input(usr, "Code 401 Unauthorized. Please enter password:", "Password required")) - if(pass != remote.server_password) - error = "Incorrect Password" + return TRUE + switch(action) + if("PRG_downloadfile") + for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers) + if(P.unique_token == text2num(params["uid"])) + remote = P + break + if(!remote || !remote.provided_file) return - downloaded_file = remote.provided_file.clone() - remote.connected_clients.Add(src) - return 1 - if(href_list["PRG_reset"]) - error = "" - upload_menu = 0 - finalize_download() - if(src in ntnet_global.fileservers) - ntnet_global.fileservers.Remove(src) - for(var/datum/computer_file/program/nttransfer/T in connected_clients) - T.crash_download("Remote server has forcibly closed the connection") - provided_file = null - return 1 - if(href_list["PRG_setpassword"]) - var/pass = sanitize(input(usr, "Enter new server password. Leave blank to cancel, input 'none' to disable password.", "Server security", "none")) - if(!pass) - return - if(pass == "none") - server_password = "" - return - server_password = pass - return 1 - if(href_list["PRG_uploadfile"]) - for(var/datum/computer_file/F in computer.hard_drive.stored_files) - if("[F.uid]" == href_list["PRG_uploadfile"]) - if(F.unsendable) - error = "I/O Error: File locked." + if(remote.server_password) + var/pass = sanitize(input(usr, "Code 401 Unauthorized. Please enter password:", "Password required")) + if(pass != remote.server_password) + error = "Incorrect Password" return - provided_file = F - ntnet_global.fileservers.Add(src) + downloaded_file = remote.provided_file.clone() + remote.connected_clients.Add(src) + return TRUE + if("PRG_reset") + error = "" + upload_menu = 0 + finalize_download() + if(src in ntnet_global.fileservers) + ntnet_global.fileservers.Remove(src) + for(var/datum/computer_file/program/nttransfer/T in connected_clients) + T.crash_download("Remote server has forcibly closed the connection") + provided_file = null + return TRUE + if("PRG_setpassword") + var/pass = sanitize(input(usr, "Enter new server password. Leave blank to cancel, input 'none' to disable password.", "Server security", "none")) + if(!pass) return - error = "I/O Error: Unable to locate file on hard drive." - return 1 - if(href_list["PRG_uploadmenu"]) - upload_menu = 1 - return 0 + if(pass == "none") + server_password = "" + return + server_password = pass + return TRUE + if("PRG_uploadfile") + for(var/datum/computer_file/F in computer.hard_drive.stored_files) + if(F.uid == text2num(params["uid"])) + if(F.unsendable) + error = "I/O Error: File locked." + return + provided_file = F + ntnet_global.fileservers |= src + return + error = "I/O Error: Unable to locate file on hard drive." + return TRUE + if("PRG_uploadmenu") + upload_menu = 1 + return TRUE diff --git a/code/modules/modular_computers/file_system/programs/generic/uav.dm b/code/modules/modular_computers/file_system/programs/generic/uav.dm index 0e98d0e0ea..24d677b679 100644 --- a/code/modules/modular_computers/file_system/programs/generic/uav.dm +++ b/code/modules/modular_computers/file_system/programs/generic/uav.dm @@ -4,7 +4,7 @@ /datum/computer_file/program/uav filename = "rigger" filedesc = "UAV Control" - nanomodule_path = /datum/nano_module/uav + tguimodule_path = /datum/tgui_module/uav program_icon_state = "comm_monitor" program_key_state = "generic_key" program_menu_icon = "link" @@ -12,255 +12,3 @@ size = 12 available_on_ntnet = 1 //requires_ntnet = 1 - -/datum/nano_module/uav - name = "UAV Control program" - var/obj/item/device/uav/current_uav = null //The UAV we're watching - var/signal_strength = 0 //Our last signal strength report (cached for a few seconds) - var/signal_test_counter = 0 //How long until next signal strength check - var/list/viewers //Who's viewing a UAV through us - var/adhoc_range = 30 //How far we can operate on a UAV without NTnet - -/datum/nano_module/uav/Destroy() - if(LAZYLEN(viewers)) - for(var/weakref/W in viewers) - var/M = W.resolve() - if(M) - unlook(M) - . = ..() - -/datum/nano_module/uav/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = default_state) - var/list/data = host.initial_data() - - if(current_uav) - if(QDELETED(current_uav)) - set_current(null) - else if(signal_test_counter-- <= 0) - signal_strength = get_signal_to(current_uav) - if(!signal_strength) - set_current(null) - else // Don't reset counter until we find a UAV that's actually in range we can stay connected to - signal_test_counter = 20 - - data["current_uav"] = null - if(current_uav) - data["current_uav"] = list("status" = current_uav.get_status_string(), "power" = current_uav.state == 1 ? 1 : null) - data["signal_strength"] = signal_strength ? signal_strength >= 2 ? "High" : "Low" : "None" - data["in_use"] = LAZYLEN(viewers) - - var/list/paired_map = list() - var/obj/item/modular_computer/mc_host = nano_host() - if(istype(mc_host)) - for(var/puav in mc_host.paired_uavs) - var/weakref/wr = puav - var/obj/item/device/uav/U = wr.resolve() - paired_map[++paired_map.len] = list("name" = "[U ? U.nickname : "!!Missing!!"]", "uavref" = "\ref[U]") - - data["paired_uavs"] = paired_map - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "mod_uav.tmpl", "UAV Control", 600, 500, state = state) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/datum/nano_module/uav/Topic(var/href, var/href_list = list(), var/datum/topic_state/state) - if((. = ..())) - return - state = state || DefaultTopicState() || global.default_state - if(CanUseTopic(usr, state, href_list) == STATUS_INTERACTIVE) - CouldUseTopic(usr) - return OnTopic(usr, href_list, state) - CouldNotUseTopic(usr) - return TRUE - -/datum/nano_module/uav/proc/OnTopic(var/mob/user, var/list/href_list) - if(href_list["switch_uav"]) - var/obj/item/device/uav/U = locate(href_list["switch_uav"]) //This is a \ref to the UAV itself - if(!istype(U)) - to_chat(usr,"Something is blocking the connection to that UAV. In-person investigation is required.") - return TOPIC_NOACTION - - if(!get_signal_to(U)) - to_chat(usr,"The screen freezes for a moment, before returning to the UAV selection menu. It's not able to connect to that UAV.") - return TOPIC_NOACTION - - set_current(U) - return TOPIC_REFRESH - - if(href_list["del_uav"]) - var/refstring = href_list["del_uav"] //This is a \ref to the UAV itself - var/obj/item/modular_computer/mc_host = nano_host() - //This is so we can really scrape up any weakrefs that can't resolve - for(var/weakref/wr in mc_host.paired_uavs) - if(wr.ref == refstring) - if(current_uav?.weakref == wr) - set_current(null) - LAZYREMOVE(mc_host.paired_uavs, wr) - - else if(href_list["view_uav"]) - if(!current_uav) - return TOPIC_NOACTION - - if(current_uav.check_eye(user) < 0) - to_chat(usr,"The screen freezes for a moment, before returning to the UAV selection menu. It's not able to connect to that UAV.") - else - viewing_uav(user) ? unlook(user) : look(user) - return TOPIC_NOACTION - - else if(href_list["power_uav"]) - if(!current_uav) - return TOPIC_NOACTION - else if(current_uav.toggle_power()) - //Clean up viewers faster - if(LAZYLEN(viewers)) - for(var/weakref/W in viewers) - var/M = W.resolve() - if(M) - unlook(M) - return TOPIC_REFRESH - -/datum/nano_module/uav/proc/DefaultTopicState() - return global.default_state - -/datum/nano_module/uav/proc/CouldNotUseTopic(mob/user) - . = ..() - unlook(user) - -/datum/nano_module/uav/proc/CouldUseTopic(mob/user) - . = ..() - if(viewing_uav(user)) - look(user) - -/datum/nano_module/uav/proc/set_current(var/obj/item/device/uav/U) - if(current_uav == U) - return - - signal_strength = 0 - current_uav = U - - if(LAZYLEN(viewers)) - for(var/weakref/W in viewers) - var/M = W.resolve() - if(M) - if(current_uav) - to_chat(M, "You're disconnected from the UAV's camera!") - unlook(M) - else - look(M) - -//// -//// Finding signal strength between us and the UAV -//// -/datum/nano_module/uav/proc/get_signal_to(var/atom/movable/AM) - // Following roughly the ntnet signal levels - // 0 is none - // 1 is weak - // 2 is strong - var/obj/item/modular_computer/host = nano_host() //Better not add this to anything other than modular computers. - if(!istype(host)) - return - var/our_signal = host.get_ntnet_status() //1 low, 2 good, 3 wired, 0 none - var/their_z = get_z(AM) - - //If we have no NTnet connection don't bother getting theirs - if(!our_signal) - if(get_z(host) == their_z && (get_dist(host, AM) < adhoc_range)) - return 1 //We can connect (with weak signal) in same z without ntnet, within 30 turfs - else - return 0 - - var/list/zlevels_in_range = using_map.get_map_levels(their_z, FALSE) - var/list/zlevels_in_long_range = using_map.get_map_levels(their_z, TRUE, om_range = DEFAULT_OVERMAP_RANGE) - zlevels_in_range - var/their_signal = 0 - for(var/relay in ntnet_global.relays) - var/obj/machinery/ntnet_relay/R = relay - if(!R.operable()) - continue - if(R.z == their_z) - their_signal = 2 - break - if(R.z in zlevels_in_range) - their_signal = 2 - break - if(R.z in zlevels_in_long_range) - their_signal = 1 - break - - if(!their_signal) //They have no NTnet at all - if(get_z(host) == their_z && (get_dist(host, AM) < adhoc_range)) - return 1 //We can connect (with weak signal) in same z without ntnet, within 30 turfs - else - return 0 - else - return max(our_signal, their_signal) - -//// -//// UAV viewer handling -//// -/datum/nano_module/uav/proc/viewing_uav(mob/user) - return (weakref(user) in viewers) - -/datum/nano_module/uav/proc/look(var/mob/user) - if(issilicon(user)) //Too complicated for me to want to mess with at the moment - to_chat(user, "Regulations prevent you from controlling several corporeal forms at the same time!") - return - - if(!current_uav) - return - - user.set_machine(nano_host()) - user.reset_view(current_uav) - current_uav.add_master(user) - LAZYDISTINCTADD(viewers, weakref(user)) - -/datum/nano_module/uav/proc/unlook(var/mob/user) - user.unset_machine() - user.reset_view() - if(current_uav) - current_uav.remove_master(user) - LAZYREMOVE(viewers, weakref(user)) - -/datum/nano_module/uav/check_eye(var/mob/user) - if(get_dist(user, nano_host()) > 1 || user.blinded || !current_uav) - unlook(user) - return -1 - - var/viewflag = current_uav.check_eye(user) - if (viewflag < 0) //camera doesn't work - unlook(user) - return -1 - - return viewflag - -//// -//// Relaying movements to the UAV -//// -/datum/nano_module/uav/relaymove(var/mob/user, direction) - if(current_uav) - return current_uav.relaymove(user, direction, signal_strength) - -//// -//// The effects when looking through a UAV -//// -/datum/nano_module/uav/apply_visual(var/mob/M) - if(!M.client) - return - if(weakref(M) in viewers) - M.overlay_fullscreen("fishbed",/obj/screen/fullscreen/fishbed) - M.overlay_fullscreen("scanlines",/obj/screen/fullscreen/scanline) - - if(signal_strength <= 1) - M.overlay_fullscreen("whitenoise",/obj/screen/fullscreen/noise) - else - M.clear_fullscreen("whitenoise", 0) - else - remove_visual(M) - -/datum/nano_module/uav/remove_visual(mob/M) - if(!M.client) - return - M.clear_fullscreen("fishbed",0) - M.clear_fullscreen("scanlines",0) - M.clear_fullscreen("whitenoise",0) diff --git a/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm b/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm index 1a4d7a1871..61f3b43da8 100644 --- a/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm +++ b/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm @@ -5,9 +5,10 @@ program_icon_state = "word" program_key_state = "atmos_key" size = 4 - requires_ntnet = 0 - available_on_ntnet = 1 - nanomodule_path = /datum/nano_module/program/computer_wordprocessor/ + requires_ntnet = FALSE + available_on_ntnet = TRUE + tgui_id = "NtosWordProcessor" + var/browsing var/open_file var/loaded_data @@ -28,7 +29,7 @@ if(F) open_file = F.filename loaded_data = F.stored_data - return 1 + return TRUE /datum/computer_file/program/wordprocessor/proc/save_file(var/filename) var/datum/computer_file/data/F = get_file(filename) @@ -46,7 +47,7 @@ HDD.store_file(backup) return 0 is_edited = 0 - return 1 + return TRUE /datum/computer_file/program/wordprocessor/proc/create_file(var/newname, var/data = "") if(!newname) @@ -64,142 +65,144 @@ if(HDD.store_file(F)) return F -/datum/computer_file/program/wordprocessor/Topic(href, href_list) +/datum/computer_file/program/wordprocessor/tgui_act(action, list/params, datum/tgui/ui) if(..()) - return 1 + return TRUE - if(href_list["PRG_txtrpeview"]) - show_browser(usr,"[open_file][pencode2html(loaded_data)]", "window=[open_file]") - return 1 + switch(action) + if("PRG_txtrpeview") + show_browser(usr,"[open_file][pencode2html(loaded_data)]", "window=[open_file]") + return TRUE - if(href_list["PRG_taghelp"]) - to_chat(usr, "The hologram of a googly-eyed paper clip helpfully tells you:") - var/help = {" - \[br\] : Creates a linebreak. - \[center\] - \[/center\] : Centers the text. - \[h1\] - \[/h1\] : First level heading. - \[h2\] - \[/h2\] : Second level heading. - \[h3\] - \[/h3\] : Third level heading. - \[b\] - \[/b\] : Bold. - \[i\] - \[/i\] : Italic. - \[u\] - \[/u\] : Underlined. - \[small\] - \[/small\] : Decreases the size of the text. - \[large\] - \[/large\] : Increases the size of the text. - \[field\] : Inserts a blank text field, which can be filled later. Useful for forms. - \[date\] : Current station date. - \[time\] : Current station time. - \[list\] - \[/list\] : Begins and ends a list. - \[*\] : A list item. - \[hr\] : Horizontal rule. - \[table\] - \[/table\] : Creates table using \[row\] and \[cell\] tags. - \[grid\] - \[/grid\] : Table without visible borders, for layouts. - \[row\] - New table row. - \[cell\] - New table cell. - \[logo\] - Inserts NT logo image. - \[redlogo\] - Inserts red NT logo image. - \[sglogo\] - Inserts Solgov insignia image."} + if("PRG_taghelp") + to_chat(usr, "The hologram of a googly-eyed paper clip helpfully tells you:") + var/help = {" + \[br\] : Creates a linebreak. + \[center\] - \[/center\] : Centers the text. + \[h1\] - \[/h1\] : First level heading. + \[h2\] - \[/h2\] : Second level heading. + \[h3\] - \[/h3\] : Third level heading. + \[b\] - \[/b\] : Bold. + \[i\] - \[/i\] : Italic. + \[u\] - \[/u\] : Underlined. + \[small\] - \[/small\] : Decreases the size of the text. + \[large\] - \[/large\] : Increases the size of the text. + \[field\] : Inserts a blank text field, which can be filled later. Useful for forms. + \[date\] : Current station date. + \[time\] : Current station time. + \[list\] - \[/list\] : Begins and ends a list. + \[*\] : A list item. + \[hr\] : Horizontal rule. + \[table\] - \[/table\] : Creates table using \[row\] and \[cell\] tags. + \[grid\] - \[/grid\] : Table without visible borders, for layouts. + \[row\] - New table row. + \[cell\] - New table cell. + \[logo\] - Inserts NT logo image. + \[redlogo\] - Inserts red NT logo image. + \[sglogo\] - Inserts Solgov insignia image."} - to_chat(usr, help) - return 1 + to_chat(usr, help) + return TRUE - if(href_list["PRG_closebrowser"]) - browsing = 0 - return 1 + if("PRG_closebrowser") + browsing = 0 + return TRUE - if(href_list["PRG_backtomenu"]) - error = null - return 1 + if("PRG_backtomenu") + error = null + return TRUE - if(href_list["PRG_loadmenu"]) - browsing = 1 - return 1 + if("PRG_loadmenu") + browsing = 1 + return TRUE - if(href_list["PRG_openfile"]) - . = 1 - if(is_edited) - if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes") - save_file(open_file) - browsing = 0 - if(!open_file(href_list["PRG_openfile"])) - error = "I/O error: Unable to open file '[href_list["PRG_openfile"]]'." + if("PRG_openfile") + if(is_edited) + if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes") + save_file(open_file) + browsing = 0 + if(!open_file(params["PRG_openfile"])) + error = "I/O error: Unable to open file '[params["PRG_openfile"]]'." + return TRUE - if(href_list["PRG_newfile"]) - . = 1 - if(is_edited) - if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes") - save_file(open_file) + if("PRG_newfile") + if(is_edited) + if(alert("Would you like to save your changes first?",,"Yes","No") == "Yes") + save_file(open_file) - var/newname = sanitize(input(usr, "Enter file name:", "New File") as text|null) - if(!newname) - return 1 - var/datum/computer_file/data/F = create_file(newname) - if(F) - open_file = F.filename - loaded_data = "" - return 1 - else - error = "I/O error: Unable to create file '[href_list["PRG_saveasfile"]]'." + var/newname = sanitize(input(usr, "Enter file name:", "New File") as text|null) + if(!newname) + return TRUE + var/datum/computer_file/data/F = create_file(newname) + if(F) + open_file = F.filename + loaded_data = "" + return TRUE + else + error = "I/O error: Unable to create file '[params["PRG_saveasfile"]]'." + return TRUE - if(href_list["PRG_saveasfile"]) - . = 1 - var/newname = sanitize(input(usr, "Enter file name:", "Save As") as text|null) - if(!newname) - return 1 - var/datum/computer_file/data/F = create_file(newname, loaded_data) - if(F) - open_file = F.filename - else - error = "I/O error: Unable to create file '[href_list["PRG_saveasfile"]]'." - return 1 + if("PRG_saveasfile") + var/newname = sanitize(input(usr, "Enter file name:", "Save As") as text|null) + if(!newname) + return TRUE + var/datum/computer_file/data/F = create_file(newname, loaded_data) + if(F) + open_file = F.filename + else + error = "I/O error: Unable to create file '[params["PRG_saveasfile"]]'." + return TRUE - if(href_list["PRG_savefile"]) - . = 1 - if(!open_file) - open_file = sanitize(input(usr, "Enter file name:", "Save As") as text|null) + if("PRG_savefile") if(!open_file) - return 0 - if(!save_file(open_file)) - error = "I/O error: Unable to save file '[open_file]'." - return 1 + open_file = sanitize(input(usr, "Enter file name:", "Save As") as text|null) + if(!open_file) + return 0 + if(!save_file(open_file)) + error = "I/O error: Unable to save file '[open_file]'." + return TRUE - if(href_list["PRG_editfile"]) - var/oldtext = html_decode(loaded_data) - oldtext = replacetext(oldtext, "\[br\]", "\n") + if("PRG_editfile") + var/oldtext = html_decode(loaded_data) + oldtext = replacetext(oldtext, "\[br\]", "\n") - var/newtext = sanitize(replacetext(input(usr, "Editing file '[open_file]'. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH) - if(!newtext) - return - loaded_data = newtext - is_edited = 1 - return 1 + var/newtext = sanitize(replacetext(input(usr, "Editing file '[open_file]'. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH) + if(!newtext) + return + loaded_data = newtext + is_edited = 1 + return TRUE - if(href_list["PRG_printfile"]) - . = 1 - if(!computer.nano_printer) - error = "Missing Hardware: Your computer does not have the required hardware to complete this operation." - return 1 - if(!computer.nano_printer.print_text(pencode2html(loaded_data))) - error = "Hardware error: Printer was unable to print the file. It may be out of paper." - return 1 + if("PRG_printfile") + if(!computer.nano_printer) + error = "Missing Hardware: Your computer does not have the required hardware to complete this operation." + return TRUE + if(!computer.nano_printer.print_text(pencode2html(loaded_data))) + error = "Hardware error: Printer was unable to print the file. It may be out of paper." + return TRUE + return TRUE -/datum/nano_module/program/computer_wordprocessor - name = "Word Processor" +/datum/computer_file/program/wordprocessor/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = get_header_data() -/datum/nano_module/program/computer_wordprocessor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() - var/datum/computer_file/program/wordprocessor/PRG - PRG = program + var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive + var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive + data["error"] = null + if(error) + data["error"] = error - var/obj/item/weapon/computer_hardware/hard_drive/HDD - var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD - if(PRG.error) - data["error"] = PRG.error - if(PRG.browsing) - data["browsing"] = PRG.browsing - if(!PRG.computer || !PRG.computer.hard_drive) + data["browsing"] = null + data["files"] = list() + data["usbconnected"] = FALSE + data["usbfiles"] = list() + data["filedata"] = null + data["filename"] = null + + if(browsing) + data["browsing"] = browsing + if(!computer || !HDD) data["error"] = "I/O ERROR: Unable to access hard drive." else - HDD = PRG.computer.hard_drive var/list/files[0] for(var/datum/computer_file/F in HDD.stored_files) if(F.filetype == "TXT") @@ -209,7 +212,6 @@ ))) data["files"] = files - RHDD = PRG.computer.portable_drive if(RHDD) data["usbconnected"] = 1 var/list/usbfiles[0] @@ -220,16 +222,11 @@ "size" = F.size, ))) data["usbfiles"] = usbfiles - else if(PRG.open_file) - data["filedata"] = pencode2html(PRG.loaded_data) - data["filename"] = PRG.is_edited ? "[PRG.open_file]*" : PRG.open_file + else if(open_file) + data["filedata"] = pencode2html(loaded_data) + data["filename"] = is_edited ? "[open_file]*" : open_file else - data["filedata"] = pencode2html(PRG.loaded_data) + data["filedata"] = pencode2html(loaded_data) data["filename"] = "UNNAMED" - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "word_processor.tmpl", "Word Processor", 575, 700, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() \ No newline at end of file + return data \ No newline at end of file diff --git a/code/modules/modular_computers/file_system/programs/research/email_administration.dm b/code/modules/modular_computers/file_system/programs/research/email_administration.dm index 93ba0bded3..eb9dfd71a6 100644 --- a/code/modules/modular_computers/file_system/programs/research/email_administration.dm +++ b/code/modules/modular_computers/file_system/programs/research/email_administration.dm @@ -8,29 +8,34 @@ size = 12 requires_ntnet = 1 available_on_ntnet = 1 - nanomodule_path = /datum/nano_module/email_administration + tgui_id = "NtosEmailAdministration" required_access = access_network - - - -/datum/nano_module/email_administration/ - name = "Email Client" var/datum/computer_file/data/email_account/current_account = null var/datum/computer_file/data/email_message/current_message = null var/error = "" -/datum/nano_module/email_administration/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() +/datum/computer_file/program/email_administration/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = get_header_data() - if(error) - data["error"] = error - else if(istype(current_message)) - data["msg_title"] = current_message.title - data["msg_body"] = pencode2html(current_message.stored_data) - data["msg_timestamp"] = current_message.timestamp - data["msg_source"] = current_message.source - else if(istype(current_account)) + data["error"] = error + + data["cur_title"] = null + data["cur_body"] = null + data["cur_timestamp"] = null + data["cur_source"] = null + + if(istype(current_message)) + data["cur_title"] = current_message.title + data["cur_body"] = pencode2html(current_message.stored_data) + data["cur_timestamp"] = current_message.timestamp + data["cur_source"] = current_message.source + + data["current_account"] = null + data["cur_suspended"] = null + data["messages"] = null + + if(istype(current_account)) data["current_account"] = current_account.login data["cur_suspended"] = current_account.suspended var/list/all_messages = list() @@ -42,103 +47,90 @@ "uid" = message.uid ))) data["messages"] = all_messages - data["messagecount"] = all_messages.len - else - var/list/all_accounts = list() - for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts) - if(!account.can_login) - continue - all_accounts.Add(list(list( - "login" = account.login, - "uid" = account.uid - ))) - data["accounts"] = all_accounts - data["accountcount"] = all_accounts.len - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "email_administration.tmpl", "Email Administration Utility", 600, 450, state = state) - if(host.update_layout()) - ui.auto_update_layout = 1 - ui.set_auto_update(1) - ui.set_initial_data(data) - ui.open() + var/list/all_accounts = list() + for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts) + if(!account.can_login) + continue + all_accounts.Add(list(list( + "login" = account.login, + "uid" = account.uid + ))) + data["accounts"] = all_accounts + return data -/datum/nano_module/email_administration/Topic(href, href_list) +/datum/computer_file/program/email_administration/tgui_act(action, list/params, datum/tgui/ui) if(..()) - return 1 - - var/mob/user = usr - if(!istype(user)) - return 1 + return TRUE // High security - can only be operated when the user has an ID with access on them. - var/obj/item/weapon/card/id/I = user.GetIdCard() + var/obj/item/weapon/card/id/I = usr.GetIdCard() if(!istype(I) || !(access_network in I.access)) - return 1 + return TRUE - if(href_list["back"]) - if(error) - error = "" - else if(current_message) - current_message = null - else - current_account = null - return 1 + switch(action) + if("back") + if(error) + error = "" + else if(current_message) + current_message = null + else + current_account = null + return TRUE - if(href_list["ban"]) - if(!current_account) - return 1 + if("ban") + if(!current_account) + return TRUE - current_account.suspended = !current_account.suspended - ntnet_global.add_log_with_ids_check("EMAIL LOG: SA-EDIT Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended by SA [I.registered_name] ([I.assignment]).") - error = "Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended." - return 1 + current_account.suspended = !current_account.suspended + ntnet_global.add_log_with_ids_check("EMAIL LOG: SA-EDIT Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended by SA [I.registered_name] ([I.assignment]).") + error = "Account [current_account.login] has been [current_account.suspended ? "" : "un" ]suspended." + return TRUE - if(href_list["changepass"]) - if(!current_account) - return 1 + if("changepass") + if(!current_account) + return TRUE - var/newpass = sanitize(input(user,"Enter new password for account [current_account.login]", "Password"), 100) - if(!newpass) - return 1 - current_account.password = newpass - ntnet_global.add_log_with_ids_check("EMAIL LOG: SA-EDIT Password for account [current_account.login] has been changed by SA [I.registered_name] ([I.assignment]).") - return 1 + var/newpass = sanitize(input(usr,"Enter new password for account [current_account.login]", "Password"), 100) + if(!newpass) + return TRUE + current_account.password = newpass + ntnet_global.add_log_with_ids_check("EMAIL LOG: SA-EDIT Password for account [current_account.login] has been changed by SA [I.registered_name] ([I.assignment]).") + return TRUE - if(href_list["viewmail"]) - if(!current_account) - return 1 + if("viewmail") + if(!current_account) + return TRUE - for(var/datum/computer_file/data/email_message/received_message in (current_account.inbox | current_account.spam | current_account.deleted)) - if(received_message.uid == text2num(href_list["viewmail"])) - current_message = received_message - break - return 1 + for(var/datum/computer_file/data/email_message/received_message in (current_account.inbox | current_account.spam | current_account.deleted)) + if(received_message.uid == text2num(params["viewmail"])) + current_message = received_message + break + return TRUE - if(href_list["viewaccount"]) - for(var/datum/computer_file/data/email_account/email_account in ntnet_global.email_accounts) - if(email_account.uid == text2num(href_list["viewaccount"])) - current_account = email_account - break - return 1 + if("viewaccount") + for(var/datum/computer_file/data/email_account/email_account in ntnet_global.email_accounts) + if(email_account.uid == text2num(params["viewaccount"])) + current_account = email_account + break + return TRUE - if(href_list["newaccount"]) - var/newdomain = sanitize(input(user,"Pick domain:", "Domain name") as null|anything in using_map.usable_email_tlds) - if(!newdomain) - return 1 - var/newlogin = sanitize(input(user,"Pick account name (@[newdomain]):", "Account name"), 100) - if(!newlogin) - return 1 + if("newaccount") + var/newdomain = sanitize(input(usr,"Pick domain:", "Domain name") as null|anything in using_map.usable_email_tlds) + if(!newdomain) + return TRUE + var/newlogin = sanitize(input(usr,"Pick account name (@[newdomain]):", "Account name"), 100) + if(!newlogin) + return TRUE - var/complete_login = "[newlogin]@[newdomain]" - if(ntnet_global.does_email_exist(complete_login)) - error = "Error creating account: An account with same address already exists." - return 1 + var/complete_login = "[newlogin]@[newdomain]" + if(ntnet_global.does_email_exist(complete_login)) + error = "Error creating account: An account with same address already exists." + return TRUE - var/datum/computer_file/data/email_account/new_account = new/datum/computer_file/data/email_account() - new_account.login = complete_login - new_account.password = GenerateKey() - error = "Email [new_account.login] has been created, with generated password [new_account.password]" - return 1 + var/datum/computer_file/data/email_account/new_account = new/datum/computer_file/data/email_account() + new_account.login = complete_login + new_account.password = GenerateKey() + error = "Email [new_account.login] has been created, with generated password [new_account.password]" + return TRUE diff --git a/code/modules/modular_computers/file_system/programs/research/ntmonitor.dm b/code/modules/modular_computers/file_system/programs/research/ntmonitor.dm index 590837f2b5..0ce6dd5c49 100644 --- a/code/modules/modular_computers/file_system/programs/research/ntmonitor.dm +++ b/code/modules/modular_computers/file_system/programs/research/ntmonitor.dm @@ -6,19 +6,15 @@ program_menu_icon = "wrench" extended_desc = "This program monitors the local NTNet network, provides access to logging systems, and allows for configuration changes" size = 12 - requires_ntnet = 1 + requires_ntnet = TRUE required_access = access_network - available_on_ntnet = 1 - nanomodule_path = /datum/nano_module/computer_ntnetmonitor/ + available_on_ntnet = TRUE + tgui_id = "NtosNetMonitor" -/datum/nano_module/computer_ntnetmonitor - name = "NTNet Diagnostics and Monitoring" - //available_to_ai = TRUE - -/datum/nano_module/computer_ntnetmonitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) +/datum/computer_file/program/ntnetmonitor/tgui_data(mob/user) if(!ntnet_global) return - var/list/data = host.initial_data() + var/list/data = get_header_data() data["ntnetstatus"] = ntnet_global.check_function() data["ntnetrelays"] = ntnet_global.relays.len @@ -30,73 +26,68 @@ data["config_communication"] = ntnet_global.setting_communication data["config_systemcontrol"] = ntnet_global.setting_systemcontrol - data["ntnetlogs"] = ntnet_global.logs - data["ntnetmaxlogs"] = ntnet_global.setting_maxlogcount + data["ntnetlogs"] = list() + data["minlogs"] = MIN_NTNET_LOGS + data["maxlogs"] = MAX_NTNET_LOGS data["banned_nids"] = list(ntnet_global.banned_nids) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "ntnet_monitor.tmpl", "NTNet Diagnostics and Monitoring Tool", 575, 700, state = state) - if(host.update_layout()) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + for(var/i in ntnet_global.logs) + data["ntnetlogs"] += list(list("entry" = i)) + data["ntnetmaxlogs"] = ntnet_global.setting_maxlogcount -/datum/nano_module/computer_ntnetmonitor/Topic(href, href_list, state) - var/mob/user = usr + return data + +/datum/computer_file/program/ntnetmonitor/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return 1 - if(href_list["resetIDS"]) - if(ntnet_global) - ntnet_global.resetIDS() - return 1 - if(href_list["toggleIDS"]) - if(ntnet_global) - ntnet_global.toggleIDS() - return 1 - if(href_list["toggleWireless"]) - if(!ntnet_global) - return 1 + return + switch(action) + if("resetIDS") + if(ntnet_global) + ntnet_global.resetIDS() + return TRUE + if("toggleIDS") + if(ntnet_global) + ntnet_global.toggleIDS() + return TRUE + if("toggleWireless") + if(!ntnet_global) + return - // NTNet is disabled. Enabling can be done without user prompt - if(ntnet_global.setting_disabled) - ntnet_global.setting_disabled = 0 - return 1 + // NTNet is disabled. Enabling can be done without user prompt + if(ntnet_global.setting_disabled) + ntnet_global.setting_disabled = FALSE + return TRUE - // NTNet is enabled and user is about to shut it down. Let's ask them if they really want to do it, as wirelessly connected computers won't connect without NTNet being enabled (which may prevent people from turning it back on) - if(!user) - return 1 - var/response = alert(user, "Really disable NTNet wireless? If your computer is connected wirelessly you won't be able to turn it back on! This will affect all connected wireless devices.", "NTNet shutdown", "Yes", "No") - if(response == "Yes") - ntnet_global.setting_disabled = 1 - return 1 - if(href_list["purgelogs"]) - if(ntnet_global) - ntnet_global.purge_logs() - return 1 - if(href_list["updatemaxlogs"]) - var/logcount = text2num(input(user,"Enter amount of logs to keep in memory ([MIN_NTNET_LOGS]-[MAX_NTNET_LOGS]):")) - if(ntnet_global) - ntnet_global.update_max_log_count(logcount) - return 1 - if(href_list["toggle_function"]) - if(!ntnet_global) - return 1 - ntnet_global.toggle_function(href_list["toggle_function"]) - return 1 - if(href_list["ban_nid"]) - if(!ntnet_global) - return 1 - var/nid = input(user,"Enter NID of device which you want to block from the network:", "Enter NID") as null|num - if(nid && CanUseTopic(user, state)) - ntnet_global.banned_nids |= nid - return 1 - if(href_list["unban_nid"]) - if(!ntnet_global) - return 1 - var/nid = input(user,"Enter NID of device which you want to unblock from the network:", "Enter NID") as null|num - if(nid && CanUseTopic(user, state)) - ntnet_global.banned_nids -= nid - return 1 + var/response = alert(usr, "Really disable NTNet wireless? If your computer is connected wirelessly you won't be able to turn it back on! This will affect all connected wireless devices.", "NTNet shutdown", "Yes", "No") + if(response == "Yes" && tgui_status(usr, state) == STATUS_INTERACTIVE) + ntnet_global.setting_disabled = TRUE + return TRUE + if("purgelogs") + if(ntnet_global) + ntnet_global.purge_logs() + return TRUE + if("updatemaxlogs") + var/logcount = params["new_number"] + if(ntnet_global) + ntnet_global.update_max_log_count(logcount) + return TRUE + if("toggle_function") + if(!ntnet_global) + return + ntnet_global.toggle_function(text2num(params["id"])) + return TRUE + if("ban_nid") + if(!ntnet_global) + return + var/nid = input(usr,"Enter NID of device which you want to block from the network:", "Enter NID") as null|num + if(nid && tgui_status(usr, state) == STATUS_INTERACTIVE) + ntnet_global.banned_nids |= nid + return TRUE + if("unban_nid") + if(!ntnet_global) + return + var/nid = input(usr,"Enter NID of device which you want to unblock from the network:", "Enter NID") as null|num + if(nid && tgui_status(usr, state) == STATUS_INTERACTIVE) + ntnet_global.banned_nids -= nid + return TRUE diff --git a/code/modules/modular_computers/file_system/programs/security/digitalwarrant.dm b/code/modules/modular_computers/file_system/programs/security/digitalwarrant.dm index 597065d27b..9cac7c920c 100644 --- a/code/modules/modular_computers/file_system/programs/security/digitalwarrant.dm +++ b/code/modules/modular_computers/file_system/programs/security/digitalwarrant.dm @@ -1,5 +1,7 @@ var/warrant_uid = 0 -/datum/datacore/var/list/warrants[] = list() +/datum/datacore + var/list/warrants = list() + /datum/data/record/warrant var/warrant_id @@ -7,7 +9,6 @@ var/warrant_uid = 0 ..() warrant_id = warrant_uid++ - /datum/computer_file/program/digitalwarrant filename = "digitalwarrant" filedesc = "Warrant Assistant" @@ -20,126 +21,119 @@ var/warrant_uid = 0 available_on_ntnet = 1 required_access = access_security usage_flags = PROGRAM_ALL - nanomodule_path = /datum/nano_module/program/digitalwarrant/ + tgui_id = "NtosDigitalWarrant" -/datum/nano_module/program/digitalwarrant/ - name = "Warrant Assistant" var/datum/data/record/warrant/activewarrant -/datum/nano_module/program/digitalwarrant/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/list/data = host.initial_data() +/datum/computer_file/program/digitalwarrant/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = get_header_data() + + data["warrantname"] = null + data["warrantcharges"] = null + data["warrantauth"] = null + data["type"] = null if(activewarrant) data["warrantname"] = activewarrant.fields["namewarrant"] data["warrantcharges"] = activewarrant.fields["charges"] data["warrantauth"] = activewarrant.fields["auth"] data["type"] = activewarrant.fields["arrestsearch"] - else - var/list/allwarrants = list() - for(var/datum/data/record/warrant/W in data_core.warrants) - allwarrants.Add(list(list( + + var/list/allwarrants = list() + for(var/datum/data/record/warrant/W in data_core.warrants) + allwarrants.Add(list(list( "warrantname" = W.fields["namewarrant"], "charges" = "[copytext(W.fields["charges"],1,min(length(W.fields["charges"]) + 1, 50))]...", "auth" = W.fields["auth"], "id" = W.warrant_id, "arrestsearch" = W.fields["arrestsearch"] ))) - data["allwarrants"] = allwarrants + data["allwarrants"] = allwarrants - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "digitalwarrant.tmpl", name, 500, 350, state = state) - ui.auto_update_layout = 1 - ui.set_initial_data(data) - ui.open() + return data -/datum/nano_module/program/digitalwarrant/Topic(href, href_list) +/datum/computer_file/program/digitalwarrant/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return 1 + return TRUE - if(href_list["sw_menu"]) - activewarrant = null + switch(action) + if("back") + . = TRUE + activewarrant = null - if(href_list["editwarrant"]) - . = 1 - for(var/datum/data/record/warrant/W in data_core.warrants) - if(W.warrant_id == text2num(href_list["editwarrant"])) - activewarrant = W - break + if("editwarrant") + . = TRUE + for(var/datum/data/record/warrant/W in data_core.warrants) + if(W.warrant_id == text2num(params["id"])) + activewarrant = W + break // The following actions will only be possible if the user has an ID with security access equipped. This is in line with modular computer framework's authentication methods, // which also use RFID scanning to allow or disallow access to some functions. Anyone can view warrants, editing requires ID. This also prevents situations where you show a tablet // to someone who is to be arrested, which allows them to change the stuff there. - - var/mob/user = usr - if(!istype(user)) - return - var/obj/item/weapon/card/id/I = user.GetIdCard() + var/obj/item/weapon/card/id/I = usr.GetIdCard() if(!istype(I) || !I.registered_name || !(access_security in I.access)) - to_chat(user, "Authentication error: Unable to locate ID with apropriate access to allow this operation.") + to_chat(usr, "Authentication error: Unable to locate ID with appropriate access to allow this operation.") return - if(href_list["addwarrant"]) - . = 1 - var/datum/data/record/warrant/W = new() - var/temp = sanitize(input(usr, "Do you want to create a search-, or an arrest warrant?") as null|anything in list("search","arrest")) - if(CanInteract(user, default_state)) - if(temp == "arrest") - W.fields["namewarrant"] = "Unknown" - W.fields["charges"] = "No charges present" - W.fields["auth"] = "Unauthorized" - W.fields["arrestsearch"] = "arrest" - if(temp == "search") - W.fields["namewarrant"] = "No suspect/location given" // VOREStation edit - W.fields["charges"] = "No reason given" - W.fields["auth"] = "Unauthorized" - W.fields["arrestsearch"] = "search" - activewarrant = W + switch(action) + if("addwarrant") + . = TRUE + var/datum/data/record/warrant/W = new() + var/temp = sanitize(input(usr, "Do you want to create a search-, or an arrest warrant?") as null|anything in list("search","arrest")) + if(tgui_status(usr, state) == STATUS_INTERACTIVE) + if(temp == "arrest") + W.fields["namewarrant"] = "Unknown" + W.fields["charges"] = "No charges present" + W.fields["auth"] = "Unauthorized" + W.fields["arrestsearch"] = "arrest" + if(temp == "search") + W.fields["namewarrant"] = "No suspect/location given" // VOREStation edit + W.fields["charges"] = "No reason given" + W.fields["auth"] = "Unauthorized" + W.fields["arrestsearch"] = "search" + activewarrant = W - if(href_list["savewarrant"]) - . = 1 - data_core.warrants |= activewarrant - activewarrant = null + if("savewarrant") + . = TRUE + data_core.warrants |= activewarrant + activewarrant = null - if(href_list["deletewarrant"]) - . = 1 - data_core.warrants -= activewarrant - activewarrant = null + if("deletewarrant") + . = TRUE + data_core.warrants -= activewarrant + activewarrant = null - if(href_list["editwarrantname"]) - . = 1 - var/namelist = list() - for(var/datum/data/record/t in data_core.general) - namelist += t.fields["name"] - var/new_name = sanitize(input(usr, "Please input name") as null|anything in namelist) - if(CanInteract(user, default_state)) - if (!new_name) - return - activewarrant.fields["namewarrant"] = new_name + if("editwarrantname") + . = TRUE + var/namelist = list() + for(var/datum/data/record/t in data_core.general) + namelist += t.fields["name"] + var/new_name = sanitize(input(usr, "Please input name") as null|anything in namelist) + if(tgui_status(usr, state) == STATUS_INTERACTIVE) + if (!new_name) + return + activewarrant.fields["namewarrant"] = new_name - if(href_list["editwarrantnamecustom"]) - . = 1 - var/new_name = sanitize(input("Please input name") as null|text) - if(CanInteract(user, default_state)) - if (!new_name) - return - activewarrant.fields["namewarrant"] = new_name + if("editwarrantnamecustom") + . = TRUE + var/new_name = sanitize(input("Please input name") as null|text) + if(tgui_status(usr, state) == STATUS_INTERACTIVE) + if (!new_name) + return + activewarrant.fields["namewarrant"] = new_name - if(href_list["editwarrantcharges"]) - . = 1 - var/new_charges = sanitize(input("Please input charges", "Charges", activewarrant.fields["charges"]) as null|text) - if(CanInteract(user, default_state)) - if (!new_charges) - return - activewarrant.fields["charges"] = new_charges + if("editwarrantcharges") + . = TRUE + var/new_charges = sanitize(input("Please input charges", "Charges", activewarrant.fields["charges"]) as null|text) + if(tgui_status(usr, state) == STATUS_INTERACTIVE) + if (!new_charges) + return + activewarrant.fields["charges"] = new_charges - if(href_list["editwarrantauth"]) - . = 1 - if(!(access_hos in I.access)) // VOREStation edit begin - to_chat(user, "You don't have the access to do this!") - return // VOREStation edit end - activewarrant.fields["auth"] = "[I.registered_name] - [I.assignment ? I.assignment : "(Unknown)"]" - - if(href_list["back"]) - . = 1 - activewarrant = null + if("editwarrantauth") + . = TRUE + if(!(access_hos in I.access)) // VOREStation edit begin + to_chat(usr, "You don't have the access to do this!") + return // VOREStation edit end + activewarrant.fields["auth"] = "[I.registered_name] - [I.assignment ? I.assignment : "(Unknown)"]" diff --git a/code/modules/modular_computers/laptop_vendor.dm b/code/modules/modular_computers/laptop_vendor.dm index ab60291f55..0f67e3b604 100644 --- a/code/modules/modular_computers/laptop_vendor.dm +++ b/code/modules/modular_computers/laptop_vendor.dm @@ -6,8 +6,8 @@ icon = 'icons/obj/vending.dmi' icon_state = "robotics" layer = OBJ_LAYER - 0.1 - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE // The actual laptop/tablet var/obj/item/modular_computer/laptop/fabricated_laptop = null @@ -160,70 +160,77 @@ return total_price return 0 - - - - -/obj/machinery/lapvend/Topic(href, href_list) +/obj/machinery/lapvend/tgui_act(action, params) if(..()) - return 1 + return TRUE - if(href_list["pick_device"]) - if(state) // We've already picked a device type - return 0 - devtype = text2num(href_list["pick_device"]) - state = 1 - fabricate_and_recalc_price(0) - return 1 - if(href_list["clean_order"]) - reset_order() - return 1 + switch(action) + if("pick_device") + if(state) // We've already picked a device type + return FALSE + devtype = text2num(params["pick"]) + state = 1 + fabricate_and_recalc_price(FALSE) + return TRUE + if("clean_order") + reset_order() + return TRUE if((state != 1) && devtype) // Following IFs should only be usable when in the Select Loadout mode - return 0 - if(href_list["confirm_order"]) - state = 2 // Wait for ID swipe for payment processing - fabricate_and_recalc_price(0) - return 1 - if(href_list["hw_cpu"]) - dev_cpu = text2num(href_list["hw_cpu"]) - fabricate_and_recalc_price(0) - return 1 - if(href_list["hw_battery"]) - dev_battery = text2num(href_list["hw_battery"]) - fabricate_and_recalc_price(0) - return 1 - if(href_list["hw_disk"]) - dev_disk = text2num(href_list["hw_disk"]) - fabricate_and_recalc_price(0) - return 1 - if(href_list["hw_netcard"]) - dev_netcard = text2num(href_list["hw_netcard"]) - fabricate_and_recalc_price(0) - return 1 - if(href_list["hw_tesla"]) - dev_tesla = text2num(href_list["hw_tesla"]) - fabricate_and_recalc_price(0) - return 1 - if(href_list["hw_nanoprint"]) - dev_nanoprint = text2num(href_list["hw_nanoprint"]) - fabricate_and_recalc_price(0) - return 1 - if(href_list["hw_card"]) - dev_card = text2num(href_list["hw_card"]) - fabricate_and_recalc_price(0) - return 1 - return 0 + return FALSE + switch(action) + if("confirm_order") + state = 2 // Wait for ID swipe for payment processing + fabricate_and_recalc_price(FALSE) + return TRUE + if("hw_cpu") + dev_cpu = text2num(params["cpu"]) + fabricate_and_recalc_price(FALSE) + return TRUE + if("hw_battery") + dev_battery = text2num(params["battery"]) + fabricate_and_recalc_price(FALSE) + return TRUE + if("hw_disk") + dev_disk = text2num(params["disk"]) + fabricate_and_recalc_price(FALSE) + return TRUE + if("hw_netcard") + dev_netcard = text2num(params["netcard"]) + fabricate_and_recalc_price(FALSE) + return TRUE + if("hw_tesla") + dev_tesla = text2num(params["tesla"]) + fabricate_and_recalc_price(FALSE) + return TRUE + if("hw_nanoprint") + dev_nanoprint = text2num(params["print"]) + fabricate_and_recalc_price(FALSE) + return TRUE + if("hw_card") + dev_card = text2num(params["card"]) + fabricate_and_recalc_price(FALSE) + return TRUE + return FALSE + + /obj/machinery/lapvend/attack_hand(var/mob/user) - ui_interact(user) + tgui_interact(user) -/obj/machinery/lapvend/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/lapvend/tgui_interact(mob/user, datum/tgui/ui) if(stat & (BROKEN | NOPOWER | MAINT)) if(ui) ui.close() - return 0 + return FALSE + + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ComputerFabricator") + ui.open() + +/obj/machinery/lapvend/tgui_data(mob/user) + var/list/data = list() - var/list/data[0] data["state"] = state if(state == 1) data["devtype"] = devtype @@ -237,13 +244,7 @@ if(state == 1 || state == 2) data["totalprice"] = total_price - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "computer_fabricator.tmpl", "Personal Computer Vendor", 500, 400) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - + return data obj/machinery/lapvend/attackby(obj/item/weapon/W as obj, mob/user as mob) var/obj/item/weapon/card/id/I = W.GetID() @@ -272,7 +273,6 @@ obj/machinery/lapvend/attackby(obj/item/weapon/W as obj, mob/user as mob) return 0 return ..() - // Simplified payment processing, returns 1 on success. /obj/machinery/lapvend/proc/process_payment(var/obj/item/weapon/card/id/I, var/obj/item/ID_container) if(I==ID_container || ID_container == null) @@ -305,4 +305,4 @@ obj/machinery/lapvend/attackby(obj/item/weapon/W as obj, mob/user as mob) T.date = current_date_string T.time = stationtime2text() customer_account.transaction_log.Add(T) - return 1 \ No newline at end of file + return 1 diff --git a/code/modules/multiz/ladder_assembly_vr.dm b/code/modules/multiz/ladder_assembly_vr.dm index e46bdca799..4decbdd47d 100644 --- a/code/modules/multiz/ladder_assembly_vr.dm +++ b/code/modules/multiz/ladder_assembly_vr.dm @@ -125,7 +125,7 @@ qdel(above) // Make them constructable in hand -/material/steel/generate_recipes() +/datum/material/steel/generate_recipes() ..() recipes += new/datum/stack_recipe("ladder assembly", /obj/structure/ladder_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1) diff --git a/code/modules/nano/interaction/admin.dm b/code/modules/nano/interaction/admin.dm index dd4ce6ad17..7ddb165f70 100644 --- a/code/modules/nano/interaction/admin.dm +++ b/code/modules/nano/interaction/admin.dm @@ -1,7 +1,7 @@ -/* - This state checks that the user is an admin, end of story -*/ -/var/global/datum/topic_state/admin_state/admin_state = new() - -/datum/topic_state/admin_state/can_use_topic(var/src_object, var/mob/user) - return check_rights(R_ADMIN|R_EVENT, 0, user) ? STATUS_INTERACTIVE : STATUS_CLOSE +/* + This state checks that the user is an admin, end of story +*/ +/var/global/datum/topic_state/admin_state/admin_state = new() + +/datum/topic_state/admin_state/can_use_topic(var/src_object, var/mob/user) + return check_rights(R_ADMIN|R_EVENT, 0, user) ? STATUS_INTERACTIVE : STATUS_CLOSE diff --git a/code/modules/nano/interaction/base.dm b/code/modules/nano/interaction/base.dm index eb3e9ae5c1..8245ee04ed 100644 --- a/code/modules/nano/interaction/base.dm +++ b/code/modules/nano/interaction/base.dm @@ -1,37 +1,37 @@ -/datum/proc/nano_host() - return src - -/datum/proc/nano_container() - return src - -/datum/proc/CanUseTopic(var/mob/user, var/datum/topic_state/state) - var/src_object = nano_host() - return state.can_use_topic(src_object, user) - -/datum/topic_state/proc/href_list(var/mob/user) - return list() - -/datum/topic_state/proc/can_use_topic(var/src_object, var/mob/user) - return STATUS_CLOSE - -/mob/proc/shared_nano_interaction() - if (src.stat || !client) - return STATUS_CLOSE // no updates, close the interface - else if (incapacitated()) - return STATUS_UPDATE // update only (orange visibility) - return STATUS_INTERACTIVE - -/mob/living/silicon/ai/shared_nano_interaction() - if(lacks_power()) - return STATUS_CLOSE - if (check_unable(1, 0)) - return STATUS_CLOSE - return ..() - -/mob/living/silicon/robot/shared_nano_interaction() - . = STATUS_INTERACTIVE - if(!has_power) - return STATUS_CLOSE - if(lockdown) - . = STATUS_DISABLED - return min(., ..()) +/datum/proc/nano_host() + return src + +/datum/proc/nano_container() + return src + +/datum/proc/CanUseTopic(var/mob/user, var/datum/topic_state/state) + var/src_object = nano_host() + return state.can_use_topic(src_object, user) + +/datum/topic_state/proc/href_list(var/mob/user) + return list() + +/datum/topic_state/proc/can_use_topic(var/src_object, var/mob/user) + return STATUS_CLOSE + +/mob/proc/shared_nano_interaction() + if (src.stat || !client) + return STATUS_CLOSE // no updates, close the interface + else if (incapacitated()) + return STATUS_UPDATE // update only (orange visibility) + return STATUS_INTERACTIVE + +/mob/living/silicon/ai/shared_nano_interaction() + if(lacks_power()) + return STATUS_CLOSE + if (check_unable(1, 0)) + return STATUS_CLOSE + return ..() + +/mob/living/silicon/robot/shared_nano_interaction() + . = STATUS_INTERACTIVE + if(!has_power) + return STATUS_CLOSE + if(lockdown) + . = STATUS_DISABLED + return min(., ..()) diff --git a/code/modules/nano/interaction/contained.dm b/code/modules/nano/interaction/contained.dm index 9ef595d020..3c84734104 100644 --- a/code/modules/nano/interaction/contained.dm +++ b/code/modules/nano/interaction/contained.dm @@ -1,18 +1,18 @@ -/* - This state checks if user is somewhere within src_object, as well as the default NanoUI interaction. -*/ -/var/global/datum/topic_state/contained_state/contained_state = new() - -/datum/topic_state/contained_state/can_use_topic(var/atom/src_object, var/mob/user) - if(!src_object.contains(user)) - return STATUS_CLOSE - - return user.shared_nano_interaction() - -/atom/proc/contains(var/atom/location) - if(!location) - return 0 - if(location == src) - return 1 - - return contains(location.loc) +/* + This state checks if user is somewhere within src_object, as well as the default NanoUI interaction. +*/ +/var/global/datum/topic_state/contained_state/contained_state = new() + +/datum/topic_state/contained_state/can_use_topic(var/atom/src_object, var/mob/user) + if(!src_object.contains(user)) + return STATUS_CLOSE + + return user.shared_nano_interaction() + +/atom/proc/contains(var/atom/location) + if(!location) + return 0 + if(location == src) + return 1 + + return contains(location.loc) diff --git a/code/modules/nano/interaction/default.dm b/code/modules/nano/interaction/default.dm index dbb0781d33..812ed40eb5 100644 --- a/code/modules/nano/interaction/default.dm +++ b/code/modules/nano/interaction/default.dm @@ -1,91 +1,91 @@ -/var/global/datum/topic_state/default/default_state = new() - -/datum/topic_state/default/href_list(var/mob/user) - return list() - -/datum/topic_state/default/can_use_topic(var/src_object, var/mob/user) - return user.default_can_use_topic(src_object) - -/mob/proc/default_can_use_topic(var/src_object) - return STATUS_CLOSE // By default no mob can do anything with NanoUI - -/mob/observer/dead/default_can_use_topic(var/src_object) - if(can_admin_interact()) - return STATUS_INTERACTIVE // Admins are more equal - if(!client || get_dist(src_object, src) > client.view) // Preventing ghosts from having a million windows open by limiting to objects in range - return STATUS_CLOSE - return STATUS_UPDATE // Ghosts can view updates - -/mob/living/silicon/pai/default_can_use_topic(var/src_object) - if((src_object == src || src_object == radio || src_object == communicator) && !stat) - return STATUS_INTERACTIVE - else - return ..() - -/mob/living/silicon/robot/default_can_use_topic(var/src_object) - . = shared_nano_interaction() - if(. <= STATUS_DISABLED) - return - - // robots can interact with things they can see within their view range - if((src_object in view(src)) && get_dist(src_object, src) <= src.client.view) - return STATUS_INTERACTIVE // interactive (green visibility) - return STATUS_DISABLED // no updates, completely disabled (red visibility) - -/mob/living/silicon/ai/default_can_use_topic(var/src_object) - . = shared_nano_interaction() - if(. != STATUS_INTERACTIVE) - return - - // Prevents the AI from using Topic on admin levels (by for example viewing through the court/thunderdome cameras) - // unless it's on the same level as the object it's interacting with. - var/turf/T = get_turf(src_object) - if(!T || !(z == T.z || (T.z in using_map.player_levels))) - return STATUS_CLOSE - - // If an object is in view then we can interact with it - if(src_object in view(client.view, src)) - return STATUS_INTERACTIVE - - // If we're installed in a chassi, rather than transfered to an inteliCard or other container, then check if we have camera view - if(is_in_chassis()) - //stop AIs from leaving windows open and using then after they lose vision - if(cameranet && !cameranet.checkTurfVis(get_turf(src_object))) - return STATUS_CLOSE - return STATUS_INTERACTIVE - else if(get_dist(src_object, src) <= client.view) // View does not return what one would expect while installed in an inteliCard - return STATUS_INTERACTIVE - - return STATUS_CLOSE - -//Some atoms such as vehicles might have special rules for how mobs inside them interact with NanoUI. -/atom/proc/contents_nano_distance(var/src_object, var/mob/living/user) - return user.shared_living_nano_distance(src_object) - -/mob/living/proc/shared_living_nano_distance(var/atom/movable/src_object) - if (!(src_object in view(4, src))) // If the src object is not in visable, disable updates - return STATUS_CLOSE - - var/dist = get_dist(src_object, src) - if (dist <= 1) - return STATUS_INTERACTIVE // interactive (green visibility) - else if (dist <= 2) - return STATUS_UPDATE // update only (orange visibility) - else if (dist <= 4) - return STATUS_DISABLED // no updates, completely disabled (red visibility) - return STATUS_CLOSE - -/mob/living/default_can_use_topic(var/src_object) - . = shared_nano_interaction(src_object) - if(. != STATUS_CLOSE) - if(loc) - . = min(., loc.contents_nano_distance(src_object, src)) - if(STATUS_INTERACTIVE) - return STATUS_UPDATE - -/mob/living/carbon/human/default_can_use_topic(var/src_object) - . = shared_nano_interaction(src_object) - if(. != STATUS_CLOSE) - . = min(., shared_living_nano_distance(src_object)) - if(. == STATUS_UPDATE && (TK in mutations)) // If we have telekinesis and remain close enough, allow interaction. - return STATUS_INTERACTIVE +/var/global/datum/topic_state/default/default_state = new() + +/datum/topic_state/default/href_list(var/mob/user) + return list() + +/datum/topic_state/default/can_use_topic(var/src_object, var/mob/user) + return user.default_can_use_topic(src_object) + +/mob/proc/default_can_use_topic(var/src_object) + return STATUS_CLOSE // By default no mob can do anything with NanoUI + +/mob/observer/dead/default_can_use_topic(var/src_object) + if(can_admin_interact()) + return STATUS_INTERACTIVE // Admins are more equal + if(!client || get_dist(src_object, src) > client.view) // Preventing ghosts from having a million windows open by limiting to objects in range + return STATUS_CLOSE + return STATUS_UPDATE // Ghosts can view updates + +/mob/living/silicon/pai/default_can_use_topic(var/src_object) + if((src_object == src || src_object == radio || src_object == communicator) && !stat) + return STATUS_INTERACTIVE + else + return ..() + +/mob/living/silicon/robot/default_can_use_topic(var/src_object) + . = shared_nano_interaction() + if(. <= STATUS_DISABLED) + return + + // robots can interact with things they can see within their view range + if((src_object in view(src)) && get_dist(src_object, src) <= src.client.view) + return STATUS_INTERACTIVE // interactive (green visibility) + return STATUS_DISABLED // no updates, completely disabled (red visibility) + +/mob/living/silicon/ai/default_can_use_topic(var/src_object) + . = shared_nano_interaction() + if(. != STATUS_INTERACTIVE) + return + + // Prevents the AI from using Topic on admin levels (by for example viewing through the court/thunderdome cameras) + // unless it's on the same level as the object it's interacting with. + var/turf/T = get_turf(src_object) + if(!T || !(z == T.z || (T.z in using_map.player_levels))) + return STATUS_CLOSE + + // If an object is in view then we can interact with it + if(src_object in view(client.view, src)) + return STATUS_INTERACTIVE + + // If we're installed in a chassi, rather than transfered to an inteliCard or other container, then check if we have camera view + if(is_in_chassis()) + //stop AIs from leaving windows open and using then after they lose vision + if(cameranet && !cameranet.checkTurfVis(get_turf(src_object))) + return STATUS_CLOSE + return STATUS_INTERACTIVE + else if(get_dist(src_object, src) <= client.view) // View does not return what one would expect while installed in an inteliCard + return STATUS_INTERACTIVE + + return STATUS_CLOSE + +//Some atoms such as vehicles might have special rules for how mobs inside them interact with NanoUI. +/atom/proc/contents_nano_distance(var/src_object, var/mob/living/user) + return user.shared_living_nano_distance(src_object) + +/mob/living/proc/shared_living_nano_distance(var/atom/movable/src_object) + if (!(src_object in view(4, src))) // If the src object is not in visable, disable updates + return STATUS_CLOSE + + var/dist = get_dist(src_object, src) + if (dist <= 1) + return STATUS_INTERACTIVE // interactive (green visibility) + else if (dist <= 2) + return STATUS_UPDATE // update only (orange visibility) + else if (dist <= 4) + return STATUS_DISABLED // no updates, completely disabled (red visibility) + return STATUS_CLOSE + +/mob/living/default_can_use_topic(var/src_object) + . = shared_nano_interaction(src_object) + if(. != STATUS_CLOSE) + if(loc) + . = min(., loc.contents_nano_distance(src_object, src)) + if(STATUS_INTERACTIVE) + return STATUS_UPDATE + +/mob/living/carbon/human/default_can_use_topic(var/src_object) + . = shared_nano_interaction(src_object) + if(. != STATUS_CLOSE) + . = min(., shared_living_nano_distance(src_object)) + if(. == STATUS_UPDATE && (TK in mutations)) // If we have telekinesis and remain close enough, allow interaction. + return STATUS_INTERACTIVE diff --git a/code/modules/nano/interaction/inventory.dm b/code/modules/nano/interaction/inventory.dm index dd320f2bb2..40e5bcb0e0 100644 --- a/code/modules/nano/interaction/inventory.dm +++ b/code/modules/nano/interaction/inventory.dm @@ -1,11 +1,11 @@ -/* - This state checks that the src_object is somewhere in the user's first-level inventory (in hands, on ear, etc.), but not further down (such as in bags). -*/ -/var/global/datum/topic_state/inventory_state/inventory_state = new() - -/datum/topic_state/inventory_state/can_use_topic(var/src_object, var/mob/user) - if(!(src_object in user)) - return STATUS_CLOSE - - - return user.shared_nano_interaction() +/* + This state checks that the src_object is somewhere in the user's first-level inventory (in hands, on ear, etc.), but not further down (such as in bags). +*/ +/var/global/datum/topic_state/inventory_state/inventory_state = new() + +/datum/topic_state/inventory_state/can_use_topic(var/src_object, var/mob/user) + if(!(src_object in user)) + return STATUS_CLOSE + + + return user.shared_nano_interaction() diff --git a/code/modules/nano/interaction/inventory_deep.dm b/code/modules/nano/interaction/inventory_deep.dm index 9637c4df75..98078c02c1 100644 --- a/code/modules/nano/interaction/inventory_deep.dm +++ b/code/modules/nano/interaction/inventory_deep.dm @@ -1,10 +1,10 @@ -/* - This state checks if src_object is contained anywhere in the user's inventory, including bags, etc. -*/ -/var/global/datum/topic_state/deep_inventory_state/deep_inventory_state = new() - -/datum/topic_state/deep_inventory_state/can_use_topic(var/src_object, var/mob/user) - if(!user.contains(src_object)) - return STATUS_CLOSE - - return user.shared_nano_interaction() +/* + This state checks if src_object is contained anywhere in the user's inventory, including bags, etc. +*/ +/var/global/datum/topic_state/deep_inventory_state/deep_inventory_state = new() + +/datum/topic_state/deep_inventory_state/can_use_topic(var/src_object, var/mob/user) + if(!user.contains(src_object)) + return STATUS_CLOSE + + return user.shared_nano_interaction() diff --git a/code/modules/nano/interaction/physical.dm b/code/modules/nano/interaction/physical.dm index 0571008481..5c59029f23 100644 --- a/code/modules/nano/interaction/physical.dm +++ b/code/modules/nano/interaction/physical.dm @@ -1,18 +1,18 @@ -/var/global/datum/topic_state/physical/physical_state = new() - -/datum/topic_state/physical/can_use_topic(var/src_object, var/mob/user) - . = user.shared_nano_interaction(src_object) - if(. > STATUS_CLOSE) - return min(., user.check_physical_distance(src_object)) - -/mob/proc/check_physical_distance(var/src_object) - return STATUS_CLOSE - -/mob/observer/dead/check_physical_distance(var/src_object) - return default_can_use_topic(src_object) - -/mob/living/check_physical_distance(var/src_object) - return shared_living_nano_distance(src_object) - -/mob/living/silicon/check_physical_distance(var/src_object) - return max(STATUS_UPDATE, shared_living_nano_distance(src_object)) +/var/global/datum/topic_state/physical/physical_state = new() + +/datum/topic_state/physical/can_use_topic(var/src_object, var/mob/user) + . = user.shared_nano_interaction(src_object) + if(. > STATUS_CLOSE) + return min(., user.check_physical_distance(src_object)) + +/mob/proc/check_physical_distance(var/src_object) + return STATUS_CLOSE + +/mob/observer/dead/check_physical_distance(var/src_object) + return default_can_use_topic(src_object) + +/mob/living/check_physical_distance(var/src_object) + return shared_living_nano_distance(src_object) + +/mob/living/silicon/check_physical_distance(var/src_object) + return max(STATUS_UPDATE, shared_living_nano_distance(src_object)) diff --git a/code/modules/nano/interaction/self.dm b/code/modules/nano/interaction/self.dm index 639e50e161..a4ae505034 100644 --- a/code/modules/nano/interaction/self.dm +++ b/code/modules/nano/interaction/self.dm @@ -1,9 +1,9 @@ -/* - This state checks that the src_object is the same the as user -*/ -/var/global/datum/topic_state/self_state/self_state = new() - -/datum/topic_state/self_state/can_use_topic(var/src_object, var/mob/user) - if(src_object != user) - return STATUS_CLOSE - return user.shared_nano_interaction() +/* + This state checks that the src_object is the same the as user +*/ +/var/global/datum/topic_state/self_state/self_state = new() + +/datum/topic_state/self_state/can_use_topic(var/src_object, var/mob/user) + if(src_object != user) + return STATUS_CLOSE + return user.shared_nano_interaction() diff --git a/code/modules/nano/interaction/zlevel.dm b/code/modules/nano/interaction/zlevel.dm index 80d4c2e601..15052bc663 100644 --- a/code/modules/nano/interaction/zlevel.dm +++ b/code/modules/nano/interaction/zlevel.dm @@ -1,13 +1,13 @@ -/* - This state checks that the user is on the same Z-level as src_object -*/ - -/var/global/datum/topic_state/z_state/z_state = new() - -/datum/topic_state/z_state/can_use_topic(var/src_object, var/mob/user) - var/turf/turf_obj = get_turf(src_object) - var/turf/turf_usr = get_turf(user) - if(!turf_obj || !turf_usr) - return STATUS_CLOSE - - return turf_obj.z == turf_usr.z ? STATUS_INTERACTIVE : STATUS_CLOSE +/* + This state checks that the user is on the same Z-level as src_object +*/ + +/var/global/datum/topic_state/z_state/z_state = new() + +/datum/topic_state/z_state/can_use_topic(var/src_object, var/mob/user) + var/turf/turf_obj = get_turf(src_object) + var/turf/turf_usr = get_turf(user) + if(!turf_obj || !turf_usr) + return STATUS_CLOSE + + return turf_obj.z == turf_usr.z ? STATUS_INTERACTIVE : STATUS_CLOSE diff --git a/code/modules/nano/modules/nano_module.dm b/code/modules/nano/modules/nano_module.dm deleted file mode 100644 index 75c38c9ed3..0000000000 --- a/code/modules/nano/modules/nano_module.dm +++ /dev/null @@ -1,67 +0,0 @@ -/datum/nano_module - var/name - var/datum/host - var/datum/topic_manager/topic_manager - var/list/using_access - -/datum/nano_module/New(var/datum/host, var/topic_manager) - ..() - src.host = host.nano_host() - src.topic_manager = topic_manager - -/datum/nano_module/nano_host() - return host ? host : src - -/datum/nano_module/proc/can_still_topic(var/datum/topic_state/state = default_state) - return CanUseTopic(usr, state) == STATUS_INTERACTIVE - -/datum/nano_module/proc/check_eye(var/mob/user) - return -1 - -/datum/nano_module/proc/check_access(var/mob/user, var/access) - if(!access) - return 1 - - if(using_access) - if(access in using_access) - return 1 - else - return 0 - - if(!istype(user)) - return 0 - - var/obj/item/weapon/card/id/I = user.GetIdCard() - if(!I) - return 0 - - if(access in I.access) - return 1 - - return 0 - -/datum/nano_module/Topic(href, href_list) - if(topic_manager && topic_manager.Topic(href, href_list)) - return TRUE - . = ..() - -/datum/nano_module/proc/print_text(var/text, var/mob/user) - var/obj/item/modular_computer/MC = nano_host() - if(istype(MC)) - if(!MC.nano_printer) - to_chat(user, "Error: No printer detected. Unable to print document.") - return - - if(!MC.nano_printer.print_text(text)) - to_chat(user, "Error: Printer was unable to print the document. It may be out of paper.") - else - to_chat(user, "Error: Unable to detect compatible printer interface. Are you running NTOSv2 compatible system?") - -/datum/proc/initial_data() - return list() - -/datum/proc/update_layout() - return FALSE - -/datum/nano_module/proc/relaymove(var/mob/user, direction) - return FALSE diff --git a/code/modules/nano/nanomanager.dm b/code/modules/nano/nanomanager.dm index 69b0e7b77e..6e1bc749a4 100644 --- a/code/modules/nano/nanomanager.dm +++ b/code/modules/nano/nanomanager.dm @@ -1,224 +1,224 @@ - - /** - * Get an open /nanoui ui for the current user, src_object and ui_key and try to update it with data - * - * @param user /mob The mob who opened/owns the ui - * @param src_object /obj|/mob The obj or mob which the ui belongs to - * @param ui_key string A string key used for the ui - * @param ui /datum/nanoui An existing instance of the ui (can be null) - * @param data list The data to be passed to the ui, if it exists - * @param force_open boolean The ui is being forced to (re)open, so close ui if it exists (instead of updating) - * - * @return /nanoui Returns the found ui, for null if none exists - */ -/datum/controller/subsystem/nanoui/proc/try_update_ui(var/mob/user, src_object, ui_key, var/datum/nanoui/ui, data, var/force_open = 0) - if (isnull(ui)) // no ui has been passed, so we'll search for one - { - ui = get_open_ui(user, src_object, ui_key) - } - if (!isnull(ui)) - // The UI is already open - if (!force_open) - ui.push_data(data) - return ui - else - ui.reinitialise(new_initial_data=data) - return ui - - return null - - /** - * Get an open /nanoui ui for the current user, src_object and ui_key - * - * @param user /mob The mob who opened/owns the ui - * @param src_object /obj|/mob The obj or mob which the ui belongs to - * @param ui_key string A string key used for the ui - * - * @return /nanoui Returns the found ui, or null if none exists - */ -/datum/controller/subsystem/nanoui/proc/get_open_ui(var/mob/user, src_object, ui_key) - var/src_object_key = "\ref[src_object]" - if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) - //testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - there are no uis open") - return null - else if (isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list)) - //testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - there are no uis open for this object") - return null - - for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key]) - if (ui.user == user) - return ui - - //testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - ui not found") - return null - - /** - * Update all /nanoui uis attached to src_object - * - * @param src_object /obj|/mob The obj or mob which the uis are attached to - * - * @return int The number of uis updated - */ -/datum/controller/subsystem/nanoui/proc/update_uis(src_object) - var/src_object_key = "\ref[src_object]" - if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) - return 0 - - var/update_count = 0 - for (var/ui_key in open_uis[src_object_key]) - for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key]) - if(ui && ui.src_object && ui.user && ui.src_object.nano_host()) - ui.process(1) - update_count++ - return update_count - - /** - * Close all /nanoui uis attached to src_object - * - * @param src_object /obj|/mob The obj or mob which the uis are attached to - * - * @return int The number of uis close - */ -/datum/controller/subsystem/nanoui/proc/close_uis(src_object) - var/src_object_key = "\ref[src_object]" - if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) - return 0 - - var/close_count = 0 - for (var/ui_key in open_uis[src_object_key]) - for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key]) - if(ui && ui.src_object && ui.user && ui.src_object.nano_host()) - ui.close() - close_count++ - return close_count - - /** - * Update /nanoui uis belonging to user - * - * @param user /mob The mob who owns the uis - * @param src_object /obj|/mob If src_object is provided, only update uis which are attached to src_object (optional) - * @param ui_key string If ui_key is provided, only update uis with a matching ui_key (optional) - * - * @return int The number of uis updated - */ -/datum/controller/subsystem/nanoui/proc/update_user_uis(var/mob/user, src_object = null, ui_key = null) - if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0) - return 0 // has no open uis - - var/update_count = 0 - for (var/datum/nanoui/ui in user.open_uis) - if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key)) - ui.process(1) - update_count++ - - return update_count - - /** - * Close /nanoui uis belonging to user - * - * @param user /mob The mob who owns the uis - * @param src_object /obj|/mob If src_object is provided, only close uis which are attached to src_object (optional) - * @param ui_key string If ui_key is provided, only close uis with a matching ui_key (optional) - * - * @return int The number of uis closed - */ -/datum/controller/subsystem/nanoui/proc/close_user_uis(var/mob/user, src_object = null, ui_key = null) - if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0) - //testing("nanomanager/close_user_uis mob [user.name] has no open uis") - return 0 // has no open uis - - var/close_count = 0 - for (var/datum/nanoui/ui in user.open_uis) - if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key)) - ui.close() - close_count++ - - //testing("nanomanager/close_user_uis mob [user.name] closed [open_uis.len] of [close_count] uis") - - return close_count - - /** - * Add a /nanoui ui to the list of open uis - * This is called by the /nanoui open() proc - * - * @param ui /nanoui The ui to add - * - * @return nothing - */ -/datum/controller/subsystem/nanoui/proc/ui_opened(var/datum/nanoui/ui) - var/src_object_key = "\ref[ui.src_object]" - if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) - open_uis[src_object_key] = list(ui.ui_key = list()) - else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list)) - open_uis[src_object_key][ui.ui_key] = list(); - - ui.user.open_uis |= ui - var/list/uis = open_uis[src_object_key][ui.ui_key] - uis |= ui - processing_uis |= ui - //testing("nanomanager/ui_opened mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.open_uis [ui.user.open_uis.len] | uis [uis.len] | processing_uis [processing_uis.len]") - - /** - * Remove a /nanoui ui from the list of open uis - * This is called by the /nanoui close() proc - * - * @param ui /nanoui The ui to remove - * - * @return int 0 if no ui was removed, 1 if removed successfully - */ -/datum/controller/subsystem/nanoui/proc/ui_closed(var/datum/nanoui/ui) - var/src_object_key = "\ref[ui.src_object]" - if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) - return 0 // wasn't open - else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list)) - return 0 // wasn't open - - processing_uis.Remove(ui) - if(ui.user) // Sanity check in case a user has been deleted (say a blown up borg watching the alarm interface) - ui.user.open_uis.Remove(ui) - var/list/uis = open_uis[src_object_key][ui.ui_key] - uis.Remove(ui) - - //testing("nanomanager/ui_closed mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.open_uis [ui.user.open_uis.len] | uis [uis.len] | processing_uis [processing_uis.len]") - - return 1 - - /** - * This is called on user logout - * Closes/clears all uis attached to the user's /mob - * - * @param user /mob The user's mob - * - * @return nothing - */ - -// -/datum/controller/subsystem/nanoui/proc/user_logout(var/mob/user) - //testing("nanomanager/user_logout user [user.name]") - return close_user_uis(user) - - /** - * This is called when a player transfers from one mob to another - * Transfers all open UIs to the new mob - * - * @param oldMob /mob The user's old mob - * @param newMob /mob The user's new mob - * - * @return nothing - */ -/datum/controller/subsystem/nanoui/proc/user_transferred(var/mob/oldMob, var/mob/newMob) - //testing("nanomanager/user_transferred from mob [oldMob.name] to mob [newMob.name]") - if (!oldMob || isnull(oldMob.open_uis) || !istype(oldMob.open_uis, /list) || open_uis.len == 0) - //testing("nanomanager/user_transferred mob [oldMob.name] has no open uis") - return 0 // has no open uis - - if (isnull(newMob.open_uis) || !istype(newMob.open_uis, /list)) - newMob.open_uis = list() - - for (var/datum/nanoui/ui in oldMob.open_uis) - ui.user = newMob - newMob.open_uis.Add(ui) - - oldMob.open_uis.Cut() - + + /** + * Get an open /nanoui ui for the current user, src_object and ui_key and try to update it with data + * + * @param user /mob The mob who opened/owns the ui + * @param src_object /obj|/mob The obj or mob which the ui belongs to + * @param ui_key string A string key used for the ui + * @param ui /datum/nanoui An existing instance of the ui (can be null) + * @param data list The data to be passed to the ui, if it exists + * @param force_open boolean The ui is being forced to (re)open, so close ui if it exists (instead of updating) + * + * @return /nanoui Returns the found ui, for null if none exists + */ +/datum/controller/subsystem/nanoui/proc/try_update_ui(var/mob/user, src_object, ui_key, var/datum/nanoui/ui, data, var/force_open = 0) + if (isnull(ui)) // no ui has been passed, so we'll search for one + { + ui = get_open_ui(user, src_object, ui_key) + } + if (!isnull(ui)) + // The UI is already open + if (!force_open) + ui.push_data(data) + return ui + else + ui.reinitialise(new_initial_data=data) + return ui + + return null + + /** + * Get an open /nanoui ui for the current user, src_object and ui_key + * + * @param user /mob The mob who opened/owns the ui + * @param src_object /obj|/mob The obj or mob which the ui belongs to + * @param ui_key string A string key used for the ui + * + * @return /nanoui Returns the found ui, or null if none exists + */ +/datum/controller/subsystem/nanoui/proc/get_open_ui(var/mob/user, src_object, ui_key) + var/src_object_key = "\ref[src_object]" + if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) + //testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - there are no uis open") + return null + else if (isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list)) + //testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - there are no uis open for this object") + return null + + for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key]) + if (ui.user == user) + return ui + + //testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - ui not found") + return null + + /** + * Update all /nanoui uis attached to src_object + * + * @param src_object /obj|/mob The obj or mob which the uis are attached to + * + * @return int The number of uis updated + */ +/datum/controller/subsystem/nanoui/proc/update_uis(src_object) + var/src_object_key = "\ref[src_object]" + if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) + return 0 + + var/update_count = 0 + for (var/ui_key in open_uis[src_object_key]) + for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key]) + if(ui && ui.src_object && ui.user && ui.src_object.nano_host()) + ui.process(1) + update_count++ + return update_count + + /** + * Close all /nanoui uis attached to src_object + * + * @param src_object /obj|/mob The obj or mob which the uis are attached to + * + * @return int The number of uis close + */ +/datum/controller/subsystem/nanoui/proc/close_uis(src_object) + var/src_object_key = "\ref[src_object]" + if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) + return 0 + + var/close_count = 0 + for (var/ui_key in open_uis[src_object_key]) + for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key]) + if(ui && ui.src_object && ui.user && ui.src_object.nano_host()) + ui.close() + close_count++ + return close_count + + /** + * Update /nanoui uis belonging to user + * + * @param user /mob The mob who owns the uis + * @param src_object /obj|/mob If src_object is provided, only update uis which are attached to src_object (optional) + * @param ui_key string If ui_key is provided, only update uis with a matching ui_key (optional) + * + * @return int The number of uis updated + */ +/datum/controller/subsystem/nanoui/proc/update_user_uis(var/mob/user, src_object = null, ui_key = null) + if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0) + return 0 // has no open uis + + var/update_count = 0 + for (var/datum/nanoui/ui in user.open_uis) + if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key)) + ui.process(1) + update_count++ + + return update_count + + /** + * Close /nanoui uis belonging to user + * + * @param user /mob The mob who owns the uis + * @param src_object /obj|/mob If src_object is provided, only close uis which are attached to src_object (optional) + * @param ui_key string If ui_key is provided, only close uis with a matching ui_key (optional) + * + * @return int The number of uis closed + */ +/datum/controller/subsystem/nanoui/proc/close_user_uis(var/mob/user, src_object = null, ui_key = null) + if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0) + //testing("nanomanager/close_user_uis mob [user.name] has no open uis") + return 0 // has no open uis + + var/close_count = 0 + for (var/datum/nanoui/ui in user.open_uis) + if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key)) + ui.close() + close_count++ + + //testing("nanomanager/close_user_uis mob [user.name] closed [open_uis.len] of [close_count] uis") + + return close_count + + /** + * Add a /nanoui ui to the list of open uis + * This is called by the /nanoui open() proc + * + * @param ui /nanoui The ui to add + * + * @return nothing + */ +/datum/controller/subsystem/nanoui/proc/ui_opened(var/datum/nanoui/ui) + var/src_object_key = "\ref[ui.src_object]" + if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) + open_uis[src_object_key] = list(ui.ui_key = list()) + else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list)) + open_uis[src_object_key][ui.ui_key] = list(); + + ui.user.open_uis |= ui + var/list/uis = open_uis[src_object_key][ui.ui_key] + uis |= ui + processing_uis |= ui + //testing("nanomanager/ui_opened mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.open_uis [ui.user.open_uis.len] | uis [uis.len] | processing_uis [processing_uis.len]") + + /** + * Remove a /nanoui ui from the list of open uis + * This is called by the /nanoui close() proc + * + * @param ui /nanoui The ui to remove + * + * @return int 0 if no ui was removed, 1 if removed successfully + */ +/datum/controller/subsystem/nanoui/proc/ui_closed(var/datum/nanoui/ui) + var/src_object_key = "\ref[ui.src_object]" + if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list)) + return 0 // wasn't open + else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list)) + return 0 // wasn't open + + processing_uis.Remove(ui) + if(ui.user) // Sanity check in case a user has been deleted (say a blown up borg watching the alarm interface) + ui.user.open_uis.Remove(ui) + var/list/uis = open_uis[src_object_key][ui.ui_key] + uis.Remove(ui) + + //testing("nanomanager/ui_closed mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.open_uis [ui.user.open_uis.len] | uis [uis.len] | processing_uis [processing_uis.len]") + + return 1 + + /** + * This is called on user logout + * Closes/clears all uis attached to the user's /mob + * + * @param user /mob The user's mob + * + * @return nothing + */ + +// +/datum/controller/subsystem/nanoui/proc/user_logout(var/mob/user) + //testing("nanomanager/user_logout user [user.name]") + return close_user_uis(user) + + /** + * This is called when a player transfers from one mob to another + * Transfers all open UIs to the new mob + * + * @param oldMob /mob The user's old mob + * @param newMob /mob The user's new mob + * + * @return nothing + */ +/datum/controller/subsystem/nanoui/proc/user_transferred(var/mob/oldMob, var/mob/newMob) + //testing("nanomanager/user_transferred from mob [oldMob.name] to mob [newMob.name]") + if (!oldMob || isnull(oldMob.open_uis) || !istype(oldMob.open_uis, /list) || open_uis.len == 0) + //testing("nanomanager/user_transferred mob [oldMob.name] has no open uis") + return 0 // has no open uis + + if (isnull(newMob.open_uis) || !istype(newMob.open_uis, /list)) + newMob.open_uis = list() + + for (var/datum/nanoui/ui in oldMob.open_uis) + ui.user = newMob + newMob.open_uis.Add(ui) + + oldMob.open_uis.Cut() + return 1 // success \ No newline at end of file diff --git a/code/modules/nifsoft/nif.dm b/code/modules/nifsoft/nif.dm index ff392d42a9..9ac7925090 100644 --- a/code/modules/nifsoft/nif.dm +++ b/code/modules/nifsoft/nif.dm @@ -101,6 +101,9 @@ You can also set the stat of a NIF to NIF_TEMPFAIL without any issues to disable //Draw me yo. update_icon() + if(!our_statclick) + our_statclick = new(null, "Open", src) + //Destructor cleans up references /obj/item/device/nif/Destroy() human = null @@ -356,6 +359,8 @@ You can also set the stat of a NIF to NIF_TEMPFAIL without any issues to disable /obj/item/device/nif/proc/notify(var/message,var/alert = 0) if(!human || stat == NIF_TEMPFAIL) return + last_notification = message // TGUI Hook + to_chat(human,"\[[bicon(src.big_icon)]NIF\] displays, \"[message]\"") if(prob(1)) human.visible_message("\The [human] [pick(look_messages)].") if(alert) @@ -379,6 +384,29 @@ You can also set the stat of a NIF to NIF_TEMPFAIL without any issues to disable human.adjust_nutrition(-use_charge) return TRUE +// This operates on a nifsoft *path*, not an instantiation. +// It tells the nifsoft shop if it's installation will succeed, to prevent it +// from charging the user for incompatible software. +/obj/item/device/nif/proc/can_install(var/datum/nifsoft/path) + if(stat == NIF_TEMPFAIL) + return FALSE + + if(nifsofts[initial(path.list_pos)]) + notify("The software \"[initial(path.name)]\" is already installed.", TRUE) + return FALSE + + if(human) + var/applies_to = initial(path.applies_to) + var/synth = human.isSynthetic() + if(synth && !(applies_to & NIF_SYNTHETIC)) + notify("The software \"[initial(path.name)]\" is not supported on your chassis type.",TRUE) + return FALSE + if(!synth && !(applies_to & NIF_ORGANIC)) + notify("The software \"[initial(path.name)]\" is not supported in organic life.",TRUE) + return FALSE + + return TRUE + //Install a piece of software /obj/item/device/nif/proc/install(var/datum/nifsoft/new_soft) if(stat == NIF_TEMPFAIL) return FALSE diff --git a/code/modules/nifsoft/nif_softshop.dm b/code/modules/nifsoft/nif_softshop.dm index d802abde4c..5cfae594c4 100644 --- a/code/modules/nifsoft/nif_softshop.dm +++ b/code/modules/nifsoft/nif_softshop.dm @@ -25,6 +25,10 @@ wires = new /datum/wires/vending/no_contraband(src) //These wires can't be hacked for contraband. entopic = new(aholder = src, aicon = icon, aicon_state = "beacon") +/obj/machinery/vending/nifsoft_shop/tgui_data(mob/user) + . = ..() + .["chargesMoney"] = TRUE + /obj/machinery/vending/nifsoft_shop/Destroy() QDEL_NULL(entopic) return ..() @@ -93,95 +97,39 @@ product_records.Add(product) -/obj/machinery/vending/nifsoft_shop/allowed(mob/user) - if(!ishuman(user)) - return FALSE +/obj/machinery/vending/nifsoft_shop/can_buy(datum/stored_item/vending_product/R, mob/user) + . = ..() + if(.) + var/datum/nifsoft/path = R.item_path + if(!ishuman(user)) + return FALSE + + var/mob/living/carbon/human/H = user + if(!H.nif || !H.nif.stat == NIF_WORKING) + to_chat(H, "[src] seems unable to connect to your NIF...") + return FALSE - var/mob/living/carbon/human/H = user - if(!H.nif || !H.nif.stat == NIF_WORKING) - to_chat(H, "[src] seems unable to connect to your NIF...") - flick("[icon_state]-deny",entopic.my_image) - return FALSE - - return ..() - -//Had to override this too -/obj/machinery/vending/nifsoft_shop/Topic(href, href_list) - if(stat & (BROKEN|NOPOWER)) - return - if(usr.stat || usr.restrained()) - return - - if(href_list["remove_coin"] && !istype(usr,/mob/living/silicon)) - if(!coin) - to_chat(usr, "There is no coin in this machine.") - return - - coin.forceMove(src.loc) - if(!usr.get_active_hand()) - usr.put_in_hands(coin) - to_chat(usr, "You remove \the [coin] from \the [src]") - coin = null - categories &= ~CAT_COIN - - if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)))) - if((href_list["vend"]) && (vend_ready) && (!currently_vending)) - if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH - to_chat(usr, "Access denied.") //Unless emagged of course - flick("[icon_state]-deny",entopic.my_image) - return - - var/key = text2num(href_list["vend"]) - var/datum/stored_item/vending_product/R = product_records[key] - - // This should not happen unless the request from NanoUI was bad - if(!(R.category & categories)) - return - - //Specific soft access checking - var/datum/nifsoft/path = R.item_path - if(initial(path.access)) - var/list/soft_access = list(initial(path.access)) - var/list/usr_access = usr.GetAccess() - if(scan_id && !has_access(soft_access, list(), usr_access) && !emagged) - to_chat(usr, "You aren't authorized to buy [initial(path.name)].") - flick("[icon_state]-deny",entopic.my_image) - return - - if(R.price <= 0) - vend(R, usr) - else if(istype(usr,/mob/living/silicon)) //If the item is not free, provide feedback if a synth is trying to buy something. - to_chat(usr, "Artificial unit recognized. Artificial units cannot complete this transaction. Purchase canceled.") - return - else - currently_vending = R - if(!vendor_account || vendor_account.suspended) - status_message = "This machine is currently unable to process payments due to problems with the associated account." - status_error = 1 - else - status_message = "[initial(path.desc)]

Please swipe a card or insert cash to pay for the item." - status_error = 0 - - else if(href_list["cancelpurchase"]) - currently_vending = null - - else if((href_list["togglevoice"]) && (panel_open)) - shut_up = !shut_up - - add_fingerprint(usr) - SSnanoui.update_uis(src) + if(!H.nif.can_install(path)) + flick("[icon_state]-deny", entopic.my_image) + return FALSE + + if(initial(path.access)) + var/list/soft_access = list(initial(path.access)) + var/list/usr_access = user.GetAccess() + if(scan_id && !has_access(soft_access, list(), usr_access) && !emagged) + to_chat(user, "You aren't authorized to buy [initial(path.name)].") + flick("[icon_state]-deny", entopic.my_image) + return FALSE // Also special treatment! /obj/machinery/vending/nifsoft_shop/vend(datum/stored_item/vending_product/R, mob/user) var/mob/living/carbon/human/H = user - if((!allowed(usr)) && !emagged && scan_id && istype(H)) //For SECURE VENDING MACHINES YEAH - to_chat(usr, "Purchase not allowed.") //Unless emagged of course + if(!can_buy(R, user)) //For SECURE VENDING MACHINES YEAH + to_chat(user, "Purchase not allowed.") //Unless emagged of course flick("[icon_state]-deny",entopic.my_image) return vend_ready = 0 //One thing at a time!! - status_message = "Installing..." - status_error = 0 - SSnanoui.update_uis(src) + SStgui.update_uis(src) if(R.category & CAT_COIN) if(!coin) @@ -209,15 +157,14 @@ spawn(vend_delay) R.amount-- new R.item_path(H.nif) + H.nif.notify("New software installed: [R.item_name]") flick("[icon_state]-vend",entopic.my_image) if(has_logs) do_logging(R, user, 1) - status_message = "" - status_error = 0 vend_ready = 1 currently_vending = null - SSnanoui.update_uis(src) + SStgui.update_uis(src) return 1 //Can't throw intangible software at people. diff --git a/code/modules/nifsoft/nif_statpanel.dm b/code/modules/nifsoft/nif_statpanel.dm index 0cf2307b65..00e928429f 100644 --- a/code/modules/nifsoft/nif_statpanel.dm +++ b/code/modules/nifsoft/nif_statpanel.dm @@ -22,6 +22,7 @@ nif_status = "Unknown - Error" nif_status += " (Condition: [nif_percent]%)" stat("NIF Status", nif_status) + stat("UI", nif.our_statclick) // TGUI Hook if(nif.stat == NIF_WORKING) stat("- Modules -", "LMB: Toggle, Shift+LMB: Info/Uninstall") diff --git a/code/modules/nifsoft/nif_tgui.dm b/code/modules/nifsoft/nif_tgui.dm new file mode 100644 index 0000000000..23d8102f79 --- /dev/null +++ b/code/modules/nifsoft/nif_tgui.dm @@ -0,0 +1,114 @@ +/************************************************************************\ + * This module controls everything to do with the NIF's tgui interface. * +\************************************************************************/ +/** + * Etc variables on the NIF to keep this self contained + */ +/obj/item/device/nif + var/static/list/valid_ui_themes = list( + "abductor", + "cardtable", + "hackerman", + "malfunction", + "ntos", + "paper", + "retro", + "syndicate" + ) + var/tmp/obj/effect/statclick/nif_open/our_statclick + var/tmp/last_notification + +/** + * Special stat button for the interface + */ +/obj/effect/statclick/nif_open +/obj/effect/statclick/nif_open/Click(location, control, params) + var/obj/item/device/nif/N = target + if(istype(N)) + N.tgui_interact(usr) + +/** + * The NIF State ensures that only our authorized implanted user can touch us. + */ +/obj/item/device/nif/tgui_state(mob/user) + return GLOB.tgui_nif_main_state + +/** + * Standard TGUI stub to open the NIF.js template. + */ +/obj/item/device/nif/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "NIF", name) + ui.open() + +/** + * tgui_data gives the UI any relevant data it needs. + * In our case, that's basically everything from our statpanel. + */ +/obj/item/device/nif/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + data["theme"] = save_data["ui_theme"] + data["last_notification"] = last_notification + + // Random biometric information + data["nutrition"] = human.nutrition + data["isSynthetic"] = human.isSynthetic() + + data["nif_percent"] = round((durability/initial(durability))*100) + data["nif_stat"] = stat + + data["modules"] = list() + if(stat == NIF_WORKING) + for(var/nifsoft in nifsofts) + if(!nifsoft) + continue + var/datum/nifsoft/NS = nifsoft + data["modules"].Add(list(list( + "name" = NS.name, + "desc" = NS.desc, + "p_drain" = NS.p_drain, + "a_drain" = NS.a_drain, + "illegal" = NS.illegal, + "wear" = NS.wear, + "cost" = NS.cost, + "activates" = NS.activates, + "active" = NS.active, + "stat_text" = NS.stat_text(), + "ref" = REF(NS), + ))) + + return data + +/** + * tgui_act handles all user input in the UI. + */ +/obj/item/device/nif/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + switch(action) + if("setTheme") + if((params["theme"] in valid_ui_themes) || params["theme"] == null) + save_data["ui_theme"] = params["theme"] + return TRUE + if("toggle_module") + var/datum/nifsoft/NS = locate(params["module"]) in nifsofts + if(!istype(NS)) + return + if(NS.activates) + if(NS.active) + NS.deactivate() + else + NS.activate() + return TRUE + if("uninstall") + var/datum/nifsoft/NS = locate(params["module"]) in nifsofts + if(!istype(NS)) + return + NS.uninstall() + return TRUE + if("dismissNotification") + last_notification = null + return TRUE \ No newline at end of file diff --git a/code/modules/nifsoft/nifsoft.dm b/code/modules/nifsoft/nifsoft.dm index 0df241799f..ca1d0199a6 100644 --- a/code/modules/nifsoft/nifsoft.dm +++ b/code/modules/nifsoft/nifsoft.dm @@ -269,7 +269,8 @@ /obj/item/weapon/storage/box/nifsofts_security name = "security nifsoft uploaders" desc = "A box of free nifsofts for security employees." - icon_state = "disk_kit" + icon = 'icons/obj/storage_vr.dmi' + icon_state = "nifsoft_kit_sec" /obj/item/weapon/storage/box/nifsofts_security/New() ..() @@ -293,7 +294,8 @@ /obj/item/weapon/storage/box/nifsofts_engineering name = "engineering nifsoft uploaders" desc = "A box of free nifsofts for engineering employees." - icon_state = "disk_kit" + icon = 'icons/obj/storage_vr.dmi' + icon_state = "nifsoft_kit_eng" /obj/item/weapon/storage/box/nifsofts_engineering/New() ..() @@ -316,7 +318,8 @@ /obj/item/weapon/storage/box/nifsofts_medical name = "medical nifsoft uploaders" desc = "A box of free nifsofts for medical employees." - icon_state = "disk_kit" + icon = 'icons/obj/storage_vr.dmi' + icon_state = "nifsoft_kit_med" /obj/item/weapon/storage/box/nifsofts_medical/New() ..() @@ -340,7 +343,8 @@ /obj/item/weapon/storage/box/nifsofts_mining name = "mining nifsoft uploaders" desc = "A box of free nifsofts for mining employees." - icon_state = "disk_kit" + icon = 'icons/obj/storage_vr.dmi' + icon_state = "nifsoft_kit_mining" /obj/item/weapon/storage/box/nifsofts_mining/New() ..() diff --git a/code/modules/nifsoft/software/01_vision.dm b/code/modules/nifsoft/software/01_vision.dm index 7c7ca02079..7a792009f4 100644 --- a/code/modules/nifsoft/software/01_vision.dm +++ b/code/modules/nifsoft/software/01_vision.dm @@ -106,12 +106,12 @@ vision_flags = (NIF_V_MESONS) incompatible_with = list(NIF_MATERIAL,NIF_THERMALS,NIF_NIGHTVIS) - life() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - H.sight |= SEE_TURFS - if(H.client) - H.client.screen |= global_hud.meson +/datum/nifsoft/mesons/life() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + H.sight |= SEE_TURFS + if(H.client) + H.client.screen |= global_hud.meson /datum/nifsoft/material name = "Material Scanner" @@ -125,12 +125,12 @@ vision_flags = (NIF_V_MATERIAL) incompatible_with = list(NIF_MESONS,NIF_THERMALS,NIF_NIGHTVIS) - life() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - H.sight |= SEE_OBJS - if(H.client) - H.client.screen |= global_hud.material +/datum/nifsoft/material/life() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + H.sight |= SEE_OBJS + if(H.client) + H.client.screen |= global_hud.material /datum/nifsoft/thermals name = "Thermal Scanner" @@ -145,12 +145,12 @@ vision_flags = (NIF_V_THERMALS) incompatible_with = list(NIF_MESONS,NIF_MATERIAL,NIF_NIGHTVIS) - life() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - H.sight |= SEE_MOBS - if(H.client) - H.client.screen |= global_hud.thermal +/datum/nifsoft/thermals/life() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + H.sight |= SEE_MOBS + if(H.client) + H.client.screen |= global_hud.thermal /datum/nifsoft/nightvis name = "Low-Light Amp" @@ -164,9 +164,9 @@ vision_flags = (NIF_V_NIGHTVIS) incompatible_with = list(NIF_MESONS,NIF_MATERIAL,NIF_THERMALS) - life() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - H.see_in_dark += 7 - if(H.client) - H.client.screen |= global_hud.nvg +/datum/nifsoft/nightvis/life() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + H.see_in_dark += 7 + if(H.client) + H.client.screen |= global_hud.nvg diff --git a/code/modules/nifsoft/software/05_health.dm b/code/modules/nifsoft/software/05_health.dm index 8ea4ef90c5..dfab36df3e 100644 --- a/code/modules/nifsoft/software/05_health.dm +++ b/code/modules/nifsoft/software/05_health.dm @@ -13,63 +13,63 @@ health_flags = (NIF_H_ORGREPAIR) //These self-activate on their own, these aren't user-settable to on/off. - activate() - if((. = ..())) - mode = 1 +/datum/nifsoft/medichines_org/activate() + if((. = ..())) + mode = 1 - deactivate() - if((. = ..())) - a_drain = initial(a_drain) - mode = initial(mode) - nif.human.Stasis(0) +/datum/nifsoft/medichines_org/deactivate() + if((. = ..())) + a_drain = initial(a_drain) + mode = initial(mode) + nif.human.Stasis(0) - life() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - var/HP_percent = H.health/H.getMaxHealth() +/datum/nifsoft/medichines_org/life() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + var/HP_percent = H.health/H.getMaxHealth() - //Mode changing state machine - if(HP_percent >= 0.9) - if(mode) - nif.notify("User Status: NORMAL. Medichines deactivating.") - deactivate() - return TRUE - else if(!mode && HP_percent < 0.8) - nif.notify("User Status: INJURED. Commencing medichine routines.",TRUE) - activate() - else if(mode == 1 && HP_percent < 0.2) - nif.notify("User Status: DANGER. Seek medical attention!",TRUE) - mode = 2 - else if(mode == 2 && HP_percent < -0.4) - nif.notify("User Status: CRITICAL. Notifying medical, and starting emergency stasis!",TRUE) - mode = 3 - if(!isbelly(H.loc)) //Not notified in case of vore, for gameplay purposes. - var/turf/T = get_turf(H) - var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset/heads/captain(null) - a.autosay("[H.real_name] has been put in emergency stasis, located at ([T.x],[T.y],[T.z])!", "[H.real_name]'s NIF", "Medical") - qdel(a) - - //Handle the actions in each mode - - //Injured but not critical + //Mode changing state machine + if(HP_percent >= 0.9) if(mode) - H.adjustToxLoss(-0.1 * mode) - H.adjustBruteLoss(-0.1 * mode) - H.adjustFireLoss(-0.1 * mode) - - if(mode >= 2) - nif.use_charge(a_drain) //A second drain if we're in level 2+ - - //Patient critical - emergency stasis - if(mode >= 3) - if(HP_percent <= 0) - H.Stasis(3) - if(HP_percent > 0.2) - H.Stasis(0) - nif.notify("Ending emergency stasis.",TRUE) - mode = 2 - + nif.notify("User Status: NORMAL. Medichines deactivating.") + deactivate() return TRUE + else if(!mode && HP_percent < 0.8) + nif.notify("User Status: INJURED. Commencing medichine routines.",TRUE) + activate() + else if(mode == 1 && HP_percent < 0.2) + nif.notify("User Status: DANGER. Seek medical attention!",TRUE) + mode = 2 + else if(mode == 2 && HP_percent < -0.4) + nif.notify("User Status: CRITICAL. Notifying medical, and starting emergency stasis!",TRUE) + mode = 3 + if(!isbelly(H.loc)) //Not notified in case of vore, for gameplay purposes. + var/turf/T = get_turf(H) + var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset/heads/captain(null) + a.autosay("[H.real_name] has been put in emergency stasis, located at ([T.x],[T.y],[T.z])!", "[H.real_name]'s NIF", "Medical") + qdel(a) + + //Handle the actions in each mode + + //Injured but not critical + if(mode) + H.adjustToxLoss(-0.1 * mode) + H.adjustBruteLoss(-0.1 * mode) + H.adjustFireLoss(-0.1 * mode) + + if(mode >= 2) + nif.use_charge(a_drain) //A second drain if we're in level 2+ + + //Patient critical - emergency stasis + if(mode >= 3) + if(HP_percent <= 0) + H.Stasis(3) + if(HP_percent > 0.2) + H.Stasis(0) + nif.notify("Ending emergency stasis.",TRUE) + mode = 2 + + return TRUE /datum/nifsoft/medichines_syn name = "Medichines" @@ -86,44 +86,44 @@ health_flags = (NIF_H_SYNTHREPAIR) //These self-activate on their own, these aren't user-settable to on/off. - activate() - if((. = ..())) - mode = 1 +/datum/nifsoft/medichines_syn/activate() + if((. = ..())) + mode = 1 - deactivate() - if((. = ..())) - mode = 0 - - life() - if((. = ..())) - //We're good! - if(!nif.human.bad_external_organs.len) - if(mode || active) - nif.notify("User Status: NORMAL. Medichines deactivating.") - deactivate() - return TRUE - - if(!mode && !active) - nif.notify("User Status: DAMAGED. Medichines performing minor repairs.",TRUE) - activate() - - for(var/eo in nif.human.bad_external_organs) - var/obj/item/organ/external/EO = eo - for(var/w in EO.wounds) - var/datum/wound/W = w - if(W.damage <= 5) - W.heal_damage(0.1) - EO.update_damages() - if(EO.update_icon()) - nif.human.UpdateDamageIcon(1) - nif.use_charge(0.1) - return TRUE //Return entirely, we only heal one at a time. - else if(mode == 1) - mode = 2 - nif.notify("Medichines unable to repair all damage. Perform manual repairs.",TRUE) +/datum/nifsoft/medichines_syn/deactivate() + if((. = ..())) + mode = 0 +/datum/nifsoft/medichines_syn/life() + if((. = ..())) + //We're good! + if(!nif.human.bad_external_organs.len) + if(mode || active) + nif.notify("User Status: NORMAL. Medichines deactivating.") + deactivate() return TRUE + if(!mode && !active) + nif.notify("User Status: DAMAGED. Medichines performing minor repairs.",TRUE) + activate() + + for(var/eo in nif.human.bad_external_organs) + var/obj/item/organ/external/EO = eo + for(var/w in EO.wounds) + var/datum/wound/W = w + if(W.damage <= 5) + W.heal_damage(0.1) + EO.update_damages() + if(EO.update_icon()) + nif.human.UpdateDamageIcon(1) + nif.use_charge(0.1) + return TRUE //Return entirely, we only heal one at a time. + else if(mode == 1) + mode = 2 + nif.notify("Medichines unable to repair all damage. Perform manual repairs.",TRUE) + + return TRUE + /datum/nifsoft/spare_breath name = "Respirocytes" desc = "Nanites simulating red blood cells will filter and recycle oxygen for a short time, preventing suffocation in hostile environments. NOTE: Only capable of supplying OXYGEN." @@ -137,47 +137,47 @@ var/filled = 100 //Tracks the internal tank 'refilling', which still uses power health_flags = (NIF_H_SPAREBREATH) - activate() - if(!(filled > 50)) - nif.notify("Respirocytes not saturated!",TRUE) - return FALSE - if((. = ..())) - nif.notify("Now taking air from reserves.") +/datum/nifsoft/spare_breath/activate() + if(!(filled > 50)) + nif.notify("Respirocytes not saturated!",TRUE) + return FALSE + if((. = ..())) + nif.notify("Now taking air from reserves.") - deactivate() - if((. = ..())) - nif.notify("Now taking air from environment and refilling reserves.") +/datum/nifsoft/spare_breath/deactivate() + if((. = ..())) + nif.notify("Now taking air from environment and refilling reserves.") - life() - if((. = ..())) - if(active) //Supplying air, not recharging it - switch(filled) //Text warnings - if(75) - nif.notify("Respirocytes at 75% saturation.",TRUE) - if(50) - nif.notify("Respirocytes at 50% saturation!",TRUE) - if(25) - nif.notify("Respirocytes at 25% saturation, seek a habitable environment!",TRUE) - if(5) - nif.notify("Respirocytes at 5% saturation! Failure imminent!",TRUE) +/datum/nifsoft/spare_breath/life() + if((. = ..())) + if(active) //Supplying air, not recharging it + switch(filled) //Text warnings + if(75) + nif.notify("Respirocytes at 75% saturation.",TRUE) + if(50) + nif.notify("Respirocytes at 50% saturation!",TRUE) + if(25) + nif.notify("Respirocytes at 25% saturation, seek a habitable environment!",TRUE) + if(5) + nif.notify("Respirocytes at 5% saturation! Failure imminent!",TRUE) - if(filled == 0) //Ran out - deactivate() - else //Drain a little - filled-- + if(filled == 0) //Ran out + deactivate() + else //Drain a little + filled-- - else //Recharging air, not supplying it - if(filled == 100) - return TRUE - else if(nif.use_charge(0.1) && ++filled == 100) - nif.notify("Respirocytes now fully saturated.") + else //Recharging air, not supplying it + if(filled == 100) + return TRUE + else if(nif.use_charge(0.1) && ++filled == 100) + nif.notify("Respirocytes now fully saturated.") - proc/resp_breath() - if(!active) return null - var/datum/gas_mixture/breath = new(BREATH_VOLUME) - breath.adjust_gas("oxygen", BREATH_MOLES) - breath.temperature = T20C - return breath +/datum/nifsoft/spare_breath/proc/resp_breath() + if(!active) return null + var/datum/gas_mixture/breath = new(BREATH_VOLUME) + breath.adjust_gas("oxygen", BREATH_MOLES) + breath.temperature = T20C + return breath /datum/nifsoft/mindbackup name = "Mind Backup" @@ -185,19 +185,19 @@ list_pos = NIF_BACKUP cost = 125 - activate() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - SStranscore.m_backup(H.mind,H.nif,one_time = TRUE) - persist_nif_data(H) - nif.notify("Mind backed up!") - nif.use_charge(0.1) - deactivate() - return TRUE +/datum/nifsoft/mindbackup/activate() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + SStranscore.m_backup(H.mind,H.nif,one_time = TRUE) + persist_nif_data(H) + nif.notify("Mind backed up!") + nif.use_charge(0.1) + deactivate() + return TRUE - deactivate() - if((. = ..())) - return TRUE +/datum/nifsoft/mindbackup/deactivate() + if((. = ..())) + return TRUE - stat_text() - return "Store Backup" +/datum/nifsoft/mindbackup/stat_text() + return "Store Backup" diff --git a/code/modules/nifsoft/software/06_screens.dm b/code/modules/nifsoft/software/06_screens.dm index 8dadc88192..253ed17c8d 100644 --- a/code/modules/nifsoft/software/06_screens.dm +++ b/code/modules/nifsoft/software/06_screens.dm @@ -7,25 +7,25 @@ p_drain = 0.025 var/datum/tgui_module/crew_monitor/nif/arscreen - New() - ..() - arscreen = new(nif) +/datum/nifsoft/crewmonitor/New() + ..() + arscreen = new(nif) - Destroy() - QDEL_NULL(arscreen) - return ..() +/datum/nifsoft/crewmonitor/Destroy() + QDEL_NULL(arscreen) + return ..() - activate() - if((. = ..())) - arscreen.tgui_interact(nif.human) - return TRUE +/datum/nifsoft/crewmonitor/activate() + if((. = ..())) + arscreen.tgui_interact(nif.human) + return TRUE - deactivate() - if((. = ..())) - return TRUE +/datum/nifsoft/crewmonitor/deactivate() + if((. = ..())) + return TRUE - stat_text() - return "Show Monitor" +/datum/nifsoft/crewmonitor/stat_text() + return "Show Monitor" /datum/nifsoft/alarmmonitor name = "Alarm Monitor" @@ -36,22 +36,22 @@ p_drain = 0.025 var/datum/tgui_module/alarm_monitor/engineering/nif/tgarscreen - New() - ..() - tgarscreen = new(nif) +/datum/nifsoft/alarmmonitor/New() + ..() + tgarscreen = new(nif) - Destroy() - QDEL_NULL(tgarscreen) - return ..() +/datum/nifsoft/alarmmonitor/Destroy() + QDEL_NULL(tgarscreen) + return ..() - activate() - if((. = ..())) - tgarscreen.tgui_interact(nif.human) - return TRUE +/datum/nifsoft/alarmmonitor/activate() + if((. = ..())) + tgarscreen.tgui_interact(nif.human) + return TRUE - deactivate() - if((. = ..())) - return TRUE +/datum/nifsoft/alarmmonitor/deactivate() + if((. = ..())) + return TRUE - stat_text() - return "Show Monitor" +/datum/nifsoft/alarmmonitor/stat_text() + return "Show Monitor" diff --git a/code/modules/nifsoft/software/10_combat.dm b/code/modules/nifsoft/software/10_combat.dm index a4af60ae6e..a63e323792 100644 --- a/code/modules/nifsoft/software/10_combat.dm +++ b/code/modules/nifsoft/software/10_combat.dm @@ -34,10 +34,10 @@ tick_flags = NIF_ACTIVETICK combat_flags = (NIF_C_PAINKILLERS) - life() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - H.bloodstr.add_reagent("numbenzyme",0.5) +/datum/nifsoft/painkillers/life() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + H.bloodstr.add_reagent("numbenzyme",0.5) /datum/nifsoft/hardclaws name = "Bloodletters" @@ -74,25 +74,25 @@ var/global/datum/unarmed_attack/hardclaws/unarmed_hardclaws = new() var/used = FALSE combat_flags = (NIF_C_HIDELASER) - activate() - if((. = ..())) - if(used) - nif.notify("You do not have a hidden weapon to deploy anymore!",TRUE) - deactivate() - return FALSE - if(!nif.use_charge(50)) - nif.notify("Insufficient energy to deploy weapon!",TRUE) - deactivate() - return FALSE +/datum/nifsoft/hidelaser/activate() + if((. = ..())) + if(used) + nif.notify("You do not have a hidden weapon to deploy anymore!",TRUE) + deactivate() + return FALSE + if(!nif.use_charge(50)) + nif.notify("Insufficient energy to deploy weapon!",TRUE) + deactivate() + return FALSE - var/mob/living/carbon/human/H = nif.human - H.adjustHalLoss(30) - var/obj/item/weapon/gun/energy/gun/martin/dazzle/dgun = new(get_turf(H)) - H.put_in_hands(dgun) - nif.notify("Weapon deployed!",TRUE) - used = TRUE - spawn(0) - uninstall() + var/mob/living/carbon/human/H = nif.human + H.adjustHalLoss(30) + var/obj/item/weapon/gun/energy/gun/martin/dazzle/dgun = new(get_turf(H)) + H.put_in_hands(dgun) + nif.notify("Weapon deployed!",TRUE) + used = TRUE + spawn(0) + uninstall() //The gun to go with this implant /obj/item/weapon/gun/energy/gun/martin/dazzle diff --git a/code/modules/nifsoft/software/13_soulcatcher.dm b/code/modules/nifsoft/software/13_soulcatcher.dm index 4cc7210bd4..c1de085532 100644 --- a/code/modules/nifsoft/software/13_soulcatcher.dm +++ b/code/modules/nifsoft/software/13_soulcatcher.dm @@ -21,243 +21,243 @@ var/list/brainmobs = list() var/inside_flavor = "A small completely white room with a couch, and a window to what seems to be the outside world. A small sign in the corner says 'Configure Me'." - New() - ..() - load_settings() +/datum/nifsoft/soulcatcher/New() + ..() + load_settings() - Destroy() - QDEL_LIST_NULL(brainmobs) - return ..() +/datum/nifsoft/soulcatcher/Destroy() + QDEL_LIST_NULL(brainmobs) + return ..() - activate() - if((. = ..())) - show_settings(nif.human) - spawn(0) - deactivate() +/datum/nifsoft/soulcatcher/activate() + if((. = ..())) + show_settings(nif.human) + spawn(0) + deactivate() - deactivate() - if((. = ..())) - return TRUE - - stat_text() - return "Change Settings ([brainmobs.len] minds)" - - install() - if((. = ..())) - nif.set_flag(NIF_O_SCOTHERS,NIF_FLAGS_OTHER) //Required on install, because other_flags aren't sufficient for our complicated settings. - nif.human.verbs |= /mob/living/carbon/human/proc/nsay - nif.human.verbs |= /mob/living/carbon/human/proc/nme - - uninstall() - QDEL_LIST_NULL(brainmobs) - if((. = ..()) && nif && nif.human) //Sometimes NIFs are deleted outside of a human - nif.human.verbs -= /mob/living/carbon/human/proc/nsay - nif.human.verbs -= /mob/living/carbon/human/proc/nme - - proc/save_settings() - if(!nif) - return - nif.save_data["[list_pos]"] = inside_flavor +/datum/nifsoft/soulcatcher/deactivate() + if((. = ..())) return TRUE - proc/load_settings() - if(!nif) - return - var/load = nif.save_data["[list_pos]"] - if(load) - inside_flavor = load - return TRUE +/datum/nifsoft/soulcatcher/stat_text() + return "Change Settings ([brainmobs.len] minds)" - proc/notify_into(var/message) - var/sound = nif.good_sound +/datum/nifsoft/soulcatcher/install() + if((. = ..())) + nif.set_flag(NIF_O_SCOTHERS,NIF_FLAGS_OTHER) //Required on install, because other_flags aren't sufficient for our complicated settings. + nif.human.verbs |= /mob/living/carbon/human/proc/nsay + nif.human.verbs |= /mob/living/carbon/human/proc/nme - to_chat(nif.human,"\[[bicon(nif.big_icon)]NIF\] Soulcatcher displays, \"[message]\"") - nif.human << sound +/datum/nifsoft/soulcatcher/uninstall() + QDEL_LIST_NULL(brainmobs) + if((. = ..()) && nif && nif.human) //Sometimes NIFs are deleted outside of a human + nif.human.verbs -= /mob/living/carbon/human/proc/nsay + nif.human.verbs -= /mob/living/carbon/human/proc/nme +/datum/nifsoft/soulcatcher/proc/save_settings() + if(!nif) + return + nif.save_data["[list_pos]"] = inside_flavor + return TRUE + +/datum/nifsoft/soulcatcher/proc/load_settings() + if(!nif) + return + var/load = nif.save_data["[list_pos]"] + if(load) + inside_flavor = load + return TRUE + +/datum/nifsoft/soulcatcher/proc/notify_into(var/message) + var/sound = nif.good_sound + + to_chat(nif.human,"\[[bicon(nif.big_icon)]NIF\] Soulcatcher displays, \"[message]\"") + nif.human << sound + + for(var/brainmob in brainmobs) + var/mob/living/carbon/brain/caught_soul/CS = brainmob + to_chat(CS,"\[[bicon(nif.big_icon)]NIF\] Soulcatcher displays, \"[message]\"") + brainmob << sound + +/datum/nifsoft/soulcatcher/proc/say_into(var/message, var/mob/living/sender, var/mob/eyeobj) + var/sender_name = eyeobj ? eyeobj.name : sender.name + + //AR Projecting + if(eyeobj) + sender.eyeobj.visible_message("[sender_name] says, \"[message]\"") + + //Not AR Projecting + else + to_chat(nif.human,"\[[bicon(nif.big_icon)]NIF\] [sender_name] speaks, \"[message]\"") for(var/brainmob in brainmobs) var/mob/living/carbon/brain/caught_soul/CS = brainmob - to_chat(CS,"\[[bicon(nif.big_icon)]NIF\] Soulcatcher displays, \"[message]\"") - brainmob << sound + to_chat(CS,"\[[bicon(nif.big_icon)]NIF\] [sender_name] speaks, \"[message]\"") - proc/say_into(var/message, var/mob/living/sender, var/mob/eyeobj) - var/sender_name = eyeobj ? eyeobj.name : sender.name + log_nsay(message,nif.human.real_name,sender) - //AR Projecting - if(eyeobj) - sender.eyeobj.visible_message("[sender_name] says, \"[message]\"") +/datum/nifsoft/soulcatcher/proc/emote_into(var/message, var/mob/living/sender, var/mob/eyeobj) + var/sender_name = eyeobj ? eyeobj.name : sender.name - //Not AR Projecting - else - to_chat(nif.human,"\[[bicon(nif.big_icon)]NIF\] [sender_name] speaks, \"[message]\"") - for(var/brainmob in brainmobs) - var/mob/living/carbon/brain/caught_soul/CS = brainmob - to_chat(CS,"\[[bicon(nif.big_icon)]NIF\] [sender_name] speaks, \"[message]\"") + //AR Projecting + if(eyeobj) + sender.eyeobj.visible_message("[sender_name] [message]") - log_nsay(message,nif.human.real_name,sender) + //Not AR Projecting + else + to_chat(nif.human,"\[[bicon(nif.big_icon)]NIF\] [sender_name] [message]") + for(var/brainmob in brainmobs) + var/mob/living/carbon/brain/caught_soul/CS = brainmob + to_chat(CS,"\[[bicon(nif.big_icon)]NIF\] [sender_name] [message]") - proc/emote_into(var/message, var/mob/living/sender, var/mob/eyeobj) - var/sender_name = eyeobj ? eyeobj.name : sender.name + log_nme(message,nif.human.real_name,sender) - //AR Projecting - if(eyeobj) - sender.eyeobj.visible_message("[sender_name] [message]") +/datum/nifsoft/soulcatcher/proc/show_settings(var/mob/living/carbon/human/H) + set waitfor = FALSE + var/settings_list = list( + "Catching You \[[setting_flags & NIF_SC_CATCHING_ME ? "Enabled" : "Disabled"]\]" = NIF_SC_CATCHING_ME, + "Catching Prey \[[setting_flags & NIF_SC_CATCHING_OTHERS ? "Enabled" : "Disabled"]\]" = NIF_SC_CATCHING_OTHERS, + "Ext. Hearing \[[setting_flags & NIF_SC_ALLOW_EARS ? "Enabled" : "Disabled"]\]" = NIF_SC_ALLOW_EARS, + "Ext. Vision \[[setting_flags & NIF_SC_ALLOW_EYES ? "Enabled" : "Disabled"]\]" = NIF_SC_ALLOW_EYES, + "Mind Backups \[[setting_flags & NIF_SC_BACKUPS ? "Enabled" : "Disabled"]\]" = NIF_SC_BACKUPS, + "AR Projecting \[[setting_flags & NIF_SC_PROJECTING ? "Enabled" : "Disabled"]\]" = NIF_SC_PROJECTING, + "Design Inside", + "Erase Contents") + var/choice = input(nif.human,"Select a setting to modify:","Soulcatcher NIFSoft") as null|anything in settings_list + if(choice in settings_list) + switch(choice) - //Not AR Projecting - else - to_chat(nif.human,"\[[bicon(nif.big_icon)]NIF\] [sender_name] [message]") - for(var/brainmob in brainmobs) - var/mob/living/carbon/brain/caught_soul/CS = brainmob - to_chat(CS,"\[[bicon(nif.big_icon)]NIF\] [sender_name] [message]") + if("Design Inside") + var/new_flavor = input(nif.human, "Type what the prey sees after being 'caught'. This will be \ + printed after an intro ending with: \"Around you, you see...\" to the prey. If you already \ + have prey, this will be printed to them after \"Your surroundings change to...\". Limit 2048 char.", \ + "VR Environment", html_decode(inside_flavor)) as message + new_flavor = sanitize(new_flavor, MAX_MESSAGE_LEN*2) + inside_flavor = new_flavor + nif.notify("Updating VR environment...") + for(var/brain in brainmobs) + var/mob/living/carbon/brain/caught_soul/CS = brain + to_chat(CS,"Your surroundings change to...\n[inside_flavor]") + save_settings() + return TRUE - log_nme(message,nif.human.real_name,sender) + if("Erase Contents") + var/mob/living/carbon/brain/caught_soul/brainpick = input(nif.human,"Select a mind to delete:","Erase Mind") as null|anything in brainmobs - proc/show_settings(var/mob/living/carbon/human/H) - set waitfor = FALSE - var/settings_list = list( - "Catching You \[[setting_flags & NIF_SC_CATCHING_ME ? "Enabled" : "Disabled"]\]" = NIF_SC_CATCHING_ME, - "Catching Prey \[[setting_flags & NIF_SC_CATCHING_OTHERS ? "Enabled" : "Disabled"]\]" = NIF_SC_CATCHING_OTHERS, - "Ext. Hearing \[[setting_flags & NIF_SC_ALLOW_EARS ? "Enabled" : "Disabled"]\]" = NIF_SC_ALLOW_EARS, - "Ext. Vision \[[setting_flags & NIF_SC_ALLOW_EYES ? "Enabled" : "Disabled"]\]" = NIF_SC_ALLOW_EYES, - "Mind Backups \[[setting_flags & NIF_SC_BACKUPS ? "Enabled" : "Disabled"]\]" = NIF_SC_BACKUPS, - "AR Projecting \[[setting_flags & NIF_SC_PROJECTING ? "Enabled" : "Disabled"]\]" = NIF_SC_PROJECTING, - "Design Inside", - "Erase Contents") - var/choice = input(nif.human,"Select a setting to modify:","Soulcatcher NIFSoft") as null|anything in settings_list - if(choice in settings_list) - switch(choice) + var/warning = alert(nif.human,"Are you SURE you want to erase \"[brainpick]\"?","Erase Mind","CANCEL","DELETE","CANCEL") + if(warning == "DELETE") + brainmobs -= brainpick + qdel(brainpick) + return TRUE - if("Design Inside") - var/new_flavor = input(nif.human, "Type what the prey sees after being 'caught'. This will be \ - printed after an intro ending with: \"Around you, you see...\" to the prey. If you already \ - have prey, this will be printed to them after \"Your surroundings change to...\". Limit 2048 char.", \ - "VR Environment", html_decode(inside_flavor)) as message - new_flavor = sanitize(new_flavor, MAX_MESSAGE_LEN*2) - inside_flavor = new_flavor - nif.notify("Updating VR environment...") - for(var/brain in brainmobs) - var/mob/living/carbon/brain/caught_soul/CS = brain - to_chat(CS,"Your surroundings change to...\n[inside_flavor]") - save_settings() - return TRUE + //Must just be a flag without special handling then. + else + var/flag = settings_list[choice] + return toggle_setting(flag) - if("Erase Contents") - var/mob/living/carbon/brain/caught_soul/brainpick = input(nif.human,"Select a mind to delete:","Erase Mind") as null|anything in brainmobs +/datum/nifsoft/soulcatcher/proc/toggle_setting(var/flag) + setting_flags ^= flag - var/warning = alert(nif.human,"Are you SURE you want to erase \"[brainpick]\"?","Erase Mind","CANCEL","DELETE","CANCEL") - if(warning == "DELETE") - brainmobs -= brainpick - qdel(brainpick) - return TRUE + var/notify_message + //Special treatment + switch(flag) + if(NIF_SC_BACKUPS) + if(setting_flags & NIF_SC_BACKUPS) + notify_message = "Mind backup system enabled." + else + notify_message = "Mind backup system disabled." - //Must just be a flag without special handling then. - else - var/flag = settings_list[choice] - return toggle_setting(flag) + if(NIF_SC_CATCHING_ME) + if(setting_flags & NIF_SC_CATCHING_ME) + nif.set_flag(NIF_O_SCMYSELF,NIF_FLAGS_OTHER) + else + nif.clear_flag(NIF_O_SCMYSELF,NIF_FLAGS_OTHER) + if(NIF_SC_CATCHING_OTHERS) + if(setting_flags & NIF_SC_CATCHING_OTHERS) + nif.set_flag(NIF_O_SCOTHERS,NIF_FLAGS_OTHER) + else + nif.clear_flag(NIF_O_SCOTHERS,NIF_FLAGS_OTHER) + if(NIF_SC_ALLOW_EARS) + if(setting_flags & NIF_SC_ALLOW_EARS) + for(var/brain in brainmobs) + var/mob/living/carbon/brain/caught_soul/brainmob = brain + brainmob.ext_deaf = FALSE + notify_message = "External audio input enabled." + else + for(var/brain in brainmobs) + var/mob/living/carbon/brain/caught_soul/brainmob = brain + brainmob.ext_deaf = TRUE + notify_message = "External audio input disabled." + if(NIF_SC_ALLOW_EYES) + if(setting_flags & NIF_SC_ALLOW_EYES) + for(var/brain in brainmobs) + var/mob/living/carbon/brain/caught_soul/brainmob = brain + brainmob.ext_blind = FALSE + notify_message = "External video input enabled." + else + for(var/brain in brainmobs) + var/mob/living/carbon/brain/caught_soul/brainmob = brain + brainmob.ext_blind = TRUE + notify_message = "External video input disabled." - proc/toggle_setting(var/flag) - setting_flags ^= flag + if(notify_message) + notify_into(notify_message) - var/notify_message - //Special treatment - switch(flag) - if(NIF_SC_BACKUPS) - if(setting_flags & NIF_SC_BACKUPS) - notify_message = "Mind backup system enabled." - else - notify_message = "Mind backup system disabled." + return TRUE - if(NIF_SC_CATCHING_ME) - if(setting_flags & NIF_SC_CATCHING_ME) - nif.set_flag(NIF_O_SCMYSELF,NIF_FLAGS_OTHER) - else - nif.clear_flag(NIF_O_SCMYSELF,NIF_FLAGS_OTHER) - if(NIF_SC_CATCHING_OTHERS) - if(setting_flags & NIF_SC_CATCHING_OTHERS) - nif.set_flag(NIF_O_SCOTHERS,NIF_FLAGS_OTHER) - else - nif.clear_flag(NIF_O_SCOTHERS,NIF_FLAGS_OTHER) - if(NIF_SC_ALLOW_EARS) - if(setting_flags & NIF_SC_ALLOW_EARS) - for(var/brain in brainmobs) - var/mob/living/carbon/brain/caught_soul/brainmob = brain - brainmob.ext_deaf = FALSE - notify_message = "External audio input enabled." - else - for(var/brain in brainmobs) - var/mob/living/carbon/brain/caught_soul/brainmob = brain - brainmob.ext_deaf = TRUE - notify_message = "External audio input disabled." - if(NIF_SC_ALLOW_EYES) - if(setting_flags & NIF_SC_ALLOW_EYES) - for(var/brain in brainmobs) - var/mob/living/carbon/brain/caught_soul/brainmob = brain - brainmob.ext_blind = FALSE - notify_message = "External video input enabled." - else - for(var/brain in brainmobs) - var/mob/living/carbon/brain/caught_soul/brainmob = brain - brainmob.ext_blind = TRUE - notify_message = "External video input disabled." +//Complex version for catching in-round characters +/datum/nifsoft/soulcatcher/proc/catch_mob(var/mob/M) + if(!M.mind) return - if(notify_message) - notify_into(notify_message) + //Create a new brain mob + var/mob/living/carbon/brain/caught_soul/brainmob = new(nif) + brainmob.nif = nif + brainmob.soulcatcher = src + brainmob.container = src + brainmob.stat = 0 + brainmob.silent = FALSE + dead_mob_list -= brainmob + brainmob.add_language(LANGUAGE_GALCOM) + brainmobs |= brainmob - return TRUE + //Put the mind and player into the mob + M.mind.transfer_to(brainmob) + brainmob.name = brainmob.mind.name + brainmob.real_name = brainmob.mind.name - //Complex version for catching in-round characters - proc/catch_mob(var/mob/M) - if(!M.mind) return + //If we caught our owner, special settings. + if(M == nif.human) + brainmob.ext_deaf = FALSE + brainmob.ext_blind = FALSE + brainmob.parent_mob = TRUE - //Create a new brain mob - var/mob/living/carbon/brain/caught_soul/brainmob = new(nif) - brainmob.nif = nif - brainmob.soulcatcher = src - brainmob.container = src - brainmob.stat = 0 - brainmob.silent = FALSE - dead_mob_list -= brainmob - brainmob.add_language(LANGUAGE_GALCOM) - brainmobs |= brainmob + //If they have these values, apply them + if(ishuman(M)) + var/mob/living/carbon/human/H = M + brainmob.dna = H.dna + brainmob.ooc_notes = H.ooc_notes + brainmob.timeofhostdeath = H.timeofdeath + SStranscore.m_backup(brainmob.mind,0) //It does ONE, so medical will hear about it. - //Put the mind and player into the mob - M.mind.transfer_to(brainmob) - brainmob.name = brainmob.mind.name - brainmob.real_name = brainmob.mind.name + //Else maybe they're a joining ghost + else if(isobserver(M)) + brainmob.transient = TRUE + qdel(M) //Bye ghost - //If we caught our owner, special settings. - if(M == nif.human) - brainmob.ext_deaf = FALSE - brainmob.ext_blind = FALSE - brainmob.parent_mob = TRUE + //Give them a flavortext message + var/message = "Your vision fades in a haze of static, before returning.\n\ + Around you, you see...\n\ + [inside_flavor]" - //If they have these values, apply them - if(ishuman(M)) - var/mob/living/carbon/human/H = M - brainmob.dna = H.dna - brainmob.ooc_notes = H.ooc_notes - brainmob.timeofhostdeath = H.timeofdeath - SStranscore.m_backup(brainmob.mind,0) //It does ONE, so medical will hear about it. + to_chat(brainmob,message) - //Else maybe they're a joining ghost - else if(isobserver(M)) - brainmob.transient = TRUE - qdel(M) //Bye ghost + //Reminder on how this works to host + if(brainmobs.len == 1) //Only spam this on the first one + to_chat(nif.human,"Your occupant's messages/actions can only be seen by you, and you can \ + send messages that only they can hear/see by using the NSay and NMe verbs (or the *nsay and *nme emotes).") - //Give them a flavortext message - var/message = "Your vision fades in a haze of static, before returning.\n\ - Around you, you see...\n\ - [inside_flavor]" - - to_chat(brainmob,message) - - //Reminder on how this works to host - if(brainmobs.len == 1) //Only spam this on the first one - to_chat(nif.human,"Your occupant's messages/actions can only be seen by you, and you can \ - send messages that only they can hear/see by using the NSay and NMe verbs (or the *nsay and *nme emotes).") - - //Announce to host and other minds - notify_into("New mind loaded: [brainmob.name]") - return TRUE + //Announce to host and other minds + notify_into("New mind loaded: [brainmob.name]") + return TRUE //////////////// //The caught mob diff --git a/code/modules/nifsoft/software/14_commlink.dm b/code/modules/nifsoft/software/14_commlink.dm index f156e3ffb5..26539f20f2 100644 --- a/code/modules/nifsoft/software/14_commlink.dm +++ b/code/modules/nifsoft/software/14_commlink.dm @@ -9,24 +9,24 @@ p_drain = 0.01 other_flags = (NIF_O_COMMLINK) - install() - if((. = ..())) - nif.comm = new(nif,src) +/datum/nifsoft/commlink/install() + if((. = ..())) + nif.comm = new(nif,src) - uninstall() - var/obj/item/device/nif/lnif = nif //Awkward. Parent clears it in an attempt to clean up. - if((. = ..()) && lnif) - QDEL_NULL(lnif.comm) +/datum/nifsoft/commlink/uninstall() + var/obj/item/device/nif/lnif = nif //Awkward. Parent clears it in an attempt to clean up. + if((. = ..()) && lnif) + QDEL_NULL(lnif.comm) - activate() - if((. = ..())) - nif.comm.initialize_exonet(nif.human) - nif.comm.ui_interact(nif.human,key_state = commlink_state) - spawn(0) - deactivate() +/datum/nifsoft/commlink/activate() + if((. = ..())) + nif.comm.initialize_exonet(nif.human) + nif.comm.tgui_interact(nif.human, custom_state = GLOB.tgui_commlink_state) + spawn(0) + deactivate() - stat_text() - return "Show Commlink" +/datum/nifsoft/commlink/stat_text() + return "Show Commlink" /datum/nifsoft/commlink/Topic(href, href_list) if(href_list["open"]) @@ -39,18 +39,18 @@ var/obj/item/device/nif/nif var/datum/nifsoft/commlink/nifsoft - New(var/newloc,var/soft) - ..() - nif = newloc - nifsoft = soft - QDEL_NULL(camera) //Not supported on internal one. +/obj/item/device/communicator/commlink/New(var/newloc,var/soft) + ..() + nif = newloc + nifsoft = soft + QDEL_NULL(camera) //Not supported on internal one. - Destroy() - if(nif) - nif.comm = null - nif = null - nifsoft = null - return ..() +/obj/item/device/communicator/commlink/Destroy() + if(nif) + nif.comm = null + nif = null + nifsoft = null + return ..() /obj/item/device/communicator/commlink/register_device(var/new_name) owner = new_name diff --git a/code/modules/nifsoft/software/15_misc.dm b/code/modules/nifsoft/software/15_misc.dm index f6406ed186..7cdd364b16 100644 --- a/code/modules/nifsoft/software/15_misc.dm +++ b/code/modules/nifsoft/software/15_misc.dm @@ -9,36 +9,36 @@ var/obj/machinery/power/apc/apc other_flags = (NIF_O_APCCHARGE) - activate() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - apc = locate(/obj/machinery/power/apc) in get_step(H,H.dir) - if(!apc) - apc = locate(/obj/machinery/power/apc) in get_step(H,0) - if(!apc) - nif.notify("You must be facing an APC to connect to.",TRUE) - spawn(0) - deactivate() - return FALSE - - H.visible_message("Thin snakelike tendrils grow from [H] and connect to \the [apc].","Thin snakelike tendrils grow from you and connect to \the [apc].") - - deactivate() - if((. = ..())) - apc = null - - life() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - if(apc && (get_dist(H,apc) <= 1) && H.nutrition < 440) // 440 vs 450, life() happens before we get here so it'll never be EXACTLY 450 - H.nutrition = min(H.nutrition+10, 450) - apc.drain_power(7000/450*10) //This is from the large rechargers. No idea what the math is. - return TRUE - else - nif.notify("APC charging has ended.") - H.visible_message("[H]'s snakelike tendrils whip back into their body from \the [apc].","The APC connector tendrils return to your body.") +/datum/nifsoft/apc_recharge/activate() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + apc = locate(/obj/machinery/power/apc) in get_step(H,H.dir) + if(!apc) + apc = locate(/obj/machinery/power/apc) in get_step(H,0) + if(!apc) + nif.notify("You must be facing an APC to connect to.",TRUE) + spawn(0) deactivate() - return FALSE + return FALSE + + H.visible_message("Thin snakelike tendrils grow from [H] and connect to \the [apc].","Thin snakelike tendrils grow from you and connect to \the [apc].") + +/datum/nifsoft/apc_recharge/deactivate() + if((. = ..())) + apc = null + +/datum/nifsoft/apc_recharge/life() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + if(apc && (get_dist(H,apc) <= 1) && H.nutrition < 440) // 440 vs 450, life() happens before we get here so it'll never be EXACTLY 450 + H.nutrition = min(H.nutrition+10, 450) + apc.drain_power(7000/450*10) //This is from the large rechargers. No idea what the math is. + return TRUE + else + nif.notify("APC charging has ended.") + H.visible_message("[H]'s snakelike tendrils whip back into their body from \the [apc].","The APC connector tendrils return to your body.") + deactivate() + return FALSE /datum/nifsoft/pressure name = "Pressure Seals" @@ -62,31 +62,31 @@ applies_to = NIF_SYNTHETIC other_flags = (NIF_O_HEATSINKS) - activate() - if((. = ..())) - if(used >= 1500) - nif.notify("Heat sinks not safe to operate again yet! Max 75% on activation.",TRUE) - spawn(0) - deactivate() - return FALSE - - stat_text() - return "[active ? "Active" : "Disabled"] (Stored Heat: [FLOOR((used/20), 1)]%)" - - life() - if((. = ..())) - //Not being used, all clean. - if(!active && !used) - return TRUE - - //Being used, and running out. - else if(active && ++used == 2000) - nif.notify("Heat sinks overloaded! Shutting down!",TRUE) +/datum/nifsoft/heatsinks/activate() + if((. = ..())) + if(used >= 1500) + nif.notify("Heat sinks not safe to operate again yet! Max 75% on activation.",TRUE) + spawn(0) deactivate() + return FALSE - //Being cleaned, and finishing empty. - else if(!active && --used == 0) - nif.notify("Heat sinks re-chilled.") +/datum/nifsoft/heatsinks/stat_text() + return "[active ? "Active" : "Disabled"] (Stored Heat: [FLOOR((used/20), 1)]%)" + +/datum/nifsoft/heatsinks/life() + if((. = ..())) + //Not being used, all clean. + if(!active && !used) + return TRUE + + //Being used, and running out. + else if(active && ++used == 2000) + nif.notify("Heat sinks overloaded! Shutting down!",TRUE) + deactivate() + + //Being cleaned, and finishing empty. + else if(!active && --used == 0) + nif.notify("Heat sinks re-chilled.") /datum/nifsoft/compliance name = "Compliance Module" @@ -99,24 +99,24 @@ access = 999 //Prevents anyone from buying it without an emag. var/laws = "Be nice to people!" - New(var/newloc,var/newlaws) - laws = newlaws //Sanitize before this (the disk does) - ..(newloc) +/datum/nifsoft/compliance/New(var/newloc,var/newlaws) + laws = newlaws //Sanitize before this (the disk does) + ..(newloc) - activate() - if((. = ..())) - to_chat(nif.human,"You are compelled to follow these rules: \n[laws]") +/datum/nifsoft/compliance/activate() + if((. = ..())) + to_chat(nif.human,"You are compelled to follow these rules: \n[laws]") - install() - if((. = ..())) - to_chat(nif.human,"You feel suddenly compelled to follow these rules: \n[laws]") +/datum/nifsoft/compliance/install() + if((. = ..())) + to_chat(nif.human,"You feel suddenly compelled to follow these rules: \n[laws]") - uninstall() - nif.notify("ERROR! Unable to comply!",TRUE) - return FALSE //NOPE. +/datum/nifsoft/compliance/uninstall() + nif.notify("ERROR! Unable to comply!",TRUE) + return FALSE //NOPE. - stat_text() - return "Show Laws" +/datum/nifsoft/compliance/stat_text() + return "Show Laws" /datum/nifsoft/sizechange name = "Mass Alteration" @@ -125,28 +125,28 @@ cost = 375 wear = 6 - activate() - if((. = ..())) - var/new_size = input("Put the desired size (25-200%)", "Set Size", 200) as num +/datum/nifsoft/sizechange/activate() + if((. = ..())) + var/new_size = input("Put the desired size (25-200%)", "Set Size", 200) as num - if (!ISINRANGE(new_size,25,200)) - to_chat(nif.human,"The safety features of the NIF Program prevent you from choosing this size.") - return - else - nif.human.resize(new_size/100) - to_chat(nif.human,"You set the size to [new_size]%") + if (!ISINRANGE(new_size,25,200)) + to_chat(nif.human,"The safety features of the NIF Program prevent you from choosing this size.") + return + else + nif.human.resize(new_size/100) + to_chat(nif.human,"You set the size to [new_size]%") - nif.human.visible_message("Swirling grey mist envelops [nif.human] as they change size!","Swirling streams of nanites wrap around you as you change size!") + nif.human.visible_message("Swirling grey mist envelops [nif.human] as they change size!","Swirling streams of nanites wrap around you as you change size!") - spawn(0) - deactivate() + spawn(0) + deactivate() - deactivate() - if((. = ..())) - return TRUE +/datum/nifsoft/sizechange/deactivate() + if((. = ..())) + return TRUE - stat_text() - return "Change Size" +/datum/nifsoft/sizechange/stat_text() + return "Change Size" /datum/nifsoft/worldbend name = "World Bender" @@ -155,22 +155,22 @@ cost = 100 a_drain = 0.01 - activate() - if((. = ..())) - var/list/justme = list(nif.human) - for(var/human in human_mob_list) - if(human == nif.human) - continue - var/mob/living/carbon/human/H = human - H.display_alt_appearance("animals", justme) - alt_farmanimals += nif.human +/datum/nifsoft/worldbend/activate() + if((. = ..())) + var/list/justme = list(nif.human) + for(var/human in human_mob_list) + if(human == nif.human) + continue + var/mob/living/carbon/human/H = human + H.display_alt_appearance("animals", justme) + alt_farmanimals += nif.human - deactivate() - if((. = ..())) - var/list/justme = list(nif.human) - for(var/human in human_mob_list) - if(human == nif.human) - continue - var/mob/living/carbon/human/H = human - H.hide_alt_appearance("animals", justme) - alt_farmanimals -= nif.human +/datum/nifsoft/worldbend/deactivate() + if((. = ..())) + var/list/justme = list(nif.human) + for(var/human in human_mob_list) + if(human == nif.human) + continue + var/mob/living/carbon/human/H = human + H.hide_alt_appearance("animals", justme) + alt_farmanimals -= nif.human diff --git a/code/modules/organs/internal/augment/armmounted.dm b/code/modules/organs/internal/augment/armmounted.dm index 73751be0d9..4131955e15 100644 --- a/code/modules/organs/internal/augment/armmounted.dm +++ b/code/modules/organs/internal/augment/armmounted.dm @@ -86,6 +86,13 @@ integrated_object_type = /obj/item/weapon/melee/energy/sword +/obj/item/organ/internal/augment/armmounted/hand/blade + name = "handblade implant" + desc = "A small implant that fits neatly into the hand. It deploys a small, but dangerous blade." + icon_state = "augment_handblade" + + integrated_object_type = /obj/item/weapon/melee/augment/blade + /* * Shoulder augment. */ @@ -136,6 +143,14 @@ if(istype(owner, /mob/living/carbon/human)) var/mob/living/carbon/human/H = owner H.add_modifier(/datum/modifier/melee_surge, 0.75 MINUTES) + +/obj/item/organ/internal/augment/armmounted/shoulder/blade + name = "armblade implant" + desc = "A large implant that fits into a subject's arm. It deploys a large metal blade by some painful means." + + icon_state = "augment_armblade" + + integrated_object_type = /obj/item/weapon/melee/augment/blade/arm // The toolkit / multi-tool implant. diff --git a/code/modules/organs/internal/stomach.dm b/code/modules/organs/internal/stomach.dm index c8e90d9f78..31adb758ae 100644 --- a/code/modules/organs/internal/stomach.dm +++ b/code/modules/organs/internal/stomach.dm @@ -64,4 +64,10 @@ if(owner && owner.stat != DEAD) owner.bodytemperature += round(owner.robobody_count * 0.25, 0.1) + if(ishuman(owner)) + var/mob/living/carbon/human/H = owner + + if(H.ingested?.total_volume && H.bloodstr) + H.ingested.trans_to_holder(H.bloodstr, rand(2,5)) + return diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index 79aae1a776..ffc3d56d1d 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -1135,6 +1135,8 @@ Note that amputating the affected organ does in fact remove the infection from t remove_splint() get_icon() unmutate() + drop_sound = 'sound/items/drop/weldingtool.ogg' + pickup_sound = 'sound/items/pickup/weldingtool.ogg' for(var/obj/item/organ/external/T in children) T.robotize(company, keep_organs = keep_organs) diff --git a/code/modules/overmap/overmap_shuttle.dm b/code/modules/overmap/overmap_shuttle.dm index bdbe6bf382..86ee893f1e 100644 --- a/code/modules/overmap/overmap_shuttle.dm +++ b/code/modules/overmap/overmap_shuttle.dm @@ -133,10 +133,20 @@ var/icon_full = "fuel_port_full" var/opened = 0 var/parent_shuttle + var/base_tank = /obj/item/weapon/tank/phoron /obj/structure/fuel_port/Initialize() . = ..() - new /obj/item/weapon/tank/phoron(src) + if(base_tank) + new base_tank(src) + +/obj/structure/fuel_port/heavy + base_tank = /obj/item/weapon/tank/phoron/pressurized + +/obj/structure/fuel_port/empty + base_tank = null //oops, no gas! + opened = 1 //shows open so you can diagnose 'oops, no gas' easily + icon_state = "fuel_port_empty" //set the default state just to be safe /obj/structure/fuel_port/attack_hand(mob/user as mob) if(!opened) diff --git a/code/modules/overmap/ships/computers/ship.dm b/code/modules/overmap/ships/computers/ship.dm index f0d54125ae..5c886fb55a 100644 --- a/code/modules/overmap/ships/computers/ship.dm +++ b/code/modules/overmap/ships/computers/ship.dm @@ -70,6 +70,10 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov apply_visual(user) user.reset_view(linked) user.set_machine(src) + if(isliving(user)) + var/mob/living/L = user + L.looking_elsewhere = 1 + L.handle_vision() user.set_viewsize(world.view + extra_view) GLOB.moved_event.register(user, src, /obj/machinery/computer/ship/proc/unlook) // TODO GLOB.stat_set_event.register(user, src, /obj/machinery/computer/ship/proc/unlook) @@ -77,6 +81,10 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov /obj/machinery/computer/ship/proc/unlook(var/mob/user) user.reset_view() + if(isliving(user)) + var/mob/living/L = user + L.looking_elsewhere = 0 + L.handle_vision() user.set_viewsize() // reset to default GLOB.moved_event.unregister(user, src, /obj/machinery/computer/ship/proc/unlook) // TODO GLOB.stat_set_event.unregister(user, src, /obj/machinery/computer/ship/proc/unlook) @@ -112,4 +120,4 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov var/M = W.resolve() if(M) unlook(M) - . = ..() \ No newline at end of file + . = ..() diff --git a/code/modules/overmap/ships/computers/shuttle.dm b/code/modules/overmap/ships/computers/shuttle.dm index f51587d594..76c0d3e6d1 100644 --- a/code/modules/overmap/ships/computers/shuttle.dm +++ b/code/modules/overmap/ships/computers/shuttle.dm @@ -47,6 +47,6 @@ else to_chat(usr,"No valid landing sites in range.") possible_d = shuttle.get_possible_destinations() - if(CanInteract(usr, global.default_state) && (D in possible_d)) + if(CanInteract(usr, GLOB.tgui_default_state) && (D in possible_d)) shuttle.set_destination(possible_d[D]) return TRUE diff --git a/code/modules/overmap/spacetravel.dm b/code/modules/overmap/spacetravel.dm index ac5846202a..8bae95434a 100644 --- a/code/modules/overmap/spacetravel.dm +++ b/code/modules/overmap/spacetravel.dm @@ -47,13 +47,35 @@ proc/get_deepspace(x,y) for(var/atom/movable/AM in contents) if(!AM.lost_in_space()) return FALSE + if(has_buckled_mobs()) + for(var/mob/M in buckled_mobs) + if(!M.lost_in_space()) + return FALSE + return TRUE +/obj/item/device/uav/lost_in_space() + if(state == 1) + return FALSE + return ..() + +/obj/machinery/power/supermatter/lost_in_space() + return FALSE + +/obj/singularity/lost_in_space() + return FALSE + +/obj/vehicle/lost_in_space() + if(load && !load.lost_in_space()) + return FALSE + return ..() + /mob/lost_in_space() return isnull(client) -/mob/living/carbon/human/lost_in_space() - return isnull(client) && !key && stat == DEAD +/mob/living/lost_in_space() + return FALSE + // return isnull(client) && !key && stat == DEAD // Allows bodies that players have ghosted from to be deleted - Ater proc/overmap_spacetravel(var/turf/space/T, var/atom/movable/A) if (!T || !A) diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm index 85ac6d5770..d67ee7b496 100644 --- a/code/modules/paperwork/faxmachine.dm +++ b/code/modules/paperwork/faxmachine.dm @@ -17,8 +17,10 @@ var/list/adminfaxes = list() //cache for faxes that have been sent to admins active_power_usage = 200 circuit = /obj/item/weapon/circuitboard/fax - var/obj/item/weapon/card/id/scan = null // identification - var/authenticated = 0 + var/obj/item/weapon/card/id/scan = null + var/authenticated = null + var/rank = null + var/sendcooldown = 0 // to avoid spamming fax messages var/department = "Unknown" // our department var/destination = null // the department we're sending to @@ -33,95 +35,105 @@ var/list/adminfaxes = list() //cache for faxes that have been sent to admins /obj/machinery/photocopier/faxmachine/attack_hand(mob/user as mob) // CH edit begins here; this allows borgs to use fax machines, meant for the Unity and Clerical modules. user.set_machine(src) - if(issilicon(usr)) // Normally, you have to insert an ID. Borgs, obviously, cannot do this, so it skips the ID process completely. + if(issilicon(usr)) authenticated = 1 - ui_interact(user) + tgui_interact(user) else - ui_interact(user) // CH edit ends here + tgui_interact(user) -/** - * Display the NanoUI window for the fax machine. - * - * See NanoUI documentation for details. - */ -/obj/machinery/photocopier/faxmachine/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/photocopier/faxmachine/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Fax", name) + ui.open() - var/list/data = list() - if(scan) - data["scanName"] = scan.name - else - data["scanName"] = null - data["bossName"] = using_map.boss_name +/obj/machinery/photocopier/faxmachine/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + data["scan"] = scan ? scan.name : null data["authenticated"] = authenticated + data["rank"] = rank + data["isAI"] = isAI(user) + data["isRobot"] = isrobot(user) + + data["bossName"] = using_map.boss_name data["copyItem"] = copyitem - if(copyitem) - data["copyItemName"] = copyitem.name - else - data["copyItemName"] = null data["cooldown"] = sendcooldown data["destination"] = destination - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "fax.tmpl", src.name, 500, 500) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(10) //this machine is so unimportant let's not have it update that often. + return data -/obj/machinery/photocopier/faxmachine/Topic(href, href_list) - if(href_list["send"]) - if(copyitem) - if (destination in admin_departments) - send_admin_fax(usr, destination) - else - sendfax(destination) +/obj/machinery/photocopier/faxmachine/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE - if (sendcooldown) - spawn(sendcooldown) // cooldown time - sendcooldown = 0 - - else if(href_list["remove"]) - if(copyitem) - if(get_dist(usr, src) >= 2) - to_chat(usr, "\The [copyitem] is too far away for you to remove it.") - return - copyitem.loc = usr.loc - usr.put_in_hands(copyitem) - to_chat(usr, "You take \the [copyitem] out of \the [src].") - copyitem = null - - if(href_list["scan"]) - if (scan) - if(ishuman(usr)) - scan.loc = usr.loc - if(!usr.get_active_hand()) + switch(action) + if("scan") + if(scan) + scan.forceMove(loc) + if(ishuman(usr) && !usr.get_active_hand()) usr.put_in_hands(scan) scan = null else - scan.loc = src.loc + var/obj/item/I = usr.get_active_hand() + if(istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.forceMove(src) + scan = I + return TRUE + if("login") + var/login_type = text2num(params["login_type"]) + if(login_type == LOGIN_TYPE_NORMAL && istype(scan)) + if(check_access(scan)) + authenticated = scan.registered_name + rank = scan.assignment + else if(login_type == LOGIN_TYPE_AI && isAI(usr)) + authenticated = usr.name + rank = "AI" + else if(login_type == LOGIN_TYPE_ROBOT && isrobot(usr)) + authenticated = usr.name + var/mob/living/silicon/robot/R = usr + rank = "[R.modtype] [R.braintype]" + return TRUE + if("logout") + if(scan) + scan.forceMove(loc) + if(ishuman(usr) && !usr.get_active_hand()) + usr.put_in_hands(scan) scan = null - else - var/obj/item/I = usr.get_active_hand() - if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I)) - I.loc = src - scan = I - authenticated = 0 + authenticated = null + return TRUE + if("remove") + if(copyitem) + if(get_dist(usr, src) >= 2) + to_chat(usr, "\The [copyitem] is too far away for you to remove it.") + return + copyitem.forceMove(loc) + usr.put_in_hands(copyitem) + to_chat(usr, "You take \the [copyitem] out of \the [src].") + copyitem = null - if(href_list["dept"]) - var/lastdestination = destination - destination = input(usr, "Which department?", "Choose a department", "") as null|anything in (alldepartments + admin_departments) - if(!destination) destination = lastdestination + if(!authenticated) + return + + switch(action) + if("send") + if(copyitem) + if (destination in admin_departments) + send_admin_fax(usr, destination) + else + sendfax(destination) - if(href_list["auth"]) - if ( (!( authenticated ) && (scan)) ) - if (check_access(scan)) - authenticated = 1 + if (sendcooldown) + spawn(sendcooldown) // cooldown time + sendcooldown = 0 - if(href_list["logout"]) - authenticated = 0 + if("dept") + var/lastdestination = destination + destination = input(usr, "Which department?", "Choose a department", "") as null|anything in (alldepartments + admin_departments) + if(!destination) + destination = lastdestination - SSnanoui.update_uis(src) + return TRUE /obj/machinery/photocopier/faxmachine/attackby(obj/item/O as obj, mob/user as mob) if(O.is_multitool() && panel_open) diff --git a/code/modules/paperwork/handlabeler.dm b/code/modules/paperwork/handlabeler.dm index 8c12f654f6..9182a17530 100644 --- a/code/modules/paperwork/handlabeler.dm +++ b/code/modules/paperwork/handlabeler.dm @@ -6,6 +6,8 @@ var/label = null var/labels_left = 30 var/mode = 0 //off or on. + drop_sound = 'sound/items/drop/device.ogg' + pickup_sound = 'sound/items/pickup/device.ogg' /obj/item/weapon/hand_labeler/attack() return diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index 5bf6a9102a..07009a99c0 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -33,33 +33,71 @@ /obj/machinery/photocopier/attack_hand(mob/user as mob) user.set_machine(src) - ui_interact(user) + tgui_interact(user) -/** - * Display the NanoUI window for the photocopier. - * - * See NanoUI documentation for details. - */ -/obj/machinery/photocopier/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) - - var/list/data = list() - data["copyItem"] = copyitem - data["assPresent"] = has_buckled_mobs() - data["toner"] = toner - data["copies"] = copies - data["maxCopies"] = maxcopies - if(istype(user,/mob/living/silicon)) - data["isSilicon"] = 1 - else - data["isSilicon"] = null - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "photocopier.tmpl", src.name, 300, 250) - ui.set_initial_data(data) +/obj/machinery/photocopier/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Photocopier", name) ui.open() - ui.set_auto_update(10) + +/obj/machinery/photocopier/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + data["has_item"] = copyitem || has_buckled_mobs() // VOREStation Edit: Ass copying + data["isAI"] = issilicon(user) + data["can_AI_print"] = (toner >= 5) + data["has_toner"] = !!toner + data["current_toner"] = toner + data["max_toner"] = 40 + data["num_copies"] = copies + data["max_copies"] = maxcopies + + return data + +/obj/machinery/photocopier/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + switch(action) + if("make_copy") + addtimer(CALLBACK(src, .proc/copy_operation, usr), 0) + . = TRUE + if("remove") + if(copyitem) + copyitem.loc = usr.loc + usr.put_in_hands(copyitem) + to_chat(usr, "You take \the [copyitem] out of \the [src].") + copyitem = null + else if(has_buckled_mobs()) + to_chat(buckled_mobs[1], "You feel a slight pressure on your ass.") // It can't eject your asscheeks, but it'll try. + . = TRUE + if("set_copies") + copies = clamp(text2num(params["num_copies"]), 1, maxcopies) + . = TRUE + if("ai_photo") + if(!issilicon(usr)) + return + if(stat & (BROKEN|NOPOWER)) + return + + if(toner >= 5) + var/mob/living/silicon/tempAI = usr + var/obj/item/device/camera/siliconcam/camera = tempAI.aiCamera + + if(!camera) + return + var/obj/item/weapon/photo/selection = camera.selectpicture() + if (!selection) + return + + var/obj/item/weapon/photo/p = photocopy(selection) + if (p.desc == "") + p.desc += "Copied by [tempAI.name]" + else + p.desc += " - Copied by [tempAI.name]" + toner -= 5 + . = TRUE /obj/machinery/photocopier/proc/copy_operation(var/mob/user) if(copying) @@ -104,51 +142,6 @@ use_power(active_power_usage) copying = FALSE -/obj/machinery/photocopier/Topic(href, href_list) - if(href_list["copy"]) - if(stat & (BROKEN|NOPOWER)) - return - addtimer(CALLBACK(src, .proc/copy_operation, usr), 0) - - else if(href_list["remove"]) - if(copyitem) - copyitem.loc = usr.loc - usr.put_in_hands(copyitem) - to_chat(usr, "You take \the [copyitem] out of \the [src].") - copyitem = null - else if(has_buckled_mobs()) - to_chat(buckled_mobs[1], "You feel a slight pressure on your ass.") // It can't eject your asscheeks, but it'll try. - return TOPIC_REFRESH - else if(href_list["min"]) - if(copies > 1) - copies-- - else if(href_list["add"]) - if(copies < maxcopies) - copies++ - else if(href_list["aipic"]) - if(!istype(usr,/mob/living/silicon)) return - if(stat & (BROKEN|NOPOWER)) return - - if(toner >= 5) - var/mob/living/silicon/tempAI = usr - var/obj/item/device/camera/siliconcam/camera = tempAI.aiCamera - - if(!camera) - return - var/obj/item/weapon/photo/selection = camera.selectpicture() - if (!selection) - return - - var/obj/item/weapon/photo/p = photocopy(selection) - if (p.desc == "") - p.desc += "Copied by [tempAI.name]" - else - p.desc += " - Copied by [tempAI.name]" - toner -= 5 - sleep(15) - - SSnanoui.update_uis(src) - /obj/machinery/photocopier/attackby(obj/item/O as obj, mob/user as mob) if(istype(O, /obj/item/weapon/paper) || istype(O, /obj/item/weapon/photo) || istype(O, /obj/item/weapon/paper_bundle)) if(!copyitem) diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index b63048fdc0..c4460e5dcf 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -195,7 +195,7 @@ var/global/photo_count = 0 for(var/i; i <= sorted.len; i++) var/atom/A = sorted[i] if(A) - var/icon/img = getFlatIcon(A)//, picture_planes = picture_planes)//build_composite_icon(A) //VOREStation Edit + var/icon/img = getFlatIcon(A, no_anim = TRUE)//, picture_planes = picture_planes)//build_composite_icon(A) //VOREStation Edit // If what we got back is actually a picture, draw it. if(istype(img, /icon)) @@ -216,7 +216,7 @@ var/global/photo_count = 0 // Calculate where we are relative to the center of the photo var/xoff = (the_turf.x - center.x) * 32 + center_offset var/yoff = (the_turf.y - center.y) * 32 + center_offset - res.Blend(getFlatIcon(the_turf.loc), blendMode2iconMode(the_turf.blend_mode),xoff,yoff) + res.Blend(getFlatIcon(the_turf.loc, no_anim = TRUE), blendMode2iconMode(the_turf.blend_mode),xoff,yoff) return res diff --git a/code/modules/paperwork/stamps.dm b/code/modules/paperwork/stamps.dm index ea614aa11e..7be509c96f 100644 --- a/code/modules/paperwork/stamps.dm +++ b/code/modules/paperwork/stamps.dm @@ -12,6 +12,8 @@ matter = list(DEFAULT_WALL_MATERIAL = 60) pressure_resistance = 2 attack_verb = list("stamped") + drop_sound = 'sound/items/drop/device.ogg' + pickup_sound = 'sound/items/pickup/device.ogg' /obj/item/weapon/stamp/captain name = "site manager's rubber stamp" diff --git a/code/modules/pda/ai.dm b/code/modules/pda/ai.dm new file mode 100644 index 0000000000..10a04effb3 --- /dev/null +++ b/code/modules/pda/ai.dm @@ -0,0 +1,58 @@ + +// Special AI/pAI PDAs that cannot explode. +/obj/item/device/pda/ai + icon_state = "NONE" + ttone = "data" + detonate = 0 + touch_silent = TRUE + programs = list( + new/datum/data/pda/app/main_menu, + new/datum/data/pda/app/notekeeper, + new/datum/data/pda/app/news, + new/datum/data/pda/app/messenger) + +/obj/item/device/pda/ai/proc/set_name_and_job(newname as text, newjob as text, newrank as null|text) + owner = newname + ownjob = newjob + if(newrank) + ownrank = newrank + else + ownrank = ownjob + name = newname + " (" + ownjob + ")" + +//AI verb and proc for sending PDA messages. +/obj/item/device/pda/ai/verb/cmd_pda_open_ui() + set category = "AI IM" + set name = "Use PDA" + set src in usr + + if(!can_use(usr)) + return + tgui_interact(usr) + +/obj/item/device/pda/ai/can_use() + return 1 + +/obj/item/device/pda/ai/attack_self(mob/user as mob) + if ((honkamt > 0) && (prob(60)))//For clown virus. + honkamt-- + playsound(src, 'sound/items/bikehorn.ogg', 30, 1) + return + + +/obj/item/device/pda/ai/pai + ttone = "assist" + var/our_owner = null // Ref to a pAI + +/obj/item/device/pda/ai/pai/New(mob/living/silicon/pai/P) + if(istype(P)) + our_owner = REF(P) + return ..() + +/obj/item/device/pda/ai/pai/tgui_status(mob/living/silicon/pai/user, datum/tgui_state/state) + if(!istype(user) || REF(user) != our_owner) // Only allow our pAI to interface with us + return STATUS_CLOSE + return ..() + +/obj/item/device/pda/ai/shell + spam_proof = TRUE // Since empty shells get a functional PDA. diff --git a/code/modules/pda/app.dm b/code/modules/pda/app.dm new file mode 100644 index 0000000000..eb64125ee9 --- /dev/null +++ b/code/modules/pda/app.dm @@ -0,0 +1,109 @@ +// Base class for anything that can show up on home screen +/datum/data/pda + var/icon = "tasks" //options comes from http://fontawesome.io/icons/ + var/notify_icon = "exclamation-circle" + var/notify_silent = 0 + var/hidden = 0 // program not displayed in main menu + var/category = "General" // the category to list it in on the main menu + var/obj/item/device/pda/pda // if this is null, and the app is running code, something's gone wrong + +/datum/data/pda/Destroy() + pda = null + return ..() + +/datum/data/pda/proc/start() + return + +/datum/data/pda/proc/stop() + return + +/datum/data/pda/proc/program_process() + return + +/datum/data/pda/proc/program_hit_check() + return + +/datum/data/pda/proc/notify(message, blink = 1) + if(message) + //Search for holder of the PDA. + var/mob/living/L = null + if(pda.loc && isliving(pda.loc)) + L = pda.loc + //Maybe they are a pAI! + else + L = get(pda, /mob/living/silicon) + + if(L) + to_chat(L, "[bicon(pda)] [message]") + SStgui.update_user_uis(L, pda) // Update the receiving user's PDA UI so that they can see the new message + + if(!notify_silent) + pda.play_ringtone() + + if(blink && !(src in pda.notifying_programs)) + pda.overlays += image('icons/obj/pda.dmi', "pda-r") + pda.notifying_programs |= src + +/datum/data/pda/proc/unnotify() + if(src in pda.notifying_programs) + pda.notifying_programs -= src + if(!pda.notifying_programs.len) + pda.overlays -= image('icons/obj/pda.dmi', "pda-r") + +// An app has a button on the home screen and its own UI +/datum/data/pda/app + name = "App" + size = 3 + var/title = null // what is displayed in the title bar when this is the current app + var/template = "" + var/update = PDA_APP_UPDATE + var/has_back = 0 + +/datum/data/pda/app/tgui_host(mob/user) + return pda || src + +/datum/data/pda/app/New() + if(!title) + title = name + +/datum/data/pda/app/start() + if(pda.current_app) + pda.current_app.stop() + pda.current_app = src + return 1 + +/datum/data/pda/app/proc/update_ui(mob/user as mob, list/data) + + +// Utilities just have a button on the home screen, but custom code when clicked +/datum/data/pda/utility + name = "Utility" + icon = "gear" + size = 1 + category = "Utilities" + + +/datum/data/pda/utility/scanmode + var/base_name + category = "Scanners" + +/datum/data/pda/utility/scanmode/New(obj/item/weapon/cartridge/C) + ..(C) + name = "Enable [base_name]" + +/datum/data/pda/utility/scanmode/start() + if(pda.scanmode) + pda.scanmode.name = "Enable [pda.scanmode.base_name]" + + if(pda.scanmode == src) + pda.scanmode = null + else + pda.scanmode = src + name = "Disable [base_name]" + + pda.update_shortcuts() + return 1 + +/datum/data/pda/utility/scanmode/proc/scan_mob(mob/living/C as mob, mob/living/user as mob) + +/datum/data/pda/utility/scanmode/proc/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) diff --git a/code/modules/pda/cart.dm b/code/modules/pda/cart.dm new file mode 100644 index 0000000000..2ec6a4e536 --- /dev/null +++ b/code/modules/pda/cart.dm @@ -0,0 +1,311 @@ +var/list/command_cartridges = list( + /obj/item/weapon/cartridge/captain, + /obj/item/weapon/cartridge/hop, + /obj/item/weapon/cartridge/hos, + /obj/item/weapon/cartridge/ce, + /obj/item/weapon/cartridge/rd, + /obj/item/weapon/cartridge/cmo, + /obj/item/weapon/cartridge/head, + /obj/item/weapon/cartridge/lawyer // Internal Affaris, + ) + +var/list/security_cartridges = list( + /obj/item/weapon/cartridge/security, + /obj/item/weapon/cartridge/detective, + /obj/item/weapon/cartridge/hos + ) + +var/list/engineering_cartridges = list( + /obj/item/weapon/cartridge/engineering, + /obj/item/weapon/cartridge/atmos, + /obj/item/weapon/cartridge/ce + ) + +var/list/medical_cartridges = list( + /obj/item/weapon/cartridge/medical, + /obj/item/weapon/cartridge/chemistry, + /obj/item/weapon/cartridge/cmo + ) + +var/list/research_cartridges = list( + /obj/item/weapon/cartridge/signal/science, + /obj/item/weapon/cartridge/rd + ) + +var/list/cargo_cartridges = list( + /obj/item/weapon/cartridge/quartermaster, // This also covers cargo-techs, apparently, + /obj/item/weapon/cartridge/miner, + /obj/item/weapon/cartridge/hop + ) + +var/list/civilian_cartridges = list( + /obj/item/weapon/cartridge/janitor, + /obj/item/weapon/cartridge/service, + /obj/item/weapon/cartridge/hop + ) + +/obj/item/weapon/cartridge + name = "generic cartridge" + desc = "A data cartridge for portable microcomputers." + icon = 'icons/obj/pda.dmi' + icon_state = "cart" + item_state = "electronic" + w_class = ITEMSIZE_TINY + drop_sound = 'sound/items/drop/component.ogg' + pickup_sound = 'sound/items/pickup/component.ogg' + + var/obj/item/radio/integrated/radio = null + + var/charges = 0 + + var/list/stored_data = list() + var/list/programs = list() + var/list/messenger_plugins = list() + +/obj/item/weapon/cartridge/Destroy() + QDEL_NULL(radio) + QDEL_LIST(programs) + QDEL_LIST(messenger_plugins) + return ..() + +/obj/item/weapon/cartridge/proc/update_programs(obj/item/device/pda/pda) + for(var/A in programs) + var/datum/data/pda/P = A + P.pda = pda + for(var/A in messenger_plugins) + var/datum/data/pda/messenger_plugin/P = A + P.pda = pda + +/obj/item/weapon/cartridge/engineering + name = "\improper Power-ON cartridge" + icon_state = "cart-e" + programs = list( + new/datum/data/pda/app/power, + new/datum/data/pda/utility/scanmode/halogen) + +/obj/item/weapon/cartridge/atmos + name = "\improper BreatheDeep cartridge" + icon_state = "cart-a" + programs = list(new/datum/data/pda/utility/scanmode/gas) + +/obj/item/weapon/cartridge/medical + name = "\improper Med-U cartridge" + icon_state = "cart-m" + programs = list( + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical) + +/obj/item/weapon/cartridge/chemistry + name = "\improper ChemWhiz cartridge" + icon_state = "cart-chem" + programs = list( + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical, + new/datum/data/pda/utility/scanmode/reagent) + +/obj/item/weapon/cartridge/security + name = "\improper R.O.B.U.S.T. cartridge" + icon_state = "cart-s" + programs = list( + new/datum/data/pda/app/crew_records/security) + +/obj/item/weapon/cartridge/detective + name = "\improper D.E.T.E.C.T. cartridge" + icon_state = "cart-s" + programs = list( + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical, + + new/datum/data/pda/app/crew_records/security) + + +/obj/item/weapon/cartridge/janitor + name = "\improper CustodiPRO cartridge" + desc = "The ultimate in clean-room design." + icon_state = "cart-j" + programs = list(new/datum/data/pda/app/janitor) + +/obj/item/weapon/cartridge/lawyer + name = "\improper P.R.O.V.E. cartridge" + icon_state = "cart-s" + programs = list(new/datum/data/pda/app/crew_records/security) + +/obj/item/weapon/cartridge/clown + name = "\improper Honkworks 5.0 cartridge" + icon_state = "cart-clown" + charges = 5 + programs = list(new/datum/data/pda/utility/honk) + messenger_plugins = list(new/datum/data/pda/messenger_plugin/virus/clown) + +/obj/item/weapon/cartridge/mime + name = "\improper Gestur-O 1000 cartridge" + icon_state = "cart-mi" + charges = 5 + messenger_plugins = list(new/datum/data/pda/messenger_plugin/virus/mime) + +/obj/item/weapon/cartridge/service + name = "\improper Serv-U Pro cartridge" + desc = "A data cartridge designed to serve YOU!" + +/obj/item/weapon/cartridge/signal + name = "generic signaler cartridge" + desc = "A data cartridge with an integrated radio signaler module." + programs = list(new/datum/data/pda/app/signaller) + +/obj/item/weapon/cartridge/signal/Initialize() + radio = new /obj/item/radio/integrated/signal(src) + ..() + +/obj/item/weapon/cartridge/signal/science + name = "\improper Signal Ace 2 cartridge" + desc = "Complete with integrated radio signaler!" + icon_state = "cart-tox" + programs = list( + new/datum/data/pda/utility/scanmode/gas, + + new/datum/data/pda/utility/scanmode/reagent, + + new/datum/data/pda/app/signaller) + +/obj/item/weapon/cartridge/quartermaster + name = "\improper Space Parts & Space Vendors cartridge" + desc = "Perfect for the Quartermaster on the go!" + icon_state = "cart-q" + programs = list( + new/datum/data/pda/app/supply) + +/obj/item/weapon/cartridge/miner + name = "\improper Drill-Jockey 4.5 cartridge" + desc = "It's covered in some sort of sand." + icon_state = "cart-q" + +/obj/item/weapon/cartridge/head + name = "\improper Easy-Record DELUXE cartridge" + icon_state = "cart-h" + programs = list(new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/hop + name = "\improper HumanResources9001 cartridge" + icon_state = "cart-h" + programs = list( + new/datum/data/pda/app/crew_records/security, + + new/datum/data/pda/app/janitor, + + new/datum/data/pda/app/supply, + + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/hos + name = "\improper R.O.B.U.S.T. DELUXE cartridge" + icon_state = "cart-hos" + programs = list( + new/datum/data/pda/app/crew_records/security, + + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/ce + name = "\improper Power-On DELUXE cartridge" + icon_state = "cart-ce" + programs = list( + new/datum/data/pda/app/power, + new/datum/data/pda/utility/scanmode/halogen, + + new/datum/data/pda/utility/scanmode/gas, + + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/cmo + name = "\improper Med-U DELUXE cartridge" + icon_state = "cart-cmo" + programs = list( + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical, + + new/datum/data/pda/utility/scanmode/reagent, + + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/rd + name = "\improper Signal Ace DELUXE cartridge" + icon_state = "cart-rd" + programs = list( + new/datum/data/pda/utility/scanmode/gas, + + new/datum/data/pda/utility/scanmode/reagent, + + new/datum/data/pda/app/signaller, + + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/rd/Initialize() + radio = new /obj/item/radio/integrated/signal(src) + . = ..() + +/obj/item/weapon/cartridge/captain + name = "\improper Value-PAK cartridge" + desc = "Now with 200% more value!" + icon_state = "cart-c" + programs = list( + new/datum/data/pda/app/power, + new/datum/data/pda/utility/scanmode/halogen, + + new/datum/data/pda/utility/scanmode/gas, + + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical, + + new/datum/data/pda/utility/scanmode/reagent, + + new/datum/data/pda/app/crew_records/security, + + new/datum/data/pda/app/janitor, + + new/datum/data/pda/app/supply, + + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/syndicate + name = "\improper Detomatix cartridge" + icon_state = "cart" + var/initial_remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing. + charges = 4 + programs = list(new/datum/data/pda/utility/toggle_door) + messenger_plugins = list(new/datum/data/pda/messenger_plugin/virus/detonate) + +/obj/item/weapon/cartridge/syndicate/New() + var/datum/data/pda/utility/toggle_door/D = programs[1] + if(istype(D)) + D.remote_door_id = initial_remote_door_id + +/obj/item/weapon/cartridge/proc/post_status(var/command, var/data1, var/data2) + + var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) + if(!frequency) return + + var/datum/signal/status_signal = new + status_signal.source = src + status_signal.transmission_method = TRANSMISSION_RADIO + status_signal.data["command"] = command + + switch(command) + if("message") + status_signal.data["msg1"] = data1 + status_signal.data["msg2"] = data2 + if(loc) + var/obj/item/PDA = loc + var/mob/user = PDA.fingerprintslast + log_admin("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]") + message_admins("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]") + + if("alert") + status_signal.data["picture_state"] = data1 + + frequency.post_signal(src, status_signal) + +/obj/item/weapon/cartridge/frame + name = "F.R.A.M.E. cartridge" + icon_state = "cart" + charges = 5 + var/telecrystals = 0 + messenger_plugins = list(new/datum/data/pda/messenger_plugin/virus/frame) diff --git a/code/modules/pda/cart_apps.dm b/code/modules/pda/cart_apps.dm new file mode 100644 index 0000000000..d7ca7717d5 --- /dev/null +++ b/code/modules/pda/cart_apps.dm @@ -0,0 +1,311 @@ +/datum/data/pda/app/status_display + name = "Status Display" + icon = "list-alt" + template = "pda_status_display" + category = "Utilities" + + var/message1 // used for status_displays + var/message2 + +/datum/data/pda/app/status_display/update_ui(mob/user as mob, list/data) + data["records"] = list( + "message1" = message1 ? message1 : "(none)", + "message2" = message2 ? message2 : "(none)") + +/datum/data/pda/app/status_display/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + switch(action) + if("Status") + switch(params["statdisp"]) + if("message") + post_status("message", message1, message2) + if("alert") + post_status("alert", params["alert"]) + if("setmsg1") + message1 = clean_input("Line 1", "Enter Message Text", message1) + if("setmsg2") + message2 = clean_input("Line 2", "Enter Message Text", message2) + else + post_status(params["statdisp"]) + return TRUE + +/datum/data/pda/app/status_display/proc/post_status(var/command, var/data1, var/data2) + var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) + if(!frequency) + return + + var/datum/signal/status_signal = new + status_signal.source = src + status_signal.transmission_method = 1 + status_signal.data["command"] = command + + switch(command) + if("message") + status_signal.data["msg1"] = data1 + status_signal.data["msg2"] = data2 + var/mob/user = pda.fingerprintslast + if(istype(pda.loc, /mob/living)) + user = pda.loc + log_admin("STATUS: [user] set status screen with [pda]. Message: [data1] [data2]") + message_admins("STATUS: [user] set status screen with [pda]. Message: [data1] [data2]") + + if("alert") + status_signal.data["picture_state"] = data1 + + spawn(0) + frequency.post_signal(src, status_signal) + + +/datum/data/pda/app/signaller + name = "Signaler System" + icon = "rss" + template = "pda_signaller" + category = "Utilities" + +/datum/data/pda/app/signaller/update_ui(mob/user as mob, list/data) + if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/signal)) + var/obj/item/radio/integrated/signal/R = pda.cartridge.radio + data["frequency"] = R.frequency + data["minFrequency"] = RADIO_LOW_FREQ + data["maxFrequency"] = RADIO_HIGH_FREQ + data["code"] = R.code + +/datum/data/pda/app/signaller/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/signal)) + var/obj/item/radio/integrated/signal/R = pda.cartridge.radio + + switch(action) + if("signal") + spawn(0) + R.send_signal("ACTIVATE") + if("freq") + var/frequency = unformat_frequency(params["freq"]) + frequency = sanitize_frequency(frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) + R.set_frequency(frequency) + . = TRUE + if("code") + R.code = clamp(round(text2num(params["code"])), 1, 100) + . = TRUE + if("reset") + if(params["reset"] == "freq") + R.set_frequency(initial(R.frequency)) + else + R.code = initial(R.code) + . = TRUE + +/datum/data/pda/app/power + name = "Power Monitor" + icon = "exclamation-triangle" + template = "pda_power" + category = "Engineering" + + var/datum/tgui_module/power_monitor/power_monitor + +/datum/data/pda/app/power/New() + power_monitor = new(src) + . = ..() + +/datum/data/pda/app/power/Destroy() + QDEL_NULL(power_monitor) + return ..() + +/datum/data/pda/app/power/update_ui(mob/user as mob, list/data) + data.Add(power_monitor.tgui_data(user)) + +/datum/data/pda/app/power/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + if(power_monitor.tgui_act(action, params, ui, state)) + return TRUE + switch(action) + if("Back") + power_monitor.active_sensor = null + return TRUE + +/datum/data/pda/app/crew_records + var/datum/data/record/general_records = null + +/datum/data/pda/app/crew_records/update_ui(mob/user as mob, list/data) + var/list/records[0] + + if(general_records && (general_records in data_core.general)) + data["records"] = records + records["general"] = general_records.fields + return records + else + for(var/A in sortRecord(data_core.general)) + var/datum/data/record/R = A + if(R) + records += list(list(Name = R.fields["name"], "ref" = "\ref[R]")) + data["recordsList"] = records + data["records"] = null + return null + +/datum/data/pda/app/crew_records/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + switch(action) + if("Records") + var/datum/data/record/R = locate(params["target"]) + if(R && (R in data_core.general)) + load_records(R) + return TRUE + if("Back") + general_records = null + has_back = 0 + return TRUE + +/datum/data/pda/app/crew_records/proc/load_records(datum/data/record/R) + general_records = R + has_back = 1 + +/datum/data/pda/app/crew_records/medical + name = "Medical Records" + icon = "heartbeat" + template = "pda_medical" + category = "Medical" + + var/datum/data/record/medical_records = null + +/datum/data/pda/app/crew_records/medical/update_ui(mob/user as mob, list/data) + var/list/records = ..() + if(!records) + return + + if(medical_records && (medical_records in data_core.medical)) + records["medical"] = medical_records.fields + + return records + +/datum/data/pda/app/crew_records/medical/load_records(datum/data/record/R) + ..(R) + for(var/A in data_core.medical) + var/datum/data/record/E = A + if(E && (E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + medical_records = E + break + +/datum/data/pda/app/crew_records/security + name = "Security Records" + icon = "tags" + template = "pda_security" + category = "Security" + + var/datum/data/record/security_records = null + +/datum/data/pda/app/crew_records/security/update_ui(mob/user as mob, list/data) + var/list/records = ..() + if(!records) + return + + if(security_records && (security_records in data_core.security)) + records["security"] = security_records.fields + + return records + +/datum/data/pda/app/crew_records/security/load_records(datum/data/record/R) + ..(R) + for(var/A in data_core.security) + var/datum/data/record/E = A + if(E && (E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + security_records = E + break + +/datum/data/pda/app/supply + name = "Supply Records" + icon = "file-word-o" + template = "pda_supply" + category = "Quartermaster" + +/datum/data/pda/app/supply/update_ui(mob/user as mob, list/data) + var/supplyData[0] + var/datum/shuttle/autodock/ferry/supply/shuttle = SSsupply.shuttle + if (shuttle) + supplyData["shuttle_moving"] = shuttle.has_arrive_time() + supplyData["shuttle_eta"] = shuttle.eta_minutes() + supplyData["shuttle_loc"] = shuttle.at_station() ? "Station" : "Dock" + var/supplyOrderCount = 0 + var/supplyOrderData[0] + for(var/S in SSsupply.shoppinglist) + var/datum/supply_order/SO = S + + supplyOrderCount++ + supplyOrderData[++supplyOrderData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "ApprovedBy" = SO.ordered_by, "Comment" = html_encode(SO.comment)) + + supplyData["approved"] = supplyOrderData + supplyData["approved_count"] = supplyOrderCount + + var/requestCount = 0 + var/requestData[0] + for(var/S in SSsupply.order_history) + var/datum/supply_order/SO = S + if(SO.status != SUP_ORDER_REQUESTED) + continue + + requestCount++ + requestData[++requestData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "OrderedBy" = SO.ordered_by, "Comment" = html_encode(SO.comment)) + + supplyData["requests"] = requestData + supplyData["requests_count"] = requestCount + + data["supply"] = supplyData + +/datum/data/pda/app/janitor + name = "Custodial Locator" + icon = "trash-alt-o" + template = "pda_janitor" + category = "Utilities" + +/datum/data/pda/app/janitor/update_ui(mob/user as mob, list/data) + var/JaniData[0] + var/turf/cl = get_turf(pda) + + if(cl) + JaniData["user_loc"] = list("x" = cl.x, "y" = cl.y) + else + JaniData["user_loc"] = list("x" = 0, "y" = 0) + + var/MopData[0] + for(var/obj/item/weapon/mop/M in GLOB.all_mops)//GLOB.janitorial_equipment) + var/turf/ml = get_turf(M) + if(ml) + if(ml.z != cl.z) + continue + var/direction = get_dir(pda, M) + MopData[++MopData.len] = list ("x" = ml.x, "y" = ml.y, "dir" = uppertext(dir2text(direction)), "status" = M.reagents.total_volume ? "Wet" : "Dry") + + var/BucketData[0] + for(var/obj/structure/mopbucket/B in GLOB.all_mopbuckets)//GLOB.janitorial_equipment) + var/turf/bl = get_turf(B) + if(bl) + if(bl.z != cl.z) + continue + var/direction = get_dir(pda,B) + BucketData[++BucketData.len] = list ("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "volume" = B.reagents.total_volume, "max_volume" = B.reagents.maximum_volume) + + var/CbotData[0] + for(var/mob/living/bot/cleanbot/B in mob_list) + var/turf/bl = get_turf(B) + if(bl) + if(bl.z != cl.z) + continue + var/direction = get_dir(pda,B) + CbotData[++CbotData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.on ? "Online" : "Offline") + + var/CartData[0] + for(var/obj/structure/janitorialcart/B in GLOB.all_janitorial_carts)//GLOB.janitorial_equipment) + var/turf/bl = get_turf(B) + if(bl) + if(bl.z != cl.z) + continue + var/direction = get_dir(pda,B) + CartData[++CartData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "volume" = B.reagents.total_volume, "max_volume" = B.reagents.maximum_volume) + + JaniData["mops"] = MopData.len ? MopData : null + JaniData["buckets"] = BucketData.len ? BucketData : null + JaniData["cleanbots"] = CbotData.len ? CbotData : null + JaniData["carts"] = CartData.len ? CartData : null + data["janitor"] = JaniData diff --git a/code/modules/pda/cart_vr.dm b/code/modules/pda/cart_vr.dm new file mode 100644 index 0000000000..1f1a1cbe52 --- /dev/null +++ b/code/modules/pda/cart_vr.dm @@ -0,0 +1,20 @@ +var/list/exploration_cartridges = list( + /obj/item/weapon/cartridge/explorer, + /obj/item/weapon/cartridge/sar + ) + +/obj/item/weapon/cartridge/explorer + name = "\improper Explorator cartridge" + icon_state = "cart-e" + programs = list( + new/datum/data/pda/utility/scanmode/reagent, + new/datum/data/pda/utility/scanmode/gas) + +/obj/item/weapon/cartridge/sar + name = "\improper Med-Exp cartridge" + icon_state = "cart-m" + programs = list( + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical, + new/datum/data/pda/utility/scanmode/reagent, + new/datum/data/pda/utility/scanmode/gas) diff --git a/code/modules/pda/core_apps.dm b/code/modules/pda/core_apps.dm new file mode 100644 index 0000000000..4b561c9844 --- /dev/null +++ b/code/modules/pda/core_apps.dm @@ -0,0 +1,206 @@ +/datum/data/pda/app/main_menu + icon = "home" + template = "pda_main_menu" + hidden = 1 + +/datum/data/pda/app/main_menu/update_ui(mob/user as mob, list/data) + title = pda.name + + data["app"]["is_home"] = 1 + + data["apps"] = pda.shortcut_cache + data["categories"] = pda.shortcut_cat_order + data["pai"] = !isnull(pda.pai) // pAI inserted? + + var/list/notifying[0] + for(var/P in pda.notifying_programs) + notifying["\ref[P]"] = 1 + data["notifying"] = notifying + +/datum/data/pda/app/main_menu/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + switch(action) + if("UpdateInfo") + pda.ownjob = pda.id.assignment + pda.ownrank = pda.id.rank + pda.name = "PDA-[pda.owner] ([pda.ownjob])" + return TRUE + if("pai") + if(pda.pai) + if(pda.pai.loc != pda) + pda.pai = null + else + switch(text2num(params["option"])) + if(1) // Configure pAI device + pda.pai.attack_self(usr) + if(2) // Eject pAI device + var/turf/T = get_turf_or_move(pda.loc) + if(T) + pda.pai.loc = T + pda.pai = null + return TRUE + +/datum/data/pda/app/notekeeper + name = "Notekeeper" + icon = "sticky-note-o" + template = "pda_notekeeper" + + var/note = null + var/notehtml = "" + +/datum/data/pda/app/notekeeper/start() + . = ..() + if(!note) + note = "Congratulations, your station has chosen the [pda.model_name]!" + +/datum/data/pda/app/notekeeper/update_ui(mob/user as mob, list/data) + data["note"] = note // current pda notes + +/datum/data/pda/app/notekeeper/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + switch(action) + if("Edit") + var/n = input("Please enter message", name, notehtml) as message + if(pda.loc == usr) + note = adminscrub(n) + notehtml = html_decode(note) + note = replacetext(note, "\n", "
") + else + pda.close(usr) + return TRUE + +/datum/data/pda/app/manifest + name = "Crew Manifest" + icon = "user" + template = "pda_manifest" + +/datum/data/pda/app/manifest/update_ui(mob/user as mob, list/data) + if(data_core) + data_core.get_manifest_list() + data["manifest"] = PDA_Manifest + +/datum/data/pda/app/manifest/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + +/datum/data/pda/app/atmos_scanner + name = "Atmospheric Scan" + icon = "fire" + template = "pda_atmos_scan" + category = "Utilities" + +/datum/data/pda/app/atmos_scanner/update_ui(mob/user as mob, list/data) + var/list/results = list() + var/turf/T = get_turf(user) + if(!isnull(T)) + var/datum/gas_mixture/environment = T.return_air() + var/pressure = environment.return_pressure() + var/total_moles = environment.total_moles + if (total_moles) + var/o2_level = environment.gas["oxygen"]/total_moles + var/n2_level = environment.gas["nitrogen"]/total_moles + var/co2_level = environment.gas["carbon_dioxide"]/total_moles + var/phoron_level = environment.gas["phoron"]/total_moles + var/unknown_level = 1-(o2_level+n2_level+co2_level+phoron_level) + + // entry is what the element is describing + // Type identifies which unit or other special characters to use + // Val is the information reported + // Bad_high/_low are the values outside of which the entry reports as dangerous + // Poor_high/_low are the values outside of which the entry reports as unideal + // Values were extracted from the template itself + results = list( + list("entry" = "Pressure", "units" = "kPa", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80), + list("entry" = "Temperature", "units" = "°C", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5), + list("entry" = "Oxygen", "units" = "kPa", "val" = "[round(o2_level*100,0.1)]", "bad_high" = 140, "poor_high" = 135, "poor_low" = 19, "bad_low" = 17), + list("entry" = "Nitrogen", "units" = "kPa", "val" = "[round(n2_level*100,0.1)]", "bad_high" = 105, "poor_high" = 85, "poor_low" = 50, "bad_low" = 40), + list("entry" = "Carbon Dioxide", "units" = "kPa", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0), + list("entry" = "Phoron", "units" = "kPa", "val" = "[round(phoron_level*100,0.01)]", "bad_high" = 0.5, "poor_high" = 0, "poor_low" = 0, "bad_low" = 0), + list("entry" = "Other", "units" = "kPa", "val" = "[round(unknown_level, 0.01)]", "bad_high" = 1, "poor_high" = 0.5, "poor_low" = 0, "bad_low" = 0) + ) + + if(isnull(results)) + results = list(list("entry" = "pressure", "units" = "kPa", "val" = "0", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80)) + + data["aircontents"] = results + +/datum/data/pda/app/news + name = "News" + icon = "newspaper" + template = "pda_news" + + var/newsfeed_channel + +/datum/data/pda/app/news/update_ui(mob/user as mob, list/data) + data["feeds"] = compile_news() + data["latest_news"] = get_recent_news() + if(newsfeed_channel) + data["target_feed"] = data["feeds"][newsfeed_channel] + else + data["target_feed"] = null + +/datum/data/pda/app/news/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + switch(action) + if("newsfeed") + newsfeed_channel = text2num(params["newsfeed"]) + +/datum/data/pda/app/news/proc/compile_news() + var/list/feeds = list() + for(var/datum/feed_channel/channel in news_network.network_channels) + var/list/messages = list() + if(!channel.censored) + var/index = 0 + for(var/datum/feed_message/FM in channel.messages) + index++ + var/list/msgdata = list( + "author" = FM.author, + "body" = FM.body, + "img" = null, + "message_type" = FM.message_type, + "time_stamp" = FM.time_stamp, + "caption" = FM.caption, + "index" = index + ) + if(FM.img) + msgdata["img"] = icon2base64(FM.img) + messages[++messages.len] = msgdata + + feeds[++feeds.len] = list( + "name" = channel.channel_name, + "censored" = channel.censored, + "author" = channel.author, + "messages" = messages, + "index" = feeds.len + 1 + ) + return feeds + +/datum/data/pda/app/news/proc/get_recent_news() + var/list/news = list() + + // Compile all the newscasts + for(var/datum/feed_channel/channel in news_network.network_channels) + if(!channel.censored) + for(var/datum/feed_message/FM in channel.messages) + var/body = replacetext(FM.body, "\n", "
") + news[++news.len] = list( + "channel" = channel.channel_name, + "author" = FM.author, + "body" = body, + "message_type" = FM.message_type, + "time_stamp" = FM.time_stamp, + "has_image" = (FM.img != null), + "caption" = FM.caption, + "time" = FM.post_time + ) + + // Cut out all but the youngest three + if(news.len > 3) + sortByKey(news, "time") + news.Cut(1, news.len - 2) // Last three have largest timestamps, youngest posts + news.Swap(1, 3) // List is sorted in ascending order of timestamp, we want descending + + return news \ No newline at end of file diff --git a/code/modules/pda/messenger.dm b/code/modules/pda/messenger.dm new file mode 100644 index 0000000000..a902bec3aa --- /dev/null +++ b/code/modules/pda/messenger.dm @@ -0,0 +1,247 @@ +/datum/data/pda/app/messenger + name = "Messenger" + icon = "comments-o" + notify_icon = "comments" + title = "SpaceMessenger V4.1.0" + template = "pda_messenger" + + var/toff = 0 //If 1, messenger disabled + var/list/tnote[0] //Current Texts + var/last_text //No text spamming + + var/m_hidden = 0 // Is the PDA hidden from the PDA list? + var/active_conversation = null // New variable that allows us to only view a single conversation. + var/list/conversations = list() // For keeping up with who we have PDA messsages from. + +/datum/data/pda/app/messenger/start() + . = ..() + unnotify() + +/datum/data/pda/app/messenger/update_ui(mob/user as mob, list/data) + data["silent"] = notify_silent // does the pda make noise when it receives a message? + data["toff"] = toff // is the messenger function turned off? + data["active_conversation"] = active_conversation // Which conversation are we following right now? + + has_back = active_conversation + if(active_conversation) + data["messages"] = tnote + for(var/c in tnote) + if(c["target"] == active_conversation) + data["convo_name"] = sanitize(c["owner"]) + data["convo_job"] = sanitize(c["job"]) + break + else + var/convopdas[0] + var/pdas[0] + for(var/A in PDAs) + var/obj/item/device/pda/P = A + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + + if(!P.owner || PM.toff || P == pda || PM.m_hidden) + continue + if(conversations.Find("\ref[P]")) + convopdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "1"))) + else + pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) + + data["convopdas"] = convopdas + data["pdas"] = pdas + + var/list/plugins = list() + if(pda.cartridge) + for(var/A in pda.cartridge.messenger_plugins) + var/datum/data/pda/messenger_plugin/P = A + plugins += list(list(name = P.name, icon = P.icon, ref = "\ref[P]")) + data["plugins"] = plugins + + if(pda.cartridge) + data["charges"] = pda.cartridge.charges ? pda.cartridge.charges : 0 + +/datum/data/pda/app/messenger/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + unnotify() + + . = TRUE + switch(action) + if("Toggle Messenger") + toff = !toff + if("Toggle Ringer")//If viewing texts then erase them, if not then toggle silent status + notify_silent = !notify_silent + if("Clear")//Clears messages + if(params["option"] == "All") + tnote.Cut() + conversations.Cut() + if(params["option"] == "Convo") + var/new_tnote[0] + for(var/i in tnote) + if(i["target"] != active_conversation) + new_tnote[++new_tnote.len] = i + tnote = new_tnote + conversations.Remove(active_conversation) + + active_conversation = null + if("Message") + var/obj/item/device/pda/P = locate(params["target"]) + create_message(usr, P) + if(params["target"] in conversations) // Need to make sure the message went through, if not welp. + active_conversation = params["target"] + if("Select Conversation") + var/P = params["target"] + for(var/n in conversations) + if(P == n) + active_conversation = P + if("Messenger Plugin") + if(!params["target"] || !params["plugin"]) + return + + var/obj/item/device/pda/P = locate(params["target"]) + if(!P) + to_chat(usr, "PDA not found.") + + var/datum/data/pda/messenger_plugin/plugin = locate(params["plugin"]) + if(plugin && (plugin in pda.cartridge.messenger_plugins)) + plugin.messenger = src + plugin.user_act(usr, P) + if("Back") + active_conversation = null + +// Specifically here for the chat message. +/datum/data/pda/app/messenger/Topic(href, href_list) + if(!pda.can_use(usr)) + return + unnotify() + + switch(href_list["choice"]) + if("Message") + var/obj/item/device/pda/P = locate(href_list["target"]) + create_message(usr, P) + if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp. + active_conversation = href_list["target"] + + +/datum/data/pda/app/messenger/proc/create_message(var/mob/living/U, var/obj/item/device/pda/P) + var/t = input(U, "Please enter message", name, null) as text|null + if(!t) + return + t = sanitize(copytext(t, 1, MAX_MESSAGE_LEN)) + t = readd_quotes(t) + if(!t || !istype(P)) + return + if(!in_range(pda, U) && pda.loc != U) + return + + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + + if(!PM || PM.toff || toff) + return + + if(last_text && world.time < last_text + 5) + return + + if(!pda.can_use(usr)) + return + + last_text = world.time + // check if telecomms I/O route 1459 is stable + //var/telecomms_intact = telecomms_process(P.owner, owner, t) + var/obj/machinery/message_server/useMS = null + if(message_servers) + for(var/A in message_servers) + var/obj/machinery/message_server/MS = A + //PDAs are now dependent on the Message Server. + if(MS.active) + useMS = MS + break + + var/datum/signal/signal = pda.telecomms_process() + + var/useTC = 0 + if(signal) + if(signal.data["done"]) + useTC = 1 + var/turf/pos = get_turf(P) + // TODO: Make the radio system cooperate with the space manager + if(pos.z in signal.data["level"]) + useTC = 2 + //Let's make this barely readable + if(signal.data["compression"] > 0) + t = Gibberish(t, signal.data["compression"] + 50) + + if(useMS && useTC) // only send the message if it's stable + if(useTC != 2) // Does our recipient have a broadcaster on their level? + to_chat(U, "ERROR: Cannot reach recipient.") + return + useMS.send_pda_message("[P.owner]","[pda.owner]","[t]") + pda.investigate_log("PDA Message - [U.key] - [pda.owner] -> [P.owner]: [t]", "pda") + + receive_message(list("sent" = 1, "owner" = "[P.owner]", "job" = "[P.ownjob]", "message" = "[t]", "target" = "\ref[P]"), "\ref[P]") + PM.receive_message(list("sent" = 0, "owner" = "[pda.owner]", "job" = "[pda.ownjob]", "message" = "[t]", "target" = "\ref[pda]"), "\ref[pda]") + + SStgui.update_user_uis(U, P) // Update the sending user's PDA UI so that they can see the new message + log_pda("(PDA: [src.name]) sent \"[t]\" to [P.name]", usr) + else + to_chat(U, "ERROR: Messaging server is not responding.") + +/datum/data/pda/app/messenger/proc/available_pdas() + var/list/names = list() + var/list/plist = list() + var/list/namecounts = list() + + if(toff) + to_chat(usr, "Turn on your receiver in order to send messages.") + return + + for(var/A in PDAs) + var/obj/item/device/pda/P = A + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + + if(!P.owner || !PM || PM.hidden || P == pda || PM.toff) + continue + + var/name = P.owner + if(name in names) + namecounts[name]++ + name = text("[name] ([namecounts[name]])") + else + names.Add(name) + namecounts[name] = 1 + + plist[text("[name]")] = P + return plist + +/datum/data/pda/app/messenger/proc/can_receive() + return pda.owner && !toff && !hidden + +/datum/data/pda/app/messenger/proc/receive_message(list/data, ref) + tnote.Add(list(data)) + if(!conversations.Find(ref)) + conversations.Add(ref) + if(!data["sent"]) + var/owner = data["owner"] + var/job = data["job"] + var/message = data["message"] + notify("Message from [owner] ([job]), \"[message]\" (Reply)") + +/datum/data/pda/app/messenger/multicast +/datum/data/pda/app/messenger/multicast/receive_message(list/data, ref) + . = ..() + + var/obj/item/device/pda/multicaster/M = pda + if(!istype(M)) + return + + var/list/modified_message = data.Copy() + modified_message["owner"] = modified_message["owner"] + " \[Relayed]" + modified_message["target"] = "\ref[M]" + + var/list/targets = list() + for(var/obj/item/device/pda/pda in PDAs) + if(pda.cartridge && pda.owner && is_type_in_list(pda.cartridge, M.cartridges_to_send_to)) + targets |= pda + if(targets.len) + for(var/obj/item/device/pda/target in targets) + var/datum/data/pda/app/messenger/P = target.find_program(/datum/data/pda/app/messenger) + if(P) + P.receive_message(modified_message, "\ref[M]") \ No newline at end of file diff --git a/code/modules/pda/messenger_plugins.dm b/code/modules/pda/messenger_plugins.dm new file mode 100644 index 0000000000..90cb9460a4 --- /dev/null +++ b/code/modules/pda/messenger_plugins.dm @@ -0,0 +1,91 @@ +/datum/data/pda/messenger_plugin + var/datum/data/pda/app/messenger/messenger + +/datum/data/pda/messenger_plugin/proc/user_act(mob/user as mob, obj/item/device/pda/P) + + +/datum/data/pda/messenger_plugin/virus + name = "*Send Virus*" + +/datum/data/pda/messenger_plugin/virus/user_act(mob/user as mob, obj/item/device/pda/P) + var/datum/data/pda/app/messenger/M = P.find_program(/datum/data/pda/app/messenger) + + if(M && !M.toff && pda.cartridge.charges > 0) + pda.cartridge.charges-- + return 1 + return 0 + + +/datum/data/pda/messenger_plugin/virus/clown + icon = "star" + +/datum/data/pda/messenger_plugin/virus/clown/user_act(mob/user as mob, obj/item/device/pda/P) + . = ..(user, P) + if(.) + user.show_message("Virus sent!", 1) + P.honkamt = (rand(15,20)) + P.ttone = "honk" + + +/datum/data/pda/messenger_plugin/virus/mime + icon = "arrow-circle-down" + +/datum/data/pda/messenger_plugin/virus/mime/user_act(mob/user as mob, obj/item/device/pda/P) + . = ..(user, P) + if(.) + user.show_message("Virus sent!", 1) + var/datum/data/pda/app/M = P.find_program(/datum/data/pda/app/messenger) + if(M) + M.notify_silent = 1 + P.ttone = "silence" + + +/datum/data/pda/messenger_plugin/virus/detonate + name = "*Detonate*" + icon = "exclamation-circle" + +/datum/data/pda/messenger_plugin/virus/detonate/user_act(mob/user as mob, obj/item/device/pda/P) + . = ..(user, P) + if(.) + var/difficulty = 0 + + if(pda.cartridge) + difficulty += pda.cartridge.programs.len / 2 + else + difficulty += 2 + + if(!P.detonate || P.hidden_uplink) + user.show_message("The target PDA does not seem to respond to the detonation command.", 1) + pda.cartridge.charges++ + else if(prob(difficulty * 12)) + user.show_message("An error flashes on your [pda].", 1) + else if(prob(difficulty * 3)) + user.show_message("Energy feeds back into your [pda]!", 1) + pda.close(user) + pda.explode() + log_admin("[key_name(user)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up") + message_admins("[key_name_admin(user)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up", 1) + else + user.show_message("Success!", 1) + log_admin("[key_name(user)] just attempted to blow up [P] with the Detomatix cartridge and succeded") + message_admins("[key_name_admin(user)] just attempted to blow up [P] with the Detomatix cartridge and succeded", 1) + P.explode() + +/datum/data/pda/messenger_plugin/virus/frame + icon = "exclamation-circle" + +/datum/data/pda/messenger_plugin/virus/frame/user_act(mob/user, obj/item/device/pda/P) + . = ..(user, P) + if(.) + var/lock_code = "[rand(100,999)] [pick("Alpha","Bravo","Charlie","Delta","Echo","Foxtrot","Golf","Hotel","India","Juliet","Kilo","Lima","Mike","November","Oscar","Papa","Quebec","Romeo","Sierra","Tango","Uniform","Victor","Whiskey","X-ray","Yankee","Zulu")]" + user.show_message("Virus Sent! The unlock code to the target is: [lock_code]") + if(!P.hidden_uplink) + var/obj/item/device/uplink/hidden/uplink = new(P) + P.hidden_uplink = uplink + P.lock_code = lock_code + // else + // P.hidden_uplink.hidden_crystals += P.hidden_uplink.uses //Temporarially hide the PDA's crystals, so you can't steal telecrystals. + var/obj/item/weapon/cartridge/frame/parent_cart = pda.cartridge + P.hidden_uplink.uses = parent_cart.telecrystals + parent_cart.telecrystals = 0 + P.hidden_uplink.active = TRUE diff --git a/code/modules/pda/pda.dm b/code/modules/pda/pda.dm new file mode 100644 index 0000000000..2c3b368730 --- /dev/null +++ b/code/modules/pda/pda.dm @@ -0,0 +1,494 @@ + +//The advanced pea-green monochrome lcd of tomorrow. + +var/global/list/obj/item/device/pda/PDAs = list() + +/obj/item/device/pda + name = "\improper PDA" + desc = "A portable microcomputer by Thinktronic Systems, LTD. Functionality determined by a preprogrammed ROM cartridge." + icon = 'icons/obj/pda.dmi' + icon_state = "pda" + item_state = "electronic" + w_class = ITEMSIZE_SMALL + slot_flags = SLOT_ID | SLOT_BELT + sprite_sheets = list(SPECIES_TESHARI = 'icons/mob/species/seromi/id.dmi') + + //Main variables + var/pdachoice = 1 + var/owner = null + var/default_cartridge = 0 // Access level defined by cartridge + var/obj/item/weapon/cartridge/cartridge = null //current cartridge + + //Secondary variables + var/model_name = "Thinktronic 5230 Personal Data Assistant" + var/datum/data/pda/utility/scanmode/scanmode = null + + var/lock_code = "" // Lockcode to unlock uplink + var/honkamt = 0 //How many honks left when infected with honk.exe + var/mimeamt = 0 //How many silence left when infected with mime.exe + var/detonate = 1 // Can the PDA be blown up? + var/ttone = "beep" //The ringtone! + var/list/ttone_sound = list("beep" = 'sound/machines/twobeep.ogg', + "boom" = 'sound/effects/explosionfar.ogg', + "slip" = 'sound/misc/slip.ogg', + "honk" = 'sound/items/bikehorn.ogg', + "SKREE" = 'sound/voice/shriek1.ogg', + // "holy" = 'sound/items/PDA/ambicha4-short.ogg', + "xeno" = 'sound/voice/hiss1.ogg') + var/hidden = 0 // Is the PDA hidden from the PDA list? + var/touch_silent = 0 //If 1, no beeps on interacting. + + var/obj/item/weapon/card/id/id = null //Making it possible to slot an ID card into the PDA so it can function as both. + var/ownjob = null //related to above - this is assignment (potentially alt title) + var/ownrank = null // this one is rank, never alt title + + var/obj/item/device/paicard/pai = null // A slot for a personal AI device + + var/spam_proof = FALSE // If true, it can't be spammed by random events. + + var/datum/data/pda/app/current_app = null + var/datum/data/pda/app/lastapp = null + var/list/programs = list( + new/datum/data/pda/app/main_menu, + new/datum/data/pda/app/notekeeper, + new/datum/data/pda/app/news, + new/datum/data/pda/app/messenger, + new/datum/data/pda/app/manifest, + new/datum/data/pda/app/atmos_scanner, + new/datum/data/pda/utility/scanmode/notes, + new/datum/data/pda/utility/flashlight) + var/list/shortcut_cache = list() + var/list/shortcut_cat_order = list() + var/list/notifying_programs = list() + var/retro_mode = 0 + +/obj/item/device/pda/examine(mob/user) + . = ..() + if(Adjacent(user)) + . += "The time [stationtime2text()] is displayed in the corner of the screen." + +/obj/item/device/pda/CtrlClick() + if(issilicon(usr)) + return + + if(can_use(usr)) + remove_pen() + return + ..() + +/obj/item/device/pda/AltClick() + if(issilicon(usr)) + return + + if ( can_use(usr) ) + if(id) + remove_id() + else + to_chat(usr, "This PDA does not have an ID in it.") + +/obj/item/device/pda/proc/play_ringtone() + var/S + + if(ttone in ttone_sound) + S = ttone_sound[ttone] + else + S = 'sound/machines/twobeep.ogg' + playsound(loc, S, 50, 1) + for(var/mob/O in hearers(3, loc)) + O.show_message(text("[bicon(src)] *[ttone]*")) + +/obj/item/device/pda/proc/set_ringtone() + var/t = input("Please enter new ringtone", name, ttone) as text + if(in_range(src, usr) && loc == usr) + if(t) + if(hidden_uplink && hidden_uplink.check_trigger(usr, lowertext(t), lowertext(lock_code))) + to_chat(usr, "The PDA softly beeps.") + close(usr) + else + t = sanitize(copytext(t, 1, 20)) + ttone = t + return 1 + else + close(usr) + return 0 + +/obj/item/device/pda/New(var/mob/living/carbon/human/H) + ..() + PDAs += src + PDAs = sortAtom(PDAs) + update_programs() + if(default_cartridge) + cartridge = new default_cartridge(src) + cartridge.update_programs(src) + new /obj/item/weapon/pen(src) + pdachoice = isnull(H) ? 1 : (ishuman(H) ? H.pdachoice : 1) + switch(pdachoice) + if(1) icon = 'icons/obj/pda.dmi' + if(2) icon = 'icons/obj/pda_slim.dmi' + if(3) icon = 'icons/obj/pda_old.dmi' + if(4) icon = 'icons/obj/pda_rugged.dmi' + if(5) icon = 'icons/obj/pda_holo.dmi' + if(6) + icon = 'icons/obj/pda_wrist.dmi' + item_state = icon_state + item_icons = list( + slot_belt_str = 'icons/mob/pda_wrist.dmi', + slot_wear_id_str = 'icons/mob/pda_wrist.dmi', + slot_gloves_str = 'icons/mob/pda_wrist.dmi' + ) + desc = "A portable microcomputer by Thinktronic Systems, LTD. This model is a wrist-bound version." + slot_flags = SLOT_ID | SLOT_BELT | SLOT_GLOVES + sprite_sheets = list( + SPECIES_TESHARI = 'icons/mob/species/seromi/pda_wrist.dmi', + SPECIES_VR_TESHARI = 'icons/mob/species/seromi/pda_wrist.dmi', + ) + else + icon = 'icons/obj/pda_old.dmi' + log_debug("Invalid switch for PDA, defaulting to old PDA icons. [pdachoice] chosen.") + start_program(find_program(/datum/data/pda/app/main_menu)) + +/obj/item/device/pda/proc/can_use(mob/user) + return (tgui_status(user, GLOB.tgui_inventory_state) == STATUS_INTERACTIVE) + +/obj/item/device/pda/GetAccess() + if(id) + return id.GetAccess() + else + return ..() + +/obj/item/device/pda/GetID() + return id + +/obj/item/device/pda/MouseDrop(obj/over_object as obj, src_location, over_location) + var/mob/M = usr + if((!istype(over_object, /obj/screen)) && can_use(usr)) + return attack_self(M) + return + +/obj/item/device/pda/proc/close(mob/user) + SStgui.close_uis(src) + +/obj/item/device/pda/attack_self(mob/user as mob) + user.set_machine(src) + + if(active_uplink_check(user)) + return + + tgui_interact(user) + return + +/obj/item/device/pda/proc/start_program(datum/data/pda/P) + if(P && ((P in programs) || (cartridge && (P in cartridge.programs)))) + return P.start() + return 0 + +/obj/item/device/pda/proc/find_program(type) + var/datum/data/pda/A = locate(type) in programs + if(A) + return A + if(cartridge) + A = locate(type) in cartridge.programs + if(A) + return A + return null + +// force the cache to rebuild on update_ui +/obj/item/device/pda/proc/update_shortcuts() + shortcut_cache.Cut() + +/obj/item/device/pda/proc/update_programs() + for(var/A in programs) + var/datum/data/pda/P = A + P.pda = src + +/obj/item/device/pda/proc/detonate_act(var/obj/item/device/pda/P) + //TODO: sometimes these attacks show up on the message server + var/i = rand(1,100) + var/j = rand(0,1) //Possibility of losing the PDA after the detonation + var/message = "" + var/mob/living/M = null + if(ismob(P.loc)) + M = P.loc + + //switch(i) //Yes, the overlapping cases are intended. + if(i<=10) //The traditional explosion + P.explode() + j=1 + message += "Your [P] suddenly explodes!" + if(i>=10 && i<= 20) //The PDA burns a hole in the holder. + j=1 + if(M && isliving(M)) + M.apply_damage( rand(30,60) , BURN) + message += "You feel a searing heat! Your [P] is burning!" + if(i>=20 && i<=25) //EMP + empulse(P.loc, 1, 2, 4, 6, 1) + message += "Your [P] emits a wave of electromagnetic energy!" + if(i>=25 && i<=40) //Smoke + var/datum/effect/effect/system/smoke_spread/chem/S = new /datum/effect/effect/system/smoke_spread/chem + S.attach(P.loc) + S.set_up(P, 10, 0, P.loc) + playsound(P, 'sound/effects/smoke.ogg', 50, 1, -3) + S.start() + message += "Large clouds of smoke billow forth from your [P]!" + if(i>=40 && i<=45) //Bad smoke + var/datum/effect/effect/system/smoke_spread/bad/B = new /datum/effect/effect/system/smoke_spread/bad + B.attach(P.loc) + B.set_up(P, 10, 0, P.loc) + playsound(P, 'sound/effects/smoke.ogg', 50, 1, -3) + B.start() + message += "Large clouds of noxious smoke billow forth from your [P]!" + if(i>=65 && i<=75) //Weaken + if(M && isliving(M)) + M.apply_effects(0,1) + message += "Your [P] flashes with a blinding white light! You feel weaker." + if(i>=75 && i<=85) //Stun and stutter + if(M && isliving(M)) + M.apply_effects(1,0,0,0,1) + message += "Your [P] flashes with a blinding white light! You feel weaker." + if(i>=85) //Sparks + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(2, 1, P.loc) + s.start() + message += "Your [P] begins to spark violently!" + if(i>45 && i<65 && prob(50)) //Nothing happens + message += "Your [P] bleeps loudly." + j = prob(10) + + if(j && detonate) //This kills the PDA + qdel(P) + if(message) + message += "It melts in a puddle of plastic." + else + message += "Your [P] shatters in a thousand pieces!" + + if(M && isliving(M)) + message = "[message]" + M.show_message(message, 1) + +/obj/item/device/pda/proc/remove_id() + if (id) + if (ismob(loc)) + var/mob/M = loc + M.put_in_hands(id) + to_chat(usr, "You remove the ID from the [name].") + playsound(src, 'sound/machines/id_swipe.ogg', 100, 1) + else + id.loc = get_turf(src) + id = null + +/obj/item/device/pda/proc/remove_pen() + var/obj/item/weapon/pen/O = locate() in src + if(O) + if(istype(loc, /mob)) + var/mob/M = loc + if(M.get_active_hand() == null) + M.put_in_hands(O) + to_chat(usr, "You remove \the [O] from \the [src].") + return + O.loc = get_turf(src) + else + to_chat(usr, "This PDA does not have a pen in it.") + +/obj/item/device/pda/verb/verb_reset_pda() + set category = "Object" + set name = "Reset PDA" + set src in usr + + if(issilicon(usr)) + return + + if(can_use(usr)) + start_program(find_program(/datum/data/pda/app/main_menu)) + notifying_programs.Cut() + overlays -= image('icons/obj/pda.dmi', "pda-r") + to_chat(usr, "You press the reset button on \the [src].") + else + to_chat(usr, "You cannot do this while restrained.") + +/obj/item/device/pda/verb/verb_remove_id() + set category = "Object" + set name = "Remove id" + set src in usr + + if(issilicon(usr)) + return + + if ( can_use(usr) ) + if(id) + remove_id() + else + to_chat(usr, "This PDA does not have an ID in it.") + else + to_chat(usr, "You cannot do this while restrained.") + + +/obj/item/device/pda/verb/verb_remove_pen() + set category = "Object" + set name = "Remove pen" + set src in usr + + if(issilicon(usr)) + return + + if ( can_use(usr) ) + remove_pen() + else + to_chat(usr, "You cannot do this while restrained.") + +/obj/item/device/pda/verb/verb_remove_cartridge() + set category = "Object" + set name = "Remove cartridge" + set src in usr + + if(issilicon(usr)) + return + + if(!can_use(usr)) + to_chat(usr, "You cannot do this while restrained.") + return + + if(isnull(cartridge)) + to_chat(usr, "There's no cartridge to eject.") + return + + cartridge.forceMove(get_turf(src)) + if(ismob(loc)) + var/mob/M = loc + M.put_in_hands(cartridge) + // mode = 0 + // scanmode = 0 + if (cartridge.radio) + cartridge.radio.hostpda = null + to_chat(usr, "You remove \the [cartridge] from the [name].") + playsound(src, 'sound/machines/id_swipe.ogg', 100, 1) + cartridge = null + update_programs() + update_shortcuts() + start_program(find_program(/datum/data/pda/app/main_menu)) + + +/obj/item/device/pda/proc/id_check(mob/user as mob, choice as num)//To check for IDs; 1 for in-pda use, 2 for out of pda use. + if(choice == 1) + if (id) + remove_id() + return 1 + else + var/obj/item/I = user.get_active_hand() + if (istype(I, /obj/item/weapon/card/id) && user.unEquip(I)) + I.loc = src + id = I + return 1 + else + var/obj/item/weapon/card/I = user.get_active_hand() + if (istype(I, /obj/item/weapon/card/id) && I:registered_name && user.unEquip(I)) + var/obj/old_id = id + I.loc = src + id = I + user.put_in_hands(old_id) + return 1 + return 0 + +// access to status display signals +/obj/item/device/pda/attackby(obj/item/C as obj, mob/user as mob) + ..() + if(istype(C, /obj/item/weapon/cartridge) && !cartridge) + cartridge = C + user.drop_item() + cartridge.loc = src + cartridge.update_programs(src) + update_shortcuts() + to_chat(usr, "You insert [cartridge] into [src].") + if(cartridge.radio) + cartridge.radio.hostpda = src + + else if(istype(C, /obj/item/weapon/card/id)) + var/obj/item/weapon/card/id/idcard = C + if(!idcard.registered_name) + to_chat(user, "\The [src] rejects the ID.") + return + if(!owner) + owner = idcard.registered_name + ownjob = idcard.assignment + ownrank = idcard.rank + name = "PDA-[owner] ([ownjob])" + to_chat(user, "Card scanned.") + else + //Basic safety check. If either both objects are held by user or PDA is on ground and card is in hand. + if(((src in user.contents) && (C in user.contents)) || (istype(loc, /turf) && in_range(src, user) && (C in user.contents)) ) + if(id_check(user, 2)) + to_chat(user, "You put the ID into \the [src]'s slot.") + updateSelfDialog()//Update self dialog on success. + return //Return in case of failed check or when successful. + updateSelfDialog()//For the non-input related code. + else if(istype(C, /obj/item/device/paicard) && !src.pai) + user.drop_item() + C.loc = src + pai = C + to_chat(user, "You slot \the [C] into \the [src].") + SStgui.update_uis(src) // update all UIs attached to src + else if(istype(C, /obj/item/weapon/pen)) + var/obj/item/weapon/pen/O = locate() in src + if(O) + to_chat(user, "There is already a pen in \the [src].") + else + user.drop_item() + C.loc = src + to_chat(user, "You slot \the [C] into \the [src].") + return + +/obj/item/device/pda/attack(mob/living/C as mob, mob/living/user as mob) + if (istype(C, /mob/living/carbon) && scanmode) + scanmode.scan_mob(C, user) + +/obj/item/device/pda/afterattack(atom/A as mob|obj|turf|area, mob/user as mob, proximity) + if(proximity && scanmode) + scanmode.scan_atom(A, user) + +/obj/item/device/pda/proc/explode() //This needs tuning. //Sure did. + if(!src.detonate) return + var/turf/T = get_turf(src.loc) + if(T) + T.hotspot_expose(700,125) + explosion(T, 0, 0, 1, rand(1,2)) + return + +/obj/item/device/pda/Destroy() + PDAs -= src + if (src.id && prob(100) && !delete_id) //IDs are kept in 90% of the cases //VOREStation Edit - 100% of the cases, excpet when specified otherwise + src.id.forceMove(get_turf(src.loc)) + else + QDEL_NULL(src.id) + + current_app = null + scanmode = null + QDEL_NULL(pai) + QDEL_LIST(programs) + QDEL_NULL(cartridge) + return ..() + +//Some spare PDAs in a box +/obj/item/weapon/storage/box/PDAs + name = "box of spare PDAs" + desc = "A box of spare PDA microcomputers." + icon = 'icons/obj/pda.dmi' + icon_state = "pdabox" + +/obj/item/weapon/storage/box/PDAs/New() + ..() + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/weapon/cartridge/head(src) + + var/newcart = pick( /obj/item/weapon/cartridge/engineering, + /obj/item/weapon/cartridge/security, + /obj/item/weapon/cartridge/medical, + /obj/item/weapon/cartridge/signal/science, + /obj/item/weapon/cartridge/quartermaster) + new newcart(src) + +// Pass along the pulse to atoms in contents, largely added so pAIs are vulnerable to EMP +/obj/item/device/pda/emp_act(severity) + for(var/atom/A in src) + A.emp_act(severity) diff --git a/code/modules/pda/pda_subtypes.dm b/code/modules/pda/pda_subtypes.dm new file mode 100644 index 0000000000..11b684b678 --- /dev/null +++ b/code/modules/pda/pda_subtypes.dm @@ -0,0 +1,246 @@ + +/obj/item/device/pda/medical + default_cartridge = /obj/item/weapon/cartridge/medical + icon_state = "pda-m" + +/obj/item/device/pda/viro + default_cartridge = /obj/item/weapon/cartridge/medical + icon_state = "pda-v" + +/obj/item/device/pda/engineering + default_cartridge = /obj/item/weapon/cartridge/engineering + icon_state = "pda-e" + +/obj/item/device/pda/security + default_cartridge = /obj/item/weapon/cartridge/security + icon_state = "pda-s" + +/obj/item/device/pda/detective + default_cartridge = /obj/item/weapon/cartridge/detective + icon_state = "pda-det" + +/obj/item/device/pda/warden + default_cartridge = /obj/item/weapon/cartridge/security + icon_state = "pda-warden" + +/obj/item/device/pda/janitor + default_cartridge = /obj/item/weapon/cartridge/janitor + icon_state = "pda-j" + ttone = "slip" + +/obj/item/device/pda/science + default_cartridge = /obj/item/weapon/cartridge/signal/science + icon_state = "pda-tox" + ttone = "boom" + +/obj/item/device/pda/clown + default_cartridge = /obj/item/weapon/cartridge/clown + icon_state = "pda-clown" + desc = "A portable microcomputer by Thinktronic Systems, LTD. The surface is coated with polytetrafluoroethylene and banana drippings." + ttone = "honk" + +/obj/item/device/pda/mime + default_cartridge = /obj/item/weapon/cartridge/mime + icon_state = "pda-mime" + +/obj/item/device/pda/mime/New() + . = ..() + var/datum/data/pda/app/M = find_program(/datum/data/pda/app/messenger) + if(M) + M.notify_silent = TRUE + +/obj/item/device/pda/heads + default_cartridge = /obj/item/weapon/cartridge/head + icon_state = "pda-h" + +/obj/item/device/pda/heads/hop + default_cartridge = /obj/item/weapon/cartridge/hop + icon_state = "pda-hop" + +/obj/item/device/pda/heads/hos + default_cartridge = /obj/item/weapon/cartridge/hos + icon_state = "pda-hos" + +/obj/item/device/pda/heads/ce + default_cartridge = /obj/item/weapon/cartridge/ce + icon_state = "pda-ce" + +/obj/item/device/pda/heads/cmo + default_cartridge = /obj/item/weapon/cartridge/cmo + icon_state = "pda-cmo" + +/obj/item/device/pda/heads/rd + default_cartridge = /obj/item/weapon/cartridge/rd + icon_state = "pda-rd" + +/obj/item/device/pda/captain + default_cartridge = /obj/item/weapon/cartridge/captain + icon_state = "pda-c" + detonate = 0 + //toff = 1 + +/obj/item/device/pda/ert + default_cartridge = /obj/item/weapon/cartridge/captain + icon_state = "pda-h" + detonate = 0 +// hidden = 1 + +/obj/item/device/pda/cargo + default_cartridge = /obj/item/weapon/cartridge/quartermaster + icon_state = "pda-cargo" + +/obj/item/device/pda/quartermaster + default_cartridge = /obj/item/weapon/cartridge/quartermaster + icon_state = "pda-q" + +/obj/item/device/pda/shaftminer + icon_state = "pda-miner" + default_cartridge = /obj/item/weapon/cartridge/miner + +/obj/item/device/pda/syndicate + default_cartridge = /obj/item/weapon/cartridge/syndicate + icon_state = "pda-syn" +// name = "Military PDA" // Vorestation Edit +// owner = "John Doe" + hidden = 1 + +/obj/item/device/pda/chaplain + default_cartridge = /obj/item/weapon/cartridge/service + icon_state = "pda-holy" + ttone = "holy" + +/obj/item/device/pda/lawyer + default_cartridge = /obj/item/weapon/cartridge/lawyer + icon_state = "pda-lawyer" + ttone = "..." + +/obj/item/device/pda/botanist + default_cartridge = /obj/item/weapon/cartridge/service + icon_state = "pda-hydro" + +/obj/item/device/pda/roboticist + default_cartridge = /obj/item/weapon/cartridge/signal/science + icon_state = "pda-robot" + +/obj/item/device/pda/librarian + default_cartridge = /obj/item/weapon/cartridge/service + icon_state = "pda-libb" + desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a WGW-11 series e-reader." + model_name = "Thinktronic 5290 WGW-11 Series E-reader and Personal Data Assistant" + +/obj/item/device/pda/librarian/New() + . = ..() + var/datum/data/pda/app/M = find_program(/datum/data/pda/app/messenger) + if(M) + M.notify_silent = TRUE //Quiet in the library! + +/obj/item/device/pda/clear + icon_state = "pda-transp" + desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a special edition with a transparent case." + model_name = "Thinktronic 5230 Personal Data Assistant Deluxe Special Max Turbo Limited Edition" + +/obj/item/device/pda/chef + default_cartridge = /obj/item/weapon/cartridge/service + icon_state = "pda-chef" + +/obj/item/device/pda/bar + default_cartridge = /obj/item/weapon/cartridge/service + icon_state = "pda-bar" + +/obj/item/device/pda/atmos + default_cartridge = /obj/item/weapon/cartridge/atmos + icon_state = "pda-atmo" + +/obj/item/device/pda/chemist + default_cartridge = /obj/item/weapon/cartridge/chemistry + icon_state = "pda-chem" + +/obj/item/device/pda/geneticist + default_cartridge = /obj/item/weapon/cartridge/medical + icon_state = "pda-gene" + + +// Used for the PDA multicaster, which mirrors messages sent to it to a specific department, +/obj/item/device/pda/multicaster + ownjob = "Relay" + icon_state = "NONE" + detonate = 0 + spam_proof = TRUE // Spam messages don't actually work and its difficult to disable these. + programs = list( + new/datum/data/pda/app/messenger/multicast + ) + var/list/cartridges_to_send_to = list() + +/obj/item/device/pda/multicaster/command/New() + ..() + owner = "Command Department" + name = "Command Department (Relay)" + cartridges_to_send_to = command_cartridges + +/obj/item/device/pda/multicaster/security/New() + ..() + owner = "Security Department" + name = "Security Department (Relay)" + cartridges_to_send_to = security_cartridges + +/obj/item/device/pda/multicaster/engineering/New() + ..() + owner = "Engineering Department" + name = "Engineering Department (Relay)" + cartridges_to_send_to = engineering_cartridges + +/obj/item/device/pda/multicaster/medical/New() + ..() + owner = "Medical Department" + name = "Medical Department (Relay)" + cartridges_to_send_to = medical_cartridges + +/obj/item/device/pda/multicaster/research/New() + ..() + owner = "Research Department" + name = "Research Department (Relay)" + cartridges_to_send_to = research_cartridges + +/obj/item/device/pda/multicaster/cargo/New() + ..() + owner = "Cargo Department" + name = "Cargo Department (Relay)" + cartridges_to_send_to = cargo_cartridges + +/obj/item/device/pda/multicaster/civilian/New() + ..() + owner = "Civilian Services Department" + name = "Civilian Services Department (Relay)" + cartridges_to_send_to = civilian_cartridges + +/obj/item/device/pda/clown/Crossed(atom/movable/AM as mob|obj) //Clown PDA is slippery. + if(AM.is_incorporeal()) + return + if (istype(AM, /mob/living)) + var/mob/living/M = AM + + if(M.slip("the PDA",8) && M.real_name != src.owner && istype(src.cartridge, /obj/item/weapon/cartridge/clown)) + if(src.cartridge.charges < 5) + src.cartridge.charges++ + +//Some spare PDAs in a box +/obj/item/weapon/storage/box/PDAs + name = "box of spare PDAs" + desc = "A box of spare PDA microcomputers." + icon = 'icons/obj/pda.dmi' + icon_state = "pdabox" + +/obj/item/weapon/storage/box/PDAs/New() + ..() + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/weapon/cartridge/head(src) + + var/newcart = pick( /obj/item/weapon/cartridge/engineering, + /obj/item/weapon/cartridge/security, + /obj/item/weapon/cartridge/medical, + /obj/item/weapon/cartridge/signal/science, + /obj/item/weapon/cartridge/quartermaster) + new newcart(src) diff --git a/code/modules/pda/pda_tgui.dm b/code/modules/pda/pda_tgui.dm new file mode 100644 index 0000000000..6d57a6c25e --- /dev/null +++ b/code/modules/pda/pda_tgui.dm @@ -0,0 +1,116 @@ +// Self contained file for all things TGUI +/obj/item/device/pda/tgui_state(mob/user) + return GLOB.tgui_inventory_state + +/obj/item/device/pda/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Pda", "Personal Data Assistant", parent_ui) + ui.open() + +/obj/item/device/pda/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + data["owner"] = owner // Who is your daddy... + data["ownjob"] = ownjob // ...and what does he do? + + // update list of shortcuts, only if they changed + if(!shortcut_cache.len) + shortcut_cache = list() + shortcut_cat_order = list() + var/prog_list = programs.Copy() + if(cartridge) + prog_list |= cartridge.programs + + for(var/A in prog_list) + var/datum/data/pda/P = A + + if(P.hidden) + continue + var/list/cat + if(P.category in shortcut_cache) + cat = shortcut_cache[P.category] + else + cat = list() + shortcut_cache[P.category] = cat + shortcut_cat_order += P.category + cat |= list(list(name = P.name, icon = P.icon, notify_icon = P.notify_icon, ref = "\ref[P]")) + + // force the order of a few core categories + shortcut_cat_order = list("General") \ + + sortList(shortcut_cat_order - list("General", "Scanners", "Utilities")) \ + + list("Scanners", "Utilities") + + data["idInserted"] = (id ? 1 : 0) + data["idLink"] = (id ? text("[id.registered_name], [id.assignment]") : "--------") + + data["useRetro"] = retro_mode + data["touch_silent"] = touch_silent + + data["cartridge_name"] = cartridge ? cartridge.name : "" + data["stationTime"] = stationtime2text() //worldtime2stationtime(world.time) // Aaa which fucking one is canonical there's SO MANY + + data["app"] = list( + "name" = current_app.title, + "icon" = current_app.icon, + "template" = current_app.template, + "has_back" = current_app.has_back) + + current_app.update_ui(user, data) + + return data + +/obj/item/device/pda/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + add_fingerprint(usr) + usr.set_machine(src) + + if(!touch_silent) + playsound(src, 'sound/machines/pda_click.ogg', 20) + + . = TRUE + switch(action) + if("Home") //Go home, largely replaces the old Return + var/datum/data/pda/app/main_menu/A = find_program(/datum/data/pda/app/main_menu) + if(A) + start_program(A) + if("StartProgram") + if(params["program"]) + var/datum/data/pda/app/A = locate(params["program"]) + if(A) + start_program(A) + if("Eject")//Ejects the cart, only done from hub. + if(!isnull(cartridge)) + var/turf/T = loc + if(ismob(T)) + T = T.loc + var/obj/item/weapon/cartridge/C = cartridge + C.forceMove(T) + if(scanmode in C.programs) + scanmode = null + if(current_app in C.programs) + start_program(find_program(/datum/data/pda/app/main_menu)) + if(C.radio) + C.radio.hostpda = null + for(var/datum/data/pda/P in notifying_programs) + if(P in C.programs) + P.unnotify() + cartridge = null + update_shortcuts() + if("Authenticate")//Checks for ID + id_check(usr, 1) + if("Retro") + retro_mode = !retro_mode + if("TouchSounds") + touch_silent = !touch_silent + if("Ringtone") + return set_ringtone() + else + if(current_app) + . = current_app.tgui_act(action, params, ui, state) + + if((honkamt > 0) && (prob(60)))//For clown virus. + honkamt-- + playsound(loc, 'sound/items/bikehorn.ogg', 30, 1) diff --git a/code/game/objects/items/devices/PDA/PDA_vr.dm b/code/modules/pda/pda_vr.dm similarity index 100% rename from code/game/objects/items/devices/PDA/PDA_vr.dm rename to code/modules/pda/pda_vr.dm diff --git a/code/modules/pda/radio.dm b/code/modules/pda/radio.dm new file mode 100644 index 0000000000..0d3b115a13 --- /dev/null +++ b/code/modules/pda/radio.dm @@ -0,0 +1,138 @@ +/obj/item/radio/integrated + name = "\improper PDA radio module" + desc = "An electronic radio system." + icon = 'icons/obj/module.dmi' + icon_state = "power_mod" + var/obj/item/device/pda/hostpda = null + + var/list/botlist = null // list of bots + var/mob/living/bot/active // the active bot; if null, show bot list + var/list/botstatus // the status signal sent by the bot + + var/bot_type //The type of bot it is. + var/bot_filter //Determines which radio filter to use. + + var/control_freq = BOT_FREQ + + var/on = 0 //Are we currently active?? + var/menu_message = "" + +/obj/item/radio/integrated/New() + ..() + if(istype(loc.loc, /obj/item/device/pda)) + hostpda = loc.loc + if(bot_filter) + spawn(5) + add_to_radio(bot_filter) + +/obj/item/radio/integrated/Destroy() + if(radio_controller) + radio_controller.remove_object(src, control_freq) + hostpda = null + return ..() + +/obj/item/radio/integrated/proc/post_signal(var/freq, var/key, var/value, var/key2, var/value2, var/key3, var/value3, s_filter) + + //to_world("Post: [freq]: [key]=[value], [key2]=[value2]") + var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq) + + if(!frequency) + return + + var/datum/signal/signal = new() + signal.source = src + signal.transmission_method = TRANSMISSION_RADIO + signal.data[key] = value + if(key2) + signal.data[key2] = value2 + if(key3) + signal.data[key3] = value3 + + frequency.post_signal(src, signal, radio_filter = s_filter) + +/obj/item/radio/integrated/Topic(href, href_list) + ..() + switch(href_list["op"]) + if("control") + active = locate(href_list["bot"]) + spawn(0) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) + + if("scanbots") // find all bots + botlist = null + spawn(0) + post_signal(control_freq, "command", "bot_status", s_filter = bot_filter) + + if("botlist") + active = null + + if("stop", "go", "home") + spawn(0) + post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = bot_filter) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) + + if("summon") + spawn(0) + post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(hostpda), "useraccess", hostpda.GetAccess(), "user", usr, s_filter = bot_filter) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) + +/obj/item/radio/integrated/receive_signal(datum/signal/signal) + if(bot_type && istype(signal.source, /mob/living/bot) && signal.data["type"] == bot_type) + if(!botlist) + botlist = new() + + botlist |= signal.source + + if(active == signal.source) + var/list/b = signal.data + botstatus = b.Copy() + +/obj/item/radio/integrated/proc/add_to_radio(bot_filter) //Master filter control for bots. Must be placed in the bot's local New() to support map spawned bots. + if(radio_controller) + radio_controller.add_object(src, control_freq, radio_filter = bot_filter) + +/* + * Radio Cartridge, essentially a signaler. + */ +/obj/item/radio/integrated/signal + var/frequency = 1457 + var/code = 30.0 + var/last_transmission + var/datum/radio_frequency/radio_connection + +/obj/item/radio/integrated/signal/Destroy() + if(radio_controller) + radio_controller.remove_object(src, frequency) + radio_connection = null + return ..() + +/obj/item/radio/integrated/signal/Initialize() + if(!radio_controller) + return + + if(src.frequency < PUBLIC_LOW_FREQ || src.frequency > PUBLIC_HIGH_FREQ) + src.frequency = sanitize_frequency(src.frequency) + + set_frequency(frequency) + +/obj/item/radio/integrated/signal/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency) + +/obj/item/radio/integrated/signal/proc/send_signal(message="ACTIVATE") + if(last_transmission && world.time < (last_transmission + 5)) + return + last_transmission = world.time + + var/time = time2text(world.realtime,"hh:mm:ss") + var/turf/T = get_turf(src) + lastsignalers.Add("[time] : [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) : [format_frequency(frequency)]/[code]") + + var/datum/signal/signal = new + signal.source = src + signal.encryption = code + signal.data["message"] = message + + spawn(0) + radio_connection.post_signal(src, signal) diff --git a/code/modules/pda/utilities.dm b/code/modules/pda/utilities.dm new file mode 100644 index 0000000000..be8bb8f444 --- /dev/null +++ b/code/modules/pda/utilities.dm @@ -0,0 +1,184 @@ +/datum/data/pda/utility/flashlight + name = "Enable Flashlight" + icon = "lightbulb-o" + + var/fon = 0 //Is the flashlight function on? + var/f_lum = 2 //Luminosity for the flashlight function + +/datum/data/pda/utility/flashlight/start() + fon = !fon + name = fon ? "Disable Flashlight" : "Enable Flashlight" + pda.update_shortcuts() + pda.set_light(fon ? f_lum : 0) + +/datum/data/pda/utility/honk + name = "Honk Synthesizer" + icon = "smile-o" + category = "Clown" + + var/last_honk //Also no honk spamming that's bad too + +/datum/data/pda/utility/honk/start() + if(!(last_honk && world.time < last_honk + 20)) + playsound(pda.loc, 'sound/items/bikehorn.ogg', 50, 1) + last_honk = world.time + +/datum/data/pda/utility/toggle_door + name = "Toggle Door" + icon = "external-link" + var/remote_door_id = "" + +// /datum/data/pda/utility/toggle_door/start() +// for(var/obj/machinery/door/poddoor/M in airlocks) +// if(M.id_tag == remote_door_id) +// if(M.density) +// M.open() +// else +// M.close() + +/datum/data/pda/utility/scanmode/medical + base_name = "Med Scanner" + icon = "heart-o" + +/datum/data/pda/utility/scanmode/medical/scan_mob(mob/living/C as mob, mob/living/user as mob) + C.visible_message("[user] has analyzed [C]'s vitals!") + + user.show_message("Analyzing Results for [C]:") + user.show_message(" Overall Status: [C.stat > 1 ? "dead" : "[C.health - C.halloss]% healthy"]", 1) + user.show_message(text(" Damage Specifics: []-[]-[]-[]", + (C.getOxyLoss() > 50) ? "warning" : "", C.getOxyLoss(), + (C.getToxLoss() > 50) ? "warning" : "", C.getToxLoss(), + (C.getFireLoss() > 50) ? "warning" : "", C.getFireLoss(), + (C.getBruteLoss() > 50) ? "warning" : "", C.getBruteLoss() + ), 1) + user.show_message(" Key: Suffocation/Toxin/Burns/Brute", 1) + user.show_message(" Body Temperature: [C.bodytemperature-T0C]°C ([C.bodytemperature*1.8-459.67]°F)", 1) + if(C.tod && (C.stat == DEAD || (C.status_flags & FAKEDEATH))) + user.show_message(" Time of Death: [C.tod]") + if(istype(C, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = C + var/list/damaged = H.get_damaged_organs(1,1) + user.show_message("Localized Damage, Brute/Burn:",1) + if(length(damaged)>0) + for(var/obj/item/organ/external/org in damaged) + user.show_message(text(" []: []-[]", + capitalize(org.name), (org.brute_dam > 0) ? "warning" : "notice", org.brute_dam, (org.burn_dam > 0) ? "warning" : "notice", org.burn_dam),1) + else + user.show_message(" Limbs are OK.",1) + +/datum/data/pda/utility/scanmode/dna + base_name = "DNA Scanner" + icon = "link" + +/datum/data/pda/utility/scanmode/dna/scan_mob(mob/living/C as mob, mob/living/user as mob) + if(istype(C, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = C + if(!istype(H.dna, /datum/dna)) + to_chat(user, "No fingerprints found on [H]") + else + to_chat(user, "[H]'s Fingerprints: [md5(H.dna.uni_identity)]") + scan_blood(C, user) + +/datum/data/pda/utility/scanmode/dna/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) + scan_blood(A, user) + +/datum/data/pda/utility/scanmode/dna/proc/scan_blood(atom/A, mob/user) + if(!A.blood_DNA) + to_chat(user, "No blood found on [A]") + if(A.blood_DNA) + qdel(A.blood_DNA) + else + to_chat(user, "Blood found on [A]. Analysing...") + spawn(15) + for(var/blood in A.blood_DNA) + to_chat(user, "Blood type: [A.blood_DNA[blood]]\nDNA: [blood]") + +/datum/data/pda/utility/scanmode/halogen + base_name = "Halogen Counter" + icon = "exclamation-circle" + +/datum/data/pda/utility/scanmode/halogen/scan_mob(mob/living/C as mob, mob/living/user as mob) + C.visible_message("[user] has analyzed [C]'s radiation levels!") + + user.show_message("Analyzing Results for [C]:") + if(C.radiation) + user.show_message("Radiation Level: [C.radiation > 0 ? "[C.radiation]" : "0"]") + else + user.show_message("No radiation detected.") + +/datum/data/pda/utility/scanmode/reagent + base_name = "Reagent Scanner" + icon = "flask" + +/datum/data/pda/utility/scanmode/reagent/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) + if(!isnull(A.reagents)) + if(A.reagents.reagent_list.len > 0) + var/reagents_length = A.reagents.reagent_list.len + to_chat(user, "[reagents_length] chemical agent[reagents_length > 1 ? "s" : ""] found.") + for(var/re in A.reagents.reagent_list) + to_chat(user, "\t [re]") + else + to_chat(user, "No active chemical agents found in [A].") + else + to_chat(user, "No significant chemical agents found in [A].") + +/datum/data/pda/utility/scanmode/gas + base_name = "Gas Scanner" + icon = "tachometer-alt" + +/datum/data/pda/utility/scanmode/gas/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) + pda.analyze_gases(A, user) + +/datum/data/pda/utility/scanmode/notes + base_name = "Note Scanner" + icon = "clipboard" + var/datum/data/pda/app/notekeeper/notes + +/datum/data/pda/utility/scanmode/notes/start() + . = ..() + notes = pda.find_program(/datum/data/pda/app/notekeeper) + +/datum/data/pda/utility/scanmode/notes/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) + if(notes && istype(A, /obj/item/weapon/paper)) + var/obj/item/weapon/paper/P = A + var/list/brlist = list("p", "/p", "br", "hr", "h1", "h2", "h3", "h4", "/h1", "/h2", "/h3", "/h4") + + // JMO 20140705: Makes scanned document show up properly in the notes. Not pretty for formatted documents, + // as this will clobber the HTML, but at least it lets you scan a document. You can restore the original + // notes by editing the note again. (Was going to allow you to edit, but scanned documents are too long.) + var/raw_scan = sanitize_simple(P.info, list("\t" = "", "ÿ" = "")) + var/formatted_scan = "" + // Scrub out the tags (replacing a few formatting ones along the way) + // Find the beginning and end of the first tag. + var/tag_start = findtext(raw_scan, "<") + var/tag_stop = findtext(raw_scan, ">") + // Until we run out of complete tags... + while(tag_start && tag_stop) + var/pre = copytext(raw_scan, 1, tag_start) // Get the stuff that comes before the tag + var/tag = lowertext(copytext(raw_scan, tag_start + 1, tag_stop)) // Get the tag so we can do intellegent replacement + var/tagend = findtext(tag, " ") // Find the first space in the tag if there is one. + // Anything that's before the tag can just be added as is. + formatted_scan = formatted_scan + pre + // If we have a space after the tag (and presumably attributes) just crop that off. + if(tagend) + tag = copytext(tag, 1, tagend) + if(tag in brlist) // Check if it's I vertical space tag. + formatted_scan = formatted_scan + "
" // If so, add some padding in. + raw_scan = copytext(raw_scan, tag_stop + 1) // continue on with the stuff after the tag + // Look for the next tag in what's left + tag_start = findtext(raw_scan, "<") + tag_stop = findtext(raw_scan, ">") + // Anything that is left in the page. just tack it on to the end as is + formatted_scan = formatted_scan + raw_scan + // If there is something in there already, pad it out. + if(length(notes.note) > 0) + notes.note += "

" + // Store the scanned document to the notes + notes.note += "Scanned Document. Edit to restore previous notes/delete scan.
----------
" + formatted_scan + "
" + // notehtml ISN'T set to allow user to get their old notes back. A better implementation would add a "scanned documents" + // feature to the PDA, which would better convey the availability of the feature, but this will work for now. + // Inform the user + to_chat(user, "Paper scanned and OCRed to notekeeper.")//concept of scanning paper copyright brainoblivion 2009 + + else + to_chat(user, "Error scanning [A].") diff --git a/code/modules/persistence/filth.dm b/code/modules/persistence/filth.dm index 2eea824f83..a7aa9e9cd4 100644 --- a/code/modules/persistence/filth.dm +++ b/code/modules/persistence/filth.dm @@ -6,6 +6,7 @@ random_icon_states = list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7") color = "#464f33" persistent = TRUE + anchored = 1 /obj/effect/decal/cleanable/filth/Initialize() . = ..() diff --git a/code/modules/persistence/graffiti.dm b/code/modules/persistence/graffiti.dm index 2780c3b9a4..539b7b7a3b 100644 --- a/code/modules/persistence/graffiti.dm +++ b/code/modules/persistence/graffiti.dm @@ -8,6 +8,7 @@ blend_mode = BLEND_MULTIPLY color = "#000000" alpha = 120 + anchored = 1 var/message var/graffiti_age = 0 diff --git a/code/modules/power/apc_vr.dm b/code/modules/power/apc_vr.dm index c08c9b8db0..ec7d4dba09 100644 --- a/code/modules/power/apc_vr.dm +++ b/code/modules/power/apc_vr.dm @@ -6,4 +6,7 @@ NA.apc = src area = NA name = "[area.name] APC" - update() \ No newline at end of file + update() + +/obj/machinery/power/apc/get_cell() + return cell \ No newline at end of file diff --git a/code/modules/power/batteryrack.dm b/code/modules/power/batteryrack.dm index f6bc1c9ff6..dc1dbe7e58 100644 --- a/code/modules/power/batteryrack.dm +++ b/code/modules/power/batteryrack.dm @@ -25,6 +25,7 @@ var/equalise = 0 // If true try to equalise charge between cells var/icon_update = 0 // Timer in ticks for icon update. var/ui_tick = 0 + should_be_mapped = TRUE /obj/machinery/power/smes/batteryrack/New() @@ -113,6 +114,8 @@ if(equalise) // Now try to get least charged cell and use the power from it. var/obj/item/weapon/cell/CL = get_least_charged_cell() + if(!CL) + return amount -= CL.give(amount) if(!amount) return @@ -209,8 +212,43 @@ celldiff = min(min(celldiff, most.charge), least.maxcharge - least.charge) least.give(most.use(celldiff)) -/obj/machinery/power/smes/batteryrack/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] +/obj/machinery/power/smes/batteryrack/dismantle() + for(var/obj/item/weapon/cell/C in internal_cells) + C.forceMove(get_turf(src)) + internal_cells -= C + return ..() + +/obj/machinery/power/smes/batteryrack/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if(istype(W, /obj/item/weapon/cell)) // ID Card, try to insert it. + if(insert_cell(W, user)) + to_chat(user, "You insert \the [W] into \the [src].") + else + to_chat(user, "\The [src] has no empty slot for \the [W]") + if(!..()) + return 0 + if(default_deconstruction_crowbar(user, W)) + return + if(default_part_replacement(user, W)) + return + +/obj/machinery/power/smes/batteryrack/inputting() + return + +/obj/machinery/power/smes/batteryrack/outputting() + return + +/obj/machinery/power/smes/batteryrack/attack_hand(var/mob/user) + tgui_interact(user) + +/obj/machinery/power/smes/batteryrack/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Batteryrack", name) + ui.open() + +/obj/machinery/power/smes/batteryrack/tgui_data(mob/user) + // DO NOT CALL PARENT. + var/list/data = list() data["mode"] = mode data["transfer_max"] = max_transfer_rate @@ -238,75 +276,44 @@ cells += list(cell) data["cells_list"] = cells - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "psu.tmpl", "Cell Rack PSU", 500, 430) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data -/obj/machinery/power/smes/batteryrack/dismantle() - for(var/obj/item/weapon/cell/C in internal_cells) - C.forceMove(get_turf(src)) - internal_cells -= C - return ..() - -/obj/machinery/power/smes/batteryrack/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - if(!..()) - return 0 - if(default_deconstruction_crowbar(user, W)) - return - if(default_part_replacement(user, W)) - return - if(istype(W, /obj/item/weapon/cell)) // ID Card, try to insert it. - if(insert_cell(W, user)) - to_chat(user, "You insert \the [W] into \the [src].") - else - to_chat(user, "\The [src] has no empty slot for \the [W]") - -/obj/machinery/power/smes/batteryrack/attack_hand(var/mob/user) - ui_interact(user) - -/obj/machinery/power/smes/batteryrack/inputting() - return - -/obj/machinery/power/smes/batteryrack/outputting() - return - -/obj/machinery/power/smes/batteryrack/Topic(href, href_list) +/obj/machinery/power/smes/batteryrack/tgui_act(action, list/params) // ..() would respond to those topic calls, but we don't want to use them at all. // Calls to these shouldn't occur anyway, due to usage of different nanoUI, but // it's here in case someone decides to try hrefhacking/modified templates. - if(href_list["input"] || href_list["output"]) - return 1 + if(!(action in list("disable", "enable", "equaliseon", "equaliseoff", "ejectcell"))) + return TRUE if(..()) - return 1 - if( href_list["disable"] ) - update_io(0) - return 1 - else if( href_list["enable"] ) - update_io(between(1, text2num(href_list["enable"]), 3)) - return 1 - else if( href_list["equaliseon"] ) - equalise = 1 - return 1 - else if( href_list["equaliseoff"] ) - equalise = 0 - return 1 - else if( href_list["ejectcell"] ) - var/obj/item/weapon/cell/C - for(var/obj/item/weapon/cell/CL in internal_cells) - if(CL.c_uid == text2num(href_list["ejectcell"])) - C = CL - break + return TRUE - if(!istype(C)) - return 1 + switch(action) + if("disable") + update_io(0) + return TRUE + if("enable") + update_io(between(1, text2num(params["enable"]), 3)) + return TRUE + if("equaliseon") + equalise = 1 + return TRUE + if("equaliseoff") + equalise = 0 + return TRUE + if("ejectcell") + var/obj/item/weapon/cell/C + for(var/obj/item/weapon/cell/CL in internal_cells) + if(CL.c_uid == text2num(params["ejectcell"])) + C = CL + break - C.forceMove(get_turf(src)) - internal_cells -= C - update_icon() - RefreshParts() - update_maxcharge() - return 1 \ No newline at end of file + if(!istype(C)) + return TRUE + + C.forceMove(get_turf(src)) + internal_cells -= C + update_icon() + RefreshParts() + update_maxcharge() + return TRUE \ No newline at end of file diff --git a/code/modules/power/batteryrack_vr.dm b/code/modules/power/batteryrack_vr.dm new file mode 100644 index 0000000000..69a2cb5330 --- /dev/null +++ b/code/modules/power/batteryrack_vr.dm @@ -0,0 +1,9 @@ +/obj/item/weapon/module/power_control/attackby(var/obj/item/I, var/mob/user) + if(I.is_multitool()) + to_chat(user, SPAN_NOTICE("You begin tweaking the power control circuits to support a power cell rack.")) + if(do_after(user, 50 * I.toolspeed)) + var/obj/item/newcircuit = new/obj/item/weapon/circuitboard/batteryrack(get_turf(user)) + qdel(src) + user.put_in_hands(newcircuit) + return + return ..() diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index ecfbf00a5f..d77f8341a6 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -25,6 +25,8 @@ var/last_use = 0 // A tracker for use in self-charging var/charge_delay = 0 // How long it takes for the cell to start recharging after last use matter = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 50) + drop_sound = 'sound/items/drop/component.ogg' + pickup_sound = 'sound/items/pickup/component.ogg' // Overlay stuff. var/overlay_half_state = "cell-o1" // Overlay used when not fully charged but not empty. diff --git a/code/modules/power/fusion/fuel_assembly/fuel_assembly.dm b/code/modules/power/fusion/fuel_assembly/fuel_assembly.dm index 73543ead92..740ef842c2 100644 --- a/code/modules/power/fusion/fuel_assembly/fuel_assembly.dm +++ b/code/modules/power/fusion/fuel_assembly/fuel_assembly.dm @@ -19,7 +19,7 @@ /obj/item/weapon/fuel_assembly/Initialize() . = ..() - var/material/material = get_material_by_name(fuel_type) + var/datum/material/material = get_material_by_name(fuel_type) if(istype(material)) name = "[material.use_name] fuel rod assembly" desc = "A fuel rod for a fusion reactor. This one is made from [material.use_name]." diff --git a/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm b/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm index d38fd76e86..71dcc7684f 100644 --- a/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm +++ b/code/modules/power/fusion/fuel_assembly/fuel_compressor.dm @@ -49,7 +49,7 @@ if(istype(thing, /obj/item/stack/material)) var/obj/item/stack/material/M = thing - var/material/mat = M.get_material() + var/datum/material/mat = M.get_material() if(!mat.is_fusion_fuel) to_chat(user, "It would be pointless to make a fuel rod out of [mat.use_name].") return diff --git a/code/modules/power/grid_checker.dm b/code/modules/power/grid_checker.dm index 224eade429..53766098f0 100644 --- a/code/modules/power/grid_checker.dm +++ b/code/modules/power/grid_checker.dm @@ -59,7 +59,7 @@ if(opened) wires.Interact(user) - return ui_interact(user) + return tgui_interact(user) /obj/machinery/power/grid_checker/proc/power_failure(var/announce = TRUE) if(announce) diff --git a/code/modules/power/singularity/particle_accelerator/particle_smasher.dm b/code/modules/power/singularity/particle_accelerator/particle_smasher.dm index 386437db0b..01fa9932d9 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_smasher.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_smasher.dm @@ -43,9 +43,12 @@ for(var/obj/item/I in contents) . += "\the [I]" +/obj/machinery/particle_smasher/atmosanalyze(var/mob/user) + return list("\The [src] reads an energy level of [energy].") + /obj/machinery/particle_smasher/attackby(obj/item/W as obj, mob/user as mob) if(W.type == /obj/item/device/analyzer) - to_chat(user, "\The [src] reads an energy level of [energy].") + return else if(istype(W, /obj/item/stack/material)) var/obj/item/stack/material/M = W if(M.uses_charge) diff --git a/code/modules/power/turbine.dm b/code/modules/power/turbine.dm index 2caa008f0c..1d5262044e 100644 --- a/code/modules/power/turbine.dm +++ b/code/modules/power/turbine.dm @@ -345,59 +345,59 @@ /obj/machinery/computer/turbine_computer/attack_hand(var/mob/user as mob) if((. = ..())) return - src.interact(user) + tgui_interact(user) -/obj/machinery/computer/turbine_computer/interact(mob/user) - return ui_interact(user) +/obj/machinery/computer/turbine_computer/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TurbineControl", name) + ui.open() -/obj/machinery/computer/turbine_computer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/computer/turbine_computer/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) var/list/data = list() data["connected"] = (compressor && compressor.turbine) ? TRUE : FALSE data["compressor_broke"] = (!compressor || (compressor.stat & BROKEN)) ? TRUE : FALSE data["turbine_broke"] = (!compressor || !compressor.turbine || (compressor.turbine.stat & BROKEN)) ? TRUE : FALSE data["broken"] = (data["compressor_broke"] || data["turbine_broke"]) data["door_status"] = door_status ? TRUE : FALSE + + data["online"] = FALSE + data["power"] = 0 + data["rpm"] = 0 + data["temp"] = 0 + if(compressor && compressor.turbine) data["online"] = compressor.starter - data["power"] = DisplayPower(compressor.turbine.lastgen) + data["power"] = compressor.turbine.lastgen // DisplayPower data["rpm"] = compressor.rpm data["temp"] = compressor.gas_contained.temperature - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "turbine_computer.tmpl", name, 520, 440) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(TRUE) + return data -/obj/machinery/computer/turbine_computer/Topic(href, href_list) +/obj/machinery/computer/turbine_computer/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) if(..()) - return - if(href_list["power-on"]) - if(compressor && compressor.turbine) - compressor.starter = TRUE + return TRUE + + switch(action) + if("power-on") + if(compressor && compressor.turbine) + compressor.starter = TRUE + . = TRUE + if("power-off") + if(compressor && compressor.turbine) + compressor.starter = FALSE + . = TRUE + if("reconnect") + locate_machinery() . = TRUE - else if(href_list["power-off"]) - if(compressor && compressor.turbine) - compressor.starter = FALSE + if("doors") + door_status = !door_status + for(var/obj/machinery/door/blast/D in src.doors) + if (door_status) + spawn(0) D.close() + else + spawn(0)D.open() . = TRUE - else if(href_list["reconnect"]) - locate_machinery() - . = TRUE - else if(href_list["doors"]) - door_status = !door_status - for(var/obj/machinery/door/blast/D in src.doors) - if (door_status) - spawn(0) D.close() - else - spawn(0)D.open() - . = TRUE #undef COMPFRICTION #undef COMPSTARTERLOAD diff --git a/code/modules/projectiles/broken.dm b/code/modules/projectiles/broken.dm index a63f685ba1..15f63f4c54 100644 --- a/code/modules/projectiles/broken.dm +++ b/code/modules/projectiles/broken.dm @@ -37,7 +37,7 @@ var/res_name = "" if(ispath(res,/obj/item/stack/material)) var/obj/item/stack/material/mat_stack = res - var/material/mat = get_material_by_name("[initial(mat_stack.default_type)]") + var/datum/material/mat = get_material_by_name("[initial(mat_stack.default_type)]") if(material_needs[resource]>1) res_name = "[mat.use_name] [mat.sheet_plural_name]" else diff --git a/code/modules/projectiles/guns/energy/hooklauncher.dm b/code/modules/projectiles/guns/energy/hooklauncher.dm index 2c170544a0..79ddf7443d 100644 --- a/code/modules/projectiles/guns/energy/hooklauncher.dm +++ b/code/modules/projectiles/guns/energy/hooklauncher.dm @@ -5,12 +5,14 @@ /obj/item/weapon/gun/energy/hooklauncher name = "gravity whip" desc = "A large, strange gauntlet." + icon = 'icons/obj/gun2.dmi' icon_state = "gravwhip" item_state = "gravwhip" fire_sound_text = "laser blast" fire_delay = 15 charge_cost = 300 + charge_meter = FALSE cell_type = /obj/item/weapon/cell/device/weapon projectile_type = /obj/item/projectile/energy/hook @@ -29,7 +31,6 @@ cell_type = /obj/item/weapon/cell/device/weapon/recharge/alien battery_lock = TRUE charge_cost = 400 - charge_meter = FALSE projectile_type = /obj/item/projectile/energy/hook/ring diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm new file mode 100644 index 0000000000..0b0678894f --- /dev/null +++ b/code/modules/projectiles/guns/magic.dm @@ -0,0 +1,60 @@ +/* + * "Magic" "Guns" + */ + +/obj/item/weapon/gun/magic + name = "staff of nothing" + desc = "This staff is boring to watch because even though it came first you've seen everything it can do in other staves for years." + icon = 'icons/obj/wizard.dmi' + icon_state = "staffofnothing" + item_icons = list( + slot_l_hand_str = 'icons/mob/items/lefthand_magic.dmi', + slot_r_hand_str = 'icons/mob/items/righthand_magic.dmi', + ) + fire_sound = 'sound/weapons/emitter.ogg' + w_class = ITEMSIZE_HUGE + projectile_type = null + var/checks_antimagic = TRUE + var/max_charges = 6 + var/charges = 0 + var/recharge_rate = 4 + var/charge_tick = 0 + var/can_charge = TRUE + +/obj/item/weapon/gun/magic/consume_next_projectile() + if(checks_antimagic && locate(/obj/item/weapon/nullrod) in usr) return null + if(!ispath(projectile_type)) return null + if(charges <= 0) return null + + charges -= 1 + + return new projectile_type(src) + +/obj/item/weapon/gun/magic/Initialize() + . = ..() + charges = max_charges + if(can_charge) + START_PROCESSING(SSobj, src) + +/obj/item/weapon/gun/magic/Destroy() + if(can_charge) + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/weapon/gun/magic/process() + if (charges >= max_charges) + charge_tick = 0 + return + charge_tick++ + if(charge_tick < recharge_rate) + return 0 + charge_tick = 0 + charges++ + return 1 + +/obj/item/weapon/gun/magic/handle_click_empty(mob/user) + if (user) + user.visible_message("*wzhzhzh*", "The [name] whizzles quietly.") + else + src.visible_message("*wzhzh*") + playsound(src, 'sound/weapons/empty.ogg', 100, 1) diff --git a/code/modules/projectiles/guns/magic/fireball.dm b/code/modules/projectiles/guns/magic/fireball.dm new file mode 100644 index 0000000000..4abe3e286e --- /dev/null +++ b/code/modules/projectiles/guns/magic/fireball.dm @@ -0,0 +1,17 @@ + +/obj/item/weapon/gun/magic/firestaff + name = "flaming staff" + desc = "A long, everburning torch." + icon = 'icons/obj/wizard.dmi' + icon_state = "staffoffire" + item_state = "staff" + fire_sound = 'sound/weapons/emitter.ogg' + w_class = ITEMSIZE_HUGE + checks_antimagic = TRUE + max_charges = 6 + charges = 0 + recharge_rate = 4 + charge_tick = 0 + can_charge = TRUE + + projectile_type = /obj/item/projectile/energy/fireball diff --git a/code/modules/projectiles/guns/magnetic/magnetic_construction.dm b/code/modules/projectiles/guns/magnetic/magnetic_construction.dm index 7745c9c623..8476e28bee 100644 --- a/code/modules/projectiles/guns/magnetic/magnetic_construction.dm +++ b/code/modules/projectiles/guns/magnetic/magnetic_construction.dm @@ -11,7 +11,7 @@ if(istype(thing, /obj/item/stack/material) && construction_stage == 1) var/obj/item/stack/material/reinforcing = thing - var/material/reinforcing_with = reinforcing.get_material() + var/datum/material/reinforcing_with = reinforcing.get_material() if(reinforcing_with.name == DEFAULT_WALL_MATERIAL) // Steel if(reinforcing.get_amount() < 5) to_chat(user, "You need at least 5 [reinforcing.singular_name]\s for this task.") diff --git a/code/modules/projectiles/guns/projectile/boltaction.dm b/code/modules/projectiles/guns/projectile/boltaction.dm index 9e93d46b8a..1aa8e83957 100644 --- a/code/modules/projectiles/guns/projectile/boltaction.dm +++ b/code/modules/projectiles/guns/projectile/boltaction.dm @@ -14,6 +14,7 @@ ammo_type = /obj/item/ammo_casing/a762 load_method = SINGLE_CASING|SPEEDLOADER action_sound = 'sound/weapons/riflebolt.ogg' + pump_animation = null /obj/item/weapon/gun/projectile/shotgun/pump/rifle/practice // For target practice desc = "A bolt-action rifle with a lightweight synthetic wood stock, designed for competitive shooting. Comes shipped with practice rounds pre-loaded into the gun. Popular among professional marksmen. Uses 7.62mm rounds." @@ -66,4 +67,4 @@ desc = "An iconic manually operated lever action rifle, offering adequate stopping power due to it's still powerful cartridge while at the same time having a rather respectable firing rate due to it's mechanism. It is very probable this is a replica instead of a museum piece, but rifles of this pattern still see usage as colonist guns in some far off regions. Uses 7.62mm rounds." item_state = "levercarabine" // That isn't how carbine is spelled ya knob! :U icon_state = "levercarabine" - animated_pump = 1 + pump_animation = "levercarabine-cycling" diff --git a/code/modules/projectiles/guns/projectile/shotgun.dm b/code/modules/projectiles/guns/projectile/shotgun.dm index 799c27ac54..6e69b65a6a 100644 --- a/code/modules/projectiles/guns/projectile/shotgun.dm +++ b/code/modules/projectiles/guns/projectile/shotgun.dm @@ -14,10 +14,10 @@ ammo_type = /obj/item/ammo_casing/a12g/beanbag projectile_type = /obj/item/projectile/bullet/shotgun handle_casings = HOLD_CASINGS - var/recentpump = 0 // to prevent spammage + var/recentpump = 0 //To prevent spammage var/action_sound = 'sound/weapons/shotgunpump.ogg' - var/animated_pump = 0 //This is for cyling animations. - var/empty_sprite = 0 //This is just a dirty var so it doesn't fudge up. + var/empty_sprite = 0 //This is just a dirty var so it doesn't fudge up. + var/pump_animation = "shotgun-pump" //You put the reference to the animation in question here. Frees up namming. Ex: "shotgun_old_pump" or "sniper_cycle" /obj/item/weapon/gun/projectile/shotgun/pump/consume_next_projectile() if(chambered) @@ -41,8 +41,8 @@ loaded -= AC //Remove casing from loaded list. chambered = AC - if(animated_pump)//This affects all bolt action and shotguns. - flick("[icon_state]-cycling", src)//This plays any pumping + if(pump_animation)//This affects all bolt action and shotguns. + flick("[pump_animation]", src)//This plays any pumping update_icon() @@ -60,6 +60,7 @@ /obj/item/weapon/gun/projectile/shotgun/pump/slug ammo_type = /obj/item/ammo_casing/a12g + pump_animation = null /obj/item/weapon/gun/projectile/shotgun/pump/combat name = "combat shotgun" @@ -71,6 +72,7 @@ max_shells = 7 //match the ammo box capacity, also it can hold a round in the chamber anyways, for a total of 8. ammo_type = /obj/item/ammo_casing/a12g load_method = SINGLE_CASING|SPEEDLOADER + pump_animation = "cshotgun-pump" /obj/item/weapon/gun/projectile/shotgun/pump/combat/empty ammo_type = null diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 8ef1bfe2a6..6cd885f0c1 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -739,6 +739,8 @@ shot_from = launcher.name silenced = launcher.silenced + if(user) + firer = user return launch_projectile(target, target_zone, user, params, angle_override, forced_spread) diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index e3ac4d0591..c72d9b35ea 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -119,7 +119,7 @@ icon_state = "bullet_chonk" //Ywedit fire_sound = 'sound/weapons/Gunshot_shotgun.ogg' damage = 50 - armor_penetration = 15 + armor_penetration = 20 /obj/item/projectile/bullet/shotgun/beanbag //because beanbags are not bullets name = "beanbag" diff --git a/code/modules/projectiles/projectile/hook.dm b/code/modules/projectiles/projectile/hook.dm index ee5fd6c471..3e98319ebd 100644 --- a/code/modules/projectiles/projectile/hook.dm +++ b/code/modules/projectiles/projectile/hook.dm @@ -27,13 +27,15 @@ var/list/help_messages = list("slaps", "pokes", "nudges", "bumps", "pinches") var/done_mob_unique = FALSE // Has the projectile already done something to a mob? + var/datum/beam/chain = null + /obj/item/projectile/energy/hook/launch_projectile(atom/target, target_zone, mob/user, params, angle_override, forced_spread = 0) var/expected_distance = get_dist(target, loc) range = expected_distance // So the hook hits the ground if no mob is hit. target_distance = expected_distance if(firer) // Needed to ensure later checks in impact and on hit function. launcher_intent = firer.a_intent - firer.Beam(src,icon_state=beam_state,icon='icons/effects/beam.dmi',time=60, maxdistance=10,beam_type=/obj/effect/ebeam,beam_sleep_time=1) + chain = firer.Beam(src,icon_state=beam_state,icon='icons/effects/beam.dmi',time=60, maxdistance=10,beam_type=/obj/effect/ebeam,beam_sleep_time=1) if(launcher_intent) switch(launcher_intent) @@ -58,10 +60,22 @@ ..() // Does the regular launching stuff. +/obj/item/projectile/energy/hook/after_move() + if(chain) + var/origin_turf = get_turf(firer) + var/target_turf = get_turf(src) + if(!chain.static_beam && (origin_turf != chain.origin_oldloc || target_turf != chain.target_oldloc)) + chain.origin_oldloc = origin_turf //so we don't keep checking against their initial positions, leading to endless Reset()+Draw() calls + chain.target_oldloc = target_turf + chain.Reset() + chain.Draw() + return + /obj/item/projectile/energy/hook/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null) if(..()) perform_intent_unique(target) + /obj/item/projectile/energy/hook/on_impact(var/atom/A) perform_intent_unique(get_turf(A)) diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm new file mode 100644 index 0000000000..9fcc1c1979 --- /dev/null +++ b/code/modules/projectiles/projectile/magic.dm @@ -0,0 +1,20 @@ + +/obj/item/projectile/energy/fireball + name = "fireball" + icon_state = "fireball2" + damage = 15 + damage_type = BURN + check_armour = "bomb" + armor_penetration = 25 // It's a great ball of fire. + + combustion = TRUE + +/obj/item/projectile/energy/fireball/on_hit(var/atom/target, var/blocked = 0) + new /obj/effect/explosion(get_turf(target)) + explosion(target, -1, 0, 2) + ..() + +/obj/item/projectile/energy/fireball/on_impact(var/atom/target) + new /obj/effect/explosion(get_turf(target)) + explosion(target, -1, 0, 2) + ..() diff --git a/code/modules/radiation/radiation.dm b/code/modules/radiation/radiation.dm index c107390094..cb701027d8 100644 --- a/code/modules/radiation/radiation.dm +++ b/code/modules/radiation/radiation.dm @@ -36,7 +36,7 @@ cached_rad_resistance += O.rad_resistance else if(O.density) //So open doors don't get counted - var/material/M = O.get_material() + var/datum/material/M = O.get_material() if(!M) continue cached_rad_resistance += (M.weight + M.radiation_resistance) / config.radiation_material_resistance_divisor // Looks like storing the contents length is meant to be a basic check if the cache is stale due to items enter/exiting. Better than nothing so I'm leaving it as is. ~Leshana diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm index ae75e5ae89..b96e223ed9 100644 --- a/code/modules/reagents/Chemistry-Holder.dm +++ b/code/modules/reagents/Chemistry-Holder.dm @@ -493,4 +493,4 @@ trans_to(M, mobportion, multiplier, copy) trans_to(T, total_volume, multiplier, copy) if (total_volume <= 0) - qdel(src) + qdel(src) \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm index 212de66431..e636a28d0a 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm @@ -118,7 +118,7 @@ remove_self(volume) /datum/reagent/blood/synthblood - name = "Synthetic blood" + name = "synthetic blood" id = "synthblood" color = "#999966" volume_mod = 2 @@ -127,8 +127,16 @@ ..() if(data && !data["blood_type"]) data["blood_type"] = "O-" + if(data && data["species"]) + data["species"] = null return +/datum/reagent/blood/synthblood/dilute + name = "synthetic plasma" + id = "synthblood_dilute" + color = "#cacaaf" + volume_mod = 1.2 + // pure concentrated antibodies /datum/reagent/antibodies data = list("antibodies"=list()) diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm index 9077b694d5..5185e5a8f4 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm @@ -18,11 +18,14 @@ return //add the new taste data - for(var/taste in newdata) - if(taste in data) - data[taste] += newdata[taste] - else - data[taste] = newdata[taste] + if(islist(data)) + for(var/taste in newdata) + if(taste in data) + data[taste] += newdata[taste] + else + data[taste] = newdata[taste] + else + initialize_data(newdata) //cull all tastes below 10% of total var/totalFlavor = 0 @@ -136,6 +139,8 @@ description = "More commonly known as fat, the third macronutrient, with over double the energy content of carbs and protein" reagent_state = SOLID + taste_description = "greasiness" + taste_mult = 0.1 nutriment_factor = 27//The caloric ratio of carb/protein/fat is 4:4:9 color = "#CCCCCC" @@ -145,6 +150,7 @@ id = "oil" description = "Oils are liquid fats." reagent_state = LIQUID + taste_description = "oil" color = "#c79705" touch_met = 1.5 var/lastburnmessage = 0 @@ -221,8 +227,6 @@ name = "Corn Oil" id = "cornoil" description = "An oil derived from various types of corn." - taste_description = "oil" - taste_mult = 0.1 reagent_state = LIQUID /datum/reagent/nutriment/triglyceride/oil/peanut @@ -588,7 +592,7 @@ //SYNNONO MEME FOODS EXPANSION - Credit to Synnono /datum/reagent/spacespice - name = "Space Spice" + name = "Wurmwoad" id = "spacespice" description = "An exotic blend of spices for cooking. Definitely not worms." reagent_state = SOLID @@ -676,7 +680,7 @@ var/mob/living/carbon/human/H = M if(!H.can_feel_pain()) return - + var/effective_dose = (dose * M.species.spice_mod) if((effective_dose < 5) && (dose == metabolism || prob(5))) to_chat(M, "Your insides feel uncomfortably hot!") diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index d2e6818701..15d471da7a 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -2674,4 +2674,4 @@ id = "browniemix" result = "browniemix" required_reagents = list("flour" = 5, "coco" = 5, "sugar" = 5) - result_amount = 15 \ No newline at end of file + result_amount = 15 diff --git a/code/modules/reagents/Chemistry-Recipes_vr.dm b/code/modules/reagents/Chemistry-Recipes_vr.dm index 2bd766213e..fa4763f41d 100644 --- a/code/modules/reagents/Chemistry-Recipes_vr.dm +++ b/code/modules/reagents/Chemistry-Recipes_vr.dm @@ -77,6 +77,14 @@ /datum/chemical_reaction/foam/softdrink required_reagents = list("cola" = 1, "mint" = 1) + +/datum/chemical_reaction/firefightingfoam //TODO: Make it so we can add this to the foam tanks to refill them + name = "Firefighting Foam" + id = "firefighting foam" + result = "firefoam" + required_reagents = list("water" = 1) + catalysts = list("fluorine" = 10) + result_amount = 1 /////////////////////////////////////////////////////////////////////////////////// /// Vore Drugs diff --git a/code/modules/reagents/dispenser/dispenser2_energy.dm b/code/modules/reagents/dispenser/dispenser2_energy.dm index 84c5260c3f..b0dec9f65b 100644 --- a/code/modules/reagents/dispenser/dispenser2_energy.dm +++ b/code/modules/reagents/dispenser/dispenser2_energy.dm @@ -25,7 +25,7 @@ C.reagents.add_reagent(id, to_restore) . = 1 if(.) - SSnanoui.update_uis(src) + SStgui.update_uis(src) /obj/machinery/chemical_dispenser dispense_reagents = list( diff --git a/code/modules/reagents/distilling/Distilling-Recipes.dm b/code/modules/reagents/distilling/Distilling-Recipes.dm index a8ac2ee975..0736ac7e61 100644 --- a/code/modules/reagents/distilling/Distilling-Recipes.dm +++ b/code/modules/reagents/distilling/Distilling-Recipes.dm @@ -128,6 +128,17 @@ temp_range = list(T0C + 100, T0C + 120) +/datum/chemical_reaction/distilling/synthplas + name = "Distilling Synthplas" + id = "distill_synthplas" + result = "synthblood_dilute" + required_reagents = list("protein" = 2, "antibodies" = 1, "bicaridine" = 1) + result_amount = 3 + + reaction_rate = HALF_LIFE(15) + + temp_range = list(T0C + 110, T0C + 130) + // Alcohol /datum/chemical_reaction/distilling/beer name = "Distilling Beer" diff --git a/code/modules/reagents/distilling/distilling.dm b/code/modules/reagents/distilling/distilling.dm index 645f13c76b..5d37f8510c 100644 --- a/code/modules/reagents/distilling/distilling.dm +++ b/code/modules/reagents/distilling/distilling.dm @@ -19,7 +19,7 @@ var/target_temp = T20C - var/max_temp = T20C + 300 + var/max_temp = T0C + 300 var/min_temp = T0C - 10 var/current_temp = T20C @@ -86,6 +86,16 @@ update_icon() +/obj/machinery/portable_atmospherics/powered/reagent_distillery/RefreshParts() + var/total_laser_rating = 0 + for(var/obj/item/weapon/stock_parts/micro_laser/ML in component_parts) + total_laser_rating += ML.rating + + max_temp = initial(max_temp) + (50 * (total_laser_rating - 1)) + min_temp = max(1, initial(min_temp) - (30 * (total_laser_rating - 1))) + + return + /obj/machinery/portable_atmospherics/powered/reagent_distillery/proc/setup_overlay_vars() overlay_output_beaker = image(icon = src.icon, icon_state = "[base_state]-output") overlay_input_beaker = image(icon = src.icon, icon_state = "[base_state]-input") diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index 223583f7dc..693330fef7 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -27,6 +27,7 @@ var/label_text = "" var/blood_type = null + var/reag_id = "blood" /obj/item/weapon/reagent_containers/blood/Initialize() . = ..() @@ -35,7 +36,7 @@ if(blood_type != null) label_text = "[blood_type]" update_iv_label() - reagents.add_reagent("blood", 200, list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=blood_type,"resistances"=null,"trace_chem"=null)) + reagents.add_reagent(reag_id, 200, list("donor"=null,"viruses"=null,"blood_DNA"=null,"blood_type"=blood_type,"resistances"=null,"trace_chem"=null)) update_icon() /obj/item/weapon/reagent_containers/blood/on_reagent_change() @@ -95,6 +96,14 @@ /obj/item/weapon/reagent_containers/blood/OMinus blood_type = "O-" +/obj/item/weapon/reagent_containers/blood/synthplas + blood_type = "O-" + reag_id = "synthblood_dilute" + +/obj/item/weapon/reagent_containers/blood/synthblood + blood_type = "O-" + reag_id = "synthblood" + /obj/item/weapon/reagent_containers/blood/empty name = "Empty BloodPack" desc = "Seems pretty useless... Maybe if there were a way to fill it?" diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghypo.dm similarity index 87% rename from code/modules/reagents/reagent_containers/borghydro.dm rename to code/modules/reagents/reagent_containers/borghypo.dm index 347c136e40..12a3df61df 100644 --- a/code/modules/reagents/reagent_containers/borghydro.dm +++ b/code/modules/reagents/reagent_containers/borghypo.dm @@ -79,9 +79,11 @@ if(!affected) to_chat(user, "\The [H] is missing that limb!") return + /* since synths have oil/coolant streams now, it only makes sense that you should be able to inject stuff. preserved for posterity. else if(affected.robotic >= ORGAN_ROBOT) to_chat(user, "You cannot inject a robotic limb.") return + */ if(M.can_inject(user, 1, ignore_thickness = bypass_protection)) to_chat(user, "You inject [M] with the injector.") @@ -133,7 +135,48 @@ recharge_time = 3 volume = 60 possible_transfer_amounts = list(5, 10, 20, 30) - reagent_ids = list("ale", "cider", "beer", "berryjuice", "bitters", "coffee", "cognac", "cola", "dr_gibb", "egg", "gin", "gingerale", "hot_coco", "ice", "icetea", "kahlua", "lemonjuice", "lemon_lime", "limejuice", "mead", "milk", "mint", "orangejuice", "rum", "sake", "sodawater", "soymilk", "space_up", "spacemountainwind", "specialwhiskey", "sugar", "tea", "tequilla", "tomatojuice", "tonic", "vermouth", "vodka", "water", "watermelonjuice", "whiskey", "wine") + reagent_ids = list("ale", + "cider", + "beer", + "berryjuice", + "bitters", + "coffee", + "cognac", + "cola", + "dr_gibb", + "egg", + "gin", + "gingerale", + "hot_coco", + "ice", + "icetea", + "kahlua", + "lemonjuice", + "lemon_lime", + "limejuice", + "mead", + "milk", + "mint", + "orangejuice", + "rum", + "sake", + "sodawater", + "soymilk", + "space_up", + "spacemountainwind", + "spacespice", + "specialwhiskey", + "sugar", + "tea", + "tequilla", + "tomatojuice", + "tonic", + "vermouth", + "vodka", + "water", + "watermelonjuice", + "whiskey", + "wine") /obj/item/weapon/reagent_containers/borghypo/service/attack(var/mob/M, var/mob/user) return diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm index 6b567f47f0..9e7eb5a575 100644 --- a/code/modules/reagents/reagent_containers/glass.dm +++ b/code/modules/reagents/reagent_containers/glass.dm @@ -135,7 +135,7 @@ update_name_label() if(istype(W,/obj/item/weapon/storage/bag)) ..() - if(W && W.w_class <= w_class && (flags & OPENCONTAINER)) + if(W && W.w_class <= w_class && (flags & OPENCONTAINER) && user.a_intent != I_HELP) to_chat(user, "You dip \the [W] into \the [src].") reagents.touch_obj(W, reagents.total_volume) diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 9a1882e47b..80d0e1e34d 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -42,9 +42,11 @@ if(!affected) to_chat(user, "\The [H] is missing that limb!") return + /* since synths have oil/coolant streams now, it only makes sense that you should be able to inject stuff. preserved for posterity. else if(affected.robotic >= ORGAN_ROBOT) to_chat(user, "You cannot inject a robotic limb.") return + */ //VOREStation Add Start - Adds Prototype Hypo functionality if(H != user && prototype) diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index 4bdf471989..fe50843852 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -170,9 +170,11 @@ if(!affected) to_chat(user, "\The [H] is missing that limb!") return + /* since synths have oil/coolant streams now, it only makes sense that you should be able to inject stuff. preserved for posterity. else if(affected.robotic >= ORGAN_ROBOT) to_chat(user, "You cannot inject a robotic limb.") return + */ var/cycle_time = injtime*0.33 //33% of the time slept between 5u doses var/warmup_time = 0 //0 for containers diff --git a/code/modules/research/designs/circuits/ai_modules_vr.dm b/code/modules/research/designs/circuits/ai_modules_vr.dm new file mode 100644 index 0000000000..d8bc3814ac --- /dev/null +++ b/code/modules/research/designs/circuits/ai_modules_vr.dm @@ -0,0 +1,41 @@ +/datum/design/aimodule/core/predator + name = "Predator" + id = "laws_predator_vr" + req_tech = list(TECH_DATA = 4, TECH_BIO = 3, TECH_ILLEGAL = 2, TECH_MATERIAL = 6) + build_path = /obj/item/weapon/aiModule/predator + sort_string = "XAVAA" + +/datum/design/aimodule/core/protective_shell + name = "Protective Shell" + id = "laws_protective_shell_vr" + req_tech = list(TECH_DATA = 4, TECH_BIO = 3, TECH_ILLEGAL = 2, TECH_MATERIAL = 6) + build_path = /obj/item/weapon/aiModule/protective_shell + sort_string = "XAVAB" + +/datum/design/aimodule/core/scientific_pursuer + name = "Scientific Pursuer" + id = "laws_scientific_pursuer_vr" + req_tech = list(TECH_DATA = 4, TECH_BIO = 3, TECH_ILLEGAL = 2, TECH_MATERIAL = 6) + build_path = /obj/item/weapon/aiModule/scientific_pursuer + sort_string = "XAVAC" + +/datum/design/aimodule/core/guard_dog + name = "Guard Dog" + id = "laws_guard_dog_vr" + req_tech = list(TECH_DATA = 4, TECH_BIO = 3, TECH_ILLEGAL = 2, TECH_MATERIAL = 6) + build_path = /obj/item/weapon/aiModule/guard_dog + sort_string = "XAVAD" + +/datum/design/aimodule/core/pleasurebot + name = "Pleasurebot" + id = "laws_pleasurebot_vr" + req_tech = list(TECH_DATA = 4, TECH_BIO = 3, TECH_ILLEGAL = 2, TECH_MATERIAL = 6) + build_path = /obj/item/weapon/aiModule/pleasurebot + sort_string = "XAVAE" + +/datum/design/aimodule/core/consuming_eradicator + name = "Consuming Eradicator" + id = "laws_consuming_eradicator_vr" + req_tech = list(TECH_DATA = 4, TECH_BIO = 3, TECH_ILLEGAL = 6, TECH_MATERIAL = 6) + build_path = /obj/item/weapon/aiModule/consuming_eradicator + sort_string = "XAVAF" diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm index 34b3510031..d12441c8fe 100644 --- a/code/modules/research/protolathe.dm +++ b/code/modules/research/protolathe.dm @@ -226,7 +226,7 @@ var/recursive = amount == -1 ? 1 : 0 material = lowertext(material) var/obj/item/stack/material/mattype - var/material/MAT = get_material_by_name(material) + var/datum/material/MAT = get_material_by_name(material) if(!MAT) return diff --git a/code/modules/research/rdmachines.dm b/code/modules/research/rdmachines.dm index 5f58c50f3d..e317c665d0 100644 --- a/code/modules/research/rdmachines.dm +++ b/code/modules/research/rdmachines.dm @@ -18,7 +18,7 @@ return /obj/machinery/r_n_d/proc/getMaterialType(var/name) - var/material/M = get_material_by_name(name) + var/datum/material/M = get_material_by_name(name) if(M && M.stack_type) return M.stack_type return null diff --git a/code/modules/resleeving/infomorph.dm b/code/modules/resleeving/infomorph.dm index 7fd716bc96..fed79fe078 100644 --- a/code/modules/resleeving/infomorph.dm +++ b/code/modules/resleeving/infomorph.dm @@ -112,7 +112,10 @@ var/list/infomorph_emotions = list( pda.ownjob = "Sleevecard" pda.owner = text("[]", src) pda.name = pda.owner + " (" + pda.ownjob + ")" - pda.toff = 1 + + var/datum/data/pda/app/messenger/M = pda.find_program(/datum/data/pda/app/messenger) + if(M) + M.toff = TRUE ..() @@ -144,9 +147,9 @@ var/list/infomorph_emotions = list( return 0 ..() -/mob/living/silicon/infomorph/default_can_use_topic(var/src_object) +/mob/living/silicon/infomorph/default_can_use_tgui_topic(var/src_object) if(src_object in src) - return shared_nano_interaction() + return shared_tgui_interaction() /////////// DAMAGES /mob/living/silicon/infomorph/emp_act(severity) @@ -187,7 +190,7 @@ var/list/infomorph_emotions = list( medicalActive1 = null medicalActive2 = null medical_cannotfind = 0 - SSnanoui.update_uis(src) + SStgui.update_uis(src) to_chat(usr, "You reset your record-viewing software.") /* @@ -460,94 +463,81 @@ var/global/list/default_infomorph_software = list() set category = "Card Commands" set name = "Software Interface" - ui_interact(src) + tgui_interact(src) -/mob/living/silicon/infomorph/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, key_state = self_state) - if(user != src) - if(ui) ui.set_status(STATUS_CLOSE, 0) - return +/mob/living/silicon/infomorph/tgui_state(mob/user) + return GLOB.tgui_self_state - if(ui_key != "main") - var/datum/infomorph_software/S = software[ui_key] - if(S && !S.toggle) - S.on_ui_interact(src, ui, force_open) - else - if(ui) ui.set_status(STATUS_CLOSE, 0) - return - - var/data[0] +/mob/living/silicon/infomorph/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "pAIInterface", "Card Software Interface") + ui.open() +/mob/living/silicon/infomorph/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + // Software we have bought - var/bought_software[0] + var/list/bought_software = list() // Software we have not bought - var/not_bought_software[0] + var/list/not_bought_software = list() for(var/key in infomorph_software_by_key) var/datum/infomorph_software/S = infomorph_software_by_key[key] - var/software_data[0] + var/list/software_data = list() software_data["name"] = S.name software_data["id"] = S.id if(key in software) software_data["on"] = S.is_active(src) - bought_software[++bought_software.len] = software_data + bought_software.Add(list(software_data)) else software_data["ram"] = S.ram_cost - not_bought_software[++not_bought_software.len] = software_data + not_bought_software.Add(list(software_data)) data["bought"] = bought_software data["not_bought"] = not_bought_software data["available_ram"] = ram // Emotions - var/emotions[0] + var/list/emotions = list() for(var/name in infomorph_emotions) - var/emote[0] + var/list/emote = list() emote["name"] = name emote["id"] = infomorph_emotions[name] - emotions[++emotions.len] = emote + emotions.Add(list(emote)) data["emotions"] = emotions data["current_emotion"] = card.current_emotion - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open, key_state) - if (!ui) - ui = new(user, src, ui_key, "pai_interface.tmpl", "Card Software Interface", 450, 600, state = key_state) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data -/mob/living/silicon/infomorph/Topic(href, href_list) - . = ..() - if(.) return +/mob/living/silicon/infomorph/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE - if(href_list["software"]) - var/soft = href_list["software"] - var/datum/infomorph_software/S = software[soft] - if(S.toggle) - S.toggle(src) - else - ui_interact(src, ui_key = soft) - return 1 + switch(action) + if("software") + var/soft = params["software"] + var/datum/infomorph_software/S = software[soft] + if(S.toggle) + S.toggle(src) + else + S.tgui_interact(src, parent_ui = ui) + return TRUE - else if(href_list["stopic"]) - var/soft = href_list["stopic"] - var/datum/infomorph_software/S = software[soft] - if(S) - return S.Topic(href, href_list) + if("purchase") + var/soft = params["purchase"] + var/datum/infomorph_software/S = infomorph_software_by_key[soft] + if(S && (ram >= S.ram_cost)) + ram -= S.ram_cost + software[S.id] = S + return TRUE - else if(href_list["purchase"]) - var/soft = href_list["purchase"] - var/datum/infomorph_software/S = infomorph_software_by_key[soft] - if(S && (ram >= S.ram_cost)) - ram -= S.ram_cost - software[S.id] = S - return 1 - - else if(href_list["image"]) - var/img = href_list["image"] - if(img) - card.setEmotion(img) - return 1 + if("image") + var/img = text2num(params["image"]) + if(img) + card.setEmotion(img) + return TRUE /mob/living/silicon/infomorph/examine(mob/user) . = ..(user, infix = ", personal AI") diff --git a/code/modules/resleeving/infomorph_software.dm b/code/modules/resleeving/infomorph_software.dm index 2d2439b614..67a2bd47f9 100644 --- a/code/modules/resleeving/infomorph_software.dm +++ b/code/modules/resleeving/infomorph_software.dm @@ -12,35 +12,38 @@ // Whether pAIs should automatically receive this module at no cost var/default = 0 - proc/on_ui_interact(mob/living/silicon/infomorph/user, datum/nanoui/ui=null, force_open=1) - return +/datum/infomorph_software/tgui_state(mob/user) + return GLOB.tgui_always_state - proc/toggle(mob/living/silicon/infomorph/user) - return +/datum/infomorph_software/tgui_status(mob/user) + if(!istype(user, /mob/living/silicon/infomorph)) + return STATUS_CLOSE + return ..() - proc/is_active(mob/living/silicon/infomorph/user) - return 0 +/datum/infomorph_software/proc/toggle(mob/living/silicon/infomorph/user) + return + +/datum/infomorph_software/proc/is_active(mob/living/silicon/infomorph/user) + return 0 /datum/infomorph_software/crew_manifest name = "Crew Manifest" - ram_cost = 15 + ram_cost = 5 id = "manifest" toggle = 0 - on_ui_interact(mob/living/silicon/infomorph/user, datum/nanoui/ui=null, force_open=1) +/datum/infomorph_software/crew_manifest/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "CrewManifest", name, parent_ui) + ui.open() + +/datum/infomorph_software/crew_manifest/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + if(data_core) data_core.get_manifest_list() - - var/data[0] - // This is dumb, but NanoUI breaks if it has no data to send - data["manifest"] = PDA_Manifest - - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_manifest.tmpl", "Crew Manifest", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + data["manifest"] = PDA_Manifest + return data /datum/infomorph_software/med_records name = "Medical Records" @@ -48,53 +51,55 @@ id = "med_records" toggle = 0 - on_ui_interact(mob/living/silicon/infomorph/user, datum/nanoui/ui=null, force_open=1) - var/data[0] +/datum/infomorph_software/med_records/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "pAIMedrecords", name, parent_ui) + ui.open() - var/records[0] - for(var/datum/data/record/general in sortRecord(data_core.general)) - var/record[0] - record["name"] = general.fields["name"] - record["ref"] = "\ref[general]" - records[++records.len] = record +/datum/infomorph_software/med_records/tgui_data(mob/living/silicon/infomorph/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + var/list/records = list() + for(var/datum/data/record/general in sortRecord(data_core.general)) + var/list/record = list() + record["name"] = general.fields["name"] + record["ref"] = "\ref[general]" + records.Add(list(record)) - data["records"] = records + data["records"] = records - var/datum/data/record/G = user.medicalActive1 - var/datum/data/record/M = user.medicalActive2 - data["general"] = G ? G.fields : null - data["medical"] = M ? M.fields : null - data["could_not_find"] = user.medical_cannotfind + var/datum/data/record/G = user.medicalActive1 + var/datum/data/record/M = user.medicalActive2 + data["general"] = G ? G.fields : null + data["medical"] = M ? M.fields : null + data["could_not_find"] = user.medical_cannotfind - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_medrecords.tmpl", "Medical Records", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data - Topic(href, href_list) - var/mob/living/silicon/infomorph/P = usr - if(!istype(P)) return +/datum/infomorph_software/med_records/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + . = ..() + var/mob/living/silicon/infomorph/P = usr + if(!istype(P)) + return - if(href_list["select"]) - var/datum/data/record/record = locate(href_list["select"]) - if(record) - var/datum/data/record/R = record - var/datum/data/record/M = null - if (!( data_core.general.Find(R) )) - P.medical_cannotfind = 1 - else - P.medical_cannotfind = 0 - for(var/datum/data/record/E in data_core.medical) - if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - M = E - P.medicalActive1 = R - P.medicalActive2 = M - else + if(action == "select") + var/datum/data/record/record = locate(params["select"]) + if(record) + var/datum/data/record/R = record + var/datum/data/record/M = null + if (!( data_core.general.Find(R) )) P.medical_cannotfind = 1 - return 1 + else + P.medical_cannotfind = 0 + for(var/datum/data/record/E in data_core.medical) + if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + M = E + P.medicalActive1 = R + P.medicalActive2 = M + else + P.medical_cannotfind = 1 + return 1 /datum/infomorph_software/sec_records name = "Security Records" @@ -102,57 +107,59 @@ id = "sec_records" toggle = 0 - on_ui_interact(mob/living/silicon/infomorph/user, datum/nanoui/ui=null, force_open=1) - var/data[0] +/datum/infomorph_software/sec_records/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "pAISecrecords", name, parent_ui) + ui.open() - var/records[0] - for(var/datum/data/record/general in sortRecord(data_core.general)) - var/record[0] - record["name"] = general.fields["name"] - record["ref"] = "\ref[general]" - records[++records.len] = record +/datum/infomorph_software/sec_records/tgui_data(mob/living/silicon/infomorph/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + var/list/records = list() + for(var/datum/data/record/general in sortRecord(data_core.general)) + var/list/record = list() + record["name"] = general.fields["name"] + record["ref"] = "\ref[general]" + records.Add(list(record)) - data["records"] = records + data["records"] = records - var/datum/data/record/G = user.securityActive1 - var/datum/data/record/S = user.securityActive2 - data["general"] = G ? G.fields : null - data["security"] = S ? S.fields : null - data["could_not_find"] = user.security_cannotfind + var/datum/data/record/G = user.securityActive1 + var/datum/data/record/S = user.securityActive2 + data["general"] = G ? G.fields : null + data["security"] = S ? S.fields : null + data["could_not_find"] = user.security_cannotfind - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_secrecords.tmpl", "Security Records", 450, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data - Topic(href, href_list) - var/mob/living/silicon/infomorph/P = usr - if(!istype(P)) return +/datum/infomorph_software/sec_records/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + . = ..() + var/mob/living/silicon/infomorph/P = usr + if(!istype(P)) + return - if(href_list["select"]) - var/datum/data/record/record = locate(href_list["select"]) - if(record) - var/datum/data/record/R = record - var/datum/data/record/S = null - if (!( data_core.general.Find(R) )) - P.securityActive1 = null - P.securityActive2 = null - P.security_cannotfind = 1 - else - P.security_cannotfind = 0 - for(var/datum/data/record/E in data_core.security) - if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - S = E - P.securityActive1 = R - P.securityActive2 = S - else + if(action == "select") + var/datum/data/record/record = locate(params["select"]) + if(record) + var/datum/data/record/R = record + var/datum/data/record/S = null + if (!( data_core.general.Find(R) )) P.securityActive1 = null P.securityActive2 = null P.security_cannotfind = 1 - return 1 + else + P.security_cannotfind = 0 + for(var/datum/data/record/E in data_core.security) + if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + S = E + P.securityActive1 = R + P.securityActive2 = S + else + P.securityActive1 = null + P.securityActive2 = null + P.security_cannotfind = 1 + return TRUE /datum/infomorph_software/door_jack name = "Door Jack" @@ -160,44 +167,45 @@ id = "door_jack" toggle = 0 - on_ui_interact(mob/living/silicon/infomorph/user, datum/nanoui/ui=null, force_open=1) - var/data[0] +/datum/infomorph_software/door_jack/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "pAIDoorjack", "Door Jack", parent_ui) + ui.open() - data["cable"] = user.cable != null - data["machine"] = user.cable && (user.cable.machine != null) - data["inprogress"] = user.hackdoor != null - data["progress_a"] = round(user.hackprogress) - data["progress_b"] = user.hackprogress % 10 - data["aborted"] = user.hack_aborted +/datum/infomorph_software/door_jack/tgui_data(mob/living/silicon/infomorph/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_doorjack.tmpl", "Door Jack", 300, 150) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + data["cable"] = user.cable != null + data["machine"] = user.cable && (user.cable.machine != null) + data["inprogress"] = user.hackdoor != null + data["progress_a"] = round(user.hackprogress / 10) + data["progress_b"] = user.hackprogress % 10 + data["aborted"] = user.hack_aborted - Topic(href, href_list) - var/mob/living/silicon/infomorph/P = usr - if(!istype(P)) return + return data - if(href_list["jack"]) +/datum/infomorph_software/door_jack/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + var/mob/living/silicon/infomorph/P = usr + if(!istype(P) || ..()) + return TRUE + + switch(action) + if("jack") if(P.cable && P.cable.machine) P.hackdoor = P.cable.machine P.hackloop() return 1 - else if(href_list["cancel"]) + if("cancel") P.hackdoor = null return 1 - else if(href_list["cable"]) + if("cable") var/turf/T = get_turf(P) P.hack_aborted = 0 P.cable = new /obj/item/weapon/pai_cable(T) - if(ishuman(P.card.loc)) - var/mob/living/carbon/human/H = P.card.loc - H.put_in_any_hand_if_possible(P.cable) - T.visible_message("A port on \the [P] opens to reveal \the [P.cable].") + for(var/mob/M in viewers(T)) + M.show_message("A port on [P] opens to reveal [P.cable], which promptly falls to the floor.", 3, + "You hear the soft click of something light and hard falling to the ground.", 2) return 1 /mob/living/silicon/infomorph/proc/hackloop() @@ -239,43 +247,54 @@ /datum/infomorph_software/atmosphere_sensor name = "Atmosphere Sensor" - ram_cost = 15 + ram_cost = 5 id = "atmos_sense" toggle = 0 - on_ui_interact(mob/living/silicon/infomorph/user, datum/nanoui/ui=null, force_open=1) - var/data[0] +/datum/infomorph_software/atmosphere_sensor/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "pAIAtmos", name, parent_ui) + ui.open() - var/turf/T = get_turf_or_move(user.loc) - if(!T) - data["reading"] = 0 - data["pressure"] = 0 - data["temperature"] = 0 - data["temperatureC"] = 0 - data["gas"] = list() - else - var/datum/gas_mixture/env = T.return_air() - data["reading"] = 1 - var/pres = env.return_pressure() * 10 - data["pressure"] = "[round(pres/10)].[pres%10]" - data["temperature"] = round(env.temperature) - data["temperatureC"] = round(env.temperature-T0C) +/datum/infomorph_software/atmosphere_sensor/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() - var/t_moles = env.total_moles - var/gases[0] - for(var/g in env.gas) - var/gas[0] - gas["name"] = gas_data.name[g] - gas["percent"] = round((env.gas[g] / t_moles) * 100) - gases[++gases.len] = gas - data["gas"] = gases + var/list/results = list() + var/turf/T = get_turf(user) + if(!isnull(T)) + var/datum/gas_mixture/environment = T.return_air() + var/pressure = environment.return_pressure() + var/total_moles = environment.total_moles + if (total_moles) + var/o2_level = environment.gas["oxygen"]/total_moles + var/n2_level = environment.gas["nitrogen"]/total_moles + var/co2_level = environment.gas["carbon_dioxide"]/total_moles + var/phoron_level = environment.gas["phoron"]/total_moles + var/unknown_level = 1-(o2_level+n2_level+co2_level+phoron_level) - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_atmosphere.tmpl", "Atmosphere Sensor", 350, 300) - ui.set_initial_data(data) - ui.open() + // entry is what the element is describing + // Type identifies which unit or other special characters to use + // Val is the information reported + // Bad_high/_low are the values outside of which the entry reports as dangerous + // Poor_high/_low are the values outside of which the entry reports as unideal + // Values were extracted from the template itself + results = list( + list("entry" = "Pressure", "units" = "kPa", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80), + list("entry" = "Temperature", "units" = "°C", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5), + list("entry" = "Oxygen", "units" = "kPa", "val" = "[round(o2_level*100,0.1)]", "bad_high" = 140, "poor_high" = 135, "poor_low" = 19, "bad_low" = 17), + list("entry" = "Nitrogen", "units" = "kPa", "val" = "[round(n2_level*100,0.1)]", "bad_high" = 105, "poor_high" = 85, "poor_low" = 50, "bad_low" = 40), + list("entry" = "Carbon Dioxide", "units" = "kPa", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0), + list("entry" = "Phoron", "units" = "kPa", "val" = "[round(phoron_level*100,0.01)]", "bad_high" = 0.5, "poor_high" = 0, "poor_low" = 0, "bad_low" = 0), + list("entry" = "Other", "units" = "kPa", "val" = "[round(unknown_level, 0.01)]", "bad_high" = 1, "poor_high" = 0.5, "poor_low" = 0, "bad_low" = 0) + ) + + if(isnull(results)) + results = list(list("entry" = "pressure", "units" = "kPa", "val" = "0", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80)) + + data["aircontents"] = results + + return data /datum/infomorph_software/ar_hud name = "AR HUD" @@ -302,45 +321,56 @@ is_active(mob/living/silicon/infomorph/user) return user.translator.listening + /datum/infomorph_software/signaller - name = "Remote Signaller" - ram_cost = 15 + name = "Remote Signaler" + ram_cost = 5 id = "signaller" toggle = 0 - on_ui_interact(mob/living/silicon/infomorph/user, datum/nanoui/ui=null, force_open=1) - var/data[0] +/datum/infomorph_software/signaller/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Signaler", "Signaler", parent_ui) + ui.open() - data["frequency"] = format_frequency(user.sradio.frequency) - data["code"] = user.sradio.code +/datum/infomorph_software/signaller/tgui_data(mob/living/silicon/infomorph/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + var/obj/item/radio/integrated/signal/R = user.sradio - ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open) - if(!ui) - // Don't copy-paste this unless you're making a pAI software module! - ui = new(user, user, id, "pai_signaller.tmpl", "Signaller", 320, 150) - ui.set_initial_data(data) - ui.open() + data["frequency"] = R.frequency + data["minFrequency"] = RADIO_LOW_FREQ + data["maxFrequency"] = RADIO_HIGH_FREQ + data["code"] = R.code - Topic(href, href_list) - var/mob/living/silicon/infomorph/P = usr - if(!istype(P)) return + return data - if(href_list["send"]) - P.sradio.send_signal("ACTIVATE") - for(var/mob/O in hearers(1, P.loc)) - O.show_message("[bicon(P)] *beep* *beep*", 3, "*beep* *beep*", 2) - return 1 +/datum/infomorph_software/signaller/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE - else if(href_list["freq"]) - var/new_frequency = (P.sradio.frequency + text2num(href_list["freq"])) - if(new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ) - new_frequency = sanitize_frequency(new_frequency) - P.sradio.set_frequency(new_frequency) - return 1 + var/mob/living/silicon/infomorph/user = usr + if(istype(user)) + var/obj/item/radio/integrated/signal/R = user.sradio - else if(href_list["code"]) - P.sradio.code += text2num(href_list["code"]) - P.sradio.code = round(P.sradio.code) - P.sradio.code = min(100, P.sradio.code) - P.sradio.code = max(1, P.sradio.code) - return 1 + switch(action) + if("signal") + spawn(0) + R.send_signal("ACTIVATE") + for(var/mob/O in hearers(1, R.loc)) + O.show_message("[bicon(R)] *beep* *beep*", 3, "*beep* *beep*", 2) + if("freq") + var/frequency = unformat_frequency(params["freq"]) + frequency = sanitize_frequency(frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) + R.set_frequency(frequency) + . = TRUE + if("code") + R.code = clamp(round(text2num(params["code"])), 1, 100) + . = TRUE + if("reset") + if(params["reset"] == "freq") + R.set_frequency(initial(R.frequency)) + else + R.code = initial(R.code) + . = TRUE diff --git a/code/modules/resleeving/sleevecard.dm b/code/modules/resleeving/sleevecard.dm index d7a7ab3c4d..8e8bb68a77 100644 --- a/code/modules/resleeving/sleevecard.dm +++ b/code/modules/resleeving/sleevecard.dm @@ -1,6 +1,9 @@ /obj/item/device/radio/sleevecard canhear_range = 0 +/obj/item/device/radio/sleevecard/tgui_state(mob/user) + return GLOB.tgui_always_state + /obj/item/device/sleevecard name = "sleevecard" desc = "This Vey-Med-upgraded pAI module has enough capacity to run a whole mind of human-level intelligence." diff --git a/code/modules/shuttles/shuttle_console_multi.dm b/code/modules/shuttles/shuttle_console_multi.dm index 9226caebfb..2e45441b1a 100644 --- a/code/modules/shuttles/shuttle_console_multi.dm +++ b/code/modules/shuttles/shuttle_console_multi.dm @@ -26,7 +26,7 @@ switch(action) if("pick") var/dest_key = input("Choose shuttle destination", "Shuttle Destination") as null|anything in shuttle.get_destinations() - if(dest_key && CanInteract(usr, global.default_state)) + if(dest_key && CanInteract(usr, GLOB.tgui_default_state)) shuttle.set_destination(dest_key, usr) return TRUE diff --git a/code/modules/shuttles/shuttle_emergency.dm b/code/modules/shuttles/shuttle_emergency.dm index 3b491a0c5b..f6f56cc7fd 100644 --- a/code/modules/shuttles/shuttle_emergency.dm +++ b/code/modules/shuttles/shuttle_emergency.dm @@ -175,84 +175,3 @@ /obj/machinery/computer/shuttle_control/emergency/attackby(obj/item/weapon/W as obj, mob/user as mob) read_authorization(W) ..() - -/obj/machinery/computer/shuttle_control/emergency/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - var/datum/shuttle/autodock/ferry/emergency/shuttle = SSshuttles.shuttles[shuttle_tag] - if (!istype(shuttle)) - return - - var/shuttle_state - switch(shuttle.moving_status) - if(SHUTTLE_IDLE) shuttle_state = "idle" - if(SHUTTLE_WARMUP) shuttle_state = "warmup" - if(SHUTTLE_INTRANSIT) shuttle_state = "in_transit" - - var/shuttle_status - switch (shuttle.process_state) - if(IDLE_STATE) - if (shuttle.in_use) - shuttle_status = "Busy." - else if (!shuttle.location) - shuttle_status = "Standing by at [station_name()]." - else - shuttle_status = "Standing by at [using_map.dock_name]." - if(WAIT_LAUNCH, FORCE_LAUNCH) - shuttle_status = "Shuttle has received command and will depart shortly." - if(WAIT_ARRIVE) - shuttle_status = "Proceeding to destination." - if(WAIT_FINISH) - shuttle_status = "Arriving at destination now." - - //build a list of authorizations - var/list/auth_list[req_authorizations] - - if (!emagged) - var/i = 1 - for (var/dna_hash in authorized) - auth_list[i++] = list("auth_name"=authorized[dna_hash], "auth_hash"=dna_hash) - - while (i <= req_authorizations) //fill up the rest of the list with blank entries - auth_list[i++] = list("auth_name"="", "auth_hash"=null) - else - for (var/i = 1; i <= req_authorizations; i++) - auth_list[i] = list("auth_name"="ERROR", "auth_hash"=null) - - var/has_auth = has_authorization() - - data = list( - "shuttle_status" = shuttle_status, - "shuttle_state" = shuttle_state, - "has_docking" = shuttle.active_docking_controller? 1 : 0, - "docking_status" = shuttle.active_docking_controller? shuttle.active_docking_controller.get_docking_status() : null, - "docking_override" = shuttle.active_docking_controller? shuttle.active_docking_controller.override_enabled : null, - "can_launch" = shuttle.can_launch(src), - "can_cancel" = shuttle.can_cancel(src), - "can_force" = shuttle.can_force(src), - "auth_list" = auth_list, - "has_auth" = has_auth, - "user" = debug? user : null, - ) - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - - if (!ui) - ui = new(user, src, ui_key, "escape_shuttle_control_console.tmpl", "Shuttle Control", 470, 420) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/computer/shuttle_control/emergency/Topic(href, href_list) - if(..()) - return 1 - - if(href_list["removeid"]) - var/dna_hash = href_list["removeid"] - authorized -= dna_hash - - if(!emagged && href_list["scanid"]) - //They selected an empty entry. Try to scan their id. - if (ishuman(usr)) - var/mob/living/carbon/human/H = usr - if (!read_authorization(H.get_active_hand())) //try to read what's in their hand first - read_authorization(H.wear_id) diff --git a/code/modules/tables/debug.dm b/code/modules/tables/debug.dm index d1b7a968a9..688758cace 100644 --- a/code/modules/tables/debug.dm +++ b/code/modules/tables/debug.dm @@ -7,7 +7,7 @@ material = get_material_by_name("debugium") ..() -/material/debug +/datum/material/debug name = "debugium" stack_type = /obj/item/stack/material/debug icon_base = "debug" diff --git a/code/modules/tables/tables.dm b/code/modules/tables/tables.dm index 2857d022a9..32aca8f090 100644 --- a/code/modules/tables/tables.dm +++ b/code/modules/tables/tables.dm @@ -20,8 +20,8 @@ var/list/table_icon_cache = list() var/can_plate = 1 var/manipulating = 0 - var/material/material = null - var/material/reinforced = null + var/datum/material/material = null + var/datum/material/reinforced = null // Gambling tables. I'd prefer reinforced with carpet/felt/cloth/whatever, but AFAIK it's either harder or impossible to get /obj/item/stack/material of those. // Convert if/when you can easily get stacks of these. @@ -237,7 +237,7 @@ var/list/table_icon_cache = list() // Returns the material to set the table to. /obj/structure/table/proc/common_material_add(obj/item/stack/material/S, mob/user, verb) // Verb is actually verb without 'e' or 'ing', which is added. Works for 'plate'/'plating' and 'reinforce'/'reinforcing'. - var/material/M = S.get_material() + var/datum/material/M = S.get_material() if(!istype(M)) to_chat(user, "You cannot [verb]e \the [src] with \the [S].") return null @@ -253,7 +253,7 @@ var/list/table_icon_cache = list() return M // Returns the material to set the table to. -/obj/structure/table/proc/common_material_remove(mob/user, material/M, delay, what, type_holding, sound) +/obj/structure/table/proc/common_material_remove(mob/user, datum/material/M, delay, what, type_holding, sound) if(!M.stack_type) to_chat(user, "You are unable to remove the [what] from this [src]!") return M @@ -322,7 +322,7 @@ var/list/table_icon_cache = list() if(full_return || prob(20)) new /obj/item/stack/material/steel(src.loc) else - var/material/M = get_material_by_name(DEFAULT_WALL_MATERIAL) + var/datum/material/M = get_material_by_name(DEFAULT_WALL_MATERIAL) S = M.place_shard(loc) if(S) shards += S qdel(src) diff --git a/code/modules/telesci/telesci_computer.dm b/code/modules/telesci/telesci_computer.dm index 1119e565ef..d2a6a0a35a 100644 --- a/code/modules/telesci/telesci_computer.dm +++ b/code/modules/telesci/telesci_computer.dm @@ -6,7 +6,7 @@ circuit = /obj/item/weapon/circuitboard/telesci_console var/sending = 1 var/obj/machinery/telepad/telepad = null - var/temp_msg = "Telescience control console initialized.
Welcome." + var/temp_msg = "Telescience control console initialized. Welcome." // VARIABLES // var/teles_left // How many teleports left until it becomes uncalibrated @@ -83,16 +83,21 @@ /obj/machinery/computer/telescience/attack_hand(mob/user) if(..()) return - ui_interact(user) + tgui_interact(user) -/obj/machinery/computer/telescience/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/computer/telescience/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TelesciConsole", name) + ui.open() - var/data[0] +/obj/machinery/computer/telescience/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = list() if(!telepad) in_use = 0 //Yeah so if you deconstruct teleporter while its in the process of shooting it wont disable the console data["noTelepad"] = 1 else + data["noTelepad"] = 0 data["insertedGps"] = inserted_gps data["rotation"] = rotation data["currentZ"] = z_co @@ -110,6 +115,7 @@ //We'll base our options on connected z's or overmap data["sectorOptions"] = using_map.get_map_levels(z, TRUE, overmap_range) + data["lastTeleData"] = null if(last_tele_data) data["lastTeleData"] = list() data["lastTeleData"]["src_x"] = last_tele_data.src_x @@ -117,12 +123,61 @@ data["lastTeleData"]["distance"] = last_tele_data.distance data["lastTeleData"]["time"] = last_tele_data.time - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "telescience_console.tmpl", src.name, 400, 450) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(5) + return data + +/obj/machinery/computer/telescience/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + if(!telepad || telepad.panel_open) + return TRUE + + switch(action) + if("setrotation") + rotation = CLAMP(text2num(params["val"]), -900, 900) + rotation = round(rotation, 0.01) + + if("setdistance") + distance = CLAMP(text2num(params["val"]), 1, get_max_allowed_distance()) + distance = FLOOR(distance, 1) + + if("setz") + var/new_z = text2num(params["setz"]) + if(new_z in using_map.player_levels) + z_co = new_z + + if("ejectGPS") + if(inserted_gps) + inserted_gps.forceMove(loc) + inserted_gps = null + + if("setMemory") + if(last_target && inserted_gps) + // TODO - What was this even supposed to do?? + //inserted_gps.locked_location = last_target + temp_msg = "Location saved." + else + temp_msg = "ERROR! No data was stored." + + if("send") + sending = 1 + teleport(usr) + + if("receive") + sending = 0 + teleport(usr) + + if("recal") + recalibrate() + sparks() + temp_msg = "NOTICE: Calibration successful." + + if("eject") + eject() + temp_msg = "NOTICE: Bluespace crystals ejected." + else + return FALSE + + return TRUE /obj/machinery/computer/telescience/proc/sparks() if(telepad) @@ -198,7 +253,7 @@ playsound(telepad, 'sound/weapons/flash.ogg', 50, 1) // Wait depending on the time the projectile took to get there teleporting = 1 - temp_msg = "Powering up bluespace crystals.
Please wait." + temp_msg = "Powering up bluespace crystals. Please wait." spawn(spawn_time) // in deciseconds if(!telepad) @@ -218,12 +273,12 @@ if(!A || (A.flags & BLUE_SHIELDED)) telefail() - temp_msg = "ERROR!
Target is shielded from bluespace intersection!" + temp_msg = "ERROR! Target is shielded from bluespace intersection!" return - temp_msg = "Teleport successful.
" + temp_msg = "Teleport successful. " if(teles_left < 10) - temp_msg += "Calibration required soon.
" + temp_msg += "Calibration required soon. " temp_msg += "Data printed below." var/sparks = get_turf(target) @@ -286,11 +341,11 @@ /obj/machinery/computer/telescience/proc/teleport(mob/user) distance = CLAMP(distance, 0, get_max_allowed_distance()) if(rotation == null || distance == null || z_co == null) - temp_msg = "ERROR!
Set a distance, rotation and sector." + temp_msg = "ERROR! Set a distance, rotation and sector." return if(distance <= 0) telefail() - temp_msg = "ERROR!
No distance selected!" + temp_msg = "ERROR! No distance selected!" return if(!(z_co in using_map.player_levels)) telefail() @@ -300,7 +355,7 @@ doteleport(user) else telefail() - temp_msg = "ERROR!
Calibration required." + temp_msg = "ERROR! Calibration required." return return @@ -310,64 +365,6 @@ crystals -= I distance = 0 -/obj/machinery/computer/telescience/Topic(href, href_list) - if(..()) - return - if(!telepad || telepad.panel_open) - updateDialog() - return - - if(href_list["setrotation"]) - var/new_rot = input("Please input desired bearing in degrees.", name, rotation) as num - if(..()) // Check after we input a value, as they could've moved after they entered something - return - rotation = CLAMP(new_rot, -900, 900) - rotation = round(rotation, 0.01) - - if(href_list["setdistance"]) - var/new_pow = input("Please input desired distance in meters.", name, rotation) as num - if(..()) // Check after we input a value, as they could've moved after they entered something - return - distance = CLAMP(new_pow, 1, get_max_allowed_distance()) - distance = FLOOR(distance, 1) - - if(href_list["setz"]) - var/new_z = text2num(href_list["setz"]) - if(new_z in using_map.player_levels) - z_co = new_z - - if(href_list["ejectGPS"]) - if(inserted_gps) - inserted_gps.forceMove(loc) - inserted_gps = null - - if(href_list["setMemory"]) - if(last_target && inserted_gps) - // TODO - What was this even supposed to do?? - //inserted_gps.locked_location = last_target - temp_msg = "Location saved." - else - temp_msg = "ERROR!
No data was stored." - - if(href_list["send"]) - sending = 1 - teleport(usr) - - if(href_list["receive"]) - sending = 0 - teleport(usr) - - if(href_list["recal"]) - recalibrate() - sparks() - temp_msg = "NOTICE:
Calibration successful." - - if(href_list["eject"]) - eject() - temp_msg = "NOTICE:
Bluespace crystals ejected." - - updateDialog() - /obj/machinery/computer/telescience/proc/recalibrate() teles_left = rand(40, 50) distance_off = rand(-4, 4) diff --git a/code/modules/tgui/modules/_base.dm b/code/modules/tgui/modules/_base.dm index 1a1027072d..7cece1c097 100644 --- a/code/modules/tgui/modules/_base.dm +++ b/code/modules/tgui/modules/_base.dm @@ -123,4 +123,7 @@ Code is pretty much ripped verbatim from nano modules, but with un-needed stuff . += new /obj/screen/plane_master{plane = PLANE_CH_BACKUP} //Backup implant status . += new /obj/screen/plane_master{plane = PLANE_CH_VANTAG} //Vore Antags . += new /obj/screen/plane_master{plane = PLANE_AUGMENTED} //Augmented reality - //VOREStation Add End \ No newline at end of file + //VOREStation Add End + +/datum/tgui_module/proc/relaymove(mob/user, direction) + return FALSE diff --git a/code/modules/tgui/modules/agentcard.dm b/code/modules/tgui/modules/agentcard.dm new file mode 100644 index 0000000000..7d35a9bc4a --- /dev/null +++ b/code/modules/tgui/modules/agentcard.dm @@ -0,0 +1,135 @@ +/datum/tgui_module/agentcard + name = "Agent Card" + tgui_id = "AgentCard" + +/datum/tgui_module/agentcard/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + var/obj/item/weapon/card/id/syndicate/S = tgui_host() + if(!istype(S)) + return list() + + var/list/entries = list() + entries += list(list("name" = "Age", "value" = S.age)) + entries += list(list("name" = "Appearance", "value" = "Set")) + entries += list(list("name" = "Assignment", "value" = S.assignment)) + entries += list(list("name" = "Blood Type", "value" = S.blood_type)) + entries += list(list("name" = "DNA Hash", "value" = S.dna_hash)) + entries += list(list("name" = "Fingerprint Hash", "value" = S.fingerprint_hash)) + entries += list(list("name" = "Name", "value" = S.registered_name)) + entries += list(list("name" = "Photo", "value" = "Update")) + entries += list(list("name" = "Sex", "value" = S.sex)) + entries += list(list("name" = "Factory Reset", "value" = "Use With Care")) + data["entries"] = entries + + data["electronic_warfare"] = S.electronic_warfare + + return data + +/datum/tgui_module/agentcard/tgui_status(mob/user, datum/tgui_state/state) + var/obj/item/weapon/card/id/syndicate/S = tgui_host() + if(!istype(S)) + return STATUS_CLOSE + if(user != S.registered_user) + return STATUS_CLOSE + return ..() + +/datum/tgui_module/agentcard/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + var/obj/item/weapon/card/id/syndicate/S = tgui_host() + switch(action) + if("electronic_warfare") + S.electronic_warfare = !S.electronic_warfare + to_chat(usr, "Electronic warfare [S.electronic_warfare ? "enabled" : "disabled"].") + . = TRUE + if("age") + var/new_age = input(usr,"What age would you like to put on this card?","Agent Card Age", S.age) as null|num + if(!isnull(new_age) && tgui_status(usr, state) == STATUS_INTERACTIVE) + if(new_age < 0) + S.age = initial(S.age) + else + S.age = new_age + to_chat(usr, "Age has been set to '[S.age]'.") + . = TRUE + if("appearance") + var/datum/card_state/choice = input(usr, "Select the appearance for this card.", "Agent Card Appearance") as null|anything in id_card_states() + if(choice && tgui_status(usr, state) == STATUS_INTERACTIVE) + S.icon_state = choice.icon_state + S.item_state = choice.item_state + to_chat(usr, "Appearance changed to [choice].") + . = TRUE + if("assignment") + var/new_job = sanitize(input(usr,"What assignment would you like to put on this card?\nChanging assignment will not grant or remove any access levels.","Agent Card Assignment", S.assignment) as null|text) + if(!isnull(new_job) && tgui_status(usr, state) == STATUS_INTERACTIVE) + S.assignment = new_job + to_chat(usr, "Occupation changed to '[new_job]'.") + S.update_name() + . = TRUE + if("bloodtype") + var/default = S.blood_type + if(default == initial(S.blood_type) && ishuman(usr)) + var/mob/living/carbon/human/H = usr + if(H.dna) + default = H.dna.b_type + var/new_blood_type = sanitize(input(usr,"What blood type would you like to be written on this card?","Agent Card Blood Type",default) as null|text) + if(!isnull(new_blood_type) && tgui_status(usr, state) == STATUS_INTERACTIVE) + S.blood_type = new_blood_type + to_chat(usr, "Blood type changed to '[new_blood_type]'.") + . = TRUE + if("dnahash") + var/default = S.dna_hash + if(default == initial(S.dna_hash) && ishuman(usr)) + var/mob/living/carbon/human/H = usr + if(H.dna) + default = H.dna.unique_enzymes + var/new_dna_hash = sanitize(input(usr,"What DNA hash would you like to be written on this card?","Agent Card DNA Hash",default) as null|text) + if(!isnull(new_dna_hash) && tgui_status(usr, state) == STATUS_INTERACTIVE) + S.dna_hash = new_dna_hash + to_chat(usr, "DNA hash changed to '[new_dna_hash]'.") + . = TRUE + if("fingerprinthash") + var/default = S.fingerprint_hash + if(default == initial(S.fingerprint_hash) && ishuman(usr)) + var/mob/living/carbon/human/H = usr + if(H.dna) + default = md5(H.dna.uni_identity) + var/new_fingerprint_hash = sanitize(input(usr,"What fingerprint hash would you like to be written on this card?","Agent Card Fingerprint Hash",default) as null|text) + if(!isnull(new_fingerprint_hash) && tgui_status(usr, state) == STATUS_INTERACTIVE) + S.fingerprint_hash = new_fingerprint_hash + to_chat(usr, "Fingerprint hash changed to '[new_fingerprint_hash]'.") + . = TRUE + if("name") + var/new_name = sanitizeName(input(usr,"What name would you like to put on this card?","Agent Card Name", S.registered_name) as null|text) + if(!isnull(new_name) && tgui_status(usr, state) == STATUS_INTERACTIVE) + S.registered_name = new_name + S.update_name() + to_chat(usr, "Name changed to '[new_name]'.") + . = TRUE + if("photo") + S.set_id_photo(usr) + to_chat(usr, "Photo changed.") + . = TRUE + if("sex") + var/new_sex = sanitize(input(usr,"What sex would you like to put on this card?","Agent Card Sex", S.sex) as null|text) + if(!isnull(new_sex) && tgui_status(usr, state) == STATUS_INTERACTIVE) + S.sex = new_sex + to_chat(usr, "Sex changed to '[new_sex]'.") + . = TRUE + if("factoryreset") + if(alert("This will factory reset the card, including access and owner. Continue?", "Factory Reset", "No", "Yes") == "Yes" && tgui_status(usr, state) == STATUS_INTERACTIVE) + S.age = initial(S.age) + S.access = syndicate_access.Copy() + S.assignment = initial(S.assignment) + S.blood_type = initial(S.blood_type) + S.dna_hash = initial(S.dna_hash) + S.electronic_warfare = initial(S.electronic_warfare) + S.fingerprint_hash = initial(S.fingerprint_hash) + S.icon_state = initial(S.icon_state) + S.name = initial(S.name) + S.registered_name = initial(S.registered_name) + S.unset_registered_user() + S.sex = initial(S.sex) + to_chat(usr, "All information has been deleted from \the [src].") + . = TRUE diff --git a/code/modules/tgui/modules/atmos_control.dm b/code/modules/tgui/modules/atmos_control.dm index 83d3db4d1e..4fd477a531 100644 --- a/code/modules/tgui/modules/atmos_control.dm +++ b/code/modules/tgui/modules/atmos_control.dm @@ -34,6 +34,11 @@ ui.set_map_z_level(params["mapZLevel"]) return TRUE +/datum/tgui_module/atmos_control/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/simple/nanomaps), + ) + /datum/tgui_module/atmos_control/tgui_interact(mob/user, datum/tgui/ui = null) ui = SStgui.try_update_ui(user, src, ui) if(!ui) diff --git a/code/modules/tgui/modules/communications.dm b/code/modules/tgui/modules/communications.dm new file mode 100644 index 0000000000..1af2a003cc --- /dev/null +++ b/code/modules/tgui/modules/communications.dm @@ -0,0 +1,486 @@ +#define COMM_SCREEN_MAIN 1 +#define COMM_SCREEN_STAT 2 +#define COMM_SCREEN_MESSAGES 3 + +#define COMM_AUTHENTICATION_NONE 0 +#define COMM_AUTHENTICATION_MIN 1 +#define COMM_AUTHENTICATION_MAX 2 + +#define COMM_MSGLEN_MINIMUM 6 +#define COMM_CCMSGLEN_MINIMUM 20 + +/datum/tgui_module/communications + name = "Command & Communications" + tgui_id = "CommunicationsConsole" + + var/emagged = FALSE + + var/current_viewing_message_id = 0 + var/current_viewing_message = null + + var/authenticated = COMM_AUTHENTICATION_NONE + var/menu_state = COMM_SCREEN_MAIN + var/ai_menu_state = COMM_SCREEN_MAIN + var/aicurrmsg + + var/message_cooldown + var/centcomm_message_cooldown + var/tmp_alertlevel = 0 + + var/stat_msg1 + var/stat_msg2 + var/display_type = "blank" + + var/datum/announcement/priority/crew_announcement + + var/datum/lore/atc_controller/ATC + + var/list/req_access = list() + +/datum/tgui_module/communications/New(host) + . = ..() + ATC = atc + crew_announcement = new() + crew_announcement.newscast = TRUE + +/datum/tgui_module/communications/tgui_interact(mob/user, datum/tgui/ui) + if(using_map && !(get_z(user) in using_map.contact_levels)) + to_chat(user, "Unable to establish a connection: You're too far away from the station!") + return FALSE + . = ..() + +/datum/tgui_module/communications/proc/is_authenticated(mob/user, message = TRUE) + if(authenticated == COMM_AUTHENTICATION_MAX) + return COMM_AUTHENTICATION_MAX + else if(isobserver(user)) + var/mob/observer/dead/D = user + if(D.can_admin_interact()) + return COMM_AUTHENTICATION_MAX + else if(authenticated) + return COMM_AUTHENTICATION_MIN + else + if(message) + to_chat(user, "Access denied.") + return COMM_AUTHENTICATION_NONE + +/datum/tgui_module/communications/proc/change_security_level(new_level) + tmp_alertlevel = new_level + var/old_level = security_level + if(!tmp_alertlevel) tmp_alertlevel = SEC_LEVEL_GREEN + if(tmp_alertlevel < SEC_LEVEL_GREEN) tmp_alertlevel = SEC_LEVEL_GREEN + if(tmp_alertlevel > SEC_LEVEL_BLUE) tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this + set_security_level(tmp_alertlevel) + if(security_level != old_level) + //Only notify the admins if an actual change happened + log_game("[key_name(usr)] has changed the security level to [get_security_level()].") + message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].") + switch(security_level) + if(SEC_LEVEL_GREEN) + feedback_inc("alert_comms_green",1) + if(SEC_LEVEL_YELLOW) + feedback_inc("alert_comms_yellow",1) + if(SEC_LEVEL_VIOLET) + feedback_inc("alert_comms_violet",1) + if(SEC_LEVEL_ORANGE) + feedback_inc("alert_comms_orange",1) + if(SEC_LEVEL_BLUE) + feedback_inc("alert_comms_blue",1) + tmp_alertlevel = 0 + +/datum/tgui_module/communications/tgui_data(mob/user) + var/list/data = ..() + data["is_ai"] = isAI(user) || isrobot(user) + data["menu_state"] = data["is_ai"] ? ai_menu_state : menu_state + data["emagged"] = emagged + data["authenticated"] = is_authenticated(user, 0) + data["authmax"] = data["authenticated"] == COMM_AUTHENTICATION_MAX ? TRUE : FALSE + data["atcsquelch"] = ATC.squelched + data["boss_short"] = using_map.boss_short + + data["stat_display"] = list( + "type" = display_type, + // "icon" = display_icon, + "line_1" = (stat_msg1 ? stat_msg1 : "-----"), + "line_2" = (stat_msg2 ? stat_msg2 : "-----"), + + "presets" = list( + list("name" = "blank", "label" = "Clear", "desc" = "Blank slate"), + list("name" = "shuttle", "label" = "Shuttle ETA", "desc" = "Display how much time is left."), + list("name" = "message", "label" = "Message", "desc" = "A custom message.") + ), + ) + + data["security_level"] = security_level + switch(security_level) + if(SEC_LEVEL_BLUE) + data["security_level_color"] = "blue"; + if(SEC_LEVEL_ORANGE) + data["security_level_color"] = "orange"; + if(SEC_LEVEL_VIOLET) + data["security_level_color"] = "violet"; + if(SEC_LEVEL_YELLOW) + data["security_level_color"] = "yellow"; + if(SEC_LEVEL_GREEN) + data["security_level_color"] = "green"; + if(SEC_LEVEL_RED) + data["security_level_color"] = "red"; + else + data["security_level_color"] = "purple"; + data["str_security_level"] = capitalize(get_security_level()) + data["levels"] = list( + list("id" = SEC_LEVEL_GREEN, "name" = "Green", "icon" = "dove"), + list("id" = SEC_LEVEL_YELLOW, "name" = "Yellow", "icon" = "exclamation-triangle"), + list("id" = SEC_LEVEL_BLUE, "name" = "Blue", "icon" = "eye"), + list("id" = SEC_LEVEL_ORANGE, "name" = "Orange", "icon" = "wrench"), + list("id" = SEC_LEVEL_VIOLET, "name" = "Violet", "icon" = "biohazard"), + ) + + var/datum/comm_message_listener/l = obtain_message_listener() + data["messages"] = l.messages + data["message_deletion_allowed"] = l != global_message_listener + data["message_current_id"] = current_viewing_message_id + data["message_current"] = current_viewing_message + + // data["lastCallLoc"] = SSshuttle.emergencyLastCallLoc ? format_text(SSshuttle.emergencyLastCallLoc.name) : null + data["msg_cooldown"] = message_cooldown ? (round((message_cooldown - world.time) / 10)) : 0 + data["cc_cooldown"] = centcomm_message_cooldown ? (round((centcomm_message_cooldown - world.time) / 10)) : 0 + + data["esc_callable"] = emergency_shuttle.location() && !emergency_shuttle.online() ? TRUE : FALSE + data["esc_recallable"] = emergency_shuttle.location() && emergency_shuttle.online() ? TRUE : FALSE + data["esc_status"] = FALSE + if(emergency_shuttle.has_eta()) + var/timeleft = emergency_shuttle.estimate_arrival_time() + data["esc_status"] = emergency_shuttle.online() ? "ETA:" : "RECALLING:" + data["esc_status"] += " [timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]" + return data + +/datum/tgui_module/communications/proc/setCurrentMessage(mob/user, value) + current_viewing_message_id = value + + var/datum/comm_message_listener/l = obtain_message_listener() + for(var/list/m in l.messages) + if(m["id"] == current_viewing_message_id) + current_viewing_message = m + +/datum/tgui_module/communications/proc/setMenuState(mob/user, value) + if(isAI(user) || isrobot(user)) + ai_menu_state = value + else + menu_state = value + +/datum/tgui_module/communications/proc/obtain_message_listener() + if(istype(host, /datum/computer_file/program/comm)) + var/datum/computer_file/program/comm/P = host + return P.message_core + return global_message_listener + +/proc/post_status(atom/source, command, data1, data2, mob/user = null) + var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) + + if(!frequency) + return + + var/datum/signal/status_signal = new + status_signal.source = source + status_signal.transmission_method = TRANSMISSION_RADIO + status_signal.data["command"] = command + + switch(command) + if("message") + status_signal.data["msg1"] = data1 + status_signal.data["msg2"] = data2 + log_admin("STATUS: [user] set status screen message: [data1] [data2]") + //message_admins("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]") + if("alert") + status_signal.data["picture_state"] = data1 + + frequency.post_signal(null, status_signal) + +/datum/tgui_module/communications/tgui_act(action, params) + if(..()) + return TRUE + if(using_map && !(get_z(usr) in using_map.contact_levels)) + to_chat(usr, "Unable to establish a connection: You're too far away from the station!") + return FALSE + + . = TRUE + if(action == "auth") + if(!ishuman(usr)) + to_chat(usr, "Access denied.") + return FALSE + // Logout function. + if(authenticated != COMM_AUTHENTICATION_NONE) + authenticated = COMM_AUTHENTICATION_NONE + crew_announcement.announcer = null + setMenuState(usr, COMM_SCREEN_MAIN) + return + // Login function. + if(check_access(usr, access_heads)) + authenticated = COMM_AUTHENTICATION_MIN + if(check_access(usr, access_captain)) + authenticated = COMM_AUTHENTICATION_MAX + var/mob/M = usr + var/obj/item/weapon/card/id = M.GetIdCard() + if(istype(id)) + crew_announcement.announcer = GetNameAndAssignmentFromId(id) + if(authenticated == COMM_AUTHENTICATION_NONE) + to_chat(usr, "You need to wear your ID.") + + // All functions below this point require authentication. + if(!is_authenticated(usr)) + return FALSE + + switch(action) + // main interface + if("main") + setMenuState(usr, COMM_SCREEN_MAIN) + + if("newalertlevel") + if(isAI(usr) || isrobot(usr)) + to_chat(usr, "Firewalls prevent you from changing the alert level.") + return + else if(isobserver(usr)) + var/mob/observer/dead/D = usr + if(D.can_admin_interact()) + change_security_level(text2num(params["level"])) + return TRUE + else if(!ishuman(usr)) + to_chat(usr, "Security measures prevent you from changing the alert level.") + return + + if(check_access(usr, access_captain)) + change_security_level(text2num(params["level"])) + else + to_chat(usr, "You are not authorized to do this.") + setMenuState(usr, COMM_SCREEN_MAIN) + + if("announce") + if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX) + if(message_cooldown > world.time) + to_chat(usr, "Please allow at least one minute to pass between announcements.") + return + var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement") as null|message + if(!input || message_cooldown > world.time || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)) + return + if(length(input) < COMM_MSGLEN_MINIMUM) + to_chat(usr, "Message '[input]' is too short. [COMM_MSGLEN_MINIMUM] character minimum.") + return + crew_announcement.Announce(input) + message_cooldown = world.time + 600 //One minute + + if("callshuttle") + if(!is_authenticated(usr)) + return + + call_shuttle_proc(usr) + if(emergency_shuttle.online()) + post_status(src, "shuttle", user = usr) + setMenuState(usr, COMM_SCREEN_MAIN) + + if("cancelshuttle") + if(isAI(usr) || isrobot(usr)) + to_chat(usr, "Firewalls prevent you from recalling the shuttle.") + return + var/response = alert("Are you sure you wish to recall the shuttle?", "Confirm", "Yes", "No") + if(response == "Yes") + cancel_call_proc(usr) + setMenuState(usr, COMM_SCREEN_MAIN) + + if("messagelist") + current_viewing_message = null + current_viewing_message_id = null + if(params["msgid"]) + setCurrentMessage(usr, text2num(params["msgid"])) + setMenuState(usr, COMM_SCREEN_MESSAGES) + + if("toggleatc") + ATC.squelched = !ATC.squelched + + if("delmessage") + var/datum/comm_message_listener/l = obtain_message_listener() + if(params["msgid"]) + setCurrentMessage(usr, text2num(params["msgid"])) + var/response = alert("Are you sure you wish to delete this message?", "Confirm", "Yes", "No") + if(response == "Yes") + if(current_viewing_message) + if(l != global_message_listener) + l.Remove(current_viewing_message) + current_viewing_message = null + setMenuState(usr, COMM_SCREEN_MESSAGES) + + if("status") + setMenuState(usr, COMM_SCREEN_STAT) + + // Status display stuff + if("setstat") + display_type = params["statdisp"] + switch(display_type) + if("message") + post_status(src, "message", stat_msg1, stat_msg2, user = usr) + if("alert") + post_status(src, "alert", params["alert"], user = usr) + else + post_status(src, params["statdisp"], user = usr) + + if("setmsg1") + stat_msg1 = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", stat_msg1) as text|null, 40), 40) + setMenuState(usr, COMM_SCREEN_STAT) + + if("setmsg2") + stat_msg2 = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", stat_msg2) as text|null, 40), 40) + setMenuState(usr, COMM_SCREEN_STAT) + + // OMG CENTCOMM LETTERHEAD + if("MessageCentCom") + if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX) + if(centcomm_message_cooldown > world.time) + to_chat(usr, "Arrays recycling. Please stand by.") + return + var/input = sanitize(input("Please choose a message to transmit to [using_map.boss_short] via quantum entanglement. \ + Please be aware that this process is very expensive, and abuse will lead to... termination. \ + Transmission does not guarantee a response. \ + There is a 30 second delay before you may send another message, be clear, full and concise.", "Central Command Quantum Messaging") as null|message) + if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)) + return + if(length(input) < COMM_CCMSGLEN_MINIMUM) + to_chat(usr, "Message '[input]' is too short. [COMM_CCMSGLEN_MINIMUM] character minimum.") + return + CentCom_announce(input, usr) + to_chat(usr, "Message transmitted.") + log_game("[key_name(usr)] has made an IA [using_map.boss_short] announcement: [input]") + centcomm_message_cooldown = world.time + 300 // 30 seconds + setMenuState(usr, COMM_SCREEN_MAIN) + + // OMG SYNDICATE ...LETTERHEAD + if("MessageSyndicate") + if((is_authenticated(usr) == COMM_AUTHENTICATION_MAX) && (emagged)) + if(centcomm_message_cooldown > world.time) + to_chat(usr, "Arrays recycling. Please stand by.") + return + var/input = sanitize(input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "")) + if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)) + return + if(length(input) < COMM_CCMSGLEN_MINIMUM) + to_chat(usr, "Message '[input]' is too short. [COMM_CCMSGLEN_MINIMUM] character minimum.") + return + Syndicate_announce(input, usr) + to_chat(usr, "Message transmitted.") + log_game("[key_name(usr)] has made an illegal announcement: [input]") + centcomm_message_cooldown = world.time + 300 // 30 seconds + + if("RestoreBackup") + to_chat(usr, "Backup routing data restored!") + emagged = FALSE + setMenuState(usr, COMM_SCREEN_MAIN) + +/datum/tgui_module/communications/ntos + ntos = TRUE + +/* Etc global procs */ +/proc/enable_prison_shuttle(var/mob/user) + for(var/obj/machinery/computer/prison_shuttle/PS in machines) + PS.allowedtocall = !(PS.allowedtocall) + +/proc/call_shuttle_proc(var/mob/user) + if ((!( ticker ) || !emergency_shuttle.location())) + return + + if(!universe.OnShuttleCall(usr)) + to_chat(user, "Cannot establish a bluespace connection.") + return + + if(deathsquad.deployed) + to_chat(user, "[using_map.boss_short] will not allow the shuttle to be called. Consider all contracts terminated.") + return + + if(emergency_shuttle.deny_shuttle) + to_chat(user, "The emergency shuttle may not be sent at this time. Please try again later.") + return + + if(world.time < 6000) // Ten minute grace period to let the game get going without lolmetagaming. -- TLE + to_chat(user, "The emergency shuttle is refueling. Please wait another [round((6000-world.time)/600)] minute\s before trying again.") + return + + if(emergency_shuttle.going_to_centcom()) + to_chat(user, "The emergency shuttle may not be called while returning to [using_map.boss_short].") + return + + if(emergency_shuttle.online()) + to_chat(user, "The emergency shuttle is already on its way.") + return + + if(ticker.mode.name == "blob") + to_chat(user, "Under directive 7-10, [station_name()] is quarantined until further notice.") + return + + emergency_shuttle.call_evac() + log_game("[key_name(user)] has called the shuttle.") + message_admins("[key_name_admin(user)] has called the shuttle.", 1) + admin_chat_message(message = "Emergency evac beginning! Called by [key_name(user)]!", color = "#CC2222") //VOREStation Add + + return + +/proc/init_shift_change(var/mob/user, var/force = 0) + if ((!( ticker ) || !emergency_shuttle.location())) + return + + if(emergency_shuttle.going_to_centcom()) + to_chat(user, "The shuttle may not be called while returning to [using_map.boss_short].") + return + + if(emergency_shuttle.online()) + to_chat(user, "The shuttle is already on its way.") + return + + // if force is 0, some things may stop the shuttle call + if(!force) + if(emergency_shuttle.deny_shuttle) + to_chat(user, "[using_map.boss_short] does not currently have a shuttle available in your sector. Please try again later.") + return + + if(deathsquad.deployed == 1) + to_chat(user, "[using_map.boss_short] will not allow the shuttle to be called. Consider all contracts terminated.") + return + + if(world.time < 54000) // 30 minute grace period to let the game get going + to_chat(user, "The shuttle is refueling. Please wait another [round((54000-world.time)/60)] minutes before trying again.") + return + + if(ticker.mode.auto_recall_shuttle) + //New version pretends to call the shuttle but cause the shuttle to return after a random duration. + emergency_shuttle.auto_recall = 1 + + if(ticker.mode.name == "blob" || ticker.mode.name == "epidemic") + to_chat(user, "Under directive 7-10, [station_name()] is quarantined until further notice.") + return + + emergency_shuttle.call_transfer() + + //delay events in case of an autotransfer + if (isnull(user)) + SSevents.delay_events(EVENT_LEVEL_MODERATE, 9000) //15 minutes + SSevents.delay_events(EVENT_LEVEL_MAJOR, 9000) + + log_game("[user? key_name(user) : "Autotransfer"] has called the shuttle.") + message_admins("[user? key_name_admin(user) : "Autotransfer"] has called the shuttle.", 1) + admin_chat_message(message = "Autotransfer shuttle dispatched, shift ending soon.", color = "#2277BB") //VOREStation Add + + return + +/proc/cancel_call_proc(var/mob/user) + if (!( ticker ) || !emergency_shuttle.can_recall()) + return + if((ticker.mode.name == "blob")||(ticker.mode.name == "Meteor")) + return + + if(!emergency_shuttle.going_to_centcom()) //check that shuttle isn't already heading to CentCom + emergency_shuttle.recall() + log_game("[key_name(user)] has recalled the shuttle.") + message_admins("[key_name_admin(user)] has recalled the shuttle.", 1) + return + +/proc/is_relay_online() + for(var/obj/machinery/telecomms/relay/M in world) + if(M.stat == 0) + return 1 + return 0 diff --git a/code/modules/tgui/modules/crew_manifest.dm b/code/modules/tgui/modules/crew_manifest.dm new file mode 100644 index 0000000000..7c4daf7f2a --- /dev/null +++ b/code/modules/tgui/modules/crew_manifest.dm @@ -0,0 +1,14 @@ +/datum/tgui_module/crew_manifest + name = "Crew Manifest" + tgui_id = "CrewManifest" + +/datum/tgui_module/crew_manifest/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + if(data_core) + data_core.get_manifest_list() + data["manifest"] = PDA_Manifest + return data + +/datum/tgui_module/crew_manifest/robot +/datum/tgui_module/crew_manifest/robot/tgui_state(mob/user) + return GLOB.tgui_self_state \ No newline at end of file diff --git a/code/modules/tgui/modules/crew_monitor.dm b/code/modules/tgui/modules/crew_monitor.dm index 9d4af68652..d24cd3414a 100644 --- a/code/modules/tgui/modules/crew_monitor.dm +++ b/code/modules/tgui/modules/crew_monitor.dm @@ -2,6 +2,11 @@ name = "Crew monitor" tgui_id = "CrewMonitor" +/datum/tgui_module/crew_monitor/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/simple/nanomaps), + ) + /datum/tgui_module/crew_monitor/tgui_act(action, params, datum/tgui/ui) if(..()) return TRUE diff --git a/code/modules/tgui/modules/ntos-only/cardmod.dm b/code/modules/tgui/modules/ntos-only/cardmod.dm new file mode 100644 index 0000000000..c5aecd8808 --- /dev/null +++ b/code/modules/tgui/modules/ntos-only/cardmod.dm @@ -0,0 +1,235 @@ +// This really should be used for both regular ID computers and NTOS, but +// the data structures are just different enough right now that I can't be assed +/datum/tgui_module/cardmod + name = "ID card modification program" + ntos = TRUE + tgui_id = "IdentificationComputer" + var/mod_mode = 1 + var/is_centcom = 0 + +/datum/tgui_module/cardmod/tgui_static_data(mob/user) + var/list/data = ..() + if(data_core) + data_core.get_manifest_list() + data["manifest"] = PDA_Manifest + return data + +/datum/tgui_module/cardmod/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/datum/computer_file/program/card_mod/program = host + if(!istype(program)) + return 0 + var/list/data = ..() + data["station_name"] = station_name() + data["mode"] = mod_mode + data["printing"] = FALSE + if(program && program.computer) + data["have_id_slot"] = !!program.computer.card_slot + data["have_printer"] = !!program.computer.nano_printer + data["authenticated"] = program.can_run(user) + if(!program.computer.card_slot) + mod_mode = 0 //We can't modify IDs when there is no card reader + else + data["have_id_slot"] = 0 + data["have_printer"] = 0 + data["authenticated"] = 0 + data["centcom_access"] = is_centcom + + + data["has_modify"] = null + data["account_number"] = null + data["id_rank"] = null + data["target_owner"] = null + data["target_name"] = null + if(program && program.computer && program.computer.card_slot) + var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card + data["has_modify"] = !!id_card + data["account_number"] = id_card ? id_card.associated_account_number : null + data["id_rank"] = id_card && id_card.assignment ? id_card.assignment : "Unassigned" + data["target_owner"] = id_card && id_card.registered_name ? id_card.registered_name : "-----" + data["target_name"] = id_card ? id_card.name : "-----" + + var/list/departments = list() + for(var/D in SSjob.get_all_department_datums()) + var/datum/department/dept = D + if(!dept.assignable) // No AI ID cards for you. + continue + if(dept.centcom_only && !is_centcom) + continue + departments.Add(list(list( + "department_name" = dept.name, + "jobs" = format_jobs(SSjob.get_job_titles_in_department(dept.name)), + ))) + + data["departments"] = departments + + var/list/all_centcom_access = list() + var/list/regions = list() + if(program.computer.card_slot && program.computer.card_slot.stored_card) + var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card + if(is_centcom) + for(var/access in get_all_centcom_access()) + all_centcom_access.Add(list(list( + "desc" = replacetext(get_centcom_access_desc(access), " ", " "), + "ref" = access, + "allowed" = (access in id_card.access) ? 1 : 0))) + data["all_centcom_access"] = all_centcom_access + else + for(var/i in ACCESS_REGION_SECURITY to ACCESS_REGION_SUPPLY) + var/list/accesses = list() + for(var/access in get_region_accesses(i)) + if(get_access_desc(access)) + accesses.Add(list(list( + "desc" = replacetext(get_access_desc(access), " ", " "), + "ref" = access, + "allowed" = (access in id_card.access) ? 1 : 0))) + + regions.Add(list(list( + "name" = get_region_accesses_name(i), + "accesses" = accesses))) + data["regions"] = regions + + data["regions"] = regions + data["all_centcom_access"] = all_centcom_access + + return data + +/datum/tgui_module/cardmod/proc/format_jobs(list/jobs) + var/datum/computer_file/program/card_mod/program = host + if(!istype(program)) + return null + + var/obj/item/weapon/card/id/id_card = program.computer.card_slot ? program.computer.card_slot.stored_card : null + var/list/formatted = list() + for(var/job in jobs) + formatted.Add(list(list( + "display_name" = replacetext(job, " ", " "), + "target_rank" = id_card && id_card.assignment ? id_card.assignment : "Unassigned", + "job" = job))) + + return formatted + +/datum/tgui_module/cardmod/tgui_act(action, list/params, datum/tgui/ui) + if(..()) + return TRUE + + + var/datum/computer_file/program/card_mod/program = host + if(!istype(program)) + return TRUE + var/obj/item/modular_computer/computer = tgui_host() + if(!istype(computer)) + return TRUE + + var/obj/item/weapon/card/id/user_id_card = usr.GetIdCard() + var/obj/item/weapon/card/id/id_card + if(computer.card_slot) + id_card = computer.card_slot.stored_card + + switch(action) + if("mode") + mod_mode = clamp(text2num(params["mode_target"]), 0, 1) + . = TRUE + if("print") + if(computer && computer.nano_printer) //This option should never be called if there is no printer + if(!mod_mode) + if(program.can_run(usr, 1)) + var/contents = {"

Access Report

+ Prepared By: [user_id_card.registered_name ? user_id_card.registered_name : "Unknown"]
+ For: [id_card.registered_name ? id_card.registered_name : "Unregistered"]
+
+ Assignment: [id_card.assignment]
+ Account Number: #[id_card.associated_account_number]
+ Blood Type: [id_card.blood_type]

+ Access:
+ "} + + var/known_access_rights = get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM) + for(var/A in id_card.access) + if(A in known_access_rights) + contents += " [get_access_desc(A)]" + + if(!computer.nano_printer.print_text(contents,"access report")) + to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") + return + else + computer.visible_message("\The [computer] prints out paper.") + else + var/contents = {"

Crew Manifest

+
+ [data_core ? data_core.get_manifest(0) : ""] + "} + if(!computer.nano_printer.print_text(contents,text("crew manifest ([])", stationtime2text()))) + to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.") + return + else + computer.visible_message("\The [computer] prints out paper.") + . = TRUE + if("modify") + if(computer && computer.card_slot) + if(id_card) + data_core.manifest_modify(id_card.registered_name, id_card.assignment) + computer.proc_eject_id(usr) + . = TRUE + if("terminate") + if(computer && program.can_run(usr, 1)) + id_card.assignment = "Dismissed" //VOREStation Edit: setting adjustment + id_card.access = list() + callHook("terminate_employee", list(id_card)) + . = TRUE + if("reg") + if(computer && program.can_run(usr, 1)) + var/temp_name = sanitizeName(params["reg"], allow_numbers = TRUE) + if(temp_name) + id_card.registered_name = temp_name + else + computer.visible_message("[computer] buzzes rudely.") + . = TRUE + if("account") + if(computer && program.can_run(usr, 1)) + var/account_num = text2num(params["account"]) + id_card.associated_account_number = account_num + . = TRUE + if("assign") + if(computer && program.can_run(usr, 1) && id_card) + var/t1 = params["assign_target"] + if(t1 == "Custom") + var/temp_t = sanitize(input("Enter a custom job assignment.","Assignment", id_card.assignment), 45) + //let custom jobs function as an impromptu alt title, mainly for sechuds + if(temp_t) + id_card.assignment = temp_t + else + var/list/access = list() + if(is_centcom) + access = get_centcom_access(t1) + else + var/datum/job/jobdatum + for(var/jobtype in typesof(/datum/job)) + var/datum/job/J = new jobtype + if(ckey(J.title) == ckey(t1)) + jobdatum = J + break + if(!jobdatum) + to_chat(usr, "No log exists for this job: [t1]") + return + + access = jobdatum.get_access() + + id_card.access = access + id_card.assignment = t1 + id_card.rank = t1 + + callHook("reassign_employee", list(id_card)) + . = TRUE + if("access") + if(computer && program.can_run(usr, 1)) + var/access_type = text2num(params["access_target"]) + var/access_allowed = text2num(params["allowed"]) + if(access_type in get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM)) + id_card.access -= access_type + if(!access_allowed) + id_card.access += access_type + . = TRUE + + if(id_card) + id_card.name = text("[id_card.registered_name]'s ID Card ([id_card.assignment])") + diff --git a/code/modules/tgui/modules/ntos-only/configurator.dm b/code/modules/tgui/modules/ntos-only/configurator.dm new file mode 100644 index 0000000000..263409f5e3 --- /dev/null +++ b/code/modules/tgui/modules/ntos-only/configurator.dm @@ -0,0 +1,48 @@ +/datum/tgui_module/computer_configurator + name = "NTOS Computer Configuration Tool" + ntos = TRUE + tgui_id = "Configuration" + var/obj/item/modular_computer/movable = null + +/datum/tgui_module/computer_configurator/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + movable = tgui_host() + // No computer connection, we can't get data from that. + if(!istype(movable)) + return 0 + + var/list/data = ..() + + data["disk_size"] = movable.hard_drive.max_capacity + data["disk_used"] = movable.hard_drive.used_capacity + data["power_usage"] = movable.last_power_usage + data["battery_exists"] = movable.battery_module ? 1 : 0 + if(movable.battery_module) + data["battery_rating"] = movable.battery_module.battery.maxcharge + data["battery_percent"] = round(movable.battery_module.battery.percent()) + + if(movable.battery_module && movable.battery_module.battery) + data["battery"] = list("max" = movable.battery_module.battery.maxcharge, "charge" = round(movable.battery_module.battery.charge)) + + var/list/hardware = movable.get_all_components() + var/list/all_entries[0] + for(var/obj/item/weapon/computer_hardware/H in hardware) + all_entries.Add(list(list( + "name" = H.name, + "desc" = H.desc, + "enabled" = H.enabled, + "critical" = H.critical, + "powerusage" = H.power_usage + ))) + + data["hardware"] = all_entries + return data + +/datum/tgui_module/computer_configurator/tgui_act(action, params) + if(..()) + return + switch(action) + if("PC_toggle_component") + var/obj/item/weapon/computer_hardware/H = movable.find_hardware_by_name(params["name"]) + if(H && istype(H)) + H.enabled = !H.enabled + . = TRUE \ No newline at end of file diff --git a/code/modules/tgui/modules/ntos-only/email.dm b/code/modules/tgui/modules/ntos-only/email.dm new file mode 100644 index 0000000000..8d8d1fbbc7 --- /dev/null +++ b/code/modules/tgui/modules/ntos-only/email.dm @@ -0,0 +1,476 @@ +/datum/tgui_module/email_client + name = "Email Client" + tgui_id = "NtosEmailClient" + + var/stored_login = "" + var/stored_password = "" + var/error = "" + + var/msg_title = "" + var/msg_body = "" + var/msg_recipient = "" + var/datum/computer_file/msg_attachment = null + var/folder = "Inbox" + var/addressbook = FALSE + var/new_message = FALSE + + var/last_message_count = 0 // How many messages were there during last check. + var/read_message_count = 0 // How many messages were there when user has last accessed the UI. + + var/datum/computer_file/downloading = null + var/download_progress = 0 + var/download_speed = 0 + + var/datum/computer_file/data/email_account/current_account = null + var/datum/computer_file/data/email_message/current_message = null + +/datum/tgui_module/email_client/proc/log_in() + for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts) + if(!account.can_login) + continue + if(account.login == stored_login) + if(account.password == stored_password) + if(account.suspended) + error = "This account has been suspended. Please contact the system administrator for assistance." + return 0 + current_account = account + return 1 + else + error = "Invalid Password" + return 0 + error = "Invalid Login" + return 0 + +// Returns 0 if no new messages were received, 1 if there is an unread message but notification has already been sent. +// and 2 if there is a new message that appeared in this tick (and therefore notification should be sent by the program). +/datum/tgui_module/email_client/proc/check_for_new_messages(var/messages_read = FALSE) + if(!current_account) + return 0 + + var/list/allmails = current_account.all_emails() + + if(allmails.len > last_message_count) + . = 2 + else if(allmails.len > read_message_count) + . = 1 + else + . = 0 + + last_message_count = allmails.len + if(messages_read) + read_message_count = allmails.len + +/datum/tgui_module/email_client/proc/log_out() + current_account = null + downloading = null + download_progress = 0 + last_message_count = 0 + read_message_count = 0 + +/datum/tgui_module/email_client/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + // Password has been changed by other client connected to this email account + if(current_account) + if(current_account.password != stored_password) + log_out() + error = "Invalid Password" + // Banned. + if(current_account.suspended) + log_out() + error = "This account has been suspended. Please contact the system administrator for assistance." + + // So, TGUI has a bug/feature where it just conveniently doesn't bother to clear out old data if it only gets + // a partial data update; as such, we have to make sure to null all of these out ourselves so the UI works properly. + data["accounts"] = null + data["addressbook"] = null + data["cur_attachment_filename"] = null + data["cur_attachment_size"] = null + data["cur_body"] = null + data["cur_hasattachment"] = null + data["cur_source"] = null + data["cur_timestamp"] = null + data["cur_title"] = null + data["cur_uid"] = null + data["current_account"] = null + data["down_filename"] = null + data["down_progress"] = null + data["down_size"] = null + data["down_speed"] = null + data["downloading"] = null + data["error"] = null + data["folder"] = null + data["label_deleted"] = null + data["label_inbox"] = null + data["label_spam"] = null + data["messagecount"] = null + data["messages"] = null + data["msg_attachment_filename"] = null + data["msg_attachment_size"] = null + data["msg_body"] = null + data["msg_hasattachment"] = null + data["msg_recipient"] = null + data["msg_title"] = null + data["new_message"] = null + data["stored_login"] = null + data["stored_password"] = null + + if(error) + data["error"] = error + else if(downloading) + data["downloading"] = 1 + data["down_filename"] = "[downloading.filename].[downloading.filetype]" + data["down_progress"] = download_progress + data["down_size"] = downloading.size + data["down_speed"] = download_speed + + else if(istype(current_account)) + data["current_account"] = current_account.login + if(addressbook) + var/list/all_accounts = list() + for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts) + if(!account.can_login) + continue + all_accounts.Add(list(list( + "login" = account.login + ))) + data["addressbook"] = 1 + data["accounts"] = all_accounts + else if(new_message) + data["new_message"] = 1 + data["msg_title"] = msg_title + data["msg_body"] = pencode2html(msg_body) + data["msg_recipient"] = msg_recipient + if(msg_attachment) + data["msg_hasattachment"] = 1 + data["msg_attachment_filename"] = "[msg_attachment.filename].[msg_attachment.filetype]" + data["msg_attachment_size"] = msg_attachment.size + else if (current_message) + data["cur_title"] = current_message.title + data["cur_body"] = pencode2html(current_message.stored_data) + data["cur_timestamp"] = current_message.timestamp + data["cur_source"] = current_message.source + data["cur_uid"] = current_message.uid + if(istype(current_message.attachment)) + data["cur_hasattachment"] = 1 + data["cur_attachment_filename"] = "[current_message.attachment.filename].[current_message.attachment.filetype]" + data["cur_attachment_size"] = current_message.attachment.size + else + data["label_inbox"] = "Inbox ([current_account.inbox.len])" + data["label_spam"] = "Spam ([current_account.spam.len])" + data["label_deleted"] = "Deleted ([current_account.deleted.len])" + var/list/message_source + if(folder == "Inbox") + message_source = current_account.inbox + else if(folder == "Spam") + message_source = current_account.spam + else if(folder == "Deleted") + message_source = current_account.deleted + + if(message_source) + data["folder"] = folder + var/list/all_messages = list() + for(var/datum/computer_file/data/email_message/message in message_source) + all_messages.Add(list(list( + "title" = message.title, + "body" = pencode2html(message.stored_data), + "source" = message.source, + "timestamp" = message.timestamp, + "uid" = message.uid + ))) + data["messages"] = all_messages + data["messagecount"] = all_messages.len + else + data["stored_login"] = stored_login + data["stored_password"] = stars(stored_password, 0) + + return data + +/datum/tgui_module/email_client/proc/find_message_by_fuid(var/fuid) + if(!istype(current_account)) + return + + // params works with strings, so this makes it a bit easier for us + if(istext(fuid)) + fuid = text2num(fuid) + + for(var/datum/computer_file/data/email_message/message in current_account.all_emails()) + if(message.uid == fuid) + return message + +/datum/tgui_module/email_client/proc/clear_message() + new_message = FALSE + msg_title = "" + msg_body = "" + msg_recipient = "" + msg_attachment = null + current_message = null + +/datum/tgui_module/email_client/proc/relayed_process(var/netspeed) + download_speed = netspeed + if(!downloading) + return + download_progress = min(download_progress + netspeed, downloading.size) + if(download_progress >= downloading.size) + var/obj/item/modular_computer/MC = tgui_host() + if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) + error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?" + downloading = null + download_progress = 0 + return 1 + + if(MC.hard_drive.store_file(downloading)) + error = "File successfully downloaded to local device." + else + error = "Error saving file: I/O Error: The hard drive may be full or nonfunctional." + downloading = null + download_progress = 0 + return 1 + + +/datum/tgui_module/email_client/tgui_act(action, params) + if(..()) + return TRUE + + var/mob/living/user = usr + check_for_new_messages(1) // Any actual interaction (button pressing) is considered as acknowledging received message, for the purpose of notification icons. + + switch(action) + if("login") + log_in() + return 1 + + if("logout") + log_out() + return 1 + + if("reset") + error = "" + return 1 + + if("new_message") + new_message = TRUE + return 1 + + if("cancel") + if(addressbook) + addressbook = FALSE + else + clear_message() + return 1 + + if("addressbook") + addressbook = TRUE + return 1 + + if("set_recipient") + msg_recipient = sanitize(params["set_recipient"]) + addressbook = FALSE + return 1 + + if("edit_title") + var/newtitle = sanitize(params["val"], 100) + if(newtitle) + msg_title = newtitle + return 1 + + // This uses similar editing mechanism as the FileManager program, therefore it supports various paper tags and remembers formatting. + if("edit_body") + var/oldtext = html_decode(msg_body) + oldtext = replacetext(oldtext, "\[editorbr\]", "\n") + + var/newtext = sanitize(replacetext(input(usr, "Enter your message. You may use most tags from paper formatting", "Message Editor", oldtext) as message|null, "\n", "\[editorbr\]"), 20000) + if(newtext) + msg_body = newtext + return 1 + + if("edit_recipient") + var/newrecipient = sanitize(params["val"], 100) + if(newrecipient) + msg_recipient = newrecipient + return 1 + + if("edit_login") + var/newlogin = sanitize(params["val"], 100) + if(newlogin) + stored_login = newlogin + return 1 + + if("edit_password") + var/newpass = sanitize(params["val"], 100) + if(newpass) + stored_password = newpass + return 1 + + if("delete") + if(!istype(current_account)) + return 1 + var/datum/computer_file/data/email_message/M = find_message_by_fuid(params["delete"]) + if(!istype(M)) + return 1 + if(folder == "Deleted") + current_account.deleted.Remove(M) + qdel(M) + else + current_account.deleted.Add(M) + current_account.inbox.Remove(M) + current_account.spam.Remove(M) + if(current_message == M) + current_message = null + return 1 + + if("send") + if(!current_account) + return 1 + if((msg_title == "") || (msg_body == "") || (msg_recipient == "")) + error = "Error sending mail: Title or message body is empty!" + return 1 + + var/datum/computer_file/data/email_message/message = new() + message.title = msg_title + message.stored_data = msg_body + message.source = current_account.login + message.attachment = msg_attachment + if(!current_account.send_mail(msg_recipient, message)) + error = "Error sending email: this address doesn't exist." + return 1 + else + error = "Email successfully sent." + clear_message() + return 1 + + if("set_folder") + folder = params["set_folder"] + return 1 + + if("reply") + var/datum/computer_file/data/email_message/M = find_message_by_fuid(params["reply"]) + if(!istype(M)) + return 1 + + new_message = TRUE + msg_recipient = M.source + msg_title = "Re: [M.title]" + msg_body = "\[editorbr\]\[editorbr\]\[editorbr\]\[br\]==============================\[br\]\[editorbr\]" + msg_body += "Received by [current_account.login] at [M.timestamp]\[br\]\[editorbr\][M.stored_data]" + return 1 + + if("view") + var/datum/computer_file/data/email_message/M = find_message_by_fuid(params["view"]) + if(istype(M)) + current_message = M + return 1 + + if("changepassword") + var/oldpassword = sanitize(input(user,"Please enter your old password:", "Password Change"), 100) + if(!oldpassword) + return 1 + var/newpassword1 = sanitize(input(user,"Please enter your new password:", "Password Change"), 100) + if(!newpassword1) + return 1 + var/newpassword2 = sanitize(input(user,"Please re-enter your new password:", "Password Change"), 100) + if(!newpassword2) + return 1 + + if(!istype(current_account)) + error = "Please log in before proceeding." + return 1 + + if(current_account.password != oldpassword) + error = "Incorrect original password" + return 1 + + if(newpassword1 != newpassword2) + error = "The entered passwords do not match." + return 1 + + current_account.password = newpassword1 + stored_password = newpassword1 + error = "Your password has been successfully changed!" + return 1 + + // The following entries are Modular Computer framework only, and therefore won't do anything in other cases (like AI View) + + if("save") + // Fully dependant on modular computers here. + var/obj/item/modular_computer/MC = tgui_host() + + if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) + error = "Error exporting file. Are you using a functional and NTOS-compliant device?" + return 1 + + var/filename = sanitize(input(user,"Please specify file name:", "Message export"), 100) + if(!filename) + return 1 + + var/datum/computer_file/data/email_message/M = find_message_by_fuid(params["save"]) + var/datum/computer_file/data/mail = istype(M) ? M.export() : null + if(!istype(mail)) + return 1 + mail.filename = filename + if(!MC.hard_drive || !MC.hard_drive.store_file(mail)) + error = "Internal I/O error when writing file, the hard drive may be full." + else + error = "Email exported successfully" + return 1 + + if("addattachment") + var/obj/item/modular_computer/MC = tgui_host() + msg_attachment = null + + if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) + error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?" + return 1 + + var/list/filenames = list() + for(var/datum/computer_file/CF in MC.hard_drive.stored_files) + if(CF.unsendable) + continue + filenames.Add(CF.filename) + var/picked_file = input(user, "Please pick a file to send as attachment (max 32GQ)") as null|anything in filenames + + if(!picked_file) + return 1 + + if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) + error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?" + return 1 + + for(var/datum/computer_file/CF in MC.hard_drive.stored_files) + if(CF.unsendable) + continue + if(CF.filename == picked_file) + msg_attachment = CF.clone() + break + if(!istype(msg_attachment)) + msg_attachment = null + error = "Unknown error when uploading attachment." + return 1 + + if(msg_attachment.size > 32) + error = "Error uploading attachment: File exceeds maximal permitted file size of 32GQ." + msg_attachment = null + else + error = "File [msg_attachment.filename].[msg_attachment.filetype] has been successfully uploaded." + return 1 + + if("downloadattachment") + if(!current_account || !current_message || !current_message.attachment) + return 1 + var/obj/item/modular_computer/MC = tgui_host() + if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality()) + error = "Error downloading file. Are you using a functional and NTOSv2-compliant device?" + return 1 + + downloading = current_message.attachment.clone() + download_progress = 0 + return 1 + + if("canceldownload") + downloading = null + download_progress = 0 + return 1 + + if("remove_attachment") + msg_attachment = null + return 1 \ No newline at end of file diff --git a/code/modules/tgui/modules/ntos-only/uav.dm b/code/modules/tgui/modules/ntos-only/uav.dm new file mode 100644 index 0000000000..f27a08eda9 --- /dev/null +++ b/code/modules/tgui/modules/ntos-only/uav.dm @@ -0,0 +1,241 @@ +/datum/tgui_module/uav + name = "UAV Control" + tgui_id = "UAV" + ntos = TRUE + var/obj/item/device/uav/current_uav = null //The UAV we're watching + var/signal_strength = 0 //Our last signal strength report (cached for a few seconds) + var/signal_test_counter = 0 //How long until next signal strength check + var/list/viewers //Who's viewing a UAV through us + var/adhoc_range = 30 //How far we can operate on a UAV without NTnet + +/datum/tgui_module/uav/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + if(current_uav) + if(QDELETED(current_uav)) + set_current(null) + else if(signal_test_counter-- <= 0) + signal_strength = get_signal_to(current_uav) + if(!signal_strength) + set_current(null) + else // Don't reset counter until we find a UAV that's actually in range we can stay connected to + signal_test_counter = 20 + + data["current_uav"] = null + if(current_uav) + data["current_uav"] = list("status" = current_uav.get_status_string(), "power" = current_uav.state == 1 ? 1 : null) + data["signal_strength"] = signal_strength ? signal_strength >= 2 ? "High" : "Low" : "None" + data["in_use"] = LAZYLEN(viewers) + + var/list/paired_map = list() + var/obj/item/modular_computer/mc_host = tgui_host() + if(istype(mc_host)) + for(var/puav in mc_host.paired_uavs) + var/weakref/wr = puav + var/obj/item/device/uav/U = wr.resolve() + paired_map.Add(list(list("name" = "[U ? U.nickname : "!!Missing!!"]", "uavref" = "\ref[U]"))) + + data["paired_uavs"] = paired_map + return data + +/datum/tgui_module/uav/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + switch(action) + if("switch_uav") + var/obj/item/device/uav/U = locate(params["switch_uav"]) //This is a \ref to the UAV itself + if(!istype(U)) + to_chat(usr,"Something is blocking the connection to that UAV. In-person investigation is required.") + return FALSE + + if(!get_signal_to(U)) + to_chat(usr,"The screen freezes for a moment, before returning to the UAV selection menu. It's not able to connect to that UAV.") + return FALSE + + set_current(U) + return TRUE + + if("del_uav") + var/refstring = params["del_uav"] //This is a \ref to the UAV itself + var/obj/item/modular_computer/mc_host = tgui_host() + //This is so we can really scrape up any weakrefs that can't resolve + for(var/weakref/wr in mc_host.paired_uavs) + if(wr.ref == refstring) + if(current_uav?.weakref == wr) + set_current(null) + LAZYREMOVE(mc_host.paired_uavs, wr) + return TRUE + + if("view_uav") + if(!current_uav) + return FALSE + + if(current_uav.check_eye(usr) < 0) + to_chat(usr,"The screen freezes for a moment, before returning to the UAV selection menu. It's not able to connect to that UAV.") + else + viewing_uav(usr) ? unlook(usr) : look(usr) + return TRUE + + if("power_uav") + if(!current_uav) + return FALSE + else if(current_uav.toggle_power()) + //Clean up viewers faster + if(LAZYLEN(viewers)) + for(var/weakref/W in viewers) + var/M = W.resolve() + if(M) + unlook(M) + return TRUE + +/datum/tgui_module/uav/proc/set_current(var/obj/item/device/uav/U) + if(current_uav == U) + return + + signal_strength = 0 + current_uav = U + + if(LAZYLEN(viewers)) + for(var/weakref/W in viewers) + var/M = W.resolve() + if(M) + if(current_uav) + to_chat(M, "You're disconnected from the UAV's camera!") + unlook(M) + else + look(M) + +//// +//// Finding signal strength between us and the UAV +//// +/datum/tgui_module/uav/proc/get_signal_to(atom/movable/AM) + // Following roughly the ntnet signal levels + // 0 is none + // 1 is weak + // 2 is strong + var/obj/item/modular_computer/host = tgui_host() //Better not add this to anything other than modular computers. + if(!istype(host)) + return + var/our_signal = host.get_ntnet_status() //1 low, 2 good, 3 wired, 0 none + var/their_z = get_z(AM) + + //If we have no NTnet connection don't bother getting theirs + if(!our_signal) + if(get_z(host) == their_z && (get_dist(host, AM) < adhoc_range)) + return 1 //We can connect (with weak signal) in same z without ntnet, within 30 turfs + else + return 0 + + var/list/zlevels_in_range = using_map.get_map_levels(their_z, FALSE) + var/list/zlevels_in_long_range = using_map.get_map_levels(their_z, TRUE, om_range = DEFAULT_OVERMAP_RANGE) - zlevels_in_range + var/their_signal = 0 + for(var/relay in ntnet_global.relays) + var/obj/machinery/ntnet_relay/R = relay + if(!R.operable()) + continue + if(R.z == their_z) + their_signal = 2 + break + if(R.z in zlevels_in_range) + their_signal = 2 + break + if(R.z in zlevels_in_long_range) + their_signal = 1 + break + + if(!their_signal) //They have no NTnet at all + if(get_z(host) == their_z && (get_dist(host, AM) < adhoc_range)) + return 1 //We can connect (with weak signal) in same z without ntnet, within 30 turfs + else + return 0 + else + return max(our_signal, their_signal) + +/* All handling viewers */ +/datum/tgui_module/uav/Destroy() + if(LAZYLEN(viewers)) + for(var/weakref/W in viewers) + var/M = W.resolve() + if(M) + unlook(M) + . = ..() + +/datum/tgui_module/uav/tgui_status(mob/user) + . = ..() + if(. > STATUS_DISABLED) + if(viewing_uav(user)) + look(user) + return + unlook(user) + +/datum/tgui_module/uav/tgui_close(mob/user) + . = ..() + unlook(user) + +/datum/tgui_module/uav/proc/viewing_uav(mob/user) + return (weakref(user) in viewers) + +/datum/tgui_module/uav/proc/look(mob/user) + if(issilicon(user)) //Too complicated for me to want to mess with at the moment + to_chat(user, "Regulations prevent you from controlling several corporeal forms at the same time!") + return + + if(!current_uav) + return + + if(user.machine != tgui_host()) + user.set_machine(tgui_host()) + user.reset_view(current_uav) + current_uav.add_master(user) + LAZYDISTINCTADD(viewers, weakref(user)) + +/datum/tgui_module/uav/proc/unlook(mob/user) + user.unset_machine() + user.reset_view() + if(current_uav) + current_uav.remove_master(user) + LAZYREMOVE(viewers, weakref(user)) + +/datum/tgui_module/uav/check_eye(mob/user) + if(get_dist(user, tgui_host()) > 1 || user.blinded || !current_uav) + unlook(user) + return -1 + + var/viewflag = current_uav.check_eye(user) + if(viewflag < 0) //camera doesn't work + unlook(user) + return -1 + + return viewflag + +//// +//// Relaying movements to the UAV +//// +/datum/tgui_module/uav/relaymove(var/mob/user, direction) + if(current_uav) + return current_uav.relaymove(user, direction, signal_strength) + +//// +//// The effects when looking through a UAV +//// +/datum/tgui_module/uav/apply_visual(mob/M) + if(!M.client) + return + if(weakref(M) in viewers) + M.overlay_fullscreen("fishbed",/obj/screen/fullscreen/fishbed) + M.overlay_fullscreen("scanlines",/obj/screen/fullscreen/scanline) + + if(signal_strength <= 1) + M.overlay_fullscreen("whitenoise",/obj/screen/fullscreen/noise) + else + M.clear_fullscreen("whitenoise", 0) + else + remove_visual(M) + +/datum/tgui_module/uav/remove_visual(mob/M) + if(!M.client) + return + M.clear_fullscreen("fishbed",0) + M.clear_fullscreen("scanlines",0) + M.clear_fullscreen("whitenoise",0) diff --git a/code/modules/tgui/modules/teleporter.dm b/code/modules/tgui/modules/teleporter.dm new file mode 100644 index 0000000000..9bba6a8659 --- /dev/null +++ b/code/modules/tgui/modules/teleporter.dm @@ -0,0 +1,85 @@ +/datum/tgui_module/teleport_control + name = "Teleporter Control" + tgui_id = "Teleporter" + var/locked_name = "Not Locked" + var/obj/item/locked = null + var/obj/machinery/teleport/station/station = null + var/obj/machinery/teleport/hub/hub = null + +/datum/tgui_module/teleport_control/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + data["locked_name"] = locked_name || "No Target" + data["station_connected"] = !!station + data["hub_connected"] = !!hub + data["calibrated"] = hub?.accurate + data["teleporter_on"] = station?.engaged + + return data + +/datum/tgui_module/teleport_control/tgui_act(action, params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + switch(action) + if("select_target") + var/list/L = list() + var/list/areaindex = list() + + for(var/obj/item/device/radio/beacon/R in GLOB.all_beacons) + var/turf/T = get_turf(R) + if(!T) + continue + if(!(T.z in using_map.player_levels)) + continue + var/tmpname = T.loc.name + if(areaindex[tmpname]) + tmpname = "[tmpname] ([++areaindex[tmpname]])" + else + areaindex[tmpname] = 1 + L[tmpname] = R + + for(var/obj/item/weapon/implant/tracking/I in GLOB.all_tracking_implants) + if(!I.implanted || !ismob(I.loc)) + continue + else + var/mob/M = I.loc + if(M.stat == 2) + if(M.timeofdeath + 6000 < world.time) + continue + var/turf/T = get_turf(M) + if(T) + continue + if(!(T in using_map.station_levels)) + continue + var/tmpname = M.real_name + if(areaindex[tmpname]) + tmpname = "[tmpname] ([++areaindex[tmpname]])" + else + areaindex[tmpname] = 1 + L[tmpname] = I + + var/desc = input("Please select a location to lock in.", "Locking Menu") in L|null + if(!desc) + return FALSE + if(tgui_status(usr, state) != STATUS_INTERACTIVE) + return FALSE + + locked = L[desc] + locked_name = desc + return TRUE + + if("test_fire") + station?.testfire() + return TRUE + + if("toggle_on") + if(!station) + return FALSE + + if(station.engaged) + station.disengage() + else + station.engage() + + return TRUE diff --git a/code/modules/tgui/states.dm b/code/modules/tgui/states.dm index 111ee9e30b..2973d51668 100644 --- a/code/modules/tgui/states.dm +++ b/code/modules/tgui/states.dm @@ -122,4 +122,4 @@ /mob/living/carbon/human/shared_living_tgui_distance(atom/movable/src_object) if((TK in mutations) && (get_dist(src, src_object) <= 2)) return STATUS_INTERACTIVE - return ..() + return ..() \ No newline at end of file diff --git a/code/modules/tgui/states/deep_inventory.dm b/code/modules/tgui/states/deep_inventory.dm index 137f262a0e..d8a5e699c2 100644 --- a/code/modules/tgui/states/deep_inventory.dm +++ b/code/modules/tgui/states/deep_inventory.dm @@ -9,4 +9,4 @@ GLOBAL_DATUM_INIT(tgui_deep_inventory_state, /datum/tgui_state/deep_inventory_st /datum/tgui_state/deep_inventory_state/can_use_topic(src_object, mob/user) if(!user.contains(src_object)) return STATUS_CLOSE - return user.shared_tgui_interaction(src_object) + return user.shared_tgui_interaction(src_object) \ No newline at end of file diff --git a/code/modules/tgui/states/default.dm b/code/modules/tgui/states/default.dm index ba8d132e0b..a69295452b 100644 --- a/code/modules/tgui/states/default.dm +++ b/code/modules/tgui/states/default.dm @@ -68,12 +68,12 @@ GLOBAL_DATUM_INIT(tgui_default_state, /datum/tgui_state/default, new) /mob/living/silicon/pai/default_can_use_tgui_topic(src_object) // pAIs can only use themselves and the owner's radio. - if((src_object == src || src_object == radio) && !stat) + if((src_object == src || src_object == radio || src_object == communicator) && !stat) return STATUS_INTERACTIVE else return ..() /mob/observer/dead/default_can_use_tgui_topic() - if(check_rights(R_ADMIN, 0, src)) + if(can_admin_interact()) return STATUS_INTERACTIVE // Admins are more equal return STATUS_UPDATE // Ghosts can view updates diff --git a/code/modules/tgui/states/inventory_vr.dm b/code/modules/tgui/states/inventory_vr.dm index b8e3ea224c..bc0fe2c3e3 100644 --- a/code/modules/tgui/states/inventory_vr.dm +++ b/code/modules/tgui/states/inventory_vr.dm @@ -16,6 +16,21 @@ GLOBAL_DATUM_INIT(tgui_nif_state, /datum/tgui_state/nif_state, new) return STATUS_CLOSE +// This is slightly distinct from the module state, as it wants to update if not working +GLOBAL_DATUM_INIT(tgui_nif_main_state, /datum/tgui_state/nif_main_state, new) +/datum/tgui_state/nif_main_state/can_use_topic(var/src_object, var/mob/user) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(!H.nif || src_object != H.nif) + return STATUS_CLOSE + + if(H.nif.stat == NIF_WORKING) + return user.shared_tgui_interaction() + else + return min(user.shared_tgui_interaction(), STATUS_UPDATE) + + return STATUS_CLOSE + GLOBAL_DATUM_INIT(tgui_commlink_state, /datum/tgui_state/commlink_state, new) /datum/tgui_state/commlink_state/can_use_topic(var/src_object, var/mob/user) if(ishuman(user)) diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm index 2f928ae6fa..eb128a129b 100644 --- a/code/modules/tgui/tgui.dm +++ b/code/modules/tgui/tgui.dm @@ -114,7 +114,6 @@ closing = TRUE for(var/datum/tgui/child in children) child.close(can_be_suspended, logout) - children.Cut() // If we don't have window_id, open proc did not have the opportunity // to finish, therefore it's safe to skip this whole block. if(window) @@ -126,6 +125,8 @@ src_object.tgui_close(user) SStgui.on_close(src) state = null + if(parent_ui) + parent_ui.children -= src parent_ui = null qdel(src) diff --git a/code/modules/vehicles/boat.dm b/code/modules/vehicles/boat.dm index ea17e29678..170ad4aa81 100644 --- a/code/modules/vehicles/boat.dm +++ b/code/modules/vehicles/boat.dm @@ -10,7 +10,7 @@ move_delay = 3 // Rather slow, but still faster than swimming, and won't get you wet. max_buckled_mobs = 2 anchored = FALSE - var/material/material = null + var/datum/material/material = null var/riding_datum_type = /datum/riding/boat/small /obj/vehicle/boat/sifwood/New(newloc, material_name) @@ -43,7 +43,7 @@ icon_state = "oar" item_state = "oar" force = 12 - var/material/material = null + var/datum/material/material = null /obj/item/weapon/oar/sifwood/New(newloc, material_name) ..(newloc, MAT_SIFWOOD) diff --git a/code/modules/vore/appearance/sprite_accessories_taur_vr.dm b/code/modules/vore/appearance/sprite_accessories_taur_vr.dm index 1d610be51c..d2bed00deb 100644 --- a/code/modules/vore/appearance/sprite_accessories_taur_vr.dm +++ b/code/modules/vore/appearance/sprite_accessories_taur_vr.dm @@ -68,8 +68,13 @@ var/mob/living/carbon/human/H = M if(isTaurTail(H.tail_style)) - to_chat(src,"Too many legs. TOO MANY LEGS!!") - return FALSE + var/datum/sprite_accessory/tail/taur/ridertype = H.tail_style + if(ridertype.can_ride) + if(istype(ridertype, /datum/sprite_accessory/tail/taur/naga) || istype(ridertype, /datum/sprite_accessory/tail/taur/slug)) + to_chat(src,"Too few legs. TOO FEW LEGS!!") + return FALSE + to_chat(src,"Too many legs. TOO MANY LEGS!!") + return FALSE . = ..() if(.) @@ -126,7 +131,7 @@ var/icon/suit_sprites = null //File for suit sprites, if any. var/icon/under_sprites = null - var/icon_sprite_tag // This is where we put stuff like _Horse, so we can assign icons easier. + var/icon_sprite_tag // This is where we put stuff like _Horse, so we can assign icons easier. var/can_ride = 1 //whether we're real rideable taur or just in that category @@ -207,6 +212,12 @@ extra_overlay = "synthwolf_markings" //icon_sprite_tag = "synthwolf" +/datum/sprite_accessory/tail/taur/skunk + name = "Skunk (Taur)" + icon_state = "skunk_s" + extra_overlay = "skunk_markings" + icon_sprite_tag = "skunk" + /datum/sprite_accessory/tail/taur/naga name = "Naga (Taur)" icon_state = "naga_s" diff --git a/code/modules/vore/appearance/sprite_accessories_vr.dm b/code/modules/vore/appearance/sprite_accessories_vr.dm index 32128c2708..f8ba23f341 100644 --- a/code/modules/vore/appearance/sprite_accessories_vr.dm +++ b/code/modules/vore/appearance/sprite_accessories_vr.dm @@ -41,6 +41,21 @@ // Ears avaliable to anyone +/datum/sprite_accessory/ears/hyena + name = "hyena ears, dual-color" + desc = "" + icon_state = "hyena" + do_colouration = 1 + color_blend_mode = ICON_MULTIPLY + extra_overlay = "hyena-inner" + +/datum/sprite_accessory/ears/moth + name = "moth antennae" + desc = "" + icon_state = "moth" + do_colouration = 1 + color_blend_mode = ICON_MULTIPLY + /datum/sprite_accessory/ears/squirrel_orange name = "squirel, orange" desc = "" diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index 80cea8ae2e..967c894f9d 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -728,7 +728,7 @@ return var/list/nom = null - var/material/M = null + var/datum/material/M = null if(istype(I, /obj/item/weapon/ore)) //Raw unrefined ore. Some things are just better untempered! var/obj/item/weapon/ore/O = I //List in list, define by material property of ore in code/mining/modules/ore.dm. @@ -743,7 +743,7 @@ "silver" = list("nutrition" = 40, "remark" = "[O] tastes quite nice indeed as you munch on it. A little tarnished, but that's just fine aging.", "WTF" = FALSE), "gold" = list("nutrition" = 40, "remark" = "You taste supreme richness that exceeds expectations and satisfies your hunger.", "WTF" = FALSE), "diamond" = list("nutrition" = 50, "remark" = "The heavenly taste of [O] almost brings a tear to your eye. Its glimmering gloriousness is even better on the tongue than you imagined, so you savour it fondly.", "WTF" = FALSE), - "platinum" = list("nutrition" = 40, "remark" = "A bit tangy but elegantly balanced with a long faintly sour finish. Delectible.", "WTF" = FALSE), + "platinum" = list("nutrition" = 40, "remark" = "A bit tangy but elegantly balanced with a long faintly sour finish. Delectable.", "WTF" = FALSE), "mhydrogen" = list("nutrition" = 30, "remark" = "Quite sweet on the tongue, you savour the light and easy to chew [O], finishing it quickly.", "WTF" = FALSE), "rutile" = list("nutrition" = 50, "remark" = "A little... angular, you savour the light but chewy [O], finishing it quickly.", "WTF" = FALSE), MAT_VERDANTIUM = list("nutrition" = 50, "remark" = "You taste scientific mystery and a rare delicacy. Your tastebuds tingle pleasantly as you eat [O] and the feeling warmly blossoms in your chest for a moment.", "WTF" = FALSE), @@ -779,11 +779,11 @@ "borosilicate glass" = list("nutrition" = 10, "remark" = "With a satisfying crunch, you grind [O] down with ease and find it somewhat palatable due to a subtle but familiar rush of phoronic warmth.", "WTF" = FALSE), "reinforced borosilicate glass" = list("nutrition" = 15, "remark" = "With a satisfying crunch, you grind [O] down. It is quite palatable due to a subtle metallic tang and familiar rush of phoronic warmth.", "WTF" = FALSE), MAT_GRAPHITE = list("nutrition" = 30, "remark" = "Satisfyingly metallic with a mildly savoury tartness, you chew [O] until its flavour is no more but are left longing for another.", "WTF" = FALSE), - "osmium" = list("nutrition" = 45, "remark" = "Successive bites serve to almost chill your palate, a rush of rich and mildly sour flavour unlocked with the grinding of your powerful jaws. Delectible.", "WTF" = FALSE), + "osmium" = list("nutrition" = 45, "remark" = "Successive bites serve to almost chill your palate, a rush of rich and mildly sour flavour unlocked with the grinding of your powerful jaws. Delectable.", "WTF" = FALSE), "mhydrogen" = list("nutrition" = 35, "remark" = "Quite sweet on the tongue, you savour the light and easy to chew [O], finishing it quickly.", "WTF" = FALSE), - "platinum" = list("nutrition" = 40, "remark" = "A bit tangy but elegantly balanced with a long faintly sour finish. Delectible.", "WTF" = FALSE), + "platinum" = list("nutrition" = 40, "remark" = "A bit tangy but elegantly balanced with a long faintly sour finish. Delectable.", "WTF" = FALSE), "iron" = list("nutrition" = 15, "remark" = "The familiar texture and taste of [O] does the job but leaves little to the imagination and hardly sates your appetite.", "WTF" = FALSE), - MAT_LEAD = list("nutrition" = 0, "remark" = "It takes some work to break down [O] but you manage it, unlocking lasting tangy goodness in the process. Yum.", "WTF" = FALSE), + MAT_LEAD = list("nutrition" = 40, "remark" = "It takes some work to break down [O] but you manage it, unlocking lasting tangy goodness in the process. Yum.", "WTF" = FALSE), MAT_VERDANTIUM = list("nutrition" = 55, "remark" = "You taste scientific mystery and a rare delicacy. Your tastebuds tingle pleasantly as you eat [O] and the feeling warmly blossoms in your chest for a moment.", "WTF" = FALSE), MAT_MORPHIUM = list("nutrition" = 75, "remark" = "The question, the answer and the taste: It all floods your mouth and your mind to momentarily overwhelm the senses. What the hell was that? Your mouth and throat are left tingling for a while.", "WTF" = 10), "alienalloy" = list("nutrition" = 120, "remark" = "Working hard for so long to rend the material apart has left your jaw sore, but a veritable explosion of mind boggling indescribable flavour is unleashed. Completely alien sensations daze and overwhelm you while it feels like an interdimensional rift opened in your mouth, briefly numbing your face.", "WTF" = 15) diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm index e8e0360555..482928985b 100644 --- a/code/modules/vore/eating/vorepanel_vr.dm +++ b/code/modules/vore/eating/vorepanel_vr.dm @@ -271,6 +271,18 @@ if("bellypick") host.vore_selected = locate(params["bellypick"]) return TRUE + if("move_belly") + var/dir = text2num(params["dir"]) + if(LAZYLEN(host.vore_organs) <= 1) + to_chat(usr, "You can't sort bellies with only one belly to sort...") + return TRUE + + var/current_index = host.vore_organs.Find(host.vore_selected) + if(current_index) + var/new_index = clamp(current_index + dir, 1, LAZYLEN(host.vore_organs)) + host.vore_organs.Swap(current_index, new_index) + unsaved_changes = TRUE + return TRUE if("set_attribute") return set_attr(usr, params) diff --git a/code/modules/vore/fluffstuff/custom_clothes_vr.dm b/code/modules/vore/fluffstuff/custom_clothes_vr.dm index 8ae03765e9..ffff210dbc 100644 --- a/code/modules/vore/fluffstuff/custom_clothes_vr.dm +++ b/code/modules/vore/fluffstuff/custom_clothes_vr.dm @@ -2002,4 +2002,9 @@ Departamental Swimsuits, for general use flags_inv = HIDEHOLSTER icon_override = 'icons/vore/custom_clothes_vr.dmi' - item_state = "flintlock_mob" \ No newline at end of file + item_state = "flintlock_mob" + +//BobOfBoblandia: Charles Gettler +/obj/item/clothing/head/that/fluff/gettler + name = "Charles' Top-Hat" + desc = "A special hat, removed from its owner." \ No newline at end of file diff --git a/code/modules/vore/fluffstuff/custom_items_vr.dm b/code/modules/vore/fluffstuff/custom_items_vr.dm index fa0acd60d6..b2d82a7066 100644 --- a/code/modules/vore/fluffstuff/custom_items_vr.dm +++ b/code/modules/vore/fluffstuff/custom_items_vr.dm @@ -1274,3 +1274,34 @@ /obj/item/clothing/accessory/solgov/department/security/aurora name = "Old security insignia" desc = "Insignia denoting assignment to the security department. These fit Expeditionary Corps uniforms. This one seems to be from the 2100s..." + +//Tigercat2000 - Shadow Larkens +/obj/item/modular_computer/laptop/preset/custom_loadout/advanced/shadowlarkens + name = "Shadow's laptop computer" + desc = "A laptop with a different color scheme than usual!" + icon = 'icons/vore/custom_items_vr.dmi' + overlay_icon = 'icons/obj/modular_laptop.dmi' + icon_state_unpowered = "shadowlaptop-open" + icon_state = "shadowlaptop-open" + icon_state_closed = "shadowlaptop-closed" + +//Rboys2 - Clara Mali +/obj/item/weapon/reagent_containers/food/drinks/glass2/fluff/claraflask + name = "Clara's Vacuum Flask" + desc = "A rose gold vacuum flask." + base_name = "Clara's Vacuum Flask" + base_icon = "claraflask" + icon = 'icons/vore/custom_items_vr.dmi' + center_of_mass = list("x" = 15,"y" = 4) + filling_states = list(15, 30, 50, 60, 80, 100) + volume = 60 + +/obj/item/weapon/reagent_containers/food/drinks/glass2/fluff/claraflask/Initialize() + . = ..() + reagents.add_reagent("tea", 40) + reagents.add_reagent("milk", 20) + +/obj/item/weapon/reagent_containers/food/drinks/glass2/fluff/claraflask/update_icon() + ..() + name = initial(name) + desc = initial(desc) \ No newline at end of file diff --git a/code/unit_tests/research_tests.dm b/code/unit_tests/research_tests.dm index 24d307c5e6..9d0174cabe 100644 --- a/code/unit_tests/research_tests.dm +++ b/code/unit_tests/research_tests.dm @@ -54,7 +54,7 @@ design = new design_type() // Unfortunately we have to actually instantiate to get a list. for(var/material_name in design.materials) - var/material/material = get_material_by_name(material_name) + var/datum/material/material = get_material_by_name(material_name) if(!material) log_unit_test("The entry [design_type] has invalid material type [material_name]") number_of_issues++ diff --git a/config/alienwhitelist.txt b/config/alienwhitelist.txt index 64ba396c77..c423c19e38 100644 --- a/config/alienwhitelist.txt +++ b/config/alienwhitelist.txt @@ -12,13 +12,6 @@ alphaprime1 - Protean bothnevarbackwards - Diona bricker98 - Protean crossexonar - Protean -<<<<<<< HEAD -======= -chillyfang - Black-Eyed Shadekin -cgr - Protean -draycu - Vox -flaktual - Vox ->>>>>>> e791692aea59a96b1b45c20d61974aa10493a7f6 funnyman2003 - Xenochimera flurriee - Protean hawkerthegreat - Vox diff --git a/config/example/config.txt b/config/example/config.txt index d56d60a5ae..dd07f7b73d 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -551,4 +551,7 @@ ENABLE_NIGHT_SHIFTS # Uncomment to allow links of the following kinds. # # ALLOW_BYOND_LINKS # ALLOW_DISCORD_LINKS -ALLOW_URL_LINKS \ No newline at end of file +ALLOW_URL_LINKS + +# Control which submaps are loaded for the Dynamic Engine system +ENGINE_MAP Supermatter Engine,Edison's Bane diff --git a/guides/Guide to Opening Your First PR.md b/guides/Guide to Opening Your First PR.md index 73d44dace5..58d28b1362 100644 --- a/guides/Guide to Opening Your First PR.md +++ b/guides/Guide to Opening Your First PR.md @@ -16,7 +16,7 @@ Everyone has their own preferred Github clients - I use Gitkraken because it’s **SourceTree:** https://www.sourcetreeapp.com/ **Github Desktop:** https://desktop.github.com/ -I recommend Gitkraken as it’s very good at handling things for you, and it comes with built-in darkmode. It DOES have paid features, but you don’t need them. +I recommend Gitkraken as it’s very good at handling things for you, and it comes with built-in darkmode. It does have paid features, but you don’t need them. Cloning your Repo: AKA “Progress bar time†I’ll give these instructions in relevance to Gitkraken as that’s what I use, but they should be relatively applicable to other platforms. diff --git a/html/changelog.html b/html/changelog.html index 7153910a42..1ddf4203de 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -53,6 +53,52 @@ -->
+

06 September 2020

+

Atermonera updated:

+
    +
  • You can use Move Up/Down to traverse ladders. No popup 'Which way do you want to go?' windows required for bidirectional ladders!.
  • +
+

Killian updated:

+
    +
  • Added a bunch more random spawners for mapping use.
  • +
  • You can now inject reagents directly into a synth's 'blood' stream using syringes and hypos (inc. borg hypos). Taking oil/coolant samples is still impossible.
  • +
+

Kot updated:

+
    +
  • Mecha drills can now butcher dead mobs better. Like gibs and gore and guts stuff.
  • +
+

Lorilili updated:

+
    +
  • You can now pet borgs on help intent and punch on hurt intent. Old behavior is now grab intent.
  • +
+

Lorilili (Port from Aurora) updated:

+
    +
  • Added knee-high and thigh-high jackboots.
  • +
  • Replaced laceup and leather shoes with oxford shoes.
  • +
  • Replaced standard shoe and high-top sprites with newer ones.
  • +
+

Mechoid updated:

+
    +
  • Mapped distillery into Chemistry, beside the Grinder.
  • +
  • Moves wrapper, spacecleaner, and labeller from the grinder table to the Chem locker.
  • +
  • Added distilling recipe for Synthetic Plasma, which acts as a blood-restoration of 1.2 units per synthplas. Also orderable in cargo.
  • +
+

Rykka Stormheart updated:

+
    +
  • Adds Ambience Chance and Repeating Ambience Preferences into Globals, underneath Client FPS
  • +
  • Random-Ambience-Frequency controls how long before it checks if it can play ambience to you again. Setting it to 0 disables the random re-play of ambience.
  • +
  • Ambience Chance affects the % chance to play ambience to your client. It defaults to 35%, but can be set from 0 to 100 to disable it or always play every time you move into an area or have the Random Ambience check called.
  • +
+

Shadow Larkens updated:

+
    +
  • Added the ability to right click and lower preferences for jobs in the Occupation Menu.
  • +
+

SplinterGP updated:

+
    +
  • Adds new hailer masks with quotes with sound, allowing you to use a hailer on a face mask to combine them.
  • +
  • Adds new sound effects for hailer face masks.
  • +
+

20 August 2020

Atermonera updated:

    @@ -65,6 +111,11 @@
  • You can now alt-click to turn on the washing machine.
  • You can now alt-click on a mech while piloting it to toggle strafing.
+

Blinskot updated:

+
    +
  • You can now alt-click on a mech while piloting it to toggle strafing.
  • +
  • You can now alt-click to turn on the washing machine.
  • +

Cerebulon updated:

  • Added extended flavour text to most things related to commercial vending machines and their contents.
  • diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 3a86bfb6b7..9444423465 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -5315,3 +5315,42 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. - rscdel: Removed monitor mask item(replaced by verb). Subber: - rscadd: 'Added a new prosthetic sprite set: Cyber Solutions - Outdated.' +2020-09-06: + Atermonera: + - tweak: You can use Move Up/Down to traverse ladders. No popup 'Which way do you + want to go?' windows required for bidirectional ladders!. + Killian: + - tweak: Added a bunch more random spawners for mapping use. + - tweak: You can now inject reagents directly into a synth's 'blood' stream using + syringes and hypos (inc. borg hypos). Taking oil/coolant samples is still impossible. + Kot: + - tweak: Mecha drills can now butcher dead mobs better. Like gibs and gore and guts + stuff. + Lorilili: + - rscadd: You can now pet borgs on help intent and punch on hurt intent. Old behavior + is now grab intent. + Lorilili (Port from Aurora): + - rscadd: Added knee-high and thigh-high jackboots. + - imageadd: Replaced laceup and leather shoes with oxford shoes. + - imageadd: Replaced standard shoe and high-top sprites with newer ones. + Mechoid: + - maptweak: Mapped distillery into Chemistry, beside the Grinder. + - maptweak: Moves wrapper, spacecleaner, and labeller from the grinder table to + the Chem locker. + - rscadd: Added distilling recipe for Synthetic Plasma, which acts as a blood-restoration + of 1.2 units per synthplas. Also orderable in cargo. + Rykka Stormheart: + - rscadd: Adds Ambience Chance and Repeating Ambience Preferences into Globals, + underneath Client FPS + - rscadd: Random-Ambience-Frequency controls how long before it checks if it can + play ambience to you again. Setting it to 0 disables the random re-play of ambience. + - rscadd: Ambience Chance affects the % chance to play ambience to your client. + It defaults to 35%, but can be set from 0 to 100 to disable it or always play + every time you move into an area or have the Random Ambience check called. + Shadow Larkens: + - rscadd: Added the ability to right click and lower preferences for jobs in the + Occupation Menu. + SplinterGP: + - rscadd: Adds new hailer masks with quotes with sound, allowing you to use a hailer + on a face mask to combine them. + - soundadd: Adds new sound effects for hailer face masks. diff --git a/html/changelogs/Lorilili - borgpet.yml b/html/changelogs/Lorilili - borgpet.yml deleted file mode 100644 index 6af4fa0c25..0000000000 --- a/html/changelogs/Lorilili - borgpet.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: Lorilili -delete-after: True -changes: - - rscadd: "You can now pet borgs on help intent and punch on hurt intent. Old behavior is now grab intent." - diff --git a/html/changelogs/shadowlarkens - job preferences.yml b/html/changelogs/Mechoid - Encumbrance.yml similarity index 91% rename from html/changelogs/shadowlarkens - job preferences.yml rename to html/changelogs/Mechoid - Encumbrance.yml index 75a2fe7a28..f013a3bcad 100644 --- a/html/changelogs/shadowlarkens - job preferences.yml +++ b/html/changelogs/Mechoid - Encumbrance.yml @@ -22,7 +22,7 @@ ################################# # Your name. -author: Shadow Larkens +author: Mechoid # Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. delete-after: True @@ -33,4 +33,4 @@ delete-after: True # Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. # Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. changes: - - rscadd: "Added the ability to right click and lower preferences for jobs in the Occupation Menu." + - rscadd: "Added system for exosuit over-encumbrance. Combat mechs and Ripleys have higher than default." diff --git a/html/changelogs/Meghan Rossi - atmosanalyzer.yml b/html/changelogs/Meghan Rossi - atmosanalyzer.yml new file mode 100644 index 0000000000..336b875578 --- /dev/null +++ b/html/changelogs/Meghan Rossi - atmosanalyzer.yml @@ -0,0 +1,4 @@ +author: Meghan-Rossi +delete-after: True +changes: + - bugfix: "Fixed some objects giving duplicate results when an analyzer was used on them" \ No newline at end of file diff --git a/html/changelogs/Meghan Rossi - fix omni filters.yml b/html/changelogs/Meghan Rossi - fix omni filters.yml new file mode 100644 index 0000000000..595dd331e7 --- /dev/null +++ b/html/changelogs/Meghan Rossi - fix omni filters.yml @@ -0,0 +1,4 @@ +author: Meghan-Rossi +delete-after: True +changes: + - bugfix: "Fixed omni filters reacting incorrectly to configuration changes that swap ports." \ No newline at end of file diff --git a/html/changelogs/Meghan Rossi - stripping.yml b/html/changelogs/Meghan Rossi - stripping.yml new file mode 100644 index 0000000000..25a4e95bec --- /dev/null +++ b/html/changelogs/Meghan Rossi - stripping.yml @@ -0,0 +1,4 @@ +author: Meghan-Rossi +delete-after: True +changes: + - tweak: "If you try to put someone in one of their own slots using the stripping menu, now you will instead try to strip that slot." \ No newline at end of file diff --git a/html/changelogs/Meghan Rossi - triglyceride taste.yml b/html/changelogs/Meghan Rossi - triglyceride taste.yml new file mode 100644 index 0000000000..c18e6ff8e9 --- /dev/null +++ b/html/changelogs/Meghan Rossi - triglyceride taste.yml @@ -0,0 +1,4 @@ +author: Meghan-Rossi +delete-after: True +changes: + - bugfix: "Fat (triglyceride) now tastes greasy instead of bitter." \ No newline at end of file diff --git a/html/changelogs/Lorilili - footwear.yml b/html/changelogs/SubberTheFabulous-PR-7642.yml similarity index 84% rename from html/changelogs/Lorilili - footwear.yml rename to html/changelogs/SubberTheFabulous-PR-7642.yml index e7b727050d..23864c64b0 100644 --- a/html/changelogs/Lorilili - footwear.yml +++ b/html/changelogs/SubberTheFabulous-PR-7642.yml @@ -1,38 +1,36 @@ -################################ -# Example Changelog File -# -# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. -# -# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) -# When it is, any changes listed below will disappear. -# -# Valid Prefixes: -# bugfix -# wip (For works in progress) -# tweak -# soundadd -# sounddel -# rscadd (general adding of nice things) -# rscdel (general deleting of nice things) -# imageadd -# imagedel -# maptweak -# spellcheck (typo fixes) -# experiment -################################# - -# Your name. -author: Lorilili (Port from Aurora) - -# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. -delete-after: True - -# Any changes you've made. See valid prefix list above. -# INDENT WITH TWO SPACES. NOT TABS. SPACES. -# SCREW THIS UP AND IT WON'T WORK. -# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. -# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. -changes: - - rscadd: "Added knee-high and thigh-high jackboots." - - imageadd: "Replaced laceup and leather shoes with oxford shoes." - - imageadd: "Replaced standard shoe and high-top sprites with newer ones." +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: Subber + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Added two new antag augments to traitor uplink: armblade and handblade." diff --git a/html/changelogs/atermonera - move updown.yml b/html/changelogs/atermonera - move updown.yml deleted file mode 100644 index ceae85d35e..0000000000 --- a/html/changelogs/atermonera - move updown.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: Atermonera -delete-after: True -changes: - - tweak: "You can use Move Up/Down to traverse ladders No popup "Which way do you want to go?" windows required for bidirectional ladders!." diff --git a/html/changelogs/rykka-stormheart - toy mechs.yml b/html/changelogs/mechoid - hydroupkeep.yml similarity index 75% rename from html/changelogs/rykka-stormheart - toy mechs.yml rename to html/changelogs/mechoid - hydroupkeep.yml index 5967df1bfa..66b4cea214 100644 --- a/html/changelogs/rykka-stormheart - toy mechs.yml +++ b/html/changelogs/mechoid - hydroupkeep.yml @@ -22,7 +22,7 @@ ################################# # Your name. -author: Rykka Stormheart +author: Mechoid # Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. delete-after: True @@ -33,6 +33,6 @@ delete-after: True # Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. # Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. changes: - - rscadd: "Adds a mech vs mech combat system for the toy mechs earned from arcades and found around the station." - - rscadd: "You can initiate combat with yourself by hitting a toy mech with another toy mech, or fight another player if you attack a player holding a mech with a mech." - - rscadd: "Each mech has its own health stat and special ability that they'll use in combat against each other." + - rscadd: "Adds Wurmwoad, a suspiciously worm-like plant that produces pods of spice." + - rscadd: "Adds Wurmwoad to the service borg synthesizer." + - bugfix: "Service borgs can work with kitchenware again." diff --git a/html/changelogs/rykka-stormheart - ambience prefs.yml b/html/changelogs/rykka-stormheart - ambience prefs.yml deleted file mode 100644 index c55ec992d7..0000000000 --- a/html/changelogs/rykka-stormheart - ambience prefs.yml +++ /dev/null @@ -1,38 +0,0 @@ -################################ -# Example Changelog File -# -# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. -# -# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) -# When it is, any changes listed below will disappear. -# -# Valid Prefixes: -# bugfix -# wip (For works in progress) -# tweak -# soundadd -# sounddel -# rscadd (general adding of nice things) -# rscdel (general deleting of nice things) -# imageadd -# imagedel -# maptweak -# spellcheck (typo fixes) -# experiment -################################# - -# Your name. -author: Rykka Stormheart - -# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. -delete-after: True - -# Any changes you've made. See valid prefix list above. -# INDENT WITH TWO SPACES. NOT TABS. SPACES. -# SCREW THIS UP AND IT WON'T WORK. -# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. -# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. -changes: - - rscadd: "Adds Ambience Chance and Repeating Ambience Preferences into Globals, underneath Client FPS" - - rscadd: "Random-Ambience-Frequency controls how long before it checks if it can play ambience to you again. Setting it to 0 disables the random re-play of ambience." - - rscadd: "Ambience Chance affects the % chance to play ambience to your client. It defaults to 35%, but can be set from 0 to 100 to disable it or always play every time you move into an area or have the Random Ambience check called." diff --git a/icons/UI_Icons/Achievements/Boss/bbgum.png b/icons/UI_Icons/Achievements/Boss/bbgum.png new file mode 100644 index 0000000000..a0962fb1ce Binary files /dev/null and b/icons/UI_Icons/Achievements/Boss/bbgum.png differ diff --git a/icons/UI_Icons/Achievements/Boss/colossus.png b/icons/UI_Icons/Achievements/Boss/colossus.png new file mode 100644 index 0000000000..f544084786 Binary files /dev/null and b/icons/UI_Icons/Achievements/Boss/colossus.png differ diff --git a/icons/UI_Icons/Achievements/Boss/drake.png b/icons/UI_Icons/Achievements/Boss/drake.png new file mode 100644 index 0000000000..19ecc5ae94 Binary files /dev/null and b/icons/UI_Icons/Achievements/Boss/drake.png differ diff --git a/icons/UI_Icons/Achievements/Boss/hierophant.png b/icons/UI_Icons/Achievements/Boss/hierophant.png new file mode 100644 index 0000000000..a8f2e6a45e Binary files /dev/null and b/icons/UI_Icons/Achievements/Boss/hierophant.png differ diff --git a/icons/UI_Icons/Achievements/Boss/legion.png b/icons/UI_Icons/Achievements/Boss/legion.png new file mode 100644 index 0000000000..dc9470a8a9 Binary files /dev/null and b/icons/UI_Icons/Achievements/Boss/legion.png differ diff --git a/icons/UI_Icons/Achievements/Boss/miner.png b/icons/UI_Icons/Achievements/Boss/miner.png new file mode 100644 index 0000000000..5164dcfb10 Binary files /dev/null and b/icons/UI_Icons/Achievements/Boss/miner.png differ diff --git a/icons/UI_Icons/Achievements/Boss/swarmer.png b/icons/UI_Icons/Achievements/Boss/swarmer.png new file mode 100644 index 0000000000..bcc017af32 Binary files /dev/null and b/icons/UI_Icons/Achievements/Boss/swarmer.png differ diff --git a/icons/UI_Icons/Achievements/Boss/tendril.png b/icons/UI_Icons/Achievements/Boss/tendril.png new file mode 100644 index 0000000000..3b6b908d3e Binary files /dev/null and b/icons/UI_Icons/Achievements/Boss/tendril.png differ diff --git a/icons/UI_Icons/Achievements/Mafia/assistant.png b/icons/UI_Icons/Achievements/Mafia/assistant.png new file mode 100644 index 0000000000..0cfc93b166 Binary files /dev/null and b/icons/UI_Icons/Achievements/Mafia/assistant.png differ diff --git a/icons/UI_Icons/Achievements/Mafia/changeling.png b/icons/UI_Icons/Achievements/Mafia/changeling.png new file mode 100644 index 0000000000..9e44c90263 Binary files /dev/null and b/icons/UI_Icons/Achievements/Mafia/changeling.png differ diff --git a/icons/UI_Icons/Achievements/Mafia/chaplain.png b/icons/UI_Icons/Achievements/Mafia/chaplain.png new file mode 100644 index 0000000000..ac48291282 Binary files /dev/null and b/icons/UI_Icons/Achievements/Mafia/chaplain.png differ diff --git a/icons/UI_Icons/Achievements/Mafia/clown.png b/icons/UI_Icons/Achievements/Mafia/clown.png new file mode 100644 index 0000000000..4f2d919471 Binary files /dev/null and b/icons/UI_Icons/Achievements/Mafia/clown.png differ diff --git a/icons/UI_Icons/Achievements/Mafia/detective.png b/icons/UI_Icons/Achievements/Mafia/detective.png new file mode 100644 index 0000000000..edeba8c402 Binary files /dev/null and b/icons/UI_Icons/Achievements/Mafia/detective.png differ diff --git a/icons/UI_Icons/Achievements/Mafia/fugitive.png b/icons/UI_Icons/Achievements/Mafia/fugitive.png new file mode 100644 index 0000000000..86beb21b1b Binary files /dev/null and b/icons/UI_Icons/Achievements/Mafia/fugitive.png differ diff --git a/icons/UI_Icons/Achievements/Mafia/hated.png b/icons/UI_Icons/Achievements/Mafia/hated.png new file mode 100644 index 0000000000..00ea735200 Binary files /dev/null and b/icons/UI_Icons/Achievements/Mafia/hated.png differ diff --git a/icons/UI_Icons/Achievements/Mafia/hop.png b/icons/UI_Icons/Achievements/Mafia/hop.png new file mode 100644 index 0000000000..f60719974d Binary files /dev/null and b/icons/UI_Icons/Achievements/Mafia/hop.png differ diff --git a/icons/UI_Icons/Achievements/Mafia/lawyer.png b/icons/UI_Icons/Achievements/Mafia/lawyer.png new file mode 100644 index 0000000000..1c9bba2036 Binary files /dev/null and b/icons/UI_Icons/Achievements/Mafia/lawyer.png differ diff --git a/icons/UI_Icons/Achievements/Mafia/md.png b/icons/UI_Icons/Achievements/Mafia/md.png new file mode 100644 index 0000000000..32bc972a4a Binary files /dev/null and b/icons/UI_Icons/Achievements/Mafia/md.png differ diff --git a/icons/UI_Icons/Achievements/Mafia/nightmare.png b/icons/UI_Icons/Achievements/Mafia/nightmare.png new file mode 100644 index 0000000000..14c50b403a Binary files /dev/null and b/icons/UI_Icons/Achievements/Mafia/nightmare.png differ diff --git a/icons/UI_Icons/Achievements/Mafia/obsessed.png b/icons/UI_Icons/Achievements/Mafia/obsessed.png new file mode 100644 index 0000000000..b92ba5b582 Binary files /dev/null and b/icons/UI_Icons/Achievements/Mafia/obsessed.png differ diff --git a/icons/UI_Icons/Achievements/Mafia/psychologist.png b/icons/UI_Icons/Achievements/Mafia/psychologist.png new file mode 100644 index 0000000000..60171ca723 Binary files /dev/null and b/icons/UI_Icons/Achievements/Mafia/psychologist.png differ diff --git a/icons/UI_Icons/Achievements/Mafia/thoughtfeeder.png b/icons/UI_Icons/Achievements/Mafia/thoughtfeeder.png new file mode 100644 index 0000000000..009bac0d99 Binary files /dev/null and b/icons/UI_Icons/Achievements/Mafia/thoughtfeeder.png differ diff --git a/icons/UI_Icons/Achievements/Mafia/traitor.png b/icons/UI_Icons/Achievements/Mafia/traitor.png new file mode 100644 index 0000000000..28c8c52191 Binary files /dev/null and b/icons/UI_Icons/Achievements/Mafia/traitor.png differ diff --git a/icons/UI_Icons/Achievements/Misc/ascension.png b/icons/UI_Icons/Achievements/Misc/ascension.png new file mode 100644 index 0000000000..ca7e875bd3 Binary files /dev/null and b/icons/UI_Icons/Achievements/Misc/ascension.png differ diff --git a/icons/UI_Icons/Achievements/Misc/clownking.png b/icons/UI_Icons/Achievements/Misc/clownking.png new file mode 100644 index 0000000000..7260c34dcd Binary files /dev/null and b/icons/UI_Icons/Achievements/Misc/clownking.png differ diff --git a/icons/UI_Icons/Achievements/Misc/clownthanks.png b/icons/UI_Icons/Achievements/Misc/clownthanks.png new file mode 100644 index 0000000000..214a4e0a74 Binary files /dev/null and b/icons/UI_Icons/Achievements/Misc/clownthanks.png differ diff --git a/icons/UI_Icons/Achievements/Misc/featofstrength.png b/icons/UI_Icons/Achievements/Misc/featofstrength.png new file mode 100644 index 0000000000..5cfc5240bd Binary files /dev/null and b/icons/UI_Icons/Achievements/Misc/featofstrength.png differ diff --git a/icons/UI_Icons/Achievements/Misc/helbital.png b/icons/UI_Icons/Achievements/Misc/helbital.png new file mode 100644 index 0000000000..10b5efdd5e Binary files /dev/null and b/icons/UI_Icons/Achievements/Misc/helbital.png differ diff --git a/icons/UI_Icons/Achievements/Misc/jackpot.png b/icons/UI_Icons/Achievements/Misc/jackpot.png new file mode 100644 index 0000000000..e171c5cb7c Binary files /dev/null and b/icons/UI_Icons/Achievements/Misc/jackpot.png differ diff --git a/icons/UI_Icons/Achievements/Misc/longshift.png b/icons/UI_Icons/Achievements/Misc/longshift.png new file mode 100644 index 0000000000..5f511e21fd Binary files /dev/null and b/icons/UI_Icons/Achievements/Misc/longshift.png differ diff --git a/icons/UI_Icons/Achievements/Misc/meteors.png b/icons/UI_Icons/Achievements/Misc/meteors.png new file mode 100644 index 0000000000..5e6d4bc9bd Binary files /dev/null and b/icons/UI_Icons/Achievements/Misc/meteors.png differ diff --git a/icons/UI_Icons/Achievements/Misc/rule8.png b/icons/UI_Icons/Achievements/Misc/rule8.png new file mode 100644 index 0000000000..2bc518d5ab Binary files /dev/null and b/icons/UI_Icons/Achievements/Misc/rule8.png differ diff --git a/icons/UI_Icons/Achievements/Misc/snail.png b/icons/UI_Icons/Achievements/Misc/snail.png new file mode 100644 index 0000000000..f38c5165cb Binary files /dev/null and b/icons/UI_Icons/Achievements/Misc/snail.png differ diff --git a/icons/UI_Icons/Achievements/Misc/timewaste.png b/icons/UI_Icons/Achievements/Misc/timewaste.png new file mode 100644 index 0000000000..24d23025fb Binary files /dev/null and b/icons/UI_Icons/Achievements/Misc/timewaste.png differ diff --git a/icons/UI_Icons/Achievements/Misc/upgrade.png b/icons/UI_Icons/Achievements/Misc/upgrade.png new file mode 100644 index 0000000000..e73bb512eb Binary files /dev/null and b/icons/UI_Icons/Achievements/Misc/upgrade.png differ diff --git a/icons/UI_Icons/Achievements/Skills/mining.png b/icons/UI_Icons/Achievements/Skills/mining.png new file mode 100644 index 0000000000..7d87d135b4 Binary files /dev/null and b/icons/UI_Icons/Achievements/Skills/mining.png differ diff --git a/icons/UI_Icons/Achievements/baseboss.png b/icons/UI_Icons/Achievements/baseboss.png new file mode 100644 index 0000000000..df2227b391 Binary files /dev/null and b/icons/UI_Icons/Achievements/baseboss.png differ diff --git a/icons/UI_Icons/Achievements/basemafia.png b/icons/UI_Icons/Achievements/basemafia.png new file mode 100644 index 0000000000..b22676d891 Binary files /dev/null and b/icons/UI_Icons/Achievements/basemafia.png differ diff --git a/icons/UI_Icons/Achievements/basemisc.png b/icons/UI_Icons/Achievements/basemisc.png new file mode 100644 index 0000000000..1346d1c001 Binary files /dev/null and b/icons/UI_Icons/Achievements/basemisc.png differ diff --git a/icons/UI_Icons/Achievements/baseskill.png b/icons/UI_Icons/Achievements/baseskill.png new file mode 100644 index 0000000000..de6ff8a2e5 Binary files /dev/null and b/icons/UI_Icons/Achievements/baseskill.png differ diff --git a/icons/UI_Icons/Achievements/default.png b/icons/UI_Icons/Achievements/default.png new file mode 100644 index 0000000000..852298aa0c Binary files /dev/null and b/icons/UI_Icons/Achievements/default.png differ diff --git a/icons/UI_Icons/Arcade/boss1.gif b/icons/UI_Icons/Arcade/boss1.gif new file mode 100644 index 0000000000..4730ac0021 Binary files /dev/null and b/icons/UI_Icons/Arcade/boss1.gif differ diff --git a/icons/UI_Icons/Arcade/boss2.gif b/icons/UI_Icons/Arcade/boss2.gif new file mode 100644 index 0000000000..d95fd84f0e Binary files /dev/null and b/icons/UI_Icons/Arcade/boss2.gif differ diff --git a/icons/UI_Icons/Arcade/boss3.gif b/icons/UI_Icons/Arcade/boss3.gif new file mode 100644 index 0000000000..e97056998a Binary files /dev/null and b/icons/UI_Icons/Arcade/boss3.gif differ diff --git a/icons/UI_Icons/Arcade/boss4.gif b/icons/UI_Icons/Arcade/boss4.gif new file mode 100644 index 0000000000..6695b6cfbf Binary files /dev/null and b/icons/UI_Icons/Arcade/boss4.gif differ diff --git a/icons/UI_Icons/Arcade/boss5.gif b/icons/UI_Icons/Arcade/boss5.gif new file mode 100644 index 0000000000..a827fb8c4e Binary files /dev/null and b/icons/UI_Icons/Arcade/boss5.gif differ diff --git a/icons/UI_Icons/Arcade/boss6.gif b/icons/UI_Icons/Arcade/boss6.gif new file mode 100644 index 0000000000..7a926cf89d Binary files /dev/null and b/icons/UI_Icons/Arcade/boss6.gif differ diff --git a/icons/UI_Icons/chat/chat_icons.dmi b/icons/UI_Icons/chat/chat_icons.dmi new file mode 100644 index 0000000000..8cc4b2c559 Binary files /dev/null and b/icons/UI_Icons/chat/chat_icons.dmi differ diff --git a/icons/UI_Icons/tgui/ntosradar_background.png b/icons/UI_Icons/tgui/ntosradar_background.png new file mode 100644 index 0000000000..bac7647e3a Binary files /dev/null and b/icons/UI_Icons/tgui/ntosradar_background.png differ diff --git a/icons/UI_Icons/tgui/ntosradar_pointer.png b/icons/UI_Icons/tgui/ntosradar_pointer.png new file mode 100644 index 0000000000..e71823f391 Binary files /dev/null and b/icons/UI_Icons/tgui/ntosradar_pointer.png differ diff --git a/icons/UI_Icons/tgui/ntosradar_pointer_S.png b/icons/UI_Icons/tgui/ntosradar_pointer_S.png new file mode 100644 index 0000000000..51a0dd49d9 Binary files /dev/null and b/icons/UI_Icons/tgui/ntosradar_pointer_S.png differ diff --git a/icons/_nanomaps/mapbase1200.png b/icons/_nanomaps/mapbase1200.png new file mode 100644 index 0000000000..868adfe0d5 Binary files /dev/null and b/icons/_nanomaps/mapbase1200.png differ diff --git a/icons/_nanomaps/nanomapBackground.png b/icons/_nanomaps/nanomapBackground.png new file mode 100644 index 0000000000..f3ead01619 Binary files /dev/null and b/icons/_nanomaps/nanomapBackground.png differ diff --git a/icons/_nanomaps/southern_cross_nanomap_z1.png b/icons/_nanomaps/southern_cross_nanomap_z1.png new file mode 100644 index 0000000000..b367430200 Binary files /dev/null and b/icons/_nanomaps/southern_cross_nanomap_z1.png differ diff --git a/icons/_nanomaps/southern_cross_nanomap_z10.png b/icons/_nanomaps/southern_cross_nanomap_z10.png new file mode 100644 index 0000000000..b9645bb74b Binary files /dev/null and b/icons/_nanomaps/southern_cross_nanomap_z10.png differ diff --git a/icons/_nanomaps/southern_cross_nanomap_z2.png b/icons/_nanomaps/southern_cross_nanomap_z2.png new file mode 100644 index 0000000000..1f4830a884 Binary files /dev/null and b/icons/_nanomaps/southern_cross_nanomap_z2.png differ diff --git a/icons/_nanomaps/southern_cross_nanomap_z3.png b/icons/_nanomaps/southern_cross_nanomap_z3.png new file mode 100644 index 0000000000..6c9d9b5a61 Binary files /dev/null and b/icons/_nanomaps/southern_cross_nanomap_z3.png differ diff --git a/icons/_nanomaps/southern_cross_nanomap_z5.png b/icons/_nanomaps/southern_cross_nanomap_z5.png new file mode 100644 index 0000000000..b89543e9de Binary files /dev/null and b/icons/_nanomaps/southern_cross_nanomap_z5.png differ diff --git a/icons/_nanomaps/southern_cross_nanomap_z6.png b/icons/_nanomaps/southern_cross_nanomap_z6.png new file mode 100644 index 0000000000..b8fb0ebfc1 Binary files /dev/null and b/icons/_nanomaps/southern_cross_nanomap_z6.png differ diff --git a/icons/_nanomaps/templates/Casino_prize_dispenser_ch.tmpl b/icons/_nanomaps/templates/Casino_prize_dispenser_ch.tmpl new file mode 100644 index 0000000000..0e3ce09fdd --- /dev/null +++ b/icons/_nanomaps/templates/Casino_prize_dispenser_ch.tmpl @@ -0,0 +1,110 @@ + + +{{if data.mode == 0}} +

    Prizes categories

    +
    +
    +
    + {{if data.category_weapons >= 1}} + {{:helper.link('Select Weapons', 'star', { 'Select' : 'selected_weapons' })}} + {{else}} + {{:helper.link('Disabled Weapons', 'cancel', { "Select" : 1}, 'disabled')}} + {{/if}} +
    +
    +
    +
    +
    +
    + {{if data.category_gear >= 1}} + {{:helper.link('Select Gear', 'star', { "Select" : 'selected_gear' })}} + {{else}} + {{:helper.link('Disabled Gear', 'cancel', { "Select" : 1}, 'disabled')}} + {{/if}} +
    +
    +
    +
    +
    +
    + {{if data.category_clothing >= 1}} + {{:helper.link('Select Clothing', 'star', { "Select" : 'selected_clothing' })}} + {{else}} + {{:helper.link('Disabled Clothing', 'cancel', { "Select" : 1}, 'disabled')}} + {{/if}} +
    +
    +
    +
    +
    +
    + {{if data.category_misc >= 1}} + {{:helper.link('Select Miscellaneous', 'star', { "Select" : 'selected_misc' })}} + {{else}} + {{:helper.link('Disabled Miscellaneous', 'cancel', { "Select" : 1}, 'disabled')}} + {{/if}} +
    +
    +
    +
    +
    +
    + {{if data.category_drinks >= 1}} + {{:helper.link('Select Drinks', 'star', { "Select" : 'selected_drinks' })}} + {{else}} + {{:helper.link('Disabled Drinks', 'cancel', { "Select" : 1}, 'disabled')}} + {{/if}} +
    +
    +
    +
    +
    +
    + {{if data.category_pets >= 1}} + {{:helper.link('Select Pets', 'star', { "Select" : 'selected_pets' })}} + {{else}} + {{:helper.link('Disabled Pets', 'cancel', { "Select" : 1}, 'disabled')}} + {{/if}} +
    +
    +
    +{{/if}} + +{{if data.mode == 1}} +

    Prizes available

    +
    + {{for data.products}} +
    +
    + {{:helper.link('Vend', 'circle-arrow-s', { "vend" : value.key })}} +
    +
    + {{if value.color}}{{:value.name}} + {{else}}{{:value.name}} + {{/if}} +
    +
    + {{empty}} + No prizes available! + {{/for}} +
    +{{/if}} + +{{if data.mode == 2}} +

    Prize selected

    +
    +
    +
    Item selected:
    {{:data.product}}
    +
    Charge:
    {{:data.price}}
    +
    +
    + {{if data.message_err}} {{/if}} {{:data.message}} +
    +
    + {{:helper.link('Cancel', 'arrowreturn-1-w', {'cancelpurchase' : 1})}} +
    +
    +{{/if}} \ No newline at end of file diff --git a/icons/_nanomaps/templates/phorochem.tmpl b/icons/_nanomaps/templates/phorochem.tmpl new file mode 100644 index 0000000000..612f2228eb --- /dev/null +++ b/icons/_nanomaps/templates/phorochem.tmpl @@ -0,0 +1,48 @@ +

    Phorochemistry Control

    +
    +
    + Test Commands: +
    +
    + {{:helper.link('Recalibrate', null, { 'recalibrate': 1}, data.timeLeft == 0 ? null : 'disabled')}} + {{:helper.link('Begin Test', null, { 'beginTest' : 1}, data.timeLeft > 0 ? 'disabled' : null)}} + {{:helper.link('Abort Test', null, { 'abortTest' : 1}, data.timeLeft == 0 ? 'disabled' : null)}} +
    +
    +
    +
    + Intensity: +
    +
    + {{:helper.link('1', null, { 'intensity' : 1}, data.intensity == 1 ? 'selected' : null)}} + {{:helper.link('2', null, { 'intensity' : 2}, data.intensity == 2 ? 'selected' : null)}} + {{:helper.link('3', null, { 'intensity' : 3}, data.intensity == 3 ? 'selected' : null)}} + {{:helper.link('4', null, { 'intensity' : 4}, data.intensity == 4 ? 'selected' : null)}} + {{:helper.link('5', null, { 'intensity' : 5}, data.intensity == 5 ? 'selected' : null)}} +
    +
    + +
    +
    + Phoron(moles): +
    +
    + {{if data.phoron < 40}} + {{:data.phoron}} + {{else}} + {{:data.phoron}} + {{/if}} +
    +
    +
    +
    + Time until next test: +
    +
    + {{:helper.displayBar(data.timeLeft, 0, data.timeLeftMax, 'bad')}} +
    +
    + +
    + {{:data.message}} +
    diff --git a/icons/_nanomaps/templates/server_shipping.tmpl b/icons/_nanomaps/templates/server_shipping.tmpl new file mode 100644 index 0000000000..e774a0d0fc --- /dev/null +++ b/icons/_nanomaps/templates/server_shipping.tmpl @@ -0,0 +1,87 @@ +{{if data.error == 1}} +
    +
    + ERROR +
    +
    + {{:data.error_msg}} +

    + {{:helper.link('Return', '', {'switch_menu' : 0}, 'selected')}} +
    +
    +{{else}} +
    + {{if data.screen == 0}} +
    + Available Stations +
    +
    + {{for data.servers}} + {{:helper.link(value.name, '', {'select_station' : value.ref})}} + {{empty}} + No stations located. + {{/for}} +
    + {{else data.screen == 1}} +
    + Options for {{:data.server}} +
    +
    + {{:helper.link('Send Shipment', '', {'switch_menu' : 4})}} + {{:helper.link('Receive Shipments (' + data.requests + ')', '', {'switch_menu' : 2})}} + {{:helper.link('Messaging', '', {'switch_menu' : 5})}} +

    + {{:helper.link('Back', '', {'switch_menu' : 0})}} +
    + {{else data.screen == 2}} +
    + Shiptments for {{:data.server}} +
    +
    + {{for data.requests}} + {{:helper.link("ID: " + value.id + "," + value.item_count + " items", '', {'switch_menu' : 3, 'shipment' : value.ref})}} + {{empty}} + No shipments found. + {{/for}} +

    + {{:helper.link('Back', '', {'switch_menu' : 1})}} +
    + {{else data.screen == 3}} +
    + Shipment #{{:data.id}} +
    +
    + {{for data.items}} + {{:value.id}} x{{:value.count}} +
    + {{empty}} + No items were sent.
    + Shipment is empty? + {{/for}} +

    + {{:helper.link('Confirm', '', {'confirm' : 1})}} + {{:helper.link('Deny', '', {'confirm' : 0})}} +
    + {{:helper.link('Back', '', {'switch_menu' : 2})}} +
    + {{else data.screen == 4}} +
    + Sending +
    +
    + TODO: Implement. +

    + {{:helper.link('Back', '', {'switch_menu' : 0})}} +
    + {{else data.screen == 5}} +
    + Messaging +
    +
    + TODO: Implement. +

    + {{:helper.link('Back', '', {'switch_menu' : 0})}} +
    + {{/if}} +
    +{{/if}} diff --git a/icons/_nanomaps/templates/starcaster_ch.tmpl b/icons/_nanomaps/templates/starcaster_ch.tmpl new file mode 100644 index 0000000000..02b4c08ab3 --- /dev/null +++ b/icons/_nanomaps/templates/starcaster_ch.tmpl @@ -0,0 +1,45 @@ + + +{{if data.article}} + Viewing: {{:data.title}}
    + {{:helper.link('CLOSE', null, { "PRG_reset" : 1 })}} +

    + {{if data.cover}} + + {{/if}} + {{:data.article}} +{{else}} +

    Listing available files

    +
    +
    + Show archived files: +
    +
    + {{if data.showing_archived}} + {{:helper.link('YES', null, { "PRG_toggle_archived" : 1 })}} + {{else}} + {{:helper.link('NO', null, { "PRG_toggle_archived" : 1 })}} + {{/if}} +
    +
    +

    + {{for data.all_articles}} +
    +
    + Name: +
    +
    + {{:value.name}} +
    +
    + Actions: +
    +
    + {{:helper.link('OPEN', null, { "PRG_openarticle" : value.uid })}} +
    +
    + {{/for}} +{{/if}} \ No newline at end of file diff --git a/icons/_nanomaps/tether_nanomap_z1.png b/icons/_nanomaps/tether_nanomap_z1.png new file mode 100644 index 0000000000..03aad88117 Binary files /dev/null and b/icons/_nanomaps/tether_nanomap_z1.png differ diff --git a/icons/_nanomaps/tether_nanomap_z10.png b/icons/_nanomaps/tether_nanomap_z10.png new file mode 100644 index 0000000000..c12164d92e Binary files /dev/null and b/icons/_nanomaps/tether_nanomap_z10.png differ diff --git a/icons/_nanomaps/tether_nanomap_z13.png b/icons/_nanomaps/tether_nanomap_z13.png new file mode 100644 index 0000000000..83792e9db4 Binary files /dev/null and b/icons/_nanomaps/tether_nanomap_z13.png differ diff --git a/icons/_nanomaps/tether_nanomap_z14.png b/icons/_nanomaps/tether_nanomap_z14.png new file mode 100644 index 0000000000..aa62758eb1 Binary files /dev/null and b/icons/_nanomaps/tether_nanomap_z14.png differ diff --git a/icons/_nanomaps/tether_nanomap_z2.png b/icons/_nanomaps/tether_nanomap_z2.png new file mode 100644 index 0000000000..8b52113523 Binary files /dev/null and b/icons/_nanomaps/tether_nanomap_z2.png differ diff --git a/icons/_nanomaps/tether_nanomap_z3.png b/icons/_nanomaps/tether_nanomap_z3.png new file mode 100644 index 0000000000..e3838796e0 Binary files /dev/null and b/icons/_nanomaps/tether_nanomap_z3.png differ diff --git a/icons/_nanomaps/tether_nanomap_z4.png b/icons/_nanomaps/tether_nanomap_z4.png new file mode 100644 index 0000000000..34759796d5 Binary files /dev/null and b/icons/_nanomaps/tether_nanomap_z4.png differ diff --git a/icons/_nanomaps/tether_nanomap_z5.png b/icons/_nanomaps/tether_nanomap_z5.png new file mode 100644 index 0000000000..394c1052a7 Binary files /dev/null and b/icons/_nanomaps/tether_nanomap_z5.png differ diff --git a/icons/_nanomaps/tether_nanomap_z6.png b/icons/_nanomaps/tether_nanomap_z6.png new file mode 100644 index 0000000000..6d67bae632 Binary files /dev/null and b/icons/_nanomaps/tether_nanomap_z6.png differ diff --git a/icons/_nanomaps/tether_nanomap_z7.png b/icons/_nanomaps/tether_nanomap_z7.png new file mode 100644 index 0000000000..8e03cc03fc Binary files /dev/null and b/icons/_nanomaps/tether_nanomap_z7.png differ diff --git a/icons/_nanomaps/tether_nanomap_z8.png b/icons/_nanomaps/tether_nanomap_z8.png new file mode 100644 index 0000000000..3d2acaf6b4 Binary files /dev/null and b/icons/_nanomaps/tether_nanomap_z8.png differ diff --git a/icons/_nanomaps/tether_nanomap_z9.png b/icons/_nanomaps/tether_nanomap_z9.png new file mode 100644 index 0000000000..734f44dd95 Binary files /dev/null and b/icons/_nanomaps/tether_nanomap_z9.png differ diff --git a/icons/effects/64x64.dmi b/icons/effects/64x64.dmi index 79eabaac4f..e4ae33567f 100644 Binary files a/icons/effects/64x64.dmi and b/icons/effects/64x64.dmi differ diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 4419ed4772..e8905467f6 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/goonstation/turf/meatland.dmi b/icons/goonstation/turf/meatland.dmi new file mode 100644 index 0000000000..ff3c9dc260 Binary files /dev/null and b/icons/goonstation/turf/meatland.dmi differ diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi index 5555d0e1ad..88f6dbf028 100644 Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ diff --git a/icons/mob/back_vr.dmi b/icons/mob/back_vr.dmi index 21eb4cfdd2..cfd5604657 100644 Binary files a/icons/mob/back_vr.dmi and b/icons/mob/back_vr.dmi differ diff --git a/icons/mob/eyes.dmi b/icons/mob/eyes.dmi index 63e7f120ce..6320593c1a 100644 Binary files a/icons/mob/eyes.dmi and b/icons/mob/eyes.dmi differ diff --git a/icons/mob/feet_vr.dmi b/icons/mob/feet_vr.dmi index 800d211b20..b1fbd831a1 100644 Binary files a/icons/mob/feet_vr.dmi and b/icons/mob/feet_vr.dmi differ diff --git a/icons/mob/hud_jobs_vr.dmi b/icons/mob/hud_jobs_vr.dmi index 9aa01e9ea5..431090e707 100644 Binary files a/icons/mob/hud_jobs_vr.dmi and b/icons/mob/hud_jobs_vr.dmi differ diff --git a/icons/mob/human_face_vr_add.dmi b/icons/mob/human_face_vr_add.dmi index 78d1b60e4c..029d1789c4 100644 Binary files a/icons/mob/human_face_vr_add.dmi and b/icons/mob/human_face_vr_add.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/unbranded/unbranded_teshari.dmi b/icons/mob/human_races/cyberlimbs/unbranded/unbranded_teshari.dmi index e8eaf7d2c6..ef2b344a41 100644 Binary files a/icons/mob/human_races/cyberlimbs/unbranded/unbranded_teshari.dmi and b/icons/mob/human_races/cyberlimbs/unbranded/unbranded_teshari.dmi differ diff --git a/icons/mob/human_races/markings_vr.dmi b/icons/mob/human_races/markings_vr.dmi index e9fcad5e63..873d455872 100644 Binary files a/icons/mob/human_races/markings_vr.dmi and b/icons/mob/human_races/markings_vr.dmi differ diff --git a/icons/mob/humanoids.dmi b/icons/mob/humanoids.dmi new file mode 100644 index 0000000000..f6dfdd2820 Binary files /dev/null and b/icons/mob/humanoids.dmi differ diff --git a/icons/mob/items/lefthand.dmi b/icons/mob/items/lefthand.dmi index 5403cac867..b707e2c742 100644 Binary files a/icons/mob/items/lefthand.dmi and b/icons/mob/items/lefthand.dmi differ diff --git a/icons/mob/items/lefthand_magic.dmi b/icons/mob/items/lefthand_magic.dmi new file mode 100644 index 0000000000..11552b79ff Binary files /dev/null and b/icons/mob/items/lefthand_magic.dmi differ diff --git a/icons/mob/items/lefthand_melee.dmi b/icons/mob/items/lefthand_melee.dmi index fa92a768f3..6889aa22b1 100644 Binary files a/icons/mob/items/lefthand_melee.dmi and b/icons/mob/items/lefthand_melee.dmi differ diff --git a/icons/mob/items/righthand.dmi b/icons/mob/items/righthand.dmi index 1c92dc0afd..9e756bf9f0 100644 Binary files a/icons/mob/items/righthand.dmi and b/icons/mob/items/righthand.dmi differ diff --git a/icons/mob/items/righthand_magic.dmi b/icons/mob/items/righthand_magic.dmi new file mode 100644 index 0000000000..490deebcf4 Binary files /dev/null and b/icons/mob/items/righthand_magic.dmi differ diff --git a/icons/mob/items/righthand_melee.dmi b/icons/mob/items/righthand_melee.dmi index 916f610112..931b902bbe 100644 Binary files a/icons/mob/items/righthand_melee.dmi and b/icons/mob/items/righthand_melee.dmi differ diff --git a/icons/mob/mask_vr.dmi b/icons/mob/mask_vr.dmi index 0d3c0479b2..ec49d3cdb7 100644 Binary files a/icons/mob/mask_vr.dmi and b/icons/mob/mask_vr.dmi differ diff --git a/icons/mob/modular_shiny_vr.dmi b/icons/mob/modular_shiny_vr.dmi new file mode 100644 index 0000000000..7398b80193 Binary files /dev/null and b/icons/mob/modular_shiny_vr.dmi differ diff --git a/icons/mob/robots_vr.dmi b/icons/mob/robots_vr.dmi index e4a3a1f755..2e34ed66d5 100644 Binary files a/icons/mob/robots_vr.dmi and b/icons/mob/robots_vr.dmi differ diff --git a/icons/mob/species/akula/mask_vr.dmi b/icons/mob/species/akula/mask_vr.dmi index eb39252fa6..2fb104616f 100644 Binary files a/icons/mob/species/akula/mask_vr.dmi and b/icons/mob/species/akula/mask_vr.dmi differ diff --git a/icons/mob/species/fennec/mask_vr.dmi b/icons/mob/species/fennec/mask_vr.dmi index fff10b3696..e956562a59 100644 Binary files a/icons/mob/species/fennec/mask_vr.dmi and b/icons/mob/species/fennec/mask_vr.dmi differ diff --git a/icons/mob/species/fox/mask_vr.dmi b/icons/mob/species/fox/mask_vr.dmi index 515e91df11..aed2ae8ece 100644 Binary files a/icons/mob/species/fox/mask_vr.dmi and b/icons/mob/species/fox/mask_vr.dmi differ diff --git a/icons/mob/species/nevrean/mask_vr.dmi b/icons/mob/species/nevrean/mask_vr.dmi index 34f501aa49..6e3d6c35de 100644 Binary files a/icons/mob/species/nevrean/mask_vr.dmi and b/icons/mob/species/nevrean/mask_vr.dmi differ diff --git a/icons/mob/species/sergal/mask_vr.dmi b/icons/mob/species/sergal/mask_vr.dmi index 5f305fa81f..99d4a069ef 100644 Binary files a/icons/mob/species/sergal/mask_vr.dmi and b/icons/mob/species/sergal/mask_vr.dmi differ diff --git a/icons/mob/species/seromi/ears.dmi b/icons/mob/species/seromi/ears.dmi index b38829b05f..d41f5d871f 100644 Binary files a/icons/mob/species/seromi/ears.dmi and b/icons/mob/species/seromi/ears.dmi differ diff --git a/icons/mob/species/seromi/eyes.dmi b/icons/mob/species/seromi/eyes.dmi index 6ea9bfb05c..c1709e7a58 100644 Binary files a/icons/mob/species/seromi/eyes.dmi and b/icons/mob/species/seromi/eyes.dmi differ diff --git a/icons/mob/species/seromi/head.dmi b/icons/mob/species/seromi/head.dmi index 849b03718c..0055a2ca5d 100644 Binary files a/icons/mob/species/seromi/head.dmi and b/icons/mob/species/seromi/head.dmi differ diff --git a/icons/mob/species/seromi/masks.dmi b/icons/mob/species/seromi/masks.dmi index 83493f851a..afe787be11 100644 Binary files a/icons/mob/species/seromi/masks.dmi and b/icons/mob/species/seromi/masks.dmi differ diff --git a/icons/mob/species/seromi/masks_vr.dmi b/icons/mob/species/seromi/masks_vr.dmi index 52f2591087..3914b57a13 100644 Binary files a/icons/mob/species/seromi/masks_vr.dmi and b/icons/mob/species/seromi/masks_vr.dmi differ diff --git a/icons/mob/species/seromi/ties.dmi b/icons/mob/species/seromi/ties.dmi index 06eee815b1..9969e78109 100644 Binary files a/icons/mob/species/seromi/ties.dmi and b/icons/mob/species/seromi/ties.dmi differ diff --git a/icons/mob/species/seromi/uniform.dmi b/icons/mob/species/seromi/uniform.dmi index 76605857c8..88408e1f58 100644 Binary files a/icons/mob/species/seromi/uniform.dmi and b/icons/mob/species/seromi/uniform.dmi differ diff --git a/icons/mob/species/tajaran/mask.dmi b/icons/mob/species/tajaran/mask.dmi index 0b68e98a67..15f0bf0fe9 100644 Binary files a/icons/mob/species/tajaran/mask.dmi and b/icons/mob/species/tajaran/mask.dmi differ diff --git a/icons/mob/species/vox/masks.dmi b/icons/mob/species/vox/masks.dmi index 6afaa10c22..29b7d76ef9 100644 Binary files a/icons/mob/species/vox/masks.dmi and b/icons/mob/species/vox/masks.dmi differ diff --git a/icons/mob/taursuits_naga_vr.dmi b/icons/mob/taursuits_naga_vr.dmi index 7df326318c..bfec658879 100644 Binary files a/icons/mob/taursuits_naga_vr.dmi and b/icons/mob/taursuits_naga_vr.dmi differ diff --git a/icons/mob/taursuits_wolf_vr.dmi b/icons/mob/taursuits_wolf_vr.dmi index 0f638ea6d3..140e6de426 100644 Binary files a/icons/mob/taursuits_wolf_vr.dmi and b/icons/mob/taursuits_wolf_vr.dmi differ diff --git a/icons/mob/vore.dmi b/icons/mob/vore.dmi index 396c6ef362..9fad9d332d 100644 Binary files a/icons/mob/vore.dmi and b/icons/mob/vore.dmi differ diff --git a/icons/mob/vore/ears_vr.dmi b/icons/mob/vore/ears_vr.dmi index e2bb2c774f..19ca05582f 100644 Binary files a/icons/mob/vore/ears_vr.dmi and b/icons/mob/vore/ears_vr.dmi differ diff --git a/icons/mob/vore/taurs_vr.dmi b/icons/mob/vore/taurs_vr.dmi index 69d0a91388..7d283e6530 100644 Binary files a/icons/mob/vore/taurs_vr.dmi and b/icons/mob/vore/taurs_vr.dmi differ diff --git a/icons/obj/closets/bases/wall.dmi b/icons/obj/closets/bases/wall.dmi index 6689e59cfc..730574ba5d 100644 Binary files a/icons/obj/closets/bases/wall.dmi and b/icons/obj/closets/bases/wall.dmi differ diff --git a/icons/obj/closets/decals/wall.dmi b/icons/obj/closets/decals/wall.dmi index b9b207407e..8d34c97d1a 100644 Binary files a/icons/obj/closets/decals/wall.dmi and b/icons/obj/closets/decals/wall.dmi differ diff --git a/icons/obj/clothing/glasses.dmi b/icons/obj/clothing/glasses.dmi index da5436c8d7..e797e4d094 100644 Binary files a/icons/obj/clothing/glasses.dmi and b/icons/obj/clothing/glasses.dmi differ diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi index 195662d14b..88fa471cfd 100644 Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ diff --git a/icons/obj/clothing/masks_vr.dmi b/icons/obj/clothing/masks_vr.dmi index 0a09e048bc..7508f018e7 100644 Binary files a/icons/obj/clothing/masks_vr.dmi and b/icons/obj/clothing/masks_vr.dmi differ diff --git a/icons/obj/clothing/modular_shiny_vr.dmi b/icons/obj/clothing/modular_shiny_vr.dmi new file mode 100644 index 0000000000..df757d6aca Binary files /dev/null and b/icons/obj/clothing/modular_shiny_vr.dmi differ diff --git a/icons/obj/clothing/ranger.dmi b/icons/obj/clothing/ranger.dmi index 5f810d2ea4..a61db90889 100644 Binary files a/icons/obj/clothing/ranger.dmi and b/icons/obj/clothing/ranger.dmi differ diff --git a/icons/obj/clothing/shoes_vr.dmi b/icons/obj/clothing/shoes_vr.dmi index c6662aa325..5b81be4b1f 100644 Binary files a/icons/obj/clothing/shoes_vr.dmi and b/icons/obj/clothing/shoes_vr.dmi differ diff --git a/icons/obj/decals_vr.dmi b/icons/obj/decals_vr.dmi index 391d37b918..41586b5f88 100644 Binary files a/icons/obj/decals_vr.dmi and b/icons/obj/decals_vr.dmi differ diff --git a/icons/obj/drinks_vr.dmi b/icons/obj/drinks_vr.dmi index 0f383a823f..3dca3dbfed 100644 Binary files a/icons/obj/drinks_vr.dmi and b/icons/obj/drinks_vr.dmi differ diff --git a/icons/obj/flora/amayastuff.dmi b/icons/obj/flora/amayastuff.dmi new file mode 100644 index 0000000000..ed5196cd86 Binary files /dev/null and b/icons/obj/flora/amayastuff.dmi differ diff --git a/icons/obj/gun2.dmi b/icons/obj/gun2.dmi index 38a4148c20..a5c13c95c4 100644 Binary files a/icons/obj/gun2.dmi and b/icons/obj/gun2.dmi differ diff --git a/icons/obj/hydroponics_growing.dmi b/icons/obj/hydroponics_growing.dmi index 9c10859527..52146b3793 100644 Binary files a/icons/obj/hydroponics_growing.dmi and b/icons/obj/hydroponics_growing.dmi differ diff --git a/icons/obj/hydroponics_products.dmi b/icons/obj/hydroponics_products.dmi index 4c9fe0b29a..af1beb5679 100644 Binary files a/icons/obj/hydroponics_products.dmi and b/icons/obj/hydroponics_products.dmi differ diff --git a/icons/obj/hydroponics_vines.dmi b/icons/obj/hydroponics_vines.dmi index 2bad94b350..66aac4a88d 100644 Binary files a/icons/obj/hydroponics_vines.dmi and b/icons/obj/hydroponics_vines.dmi differ diff --git a/icons/obj/machines/drone_fab.dmi b/icons/obj/machines/drone_fab.dmi index 066b51c258..2bbef003b8 100644 Binary files a/icons/obj/machines/drone_fab.dmi and b/icons/obj/machines/drone_fab.dmi differ diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index 40cec418bc..cb79babe03 100644 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ diff --git a/icons/obj/seeds.dmi b/icons/obj/seeds.dmi index d234aba525..2ed8360e95 100644 Binary files a/icons/obj/seeds.dmi and b/icons/obj/seeds.dmi differ diff --git a/icons/obj/stacks.dmi b/icons/obj/stacks.dmi index 0f5453bde0..7fc0482b1b 100644 Binary files a/icons/obj/stacks.dmi and b/icons/obj/stacks.dmi differ diff --git a/icons/obj/storage_vr.dmi b/icons/obj/storage_vr.dmi index bf884c2ded..674f7e0d9c 100644 Binary files a/icons/obj/storage_vr.dmi and b/icons/obj/storage_vr.dmi differ diff --git a/icons/obj/wizard.dmi b/icons/obj/wizard.dmi index b7d095f87a..0878311519 100644 Binary files a/icons/obj/wizard.dmi and b/icons/obj/wizard.dmi differ diff --git a/icons/program_icons/alarm_green.gif b/icons/program_icons/alarm_green.gif new file mode 100644 index 0000000000..7c2570c8ce Binary files /dev/null and b/icons/program_icons/alarm_green.gif differ diff --git a/icons/program_icons/alarm_red.gif b/icons/program_icons/alarm_red.gif new file mode 100644 index 0000000000..327d58e4db Binary files /dev/null and b/icons/program_icons/alarm_red.gif differ diff --git a/icons/program_icons/batt_100.gif b/icons/program_icons/batt_100.gif new file mode 100644 index 0000000000..ccdbd4333e Binary files /dev/null and b/icons/program_icons/batt_100.gif differ diff --git a/icons/program_icons/batt_20.gif b/icons/program_icons/batt_20.gif new file mode 100644 index 0000000000..1d5e38fc88 Binary files /dev/null and b/icons/program_icons/batt_20.gif differ diff --git a/icons/program_icons/batt_40.gif b/icons/program_icons/batt_40.gif new file mode 100644 index 0000000000..d5cedb9967 Binary files /dev/null and b/icons/program_icons/batt_40.gif differ diff --git a/icons/program_icons/batt_5.gif b/icons/program_icons/batt_5.gif new file mode 100644 index 0000000000..ceac8f3a94 Binary files /dev/null and b/icons/program_icons/batt_5.gif differ diff --git a/icons/program_icons/batt_60.gif b/icons/program_icons/batt_60.gif new file mode 100644 index 0000000000..d39534c8cb Binary files /dev/null and b/icons/program_icons/batt_60.gif differ diff --git a/icons/program_icons/batt_80.gif b/icons/program_icons/batt_80.gif new file mode 100644 index 0000000000..9c299773f0 Binary files /dev/null and b/icons/program_icons/batt_80.gif differ diff --git a/icons/program_icons/charging.gif b/icons/program_icons/charging.gif new file mode 100644 index 0000000000..cf19ca7287 Binary files /dev/null and b/icons/program_icons/charging.gif differ diff --git a/icons/program_icons/downloader_finished.gif b/icons/program_icons/downloader_finished.gif new file mode 100644 index 0000000000..f01b7c42af Binary files /dev/null and b/icons/program_icons/downloader_finished.gif differ diff --git a/icons/program_icons/downloader_running.gif b/icons/program_icons/downloader_running.gif new file mode 100644 index 0000000000..68fb977c86 Binary files /dev/null and b/icons/program_icons/downloader_running.gif differ diff --git a/icons/program_icons/ntnrc_idle.gif b/icons/program_icons/ntnrc_idle.gif new file mode 100644 index 0000000000..d47c01d580 Binary files /dev/null and b/icons/program_icons/ntnrc_idle.gif differ diff --git a/icons/program_icons/ntnrc_new.gif b/icons/program_icons/ntnrc_new.gif new file mode 100644 index 0000000000..af72a8b332 Binary files /dev/null and b/icons/program_icons/ntnrc_new.gif differ diff --git a/icons/program_icons/power_norm.gif b/icons/program_icons/power_norm.gif new file mode 100644 index 0000000000..2b8d60edfa Binary files /dev/null and b/icons/program_icons/power_norm.gif differ diff --git a/icons/program_icons/power_warn.gif b/icons/program_icons/power_warn.gif new file mode 100644 index 0000000000..0c85b3a85a Binary files /dev/null and b/icons/program_icons/power_warn.gif differ diff --git a/icons/program_icons/sig_high.gif b/icons/program_icons/sig_high.gif new file mode 100644 index 0000000000..efb20f6730 Binary files /dev/null and b/icons/program_icons/sig_high.gif differ diff --git a/icons/program_icons/sig_lan.gif b/icons/program_icons/sig_lan.gif new file mode 100644 index 0000000000..07ba929f7f Binary files /dev/null and b/icons/program_icons/sig_lan.gif differ diff --git a/icons/program_icons/sig_low.gif b/icons/program_icons/sig_low.gif new file mode 100644 index 0000000000..08f98baea8 Binary files /dev/null and b/icons/program_icons/sig_low.gif differ diff --git a/icons/program_icons/sig_none.gif b/icons/program_icons/sig_none.gif new file mode 100644 index 0000000000..79840d8a2b Binary files /dev/null and b/icons/program_icons/sig_none.gif differ diff --git a/icons/program_icons/sig_warning.gif b/icons/program_icons/sig_warning.gif new file mode 100644 index 0000000000..17f6f61981 Binary files /dev/null and b/icons/program_icons/sig_warning.gif differ diff --git a/icons/program_icons/smmon_0.gif b/icons/program_icons/smmon_0.gif new file mode 100644 index 0000000000..7b716c4e1c Binary files /dev/null and b/icons/program_icons/smmon_0.gif differ diff --git a/icons/program_icons/smmon_1.gif b/icons/program_icons/smmon_1.gif new file mode 100644 index 0000000000..bbe319b820 Binary files /dev/null and b/icons/program_icons/smmon_1.gif differ diff --git a/icons/program_icons/smmon_2.gif b/icons/program_icons/smmon_2.gif new file mode 100644 index 0000000000..9c58edd340 Binary files /dev/null and b/icons/program_icons/smmon_2.gif differ diff --git a/icons/program_icons/smmon_3.gif b/icons/program_icons/smmon_3.gif new file mode 100644 index 0000000000..dc7c8734ee Binary files /dev/null and b/icons/program_icons/smmon_3.gif differ diff --git a/icons/program_icons/smmon_4.gif b/icons/program_icons/smmon_4.gif new file mode 100644 index 0000000000..8a75e6e118 Binary files /dev/null and b/icons/program_icons/smmon_4.gif differ diff --git a/icons/program_icons/smmon_5.gif b/icons/program_icons/smmon_5.gif new file mode 100644 index 0000000000..59356beda0 Binary files /dev/null and b/icons/program_icons/smmon_5.gif differ diff --git a/icons/program_icons/smmon_6.gif b/icons/program_icons/smmon_6.gif new file mode 100644 index 0000000000..aea2f87921 Binary files /dev/null and b/icons/program_icons/smmon_6.gif differ diff --git a/icons/turf/areas_vr_talon.dmi b/icons/turf/areas_vr_talon.dmi new file mode 100644 index 0000000000..0878adbfea Binary files /dev/null and b/icons/turf/areas_vr_talon.dmi differ diff --git a/icons/turf/shuttle_parts.dmi b/icons/turf/shuttle_parts.dmi index 0604db6d7d..33d91a24d4 100644 Binary files a/icons/turf/shuttle_parts.dmi and b/icons/turf/shuttle_parts.dmi differ diff --git a/icons/turf/wall_masks_vr.dmi b/icons/turf/wall_masks_vr.dmi index 1e767e6994..dc4e2300f0 100644 Binary files a/icons/turf/wall_masks_vr.dmi and b/icons/turf/wall_masks_vr.dmi differ diff --git a/icons/vore/custom_items_vr.dmi b/icons/vore/custom_items_vr.dmi index a16ebe46d9..4856d6c311 100644 Binary files a/icons/vore/custom_items_vr.dmi and b/icons/vore/custom_items_vr.dmi differ diff --git a/interface/skin.dmf b/interface/skin.dmf index 4750d0b91b..84b74d0d2f 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -564,6 +564,9 @@ macro "hotkeymode" elem name = "CTRL+Z" command = "Activate-Held-Object" + elem + name = "U" + command = "Rest" elem name = "NUMPAD1" command = "body-r-leg" diff --git a/maps/offmap_vr/om_ships/curashuttle.dmm b/maps/offmap_vr/om_ships/curashuttle.dmm index b6a9885353..6a54db8db6 100644 --- a/maps/offmap_vr/om_ships/curashuttle.dmm +++ b/maps/offmap_vr/om_ships/curashuttle.dmm @@ -1,1922 +1,1922 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"aa" = ( -/turf/template_noop, -/area/template_noop) -"ab" = ( -/turf/simulated/wall/rdshull, -/area/shuttle/curabitur/curashuttle/med) -"ac" = ( -/obj/machinery/shipsensors{ - dir = 1 - }, -/obj/effect/floor_decal/techfloor/orange{ - dir = 4 - }, -/obj/effect/floor_decal/techfloor/orange{ - dir = 8 - }, -/turf/simulated/shuttle/plating/airless, -/area/shuttle/curabitur/curashuttle/cockpit) -"ad" = ( -/turf/simulated/wall/rdshull, -/area/shuttle/curabitur/curashuttle/cockpit) -"ae" = ( -/obj/structure/window/plastitanium/full, -/obj/structure/window/plastitanium{ - dir = 1; - icon_state = "window" - }, -/obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id = "mediwindowshutters"; - name = "Window Blast Door"; - opacity = 0 - }, -/obj/structure/grille, -/turf/simulated/floor/plating, -/area/shuttle/curabitur/curashuttle/med) -"af" = ( -/obj/structure/window/plastitanium/full, -/obj/structure/window/plastitanium{ - dir = 1; - icon_state = "window" - }, -/obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id = "mediwindowshutters"; - name = "Window Blast Door"; - opacity = 0 - }, -/obj/structure/grille, -/turf/simulated/floor/plating, -/area/shuttle/curabitur/curashuttle/cockpit) -"ag" = ( -/obj/structure/sign/redcross, -/obj/machinery/vending/nifsoft_shop, -/turf/simulated/wall/rdshull, -/area/shuttle/curabitur/curashuttle/med) -"ah" = ( -/obj/machinery/optable, -/obj/machinery/oxygen_pump/anesthetic{ - pixel_x = -25 - }, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"ai" = ( -/obj/machinery/computer/operating, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"aj" = ( -/obj/machinery/vending/blood{ - density = 0; - pixel_y = 18; - req_access = newlist() - }, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"ak" = ( -/obj/machinery/body_scanconsole{ - dir = 4 - }, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"al" = ( -/obj/machinery/bodyscanner{ - dir = 4 - }, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"am" = ( -/turf/simulated/wall/shull, -/area/shuttle/curabitur/curashuttle/cockpit) -"an" = ( -/obj/machinery/computer/shuttle_control/explore/curashuttle{ - dir = 4; - icon_state = "computer" - }, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"ao" = ( -/obj/structure/cable{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"ap" = ( -/obj/structure/cable{ - d2 = 8; - icon_state = "0-8" - }, -/obj/machinery/power/apc{ - dir = 4; - name = "east bump"; - pixel_x = 24; - pixel_y = 0 - }, -/obj/structure/table/darkglass, -/obj/item/weapon/paper_bin{ - pixel_x = 8; - pixel_y = -2 - }, -/obj/item/weapon/pen/fountain, -/obj/machinery/photocopier/faxmachine{ - department = "Curabitur Rescue Service"; - name = "curabitur fax machine"; - pixel_y = 6 - }, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"aq" = ( -/obj/structure/sign/redcross, -/turf/simulated/wall/rdshull, -/area/shuttle/curabitur/curashuttle/cockpit) -"ar" = ( -/obj/item/weapon/storage/firstaid/surgery, -/obj/item/weapon/surgical/scalpel/manager, -/obj/item/weapon/surgical/scalpel/ripper, -/obj/item/weapon/surgical/circular_saw/manager, -/obj/item/stack/nanopaste/advanced, -/obj/item/stack/nanopaste/advanced, -/obj/structure/table/standard, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"as" = ( -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"at" = ( -/obj/structure/closet/crate/large, -/obj/item/weapon/gun/projectile/multi_cannon, -/obj/item/weapon/gun/projectile/multi_cannon, -/obj/item/ammo_casing/macrobattery/buff, -/obj/item/ammo_casing/macrobattery/buff, -/obj/item/ammo_casing/macrobattery/detox, -/obj/item/ammo_casing/macrobattery/detox, -/obj/item/ammo_casing/macrobattery/healie, -/obj/item/ammo_casing/macrobattery/healie, -/obj/item/ammo_casing/macrobattery/ouchie, -/obj/item/ammo_casing/macrobattery/ouchie, -/obj/item/ammo_casing/macrobattery/stabilize, -/obj/item/ammo_casing/macrobattery/stabilize, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"au" = ( -/obj/structure/medical_stand, -/obj/machinery/vending/nifsoft_shop{ - categories = 3; - emagged = 1; - pixel_x = 23; - pixel_y = -5 - }, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"av" = ( -/obj/machinery/computer/ship/helm{ - dir = 4; - req_one_access = null - }, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"aw" = ( -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/structure/bed/chair/bay/comfy{ - dir = 1; - icon_state = "bay_comfychair_preview" - }, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"ax" = ( -/obj/machinery/computer/ship/engines{ - dir = 8; - icon_state = "computer" - }, -/obj/structure/window/plastitanium{ - dir = 4; - icon_state = "window" - }, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"ay" = ( -/obj/item/weapon/bedsheet/bluedouble, -/obj/structure/bed/double/padded, -/obj/structure/curtain/open/bed, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"az" = ( -/turf/simulated/wall/rpshull, -/area/shuttle/curabitur/curashuttle/med) -"aA" = ( -/obj/item/weapon/storage/firstaid/adv, -/obj/item/weapon/storage/firstaid/fire, -/obj/item/weapon/storage/firstaid/o2, -/obj/item/weapon/storage/firstaid/regular, -/obj/item/weapon/storage/firstaid/toxin, -/obj/item/weapon/storage/pill_bottle/spaceacillin, -/obj/structure/table/standard, -/obj/item/device/healthanalyzer/advanced, -/obj/item/device/healthanalyzer/advanced, -/obj/item/weapon/reagent_containers/spray/cleaner, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"aB" = ( -/obj/item/weapon/surgical/scalpel/alien, -/obj/item/weapon/surgical/retractor/alien, -/obj/item/weapon/surgical/hemostat/alien, -/obj/item/weapon/surgical/circular_saw/alien, -/obj/item/weapon/surgical/cautery/alien, -/obj/item/weapon/surgical/FixOVein/alien, -/obj/item/weapon/surgical/surgicaldrill/alien, -/obj/structure/table/standard, -/obj/machinery/recharger{ - pixel_x = -8; - pixel_y = 8 - }, -/obj/machinery/recharger{ - pixel_x = 2; - pixel_y = 8 - }, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"aC" = ( -/obj/machinery/organ_printer/flesh/full, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"aD" = ( -/obj/item/weapon/storage/backpack/dufflebag/syndie/med, -/obj/item/weapon/storage/belt/medical, -/obj/item/weapon/storage/belt/medical, -/obj/item/weapon/storage/belt/medical, -/obj/structure/table/rack, -/obj/item/weapon/storage/backpack/dufflebag/syndie/med, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"aE" = ( -/obj/machinery/computer/ship/sensors{ - dir = 4; - icon_state = "computer" - }, -/obj/machinery/firealarm{ - dir = 8; - pixel_x = -29; - pixel_y = 0 - }, -/obj/machinery/light{ - dir = 8; - icon_state = "tube1"; - pixel_x = 0 - }, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"aF" = ( -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"aG" = ( -/obj/machinery/button/remote/blast_door{ - id = "medihangar"; - name = "Hangar blast door control"; - pixel_x = 8; - pixel_y = 8; - plane = 0 - }, -/obj/structure/table/darkglass, -/obj/machinery/button/remote/blast_door{ - id = "mediwindowshutters"; - name = "Window shutters"; - pixel_x = -9; - pixel_y = 8 - }, -/obj/machinery/atmospherics/pipe/vent, -/obj/structure/window/plastitanium{ - dir = 4; - icon_state = "window" - }, -/obj/machinery/button/remote/airlock/survival_pod{ - id = "curadocking"; - name = "Main airlock lock"; - pixel_y = 8 - }, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"aH" = ( -/obj/item/weapon/storage/secure/safe{ - pixel_x = 31 - }, -/obj/item/weapon/gun/projectile/automatic/mini_uzi, -/obj/item/weapon/card/id/syndicate{ - access = list(616); - assignment = "Curabitur Contractor"; - origin_tech = newlist() - }, -/obj/item/weapon/card/id/syndicate{ - access = list(616); - assignment = "Curabitur Contractor"; - origin_tech = newlist() - }, -/obj/item/weapon/spacecash/c1000, -/obj/item/weapon/spacecash/c1000, -/obj/item/weapon/spacecash/c1000, -/obj/item/weapon/spacecash/c1000, -/obj/item/weapon/spacecash/c1000, -/obj/item/weapon/spacecash/c1000, -/obj/item/weapon/spacecash/c1000, -/obj/item/weapon/spacecash/c1000, -/obj/item/weapon/spacecash/c1000, -/obj/item/weapon/spacecash/c1000, -/obj/item/weapon/spacecash/c1000, -/obj/item/weapon/spacecash/c1000, -/obj/item/weapon/spacecash/c1000, -/obj/item/weapon/spacecash/c1000, -/obj/item/weapon/spacecash/c1000, -/obj/item/weapon/spacecash/c1000, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"aI" = ( -/turf/simulated/wall/rpshull, -/area/shuttle/curabitur/curashuttle/cockpit) -"aJ" = ( -/obj/machinery/sleep_console{ - dir = 2; - icon_state = "sleeperconsole"; - pixel_x = -1 - }, -/obj/machinery/light{ - dir = 8; - icon_state = "tube1"; - pixel_x = 0 - }, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"aK" = ( -/obj/structure/table/standard, -/obj/item/stack/cable_coil, -/obj/item/stack/cable_coil, -/obj/item/stack/cable_coil, -/obj/item/stack/cable_coil, -/obj/item/device/robotanalyzer, -/obj/item/device/robotanalyzer, -/obj/item/weapon/reagent_containers/spray/cleaner, -/obj/item/weapon/reagent_containers/dropper, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"aL" = ( -/obj/machinery/embedded_controller/radio/simple_docking_controller{ - dir = 8; - frequency = 1480; - id_tag = "curadocking"; - pixel_x = 28; - pixel_y = 0 - }, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/med) -"aM" = ( -/obj/structure/table/rack, -/obj/item/device/defib_kit/jumper_kit/loaded, -/obj/item/device/defib_kit/compact/combat/loaded, -/obj/item/device/defib_kit/compact/combat/loaded, -/obj/item/device/mmi/radio_enabled{ - req_access = newlist() - }, -/obj/machinery/light{ - dir = 4; - icon_state = "tube1" - }, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"aN" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 8 - }, -/obj/structure/closet, -/obj/item/clothing/under/rank/nurse, -/obj/item/clothing/under/rank/nurse, -/obj/item/clothing/under/rank/medical, -/obj/item/clothing/shoes/blue, -/obj/item/clothing/shoes/blue, -/obj/item/clothing/suit/storage/toggle/bomber/pilot, -/obj/item/clothing/suit/storage/toggle/labcoat, -/obj/item/clothing/accessory/storage/white_drop_pouches, -/obj/item/clothing/accessory/storage/white_drop_pouches, -/obj/item/clothing/accessory/holster/machete, -/obj/item/clothing/accessory/holster/hip, -/obj/item/weapon/material/knife/machete, -/obj/item/clothing/accessory/storage/white_drop_pouches, -/obj/item/clothing/accessory/storage/white_drop_pouches, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"aO" = ( -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"aP" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"aQ" = ( -/obj/machinery/recharger/wallcharger{ - pixel_x = 31; - pixel_y = -10 - }, -/obj/machinery/recharger/wallcharger{ - pixel_x = 31; - pixel_y = -2 - }, -/obj/machinery/recharger/wallcharger{ - pixel_x = 31; - pixel_y = 7 - }, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"aR" = ( -/obj/machinery/sleeper, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"aS" = ( -/obj/structure/table/standard, -/obj/item/wheelchair, -/obj/item/roller/adv, -/obj/item/roller/adv, -/obj/item/roller/adv, -/obj/item/bodybag/cryobag, -/obj/item/bodybag/cryobag, -/obj/item/bodybag/cryobag, -/obj/item/bodybag/cryobag, -/obj/item/bodybag/cryobag/robobag, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"aT" = ( -/obj/structure/table/rack, -/obj/item/wheelchair, -/obj/item/wheelchair, -/obj/item/weapon/cane/crutch, -/obj/item/weapon/cane/crutch, -/obj/item/weapon/cane/white/collapsible, -/obj/item/clothing/accessory/stethoscope, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"aU" = ( -/obj/structure/window/plastitanium{ - dir = 8; - icon_state = "window" - }, -/obj/structure/cable{ - icon_state = "0-4" - }, -/obj/machinery/power/shield_generator/charged{ - initial_shield_modes = 2133; - input_cap = 50000 - }, -/obj/structure/curtain/black, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/cockpit) -"aV" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"aW" = ( -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 6 - }, -/obj/structure/cable{ - icon_state = "2-8" - }, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"aX" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/carpet/bcarpet, -/area/shuttle/curabitur/curashuttle/cockpit) -"aY" = ( -/obj/machinery/atmospherics/pipe/simple/visible/blue{ - dir = 6; - icon_state = "intact" - }, -/obj/structure/table/standard, -/obj/fiftyspawner/steel, -/obj/item/weapon/storage/toolbox/syndicate/powertools, -/obj/item/stack/nanopaste/advanced, -/obj/item/stack/cable_coil, -/obj/item/stack/cable_coil, -/obj/item/stack/cable_coil, -/obj/item/device/multitool, -/obj/item/weapon/storage/box/metalfoam, -/obj/item/bodybag/cryobag/robobag, -/obj/item/bodybag/cryobag/robobag, -/obj/item/weapon/storage/belt/utility, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"aZ" = ( -/obj/machinery/vending/medical{ - dir = 4; - pixel_x = -14; - req_access = newlist() - }, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"ba" = ( -/obj/structure/sink{ - dir = 4; - icon_state = "sink"; - pixel_x = 12; - pixel_y = 0 - }, -/obj/machinery/recharger/wallcharger{ - pixel_x = 31; - pixel_y = 6 - }, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"bb" = ( -/obj/structure/window/plastitanium, -/obj/structure/window/plastitanium{ - dir = 1; - icon_state = "window" - }, -/obj/structure/window/reinforced/full, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/cockpit) -"bc" = ( -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/machinery/door/firedoor/glass, -/obj/machinery/door/airlock/glass_command{ - name = "Rescue Ship Cockpit"; - req_one_access = null - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/cockpit) -"bd" = ( -/obj/structure/curtain/medical, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"be" = ( -/turf/simulated/wall/shull, -/area/shuttle/curabitur/curashuttle/med) -"bf" = ( -/obj/structure/table/darkglass, -/obj/machinery/recharger{ - pixel_x = -8; - pixel_y = 8 - }, -/obj/machinery/recharger{ - pixel_x = 2; - pixel_y = 8 - }, -/obj/item/device/gps/medical, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/med) -"bg" = ( -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/med) -"bh" = ( -/obj/item/device/suit_cooling_unit, -/obj/item/device/suit_cooling_unit, -/obj/item/device/suit_cooling_unit, -/obj/structure/table/rack, -/obj/item/clothing/head/helmet/space/void/medical, -/obj/item/clothing/head/helmet/space/void/medical, -/obj/item/clothing/head/helmet/space/void/medical, -/obj/item/clothing/suit/space/void/medical, -/obj/item/clothing/suit/space/void/medical, -/obj/item/clothing/suit/space/void/medical, -/obj/item/weapon/tank/air, -/obj/item/weapon/tank/air, -/obj/item/weapon/tank/air, -/obj/item/weapon/tank/jetpack/carbondioxide, -/obj/item/weapon/tank/jetpack/carbondioxide, -/obj/item/weapon/tank/jetpack/carbondioxide, -/obj/item/weapon/tank/emergency/oxygen/engi, -/obj/item/weapon/tank/emergency/oxygen/engi, -/obj/item/clothing/mask/breath, -/obj/item/clothing/mask/breath, -/obj/item/clothing/mask/breath, -/obj/item/clothing/shoes/magboots, -/obj/item/clothing/shoes/magboots, -/obj/item/clothing/shoes/magboots, -/obj/item/device/gps/medical, -/obj/item/device/gps/medical, -/obj/item/device/gps/medical, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/med) -"bi" = ( -/obj/machinery/suit_cycler/medical, -/obj/machinery/alarm{ - pixel_y = 25 - }, -/obj/machinery/firealarm{ - dir = 4; - layer = 3.3; - pixel_y = 26 - }, -/obj/machinery/light{ - dir = 1 - }, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/med) -"bj" = ( -/obj/structure/window/plastitanium/full, -/obj/structure/window/plastitanium{ - dir = 8; - icon_state = "window" - }, -/obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id = "mediwindowshutters"; - name = "Window Blast Door"; - opacity = 0 - }, -/obj/structure/grille, -/turf/simulated/floor/plating, -/area/shuttle/curabitur/curashuttle/med) -"bk" = ( -/obj/machinery/smartfridge/chemistry{ - dir = 4; - icon_state = "fridge_food" - }, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"bl" = ( -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/med) -"bm" = ( -/obj/structure/filingcabinet/medical, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"bn" = ( -/obj/structure/window/plastitanium/full, -/obj/structure/window/plastitanium{ - dir = 4; - icon_state = "window" - }, -/obj/machinery/door/firedoor, -/obj/machinery/door/blast/regular{ - density = 0; - dir = 4; - icon_state = "pdoor0"; - id = "mediwindowshutters"; - name = "Window Blast Door"; - opacity = 0 - }, -/obj/structure/grille, -/turf/simulated/floor/plating, -/area/shuttle/curabitur/curashuttle/med) -"bo" = ( -/obj/machinery/chem_master, -/obj/structure/table/standard, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"bp" = ( -/obj/structure/bed/chair/bay/comfy, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/med) -"br" = ( -/obj/machinery/chemical_dispenser/ert/specialops, -/obj/structure/table/standard, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"bs" = ( -/obj/structure/bed/chair/bay/comfy{ - dir = 8; - icon_state = "bay_comfychair_preview" - }, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"bt" = ( -/obj/structure/reagent_dispensers/water_cooler/full{ - density = 0; - pixel_x = 11 - }, -/turf/simulated/floor/carpet/sblucarpet, -/area/shuttle/curabitur/curashuttle/med) -"bu" = ( -/obj/structure/table/darkglass, -/obj/machinery/atmospherics/pipe/vent, -/obj/item/weapon/reagent_containers/food/snacks/bagelsunflower, -/obj/item/weapon/reagent_containers/food/snacks/applepie, -/obj/item/weapon/reagent_containers/food/snacks/carrotfries, -/obj/item/weapon/reagent_containers/food/snacks/cube/nutriment, -/obj/item/weapon/reagent_containers/food/snacks/cube/protein, -/obj/item/weapon/reagent_containers/food/snacks/cube/protein, -/obj/item/weapon/reagent_containers/food/snacks/cube/protein, -/obj/item/weapon/reagent_containers/food/snacks/cracker, -/turf/simulated/floor/carpet/sblucarpet, -/area/shuttle/curabitur/curashuttle/med) -"bv" = ( -/obj/structure/table/darkglass, -/obj/item/weapon/reagent_containers/food/snacks/bangersandmash, -/obj/item/weapon/reagent_containers/food/snacks/candiedapple, -/obj/item/weapon/reagent_containers/food/snacks/chickenwing, -/turf/simulated/floor/carpet/sblucarpet, -/area/shuttle/curabitur/curashuttle/med) -"bw" = ( -/obj/structure/closet/crate/bin, -/turf/simulated/floor/carpet/sblucarpet, -/area/shuttle/curabitur/curashuttle/med) -"bx" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 6 - }, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/med) -"by" = ( -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 9 - }, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/med) -"bA" = ( -/obj/structure/sign/redcross, -/turf/simulated/wall/rpshull, -/area/shuttle/curabitur/curashuttle/med) -"bB" = ( -/obj/structure/table/standard, -/obj/item/weapon/storage/bag/chemistry, -/obj/item/weapon/storage/box/pillbottles, -/obj/item/weapon/reagent_containers/dropper, -/obj/item/weapon/reagent_containers/dropper, -/obj/structure/cable{ - icon_state = "0-4" - }, -/obj/machinery/power/apc{ - dir = 8; - name = "west bump"; - pixel_x = -28; - pixel_y = 0 - }, -/obj/machinery/power/terminal{ - dir = 8; - icon_state = "term" - }, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"bC" = ( -/obj/structure/sign/department/eng{ - pixel_x = 0; - pixel_y = -31 - }, -/obj/structure/table/standard, -/obj/item/weapon/reagent_containers/glass/beaker/bluespace, -/obj/item/weapon/reagent_containers/glass/beaker/bluespace, -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 4 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"bD" = ( -/obj/structure/cable{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/obj/structure/cable{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/yellow{ - dir = 6 - }, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/med) -"bE" = ( -/obj/structure/bed/chair/sofa/teal/left{ - dir = 1; - icon_state = "sofaend_left" - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/light, -/obj/structure/sign/directions/engineering{ - pixel_y = -32 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/yellow{ - dir = 4 - }, -/turf/simulated/floor/carpet/sblucarpet, -/area/shuttle/curabitur/curashuttle/med) -"bF" = ( -/obj/machinery/vending/wallmed1/public{ - dir = 1; - icon_state = "wallmed"; - pixel_y = -28 - }, -/obj/structure/bed/chair/sofa/teal{ - dir = 1; - icon_state = "sofamiddle" - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/yellow{ - dir = 4 - }, -/turf/simulated/floor/carpet/sblucarpet, -/area/shuttle/curabitur/curashuttle/med) -"bG" = ( -/obj/machinery/computer/ship/navigation/telescreen{ - pixel_y = -32 - }, -/obj/structure/bed/chair/sofa/teal{ - dir = 1; - icon_state = "sofamiddle" - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/yellow{ - dir = 4 - }, -/turf/simulated/floor/carpet/sblucarpet, -/area/shuttle/curabitur/curashuttle/med) -"bH" = ( -/obj/machinery/vending/wallmed1/public{ - dir = 1; - icon_state = "wallmed"; - pixel_y = -29 - }, -/obj/structure/bed/chair/sofa/teal/right{ - dir = 1; - icon_state = "sofaend_right" - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/yellow{ - dir = 4 - }, -/turf/simulated/floor/carpet/sblucarpet, -/area/shuttle/curabitur/curashuttle/med) -"bI" = ( -/obj/structure/cable{ - icon_state = "2-8" - }, -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 4; - icon_state = "map-scrubbers" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/yellow{ - dir = 4 - }, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/med) -"bJ" = ( -/obj/machinery/recharger/wallcharger{ - pixel_x = 4; - pixel_y = -26 - }, -/obj/structure/cable{ - icon_state = "1-8" - }, -/obj/structure/handrail{ - dir = 1 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/universal{ - dir = 4 - }, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/med) -"bK" = ( -/obj/structure/extinguisher_cabinet{ - pixel_y = -26 - }, -/obj/machinery/light, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/obj/machinery/atmospherics/binary/pump/fuel{ - dir = 8; - icon_state = "map_off-fuel" - }, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/med) -"bL" = ( -/obj/effect/shuttle_landmark/shuttle_initializer/curashuttle, -/obj/effect/overmap/visitable/ship/landable/curashuttle, -/obj/structure/handrail{ - dir = 1 - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - dir = 8; - icon_state = "intact-fuel" - }, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/med) -"bM" = ( -/obj/structure/fans/hardlight, -/obj/machinery/door/airlock/external/glass/bolted{ - frequency = 1480; - id_tag = "curadocking" - }, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_y = 0 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ - dir = 8; - icon_state = "intact-fuel" - }, -/turf/simulated/floor/plating, -/area/shuttle/curabitur/curashuttle/med) -"bN" = ( -/turf/simulated/wall/rpshull, -/area/shuttle/curabitur/curashuttle/eng) -"bO" = ( -/turf/simulated/wall/shull, -/area/shuttle/curabitur/curashuttle/eng) -"bP" = ( -/obj/machinery/door/airlock/voidcraft, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/machinery/door/firedoor/glass, -/obj/machinery/atmospherics/pipe/simple/hidden/yellow, -/turf/simulated/floor/tiled{ - icon_state = "monotile" - }, -/area/shuttle/curabitur/curashuttle/eng) -"bQ" = ( -/turf/simulated/wall/shull, -/area/shuttle/curabitur/curashuttle/hangar) -"bR" = ( -/obj/machinery/door/airlock/voidcraft, -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/machinery/door/firedoor/glass, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/hangar) -"bS" = ( -/turf/simulated/wall/rpshull, -/area/shuttle/curabitur/curashuttle/hangar) -"bT" = ( -/obj/structure/handrail, -/obj/machinery/power/apc{ - dir = 1; - name = "north bump"; - pixel_x = 0; - pixel_y = 28 - }, -/obj/structure/cable{ - icon_state = "0-8" - }, -/obj/structure/cable{ - icon_state = "0-6" - }, -/obj/machinery/atmospherics/pipe/simple/visible/yellow{ - dir = 4 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"bU" = ( -/obj/machinery/atmospherics/pipe/simple/visible/universal{ - dir = 4 - }, -/obj/machinery/recharge_station, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"bV" = ( -/obj/machinery/atmospherics/pipe/simple/visible/scrubbers, -/obj/structure/cable{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/machinery/atmospherics/pipe/simple/visible/supply{ - dir = 9; - icon_state = "intact-supply" - }, -/obj/machinery/atmospherics/pipe/simple/visible/yellow{ - dir = 5 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"bX" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 8 - }, -/obj/machinery/portable_atmospherics/canister/phoron{ - start_pressure = 8000.25 - }, -/turf/simulated/floor/tiled/monofloor{ - dir = 8 - }, -/area/shuttle/curabitur/curashuttle/eng) -"bY" = ( -/obj/structure/window/plastitanium{ - dir = 8; - icon_state = "window" - }, -/obj/structure/window/plastitanium{ - dir = 4; - icon_state = "window" - }, -/obj/structure/curtain/black, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"bZ" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/hangar) -"ca" = ( -/obj/structure/table/standard, -/obj/item/device/survivalcapsule, -/obj/item/device/survivalcapsule, -/obj/item/clothing/gloves/sterile/nitrile, -/obj/item/clothing/gloves/sterile/nitrile, -/obj/item/clothing/suit/surgicalapron, -/turf/simulated/floor/tiled/white, -/area/shuttle/curabitur/curashuttle/med) -"cb" = ( -/obj/structure/closet/crate/medical, -/obj/item/weapon/surgical/scalpel/manager, -/obj/item/weapon/surgical/scalpel/manager, -/obj/item/weapon/surgical/circular_saw/manager, -/obj/item/weapon/surgical/circular_saw/manager, -/obj/item/stack/nanopaste/advanced, -/obj/item/stack/nanopaste/advanced, -/obj/item/device/defib_kit/compact/combat/loaded, -/obj/item/device/defib_kit/compact/combat/loaded, -/obj/item/device/healthanalyzer/advanced, -/obj/item/weapon/storage/backpack/dufflebag/syndie/med, -/obj/item/weapon/surgical/bone_clamp, -/obj/item/weapon/surgical/bone_clamp, -/obj/item/weapon/surgical/scalpel/ripper, -/obj/machinery/firealarm{ - pixel_y = 24 - }, -/obj/machinery/atmospherics/pipe/vent, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"cc" = ( -/obj/structure/table/rack, -/obj/item/mecha_parts/mecha_equipment/crisis_drone, -/obj/item/mecha_parts/mecha_equipment/crisis_drone/rad, -/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun, -/obj/item/mecha_parts/mecha_equipment/weapon/energy/medigun, -/obj/item/mecha_parts/mecha_equipment/tool/powertool/inflatables, -/obj/item/mecha_parts/mecha_equipment/tool/powertool/medanalyzer, -/obj/item/mecha_parts/mecha_equipment/tool/powertool/prybar, -/obj/item/mecha_parts/mecha_equipment/weapon/energy/taser, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/hangar) -"cd" = ( -/obj/machinery/atmospherics/binary/pump{ - dir = 1 - }, -/obj/structure/fireaxecabinet{ - pixel_x = -31 - }, -/obj/structure/handrail{ - dir = 4 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"ce" = ( -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 4 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"cf" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers{ - dir = 4; - icon_state = "map-scrubbers" - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"cg" = ( -/obj/fiftyspawner/tritium, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"ch" = ( -/obj/structure/cable{ - icon_state = "6-9" - }, -/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ - dir = 8 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"cj" = ( -/obj/machinery/mech_recharger, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 5; - icon_state = "intact-supply" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5; - icon_state = "intact-scrubbers" - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/hangar) -"ck" = ( -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/hangar) -"cl" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 9 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/hangar) -"cm" = ( -/obj/structure/table/rack, -/obj/item/mecha_parts/mecha_equipment/tool/passenger, -/obj/item/mecha_parts/mecha_equipment/tool/sleeper, -/obj/item/mecha_parts/mecha_equipment/tool/sleeper, -/obj/item/mecha_parts/mecha_equipment/tool/sleeper, -/obj/item/mecha_parts/mecha_equipment/tool/sleeper, -/obj/machinery/atmospherics/unary/vent_scrubber/on{ - dir = 8 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/hangar) -"cn" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 1 - }, -/obj/machinery/portable_atmospherics/canister/air, -/turf/simulated/floor/tiled/monofloor{ - dir = 1 - }, -/area/shuttle/curabitur/curashuttle/eng) -"co" = ( -/obj/structure/fuel_port, -/turf/simulated/floor/tiled/monofloor{ - dir = 1 - }, -/area/shuttle/curabitur/curashuttle/eng) -"cp" = ( -/obj/machinery/atmospherics/pipe/simple/visible/universal, -/obj/machinery/portable_atmospherics/canister/carbon_dioxide, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"cq" = ( -/obj/machinery/portable_atmospherics/canister/phoron{ - start_pressure = 8000.25 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"cr" = ( -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/hangar) -"cs" = ( -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/hangar) -"ct" = ( -/obj/structure/fans/hardlight, -/obj/machinery/door/blast/regular{ - id = "medihangar" - }, -/turf/simulated/floor/plating, -/area/shuttle/curabitur/curashuttle/hangar) -"cu" = ( -/obj/machinery/atmospherics/portables_connector{ - dir = 4 - }, -/obj/machinery/portable_atmospherics/canister/empty, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/tiled/monofloor, -/area/shuttle/curabitur/curashuttle/eng) -"cv" = ( -/obj/machinery/atmospherics/binary/pump{ - dir = 8 - }, -/obj/machinery/light/small, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"cw" = ( -/obj/machinery/atmospherics/pipe/simple/visible/red{ - dir = 9 - }, -/obj/machinery/autolathe, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"cx" = ( -/obj/machinery/computer/ship/engines{ - dir = 1; - icon_state = "computer" - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"cy" = ( -/obj/machinery/light/small, -/obj/machinery/atmospherics/binary/pump, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"cz" = ( -/obj/machinery/vending/fitness{ - density = 0; - pixel_y = 16 - }, -/turf/simulated/floor/tiled, -/area/shuttle/curabitur/curashuttle/med) -"cA" = ( -/obj/structure/cable, -/obj/machinery/power/apc{ - dir = 2; - name = "south bump"; - pixel_x = 0; - pixel_y = -28 - }, -/obj/structure/handrail{ - dir = 1 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/hangar) -"cB" = ( -/obj/machinery/light, -/obj/machinery/alarm{ - dir = 1; - icon_state = "alarm0"; - pixel_y = -32 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/hangar) -"cC" = ( -/obj/structure/sign/redcross, -/turf/simulated/wall/rpshull, -/area/shuttle/curabitur/curashuttle/eng) -"cD" = ( -/obj/machinery/atmospherics/pipe/simple/visible/yellow{ - dir = 6 - }, -/turf/simulated/wall/rpshull, -/area/shuttle/curabitur/curashuttle/eng) -"cE" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ - dir = 1 - }, -/turf/simulated/wall/rpshull, -/area/shuttle/curabitur/curashuttle/eng) -"cF" = ( -/obj/machinery/button/remote/blast_door{ - id = "medihangar"; - name = "Hangar blast door control"; - pixel_x = -7; - pixel_y = 24 - }, -/obj/structure/cable{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/structure/table/standard, -/obj/item/device/flashlight/flare, -/obj/item/device/flashlight/flare, -/obj/item/device/flashlight/flare, -/obj/machinery/cell_charger{ - pixel_x = -3; - pixel_y = 13 - }, -/obj/item/weapon/cell/high, -/obj/item/weapon/cell/high, -/obj/item/weapon/storage/briefcase/inflatable, -/obj/item/weapon/storage/briefcase/inflatable, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/hangar) -"cG" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/yellow, -/turf/simulated/wall/rpshull, -/area/shuttle/curabitur/curashuttle/eng) -"cI" = ( -/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ - dir = 1 - }, -/turf/simulated/wall/rpshull, -/area/shuttle/curabitur/curashuttle/hangar) -"cJ" = ( -/obj/machinery/atmospherics/pipe/simple/visible/yellow{ - dir = 10 - }, -/turf/simulated/wall/rpshull, -/area/shuttle/curabitur/curashuttle/hangar) -"cK" = ( -/obj/structure/sign/redcross, -/turf/simulated/wall/rpshull, -/area/shuttle/curabitur/curashuttle/hangar) -"cL" = ( -/obj/mecha/combat/fighter/pinnace{ - desc = "A modified Pinnace made to be able to fit a wide arsenal of equipment for rescue missions in space."; - health = 200; - max_equip = 1; - max_hull_equip = 2; - max_special_equip = 1; - max_universal_equip = 2; - max_utility_equip = 3; - maxhealth = 200; - name = "Curabitur Pinnace" - }, -/obj/machinery/mech_recharger, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/hangar) -"cM" = ( -/obj/machinery/atmospherics/unary/engine{ - dir = 1 - }, -/turf/simulated/shuttle/plating/airless/carry, -/area/shuttle/curabitur/curashuttle/eng) -"cN" = ( -/obj/structure/handrail{ - dir = 1 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/hangar) -"cO" = ( -/obj/machinery/atmospherics/unary/engine{ - dir = 1 - }, -/turf/space, -/turf/simulated/shuttle/plating/airless/carry, -/area/shuttle/curabitur/curashuttle/eng) -"cP" = ( -/obj/machinery/ion_engine{ - dir = 1; - icon_state = "nozzle" - }, -/turf/space, -/turf/simulated/shuttle/plating/airless/carry, -/area/shuttle/curabitur/curashuttle/eng) -"dF" = ( -/obj/structure/handrail, -/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ - dir = 1 - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"ic" = ( -/obj/machinery/power/terminal{ - dir = 4 - }, -/obj/structure/cable{ - icon_state = "0-6" - }, -/obj/machinery/atmospherics/pipe/simple/visible/yellow, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"qN" = ( -/obj/machinery/atmospherics/pipe/simple/visible/yellow{ - dir = 4 - }, -/turf/simulated/wall/rpshull, -/area/shuttle/curabitur/curashuttle/eng) -"tI" = ( -/obj/machinery/power/smes/buildable/point_of_interest, -/obj/structure/cable{ - icon_state = "0-9" - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"MI" = ( -/obj/machinery/power/port_gen/pacman/mrs{ - anchored = 1 - }, -/obj/structure/cable{ - icon_state = "0-9" - }, -/turf/simulated/floor/tiled/techfloor/grid, -/area/shuttle/curabitur/curashuttle/eng) -"OD" = ( -/obj/machinery/light/small{ - dir = 4 - }, -/obj/machinery/atmospherics/portables_connector{ - dir = 8 - }, -/obj/machinery/portable_atmospherics/canister/phoron{ - start_pressure = 8000.25 - }, -/turf/simulated/floor/tiled/monofloor{ - dir = 8 - }, -/area/shuttle/curabitur/curashuttle/eng) - -(1,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(2,1,1) = {" -aa -aa -aa -ag -az -az -az -az -az -az -bj -bj -bj -az -bN -bN -bN -bN -bN -cC -aa -aa -aa -"} -(3,1,1) = {" -aa -ab -ab -ab -ar -aA -aJ -aR -aZ -bd -bk -bo -br -bB -bO -aY -cd -cn -cu -bN -bN -aa -aa -"} -(4,1,1) = {" -aa -aa -ae -ah -as -as -as -as -as -bd -as -as -bs -bC -bO -bU -ce -co -cv -cD -cO -aa -aa -"} -(5,1,1) = {" -aa -aa -ae -ai -as -aB -aK -aS -as -bd -bl -bl -bl -bD -bP -bV -cf -cp -cw -cE -cM -aa -aa -"} -(6,1,1) = {" -aa -aa -ab -aj -as -aC -ca -bm -as -bd -bl -bl -bt -bE -bO -bT -cg -cq -cx -cE -cM -aa -aa -"} -(7,1,1) = {" -aa -ab -ab -ak -as -as -as -as -as -bd -bl -bp -bu -bF -bO -dF -ch -ic -cy -cG -cP -aa -aa -"} -(8,1,1) = {" -aa -ac -ab -al -au -aD -aM -aT -ba -bd -bl -bl -bv -bG -bO -bX -OD -tI -MI -qN -bN -aa -aa -"} -(9,1,1) = {" -aa -ad -ad -am -am -am -am -aU -am -be -cz -bl -bw -bH -bQ -bY -bO -bO -bO -qN -cP -aa -aa -"} -(10,1,1) = {" -aa -aa -af -an -av -aE -at -aV -bb -bf -bl -bl -bx -bI -bR -bZ -cj -cr -cL -cI -cM -aa -aa -"} -(11,1,1) = {" -aa -aa -af -ao -aw -aF -aO -aW -bc -bg -bg -bg -by -bJ -bQ -cF -ck -cs -cA -cI -cM -aa -aa -"} -(12,1,1) = {" -aa -aa -af -ap -ax -aG -aP -aX -bb -bh -bl -bl -bl -bK -bQ -cb -cl -cr -cB -cJ -cO -aa -aa -"} -(13,1,1) = {" -aa -ad -ad -ad -ay -aH -aQ -aN -aI -bi -bl -bl -aL -bL -bQ -cc -cm -cr -cN -bS -bN -aa -aa -"} -(14,1,1) = {" -aa -aa -aa -aq -aI -aI -aI -aI -aI -az -bn -bn -bA -bM -bS -bS -bS -ct -ct -cK -aa -aa -aa -"} -(15,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aa" = ( +/turf/template_noop, +/area/template_noop) +"ab" = ( +/turf/simulated/wall/rdshull, +/area/shuttle/curabitur/curashuttle/med) +"ac" = ( +/obj/machinery/shipsensors{ + dir = 1 + }, +/obj/effect/floor_decal/techfloor/orange{ + dir = 4 + }, +/obj/effect/floor_decal/techfloor/orange{ + dir = 8 + }, +/turf/simulated/shuttle/plating/airless, +/area/shuttle/curabitur/curashuttle/cockpit) +"ad" = ( +/turf/simulated/wall/rdshull, +/area/shuttle/curabitur/curashuttle/cockpit) +"ae" = ( +/obj/structure/window/plastitanium/full, +/obj/structure/window/plastitanium{ + dir = 1; + icon_state = "window" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular{ + density = 0; + dir = 4; + icon_state = "pdoor0"; + id = "mediwindowshutters"; + name = "Window Blast Door"; + opacity = 0 + }, +/obj/structure/grille, +/turf/simulated/floor/plating, +/area/shuttle/curabitur/curashuttle/med) +"af" = ( +/obj/structure/window/plastitanium/full, +/obj/structure/window/plastitanium{ + dir = 1; + icon_state = "window" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular{ + density = 0; + dir = 4; + icon_state = "pdoor0"; + id = "mediwindowshutters"; + name = "Window Blast Door"; + opacity = 0 + }, +/obj/structure/grille, +/turf/simulated/floor/plating, +/area/shuttle/curabitur/curashuttle/cockpit) +"ag" = ( +/obj/structure/sign/redcross, +/obj/machinery/vending/nifsoft_shop, +/turf/simulated/wall/rdshull, +/area/shuttle/curabitur/curashuttle/med) +"ah" = ( +/obj/machinery/optable, +/obj/machinery/oxygen_pump/anesthetic{ + pixel_x = -25 + }, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"ai" = ( +/obj/machinery/computer/operating, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"aj" = ( +/obj/machinery/vending/blood{ + density = 0; + pixel_y = 18; + req_access = newlist() + }, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"ak" = ( +/obj/machinery/body_scanconsole{ + dir = 4 + }, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"al" = ( +/obj/machinery/bodyscanner{ + dir = 4 + }, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"am" = ( +/turf/simulated/wall/shull, +/area/shuttle/curabitur/curashuttle/cockpit) +"an" = ( +/obj/machinery/computer/shuttle_control/explore/curashuttle{ + dir = 4; + icon_state = "computer" + }, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"ao" = ( +/obj/structure/cable{ + d1 = 2; + d2 = 4; + icon_state = "2-4" + }, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"ap" = ( +/obj/structure/cable{ + d2 = 8; + icon_state = "0-8" + }, +/obj/machinery/power/apc{ + dir = 4; + name = "east bump"; + pixel_x = 24; + pixel_y = 0 + }, +/obj/structure/table/darkglass, +/obj/item/weapon/paper_bin{ + pixel_x = 8; + pixel_y = -2 + }, +/obj/item/weapon/pen/fountain, +/obj/machinery/photocopier/faxmachine{ + department = "Curabitur Rescue Service"; + name = "curabitur fax machine"; + pixel_y = 6 + }, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"aq" = ( +/obj/structure/sign/redcross, +/turf/simulated/wall/rdshull, +/area/shuttle/curabitur/curashuttle/cockpit) +"ar" = ( +/obj/item/weapon/storage/firstaid/surgery, +/obj/item/weapon/surgical/scalpel/manager, +/obj/item/weapon/surgical/scalpel/ripper, +/obj/item/weapon/surgical/circular_saw/manager, +/obj/item/stack/nanopaste/advanced, +/obj/item/stack/nanopaste/advanced, +/obj/structure/table/standard, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"as" = ( +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"at" = ( +/obj/structure/closet/crate/large, +/obj/item/weapon/gun/projectile/multi_cannon, +/obj/item/weapon/gun/projectile/multi_cannon, +/obj/item/ammo_casing/macrobattery/buff, +/obj/item/ammo_casing/macrobattery/buff, +/obj/item/ammo_casing/macrobattery/detox, +/obj/item/ammo_casing/macrobattery/detox, +/obj/item/ammo_casing/macrobattery/healie, +/obj/item/ammo_casing/macrobattery/healie, +/obj/item/ammo_casing/macrobattery/ouchie, +/obj/item/ammo_casing/macrobattery/ouchie, +/obj/item/ammo_casing/macrobattery/stabilize, +/obj/item/ammo_casing/macrobattery/stabilize, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"au" = ( +/obj/structure/medical_stand, +/obj/machinery/vending/nifsoft_shop{ + categories = 3; + emagged = 1; + pixel_x = 23; + pixel_y = -5 + }, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"av" = ( +/obj/machinery/computer/ship/helm{ + dir = 4; + req_one_access = null + }, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"aw" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/structure/bed/chair/bay/comfy{ + dir = 1; + icon_state = "bay_comfychair_preview" + }, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"ax" = ( +/obj/machinery/computer/ship/engines{ + dir = 8; + icon_state = "computer" + }, +/obj/structure/window/plastitanium{ + dir = 4; + icon_state = "window" + }, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"ay" = ( +/obj/item/weapon/bedsheet/bluedouble, +/obj/structure/bed/double/padded, +/obj/structure/curtain/open/bed, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"az" = ( +/turf/simulated/wall/rpshull, +/area/shuttle/curabitur/curashuttle/med) +"aA" = ( +/obj/item/weapon/storage/firstaid/adv, +/obj/item/weapon/storage/firstaid/fire, +/obj/item/weapon/storage/firstaid/o2, +/obj/item/weapon/storage/firstaid/regular, +/obj/item/weapon/storage/firstaid/toxin, +/obj/item/weapon/storage/pill_bottle/spaceacillin, +/obj/structure/table/standard, +/obj/item/device/healthanalyzer/advanced, +/obj/item/device/healthanalyzer/advanced, +/obj/item/weapon/reagent_containers/spray/cleaner, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"aB" = ( +/obj/item/weapon/surgical/scalpel/alien, +/obj/item/weapon/surgical/retractor/alien, +/obj/item/weapon/surgical/hemostat/alien, +/obj/item/weapon/surgical/circular_saw/alien, +/obj/item/weapon/surgical/cautery/alien, +/obj/item/weapon/surgical/FixOVein/alien, +/obj/item/weapon/surgical/surgicaldrill/alien, +/obj/structure/table/standard, +/obj/machinery/recharger{ + pixel_x = -8; + pixel_y = 8 + }, +/obj/machinery/recharger{ + pixel_x = 2; + pixel_y = 8 + }, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"aC" = ( +/obj/machinery/organ_printer/flesh/full, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"aD" = ( +/obj/item/weapon/storage/backpack/dufflebag/syndie/med, +/obj/item/weapon/storage/belt/medical, +/obj/item/weapon/storage/belt/medical, +/obj/item/weapon/storage/belt/medical, +/obj/structure/table/rack, +/obj/item/weapon/storage/backpack/dufflebag/syndie/med, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"aE" = ( +/obj/machinery/computer/ship/sensors{ + dir = 4; + icon_state = "computer" + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = -29; + pixel_y = 0 + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1"; + pixel_x = 0 + }, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"aF" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"aG" = ( +/obj/machinery/button/remote/blast_door{ + id = "medihangar"; + name = "Hangar blast door control"; + pixel_x = 8; + pixel_y = 8; + plane = 0 + }, +/obj/structure/table/darkglass, +/obj/machinery/button/remote/blast_door{ + id = "mediwindowshutters"; + name = "Window shutters"; + pixel_x = -9; + pixel_y = 8 + }, +/obj/machinery/atmospherics/pipe/vent, +/obj/structure/window/plastitanium{ + dir = 4; + icon_state = "window" + }, +/obj/machinery/button/remote/airlock/survival_pod{ + id = "curadocking"; + name = "Main airlock lock"; + pixel_y = 8 + }, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"aH" = ( +/obj/item/weapon/storage/secure/safe{ + pixel_x = 31 + }, +/obj/item/weapon/gun/projectile/automatic/mini_uzi, +/obj/item/weapon/card/id/syndicate{ + access = list(616); + assignment = "Curabitur Contractor"; + origin_tech = newlist() + }, +/obj/item/weapon/card/id/syndicate{ + access = list(616); + assignment = "Curabitur Contractor"; + origin_tech = newlist() + }, +/obj/item/weapon/spacecash/c1000, +/obj/item/weapon/spacecash/c1000, +/obj/item/weapon/spacecash/c1000, +/obj/item/weapon/spacecash/c1000, +/obj/item/weapon/spacecash/c1000, +/obj/item/weapon/spacecash/c1000, +/obj/item/weapon/spacecash/c1000, +/obj/item/weapon/spacecash/c1000, +/obj/item/weapon/spacecash/c1000, +/obj/item/weapon/spacecash/c1000, +/obj/item/weapon/spacecash/c1000, +/obj/item/weapon/spacecash/c1000, +/obj/item/weapon/spacecash/c1000, +/obj/item/weapon/spacecash/c1000, +/obj/item/weapon/spacecash/c1000, +/obj/item/weapon/spacecash/c1000, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"aI" = ( +/turf/simulated/wall/rpshull, +/area/shuttle/curabitur/curashuttle/cockpit) +"aJ" = ( +/obj/machinery/sleep_console{ + dir = 2; + icon_state = "sleeperconsole"; + pixel_x = -1 + }, +/obj/machinery/light{ + dir = 8; + icon_state = "tube1"; + pixel_x = 0 + }, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"aK" = ( +/obj/structure/table/standard, +/obj/item/stack/cable_coil, +/obj/item/stack/cable_coil, +/obj/item/stack/cable_coil, +/obj/item/stack/cable_coil, +/obj/item/device/robotanalyzer, +/obj/item/device/robotanalyzer, +/obj/item/weapon/reagent_containers/spray/cleaner, +/obj/item/weapon/reagent_containers/dropper, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"aL" = ( +/obj/machinery/embedded_controller/radio/simple_docking_controller{ + dir = 8; + frequency = 1480; + id_tag = "curadocking"; + pixel_x = 28; + pixel_y = 0 + }, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/med) +"aM" = ( +/obj/structure/table/rack, +/obj/item/device/defib_kit/jumper_kit/loaded, +/obj/item/device/defib_kit/compact/combat/loaded, +/obj/item/device/defib_kit/compact/combat/loaded, +/obj/item/device/mmi/radio_enabled{ + req_access = newlist() + }, +/obj/machinery/light{ + dir = 4; + icon_state = "tube1" + }, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"aN" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/obj/structure/closet, +/obj/item/clothing/under/rank/nurse, +/obj/item/clothing/under/rank/nurse, +/obj/item/clothing/under/rank/medical, +/obj/item/clothing/shoes/blue, +/obj/item/clothing/shoes/blue, +/obj/item/clothing/suit/storage/toggle/bomber/pilot, +/obj/item/clothing/suit/storage/toggle/labcoat, +/obj/item/clothing/accessory/storage/white_drop_pouches, +/obj/item/clothing/accessory/storage/white_drop_pouches, +/obj/item/clothing/accessory/holster/machete, +/obj/item/clothing/accessory/holster/hip, +/obj/item/weapon/material/knife/machete, +/obj/item/clothing/accessory/storage/white_drop_pouches, +/obj/item/clothing/accessory/storage/white_drop_pouches, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"aO" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"aP" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"aQ" = ( +/obj/machinery/recharger/wallcharger{ + pixel_x = 31; + pixel_y = -10 + }, +/obj/machinery/recharger/wallcharger{ + pixel_x = 31; + pixel_y = -2 + }, +/obj/machinery/recharger/wallcharger{ + pixel_x = 31; + pixel_y = 7 + }, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"aR" = ( +/obj/machinery/sleeper, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"aS" = ( +/obj/structure/table/standard, +/obj/item/wheelchair, +/obj/item/roller/adv, +/obj/item/roller/adv, +/obj/item/roller/adv, +/obj/item/bodybag/cryobag, +/obj/item/bodybag/cryobag, +/obj/item/bodybag/cryobag, +/obj/item/bodybag/cryobag, +/obj/item/bodybag/cryobag/robobag, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"aT" = ( +/obj/structure/table/rack, +/obj/item/wheelchair, +/obj/item/wheelchair, +/obj/item/weapon/cane/crutch, +/obj/item/weapon/cane/crutch, +/obj/item/weapon/cane/white/collapsible, +/obj/item/clothing/accessory/stethoscope, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"aU" = ( +/obj/structure/window/plastitanium{ + dir = 8; + icon_state = "window" + }, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power/shield_generator/charged{ + initial_shield_modes = 2133; + input_cap = 50000 + }, +/obj/structure/curtain/black, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/cockpit) +"aV" = ( +/obj/structure/cable{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"aW" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"aX" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/simulated/floor/carpet/bcarpet, +/area/shuttle/curabitur/curashuttle/cockpit) +"aY" = ( +/obj/machinery/atmospherics/pipe/simple/visible/blue{ + dir = 6; + icon_state = "intact" + }, +/obj/structure/table/standard, +/obj/fiftyspawner/steel, +/obj/item/weapon/storage/toolbox/syndicate/powertools, +/obj/item/stack/nanopaste/advanced, +/obj/item/stack/cable_coil, +/obj/item/stack/cable_coil, +/obj/item/stack/cable_coil, +/obj/item/device/multitool, +/obj/item/weapon/storage/box/metalfoam, +/obj/item/bodybag/cryobag/robobag, +/obj/item/bodybag/cryobag/robobag, +/obj/item/weapon/storage/belt/utility, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"aZ" = ( +/obj/machinery/vending/medical{ + dir = 4; + pixel_x = -14; + req_access = newlist() + }, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"ba" = ( +/obj/structure/sink{ + dir = 4; + icon_state = "sink"; + pixel_x = 12; + pixel_y = 0 + }, +/obj/machinery/recharger/wallcharger{ + pixel_x = 31; + pixel_y = 6 + }, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"bb" = ( +/obj/structure/window/plastitanium, +/obj/structure/window/plastitanium{ + dir = 1; + icon_state = "window" + }, +/obj/structure/window/reinforced/full, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/cockpit) +"bc" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor/glass, +/obj/machinery/door/airlock/glass_command{ + name = "Rescue Ship Cockpit"; + req_one_access = null + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/cockpit) +"bd" = ( +/obj/structure/curtain/medical, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"be" = ( +/turf/simulated/wall/shull, +/area/shuttle/curabitur/curashuttle/med) +"bf" = ( +/obj/structure/table/darkglass, +/obj/machinery/recharger{ + pixel_x = -8; + pixel_y = 8 + }, +/obj/machinery/recharger{ + pixel_x = 2; + pixel_y = 8 + }, +/obj/item/device/gps/medical, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/med) +"bg" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/med) +"bh" = ( +/obj/item/device/suit_cooling_unit, +/obj/item/device/suit_cooling_unit, +/obj/item/device/suit_cooling_unit, +/obj/structure/table/rack, +/obj/item/clothing/head/helmet/space/void/medical, +/obj/item/clothing/head/helmet/space/void/medical, +/obj/item/clothing/head/helmet/space/void/medical, +/obj/item/clothing/suit/space/void/medical, +/obj/item/clothing/suit/space/void/medical, +/obj/item/clothing/suit/space/void/medical, +/obj/item/weapon/tank/air, +/obj/item/weapon/tank/air, +/obj/item/weapon/tank/air, +/obj/item/weapon/tank/jetpack/carbondioxide, +/obj/item/weapon/tank/jetpack/carbondioxide, +/obj/item/weapon/tank/jetpack/carbondioxide, +/obj/item/weapon/tank/emergency/oxygen/engi, +/obj/item/weapon/tank/emergency/oxygen/engi, +/obj/item/clothing/mask/breath, +/obj/item/clothing/mask/breath, +/obj/item/clothing/mask/breath, +/obj/item/clothing/shoes/magboots, +/obj/item/clothing/shoes/magboots, +/obj/item/clothing/shoes/magboots, +/obj/item/device/gps/medical, +/obj/item/device/gps/medical, +/obj/item/device/gps/medical, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/med) +"bi" = ( +/obj/machinery/suit_cycler/medical, +/obj/machinery/alarm{ + pixel_y = 25 + }, +/obj/machinery/firealarm{ + dir = 4; + layer = 3.3; + pixel_y = 26 + }, +/obj/machinery/light{ + dir = 1 + }, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/med) +"bj" = ( +/obj/structure/window/plastitanium/full, +/obj/structure/window/plastitanium{ + dir = 8; + icon_state = "window" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular{ + density = 0; + dir = 4; + icon_state = "pdoor0"; + id = "mediwindowshutters"; + name = "Window Blast Door"; + opacity = 0 + }, +/obj/structure/grille, +/turf/simulated/floor/plating, +/area/shuttle/curabitur/curashuttle/med) +"bk" = ( +/obj/machinery/smartfridge/chemistry{ + dir = 4; + icon_state = "fridge_food" + }, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"bl" = ( +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/med) +"bm" = ( +/obj/structure/filingcabinet/medical, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"bn" = ( +/obj/structure/window/plastitanium/full, +/obj/structure/window/plastitanium{ + dir = 4; + icon_state = "window" + }, +/obj/machinery/door/firedoor, +/obj/machinery/door/blast/regular{ + density = 0; + dir = 4; + icon_state = "pdoor0"; + id = "mediwindowshutters"; + name = "Window Blast Door"; + opacity = 0 + }, +/obj/structure/grille, +/turf/simulated/floor/plating, +/area/shuttle/curabitur/curashuttle/med) +"bo" = ( +/obj/machinery/chem_master, +/obj/structure/table/standard, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"bp" = ( +/obj/structure/bed/chair/bay/comfy, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/med) +"br" = ( +/obj/machinery/chemical_dispenser/ert/specialops, +/obj/structure/table/standard, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"bs" = ( +/obj/structure/bed/chair/bay/comfy{ + dir = 8; + icon_state = "bay_comfychair_preview" + }, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"bt" = ( +/obj/structure/reagent_dispensers/water_cooler/full{ + density = 0; + pixel_x = 11 + }, +/turf/simulated/floor/carpet/sblucarpet, +/area/shuttle/curabitur/curashuttle/med) +"bu" = ( +/obj/structure/table/darkglass, +/obj/machinery/atmospherics/pipe/vent, +/obj/item/weapon/reagent_containers/food/snacks/bagelsunflower, +/obj/item/weapon/reagent_containers/food/snacks/applepie, +/obj/item/weapon/reagent_containers/food/snacks/carrotfries, +/obj/item/weapon/reagent_containers/food/snacks/cube/nutriment, +/obj/item/weapon/reagent_containers/food/snacks/cube/protein, +/obj/item/weapon/reagent_containers/food/snacks/cube/protein, +/obj/item/weapon/reagent_containers/food/snacks/cube/protein, +/obj/item/weapon/reagent_containers/food/snacks/cracker, +/turf/simulated/floor/carpet/sblucarpet, +/area/shuttle/curabitur/curashuttle/med) +"bv" = ( +/obj/structure/table/darkglass, +/obj/item/weapon/reagent_containers/food/snacks/bangersandmash, +/obj/item/weapon/reagent_containers/food/snacks/candiedapple, +/obj/item/weapon/reagent_containers/food/snacks/chickenwing, +/turf/simulated/floor/carpet/sblucarpet, +/area/shuttle/curabitur/curashuttle/med) +"bw" = ( +/obj/structure/closet/crate/bin, +/turf/simulated/floor/carpet/sblucarpet, +/area/shuttle/curabitur/curashuttle/med) +"bx" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 6 + }, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/med) +"by" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 9 + }, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/med) +"bA" = ( +/obj/structure/sign/redcross, +/turf/simulated/wall/rpshull, +/area/shuttle/curabitur/curashuttle/med) +"bB" = ( +/obj/structure/table/standard, +/obj/item/weapon/storage/bag/chemistry, +/obj/item/weapon/storage/box/pillbottles, +/obj/item/weapon/reagent_containers/dropper, +/obj/item/weapon/reagent_containers/dropper, +/obj/structure/cable{ + icon_state = "0-4" + }, +/obj/machinery/power/apc{ + dir = 8; + name = "west bump"; + pixel_x = -28; + pixel_y = 0 + }, +/obj/machinery/power/terminal{ + dir = 8; + icon_state = "term" + }, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"bC" = ( +/obj/structure/sign/department/eng{ + pixel_x = 0; + pixel_y = -31 + }, +/obj/structure/table/standard, +/obj/item/weapon/reagent_containers/glass/beaker/bluespace, +/obj/item/weapon/reagent_containers/glass/beaker/bluespace, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/obj/structure/cable{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"bD" = ( +/obj/structure/cable{ + d1 = 2; + d2 = 4; + icon_state = "2-4" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/structure/cable{ + d1 = 2; + d2 = 8; + icon_state = "2-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/yellow{ + dir = 6 + }, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/med) +"bE" = ( +/obj/structure/bed/chair/sofa/teal/left{ + dir = 1; + icon_state = "sofaend_left" + }, +/obj/structure/cable{ + d1 = 4; + d2 = 8; + icon_state = "4-8"; + pixel_y = 0 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/light, +/obj/structure/sign/directions/engineering{ + pixel_y = -32 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/yellow{ + dir = 4 + }, +/turf/simulated/floor/carpet/sblucarpet, +/area/shuttle/curabitur/curashuttle/med) +"bF" = ( +/obj/machinery/vending/wallmed1/public{ + dir = 1; + icon_state = "wallmed"; + pixel_y = -28 + }, +/obj/structure/bed/chair/sofa/teal{ + dir = 1; + icon_state = "sofamiddle" + }, +/obj/structure/cable{ + d1 = 4; + d2 = 8; + icon_state = "4-8"; + pixel_y = 0 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/yellow{ + dir = 4 + }, +/turf/simulated/floor/carpet/sblucarpet, +/area/shuttle/curabitur/curashuttle/med) +"bG" = ( +/obj/machinery/computer/ship/navigation/telescreen{ + pixel_y = -32 + }, +/obj/structure/bed/chair/sofa/teal{ + dir = 1; + icon_state = "sofamiddle" + }, +/obj/structure/cable{ + d1 = 4; + d2 = 8; + icon_state = "4-8"; + pixel_y = 0 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/yellow{ + dir = 4 + }, +/turf/simulated/floor/carpet/sblucarpet, +/area/shuttle/curabitur/curashuttle/med) +"bH" = ( +/obj/machinery/vending/wallmed1/public{ + dir = 1; + icon_state = "wallmed"; + pixel_y = -29 + }, +/obj/structure/bed/chair/sofa/teal/right{ + dir = 1; + icon_state = "sofaend_right" + }, +/obj/structure/cable{ + d1 = 4; + d2 = 8; + icon_state = "4-8"; + pixel_y = 0 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/yellow{ + dir = 4 + }, +/turf/simulated/floor/carpet/sblucarpet, +/area/shuttle/curabitur/curashuttle/med) +"bI" = ( +/obj/structure/cable{ + icon_state = "2-8" + }, +/obj/structure/cable{ + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4; + icon_state = "map-scrubbers" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/yellow{ + dir = 4 + }, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/med) +"bJ" = ( +/obj/machinery/recharger/wallcharger{ + pixel_x = 4; + pixel_y = -26 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/obj/structure/handrail{ + dir = 1 + }, +/obj/structure/cable{ + d1 = 4; + d2 = 8; + icon_state = "4-8"; + pixel_y = 0 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/universal{ + dir = 4 + }, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/med) +"bK" = ( +/obj/structure/extinguisher_cabinet{ + pixel_y = -26 + }, +/obj/machinery/light, +/obj/structure/cable{ + d1 = 4; + d2 = 8; + icon_state = "4-8"; + pixel_y = 0 + }, +/obj/machinery/atmospherics/binary/pump/fuel{ + dir = 8; + icon_state = "map_off-fuel" + }, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/med) +"bL" = ( +/obj/effect/shuttle_landmark/shuttle_initializer/curashuttle, +/obj/effect/overmap/visitable/ship/landable/curashuttle, +/obj/structure/handrail{ + dir = 1 + }, +/obj/structure/cable{ + d1 = 4; + d2 = 8; + icon_state = "4-8"; + pixel_y = 0 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 8; + icon_state = "intact-fuel" + }, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/med) +"bM" = ( +/obj/structure/fans/hardlight, +/obj/machinery/door/airlock/external/glass/bolted{ + frequency = 1480; + id_tag = "curadocking" + }, +/obj/structure/cable{ + d1 = 4; + d2 = 8; + icon_state = "4-8"; + pixel_y = 0 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/fuel{ + dir = 8; + icon_state = "intact-fuel" + }, +/turf/simulated/floor/plating, +/area/shuttle/curabitur/curashuttle/med) +"bN" = ( +/turf/simulated/wall/rpshull, +/area/shuttle/curabitur/curashuttle/eng) +"bO" = ( +/turf/simulated/wall/shull, +/area/shuttle/curabitur/curashuttle/eng) +"bP" = ( +/obj/machinery/door/airlock/voidcraft, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor/glass, +/obj/machinery/atmospherics/pipe/simple/hidden/yellow, +/turf/simulated/floor/tiled{ + icon_state = "monotile" + }, +/area/shuttle/curabitur/curashuttle/eng) +"bQ" = ( +/turf/simulated/wall/shull, +/area/shuttle/curabitur/curashuttle/hangar) +"bR" = ( +/obj/machinery/door/airlock/voidcraft, +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/firedoor/glass, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/hangar) +"bS" = ( +/turf/simulated/wall/rpshull, +/area/shuttle/curabitur/curashuttle/hangar) +"bT" = ( +/obj/structure/handrail, +/obj/machinery/power/apc{ + dir = 1; + name = "north bump"; + pixel_x = 0; + pixel_y = 28 + }, +/obj/structure/cable{ + icon_state = "0-8" + }, +/obj/structure/cable{ + icon_state = "0-6" + }, +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 4 + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"bU" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal{ + dir = 4 + }, +/obj/machinery/recharge_station, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"bV" = ( +/obj/machinery/atmospherics/pipe/simple/visible/scrubbers, +/obj/structure/cable{ + d1 = 1; + d2 = 4; + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/visible/supply{ + dir = 9; + icon_state = "intact-supply" + }, +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 5 + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"bX" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/phoron{ + start_pressure = 8000.25 + }, +/turf/simulated/floor/tiled/monofloor{ + dir = 8 + }, +/area/shuttle/curabitur/curashuttle/eng) +"bY" = ( +/obj/structure/window/plastitanium{ + dir = 8; + icon_state = "window" + }, +/obj/structure/window/plastitanium{ + dir = 4; + icon_state = "window" + }, +/obj/structure/curtain/black, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"bZ" = ( +/obj/structure/cable{ + d1 = 1; + d2 = 4; + icon_state = "1-4" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/hangar) +"ca" = ( +/obj/structure/table/standard, +/obj/item/device/survivalcapsule, +/obj/item/device/survivalcapsule, +/obj/item/clothing/gloves/sterile/nitrile, +/obj/item/clothing/gloves/sterile/nitrile, +/obj/item/clothing/suit/surgicalapron, +/turf/simulated/floor/tiled/white, +/area/shuttle/curabitur/curashuttle/med) +"cb" = ( +/obj/structure/closet/crate/medical, +/obj/item/weapon/surgical/scalpel/manager, +/obj/item/weapon/surgical/scalpel/manager, +/obj/item/weapon/surgical/circular_saw/manager, +/obj/item/weapon/surgical/circular_saw/manager, +/obj/item/stack/nanopaste/advanced, +/obj/item/stack/nanopaste/advanced, +/obj/item/device/defib_kit/compact/combat/loaded, +/obj/item/device/defib_kit/compact/combat/loaded, +/obj/item/device/healthanalyzer/advanced, +/obj/item/weapon/storage/backpack/dufflebag/syndie/med, +/obj/item/weapon/surgical/bone_clamp, +/obj/item/weapon/surgical/bone_clamp, +/obj/item/weapon/surgical/scalpel/ripper, +/obj/machinery/firealarm{ + pixel_y = 24 + }, +/obj/machinery/atmospherics/pipe/vent, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"cc" = ( +/obj/structure/table/rack, +/obj/item/mecha_parts/mecha_equipment/crisis_drone, +/obj/item/mecha_parts/mecha_equipment/crisis_drone/rad, +/obj/item/mecha_parts/mecha_equipment/tool/syringe_gun, +/obj/item/mecha_parts/mecha_equipment/weapon/energy/medigun, +/obj/item/mecha_parts/mecha_equipment/tool/powertool/inflatables, +/obj/item/mecha_parts/mecha_equipment/tool/powertool/medanalyzer, +/obj/item/mecha_parts/mecha_equipment/tool/powertool/prybar, +/obj/item/mecha_parts/mecha_equipment/weapon/energy/taser, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/hangar) +"cd" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 1 + }, +/obj/structure/fireaxecabinet{ + pixel_x = -31 + }, +/obj/structure/handrail{ + dir = 4 + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"ce" = ( +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 4 + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"cf" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers{ + dir = 4; + icon_state = "map-scrubbers" + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"cg" = ( +/obj/fiftyspawner/tritium, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"ch" = ( +/obj/structure/cable{ + icon_state = "6-9" + }, +/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ + dir = 8 + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"cj" = ( +/obj/machinery/mech_recharger, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 5; + icon_state = "intact-supply" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5; + icon_state = "intact-scrubbers" + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/hangar) +"ck" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/hangar) +"cl" = ( +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/hangar) +"cm" = ( +/obj/structure/table/rack, +/obj/item/mecha_parts/mecha_equipment/tool/passenger, +/obj/item/mecha_parts/mecha_equipment/tool/sleeper, +/obj/item/mecha_parts/mecha_equipment/tool/sleeper, +/obj/item/mecha_parts/mecha_equipment/tool/sleeper, +/obj/item/mecha_parts/mecha_equipment/tool/sleeper, +/obj/machinery/atmospherics/unary/vent_scrubber/on{ + dir = 8 + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/hangar) +"cn" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 1 + }, +/obj/machinery/portable_atmospherics/canister/air, +/turf/simulated/floor/tiled/monofloor{ + dir = 1 + }, +/area/shuttle/curabitur/curashuttle/eng) +"co" = ( +/obj/structure/fuel_port, +/turf/simulated/floor/tiled/monofloor{ + dir = 1 + }, +/area/shuttle/curabitur/curashuttle/eng) +"cp" = ( +/obj/machinery/atmospherics/pipe/simple/visible/universal, +/obj/machinery/portable_atmospherics/canister/carbon_dioxide, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"cq" = ( +/obj/machinery/portable_atmospherics/canister/phoron{ + start_pressure = 8000.25 + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"cr" = ( +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/hangar) +"cs" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/hangar) +"ct" = ( +/obj/structure/fans/hardlight, +/obj/machinery/door/blast/regular{ + id = "medihangar" + }, +/turf/simulated/floor/plating, +/area/shuttle/curabitur/curashuttle/hangar) +"cu" = ( +/obj/machinery/atmospherics/portables_connector{ + dir = 4 + }, +/obj/machinery/portable_atmospherics/canister/empty, +/obj/structure/cable{ + d1 = 4; + d2 = 8; + icon_state = "4-8"; + pixel_x = 0 + }, +/turf/simulated/floor/tiled/monofloor, +/area/shuttle/curabitur/curashuttle/eng) +"cv" = ( +/obj/machinery/atmospherics/binary/pump{ + dir = 8 + }, +/obj/machinery/light/small, +/obj/structure/cable{ + d1 = 4; + d2 = 8; + icon_state = "4-8"; + pixel_x = 0 + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"cw" = ( +/obj/machinery/atmospherics/pipe/simple/visible/red{ + dir = 9 + }, +/obj/machinery/autolathe, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"cx" = ( +/obj/machinery/computer/ship/engines{ + dir = 1; + icon_state = "computer" + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"cy" = ( +/obj/machinery/light/small, +/obj/machinery/atmospherics/binary/pump, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"cz" = ( +/obj/machinery/vending/fitness{ + density = 0; + pixel_y = 16 + }, +/turf/simulated/floor/tiled, +/area/shuttle/curabitur/curashuttle/med) +"cA" = ( +/obj/structure/cable, +/obj/machinery/power/apc{ + dir = 2; + name = "south bump"; + pixel_x = 0; + pixel_y = -28 + }, +/obj/structure/handrail{ + dir = 1 + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/hangar) +"cB" = ( +/obj/machinery/light, +/obj/machinery/alarm{ + dir = 1; + icon_state = "alarm0"; + pixel_y = -32 + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/hangar) +"cC" = ( +/obj/structure/sign/redcross, +/turf/simulated/wall/rpshull, +/area/shuttle/curabitur/curashuttle/eng) +"cD" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 6 + }, +/turf/simulated/wall/rpshull, +/area/shuttle/curabitur/curashuttle/eng) +"cE" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ + dir = 1 + }, +/turf/simulated/wall/rpshull, +/area/shuttle/curabitur/curashuttle/eng) +"cF" = ( +/obj/machinery/button/remote/blast_door{ + id = "medihangar"; + name = "Hangar blast door control"; + pixel_x = -7; + pixel_y = 24 + }, +/obj/structure/cable{ + d1 = 2; + d2 = 8; + icon_state = "2-8" + }, +/obj/structure/table/standard, +/obj/item/device/flashlight/flare, +/obj/item/device/flashlight/flare, +/obj/item/device/flashlight/flare, +/obj/machinery/cell_charger{ + pixel_x = -3; + pixel_y = 13 + }, +/obj/item/weapon/cell/high, +/obj/item/weapon/cell/high, +/obj/item/weapon/storage/briefcase/inflatable, +/obj/item/weapon/storage/briefcase/inflatable, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/hangar) +"cG" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/yellow, +/turf/simulated/wall/rpshull, +/area/shuttle/curabitur/curashuttle/eng) +"cI" = ( +/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ + dir = 1 + }, +/turf/simulated/wall/rpshull, +/area/shuttle/curabitur/curashuttle/hangar) +"cJ" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 10 + }, +/turf/simulated/wall/rpshull, +/area/shuttle/curabitur/curashuttle/hangar) +"cK" = ( +/obj/structure/sign/redcross, +/turf/simulated/wall/rpshull, +/area/shuttle/curabitur/curashuttle/hangar) +"cL" = ( +/obj/mecha/combat/fighter/pinnace{ + desc = "A modified Pinnace made to be able to fit a wide arsenal of equipment for rescue missions in space."; + health = 200; + max_equip = 1; + max_hull_equip = 2; + max_special_equip = 1; + max_universal_equip = 2; + max_utility_equip = 3; + maxhealth = 200; + name = "Curabitur Pinnace" + }, +/obj/machinery/mech_recharger, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/hangar) +"cM" = ( +/obj/machinery/atmospherics/unary/engine{ + dir = 1 + }, +/turf/simulated/shuttle/plating/airless/carry, +/area/shuttle/curabitur/curashuttle/eng) +"cN" = ( +/obj/structure/handrail{ + dir = 1 + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/hangar) +"cO" = ( +/obj/machinery/atmospherics/unary/engine{ + dir = 1 + }, +/turf/space, +/turf/simulated/shuttle/plating/airless/carry, +/area/shuttle/curabitur/curashuttle/eng) +"cP" = ( +/obj/machinery/ion_engine{ + dir = 1; + icon_state = "nozzle" + }, +/turf/space, +/turf/simulated/shuttle/plating/airless/carry, +/area/shuttle/curabitur/curashuttle/eng) +"dF" = ( +/obj/structure/handrail, +/obj/machinery/atmospherics/pipe/manifold/visible/yellow{ + dir = 1 + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"ic" = ( +/obj/machinery/power/terminal{ + dir = 4 + }, +/obj/structure/cable{ + icon_state = "0-6" + }, +/obj/machinery/atmospherics/pipe/simple/visible/yellow, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"qN" = ( +/obj/machinery/atmospherics/pipe/simple/visible/yellow{ + dir = 4 + }, +/turf/simulated/wall/rpshull, +/area/shuttle/curabitur/curashuttle/eng) +"tI" = ( +/obj/machinery/power/smes/buildable/point_of_interest, +/obj/structure/cable{ + icon_state = "0-9" + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"MI" = ( +/obj/machinery/power/port_gen/pacman/mrs{ + anchored = 1 + }, +/obj/structure/cable{ + icon_state = "0-9" + }, +/turf/simulated/floor/tiled/techfloor/grid, +/area/shuttle/curabitur/curashuttle/eng) +"OD" = ( +/obj/machinery/light/small{ + dir = 4 + }, +/obj/machinery/atmospherics/portables_connector{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/phoron{ + start_pressure = 8000.25 + }, +/turf/simulated/floor/tiled/monofloor{ + dir = 8 + }, +/area/shuttle/curabitur/curashuttle/eng) + +(1,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} +(2,1,1) = {" +aa +aa +aa +ag +az +az +az +az +az +az +bj +bj +bj +az +bN +bN +bN +bN +bN +cC +aa +aa +aa +"} +(3,1,1) = {" +aa +ab +ab +ab +ar +aA +aJ +aR +aZ +bd +bk +bo +br +bB +bO +aY +cd +cn +cu +bN +bN +aa +aa +"} +(4,1,1) = {" +aa +aa +ae +ah +as +as +as +as +as +bd +as +as +bs +bC +bO +bU +ce +co +cv +cD +cO +aa +aa +"} +(5,1,1) = {" +aa +aa +ae +ai +as +aB +aK +aS +as +bd +bl +bl +bl +bD +bP +bV +cf +cp +cw +cE +cM +aa +aa +"} +(6,1,1) = {" +aa +aa +ab +aj +as +aC +ca +bm +as +bd +bl +bl +bt +bE +bO +bT +cg +cq +cx +cE +cM +aa +aa +"} +(7,1,1) = {" +aa +ab +ab +ak +as +as +as +as +as +bd +bl +bp +bu +bF +bO +dF +ch +ic +cy +cG +cP +aa +aa +"} +(8,1,1) = {" +aa +ac +ab +al +au +aD +aM +aT +ba +bd +bl +bl +bv +bG +bO +bX +OD +tI +MI +qN +bN +aa +aa +"} +(9,1,1) = {" +aa +ad +ad +am +am +am +am +aU +am +be +cz +bl +bw +bH +bQ +bY +bO +bO +bO +qN +cP +aa +aa +"} +(10,1,1) = {" +aa +aa +af +an +av +aE +at +aV +bb +bf +bl +bl +bx +bI +bR +bZ +cj +cr +cL +cI +cM +aa +aa +"} +(11,1,1) = {" +aa +aa +af +ao +aw +aF +aO +aW +bc +bg +bg +bg +by +bJ +bQ +cF +ck +cs +cA +cI +cM +aa +aa +"} +(12,1,1) = {" +aa +aa +af +ap +ax +aG +aP +aX +bb +bh +bl +bl +bl +bK +bQ +cb +cl +cr +cB +cJ +cO +aa +aa +"} +(13,1,1) = {" +aa +ad +ad +ad +ay +aH +aQ +aN +aI +bi +bl +bl +aL +bL +bQ +cc +cm +cr +cN +bS +bN +aa +aa +"} +(14,1,1) = {" +aa +aa +aa +aq +aI +aI +aI +aI +aI +az +bn +bn +bA +bM +bS +bS +bS +ct +ct +cK +aa +aa +aa +"} +(15,1,1) = {" +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +"} diff --git a/nano/templates/agent_id_card.tmpl b/nano/templates/agent_id_card.tmpl index 7a41dcdf1b..a802efbc82 100644 --- a/nano/templates/agent_id_card.tmpl +++ b/nano/templates/agent_id_card.tmpl @@ -1,21 +1,21 @@ - -{{:helper.syndicateMode()}} -

    Available Entries

    - -{{for data.entries}} - - - -{{/for}} -
    {{:helper.link('', 'gear', {'set' : value.name})}}{{:value.name}}{{:value.value}}
    - - - - - - - -
    Electronic warfare:{{:helper.link('Enabled', null, {'electronic_warfare' : 1}, data.electronic_warfare ? 'selected' : null)}}{{:helper.link('Disabled',null, {'electronic_warfare' : 0}, data.electronic_warfare ? null : 'selected')}}
    + +{{:helper.syndicateMode()}} +

    Available Entries

    + +{{for data.entries}} + + + +{{/for}} +
    {{:helper.link('', 'gear', {'set' : value.name})}}{{:value.name}}{{:value.value}}
    + + + + + + + +
    Electronic warfare:{{:helper.link('Enabled', null, {'electronic_warfare' : 1}, data.electronic_warfare ? 'selected' : null)}}{{:helper.link('Disabled',null, {'electronic_warfare' : 0}, data.electronic_warfare ? null : 'selected')}}
    diff --git a/nano/templates/door_control.tmpl b/nano/templates/door_control.tmpl index a1b0e35a26..4197497ce8 100644 --- a/nano/templates/door_control.tmpl +++ b/nano/templates/door_control.tmpl @@ -1,65 +1,65 @@ - - -
    -
    - Main power is - {{if data.main_power_loss == 0}} - online - {{else data.main_power_loss == -1}} - offline - {{else}} - offline for {{:data.main_power_loss}} second{{:data.main_power_loss == 1 ? '' : 's'}} - {{/if}}. -
    -
    - {{:helper.link(data.main_power_loss ? 'Disabled' : 'Disable', null, {'command' : 'main_power'}, data.main_power_loss == 0 ? null : 'disabled', data.main_power_loss == 0 ? 'redButton' : null)}} -
    -
    - -
    -
    - Backup power is - {{if data.backup_power_loss == 0}} - online - {{else data.backup_power_loss == -1}} - offline - {{else}} - offline for {{:data.backup_power_loss}} second{{:data.backup_power_loss == 1 ? '' : 's'}} - {{/if}}. -
    -
    - {{:helper.link(data.backup_power_loss ? 'Disabled' : 'Disable', null, {'command' : 'backup_power'}, data.backup_power_loss == 0 ? null : 'disabled', data.backup_power_loss == 0 ? 'redButton' : null)}} -
    -
    - -
    -
    - Electrified Status: -
    -
    - {{:helper.link('Offline' , null, {'command' : 'electrify_permanently', 'activate' : "0" }, data.electrified == 0 ? 'selected' : null)}} - {{:helper.link(data.electrified <= 0 ? 'Temporary (30s)' : 'Temporary (' + data.electrified +'s)', null, {'command' : 'electrify_temporary', 'activate' : "1"}, data.electrified > 0 ? 'redButton' : null)}} - {{:helper.link('Permanent', null, {'command' : 'electrify_permanently', 'activate' : "1"}, data.electrified == -1 ? 'redButton' : null)}} -
    -
    - -
    - - - {{for data.commands}} - - - - - - {{/for}} -
    {{:value.name}}:{{:helper.link(value.enabled, null, {'command' : value.command, 'activate' : value.act ? 1 : 0}, value.active ? 'selected' : null)}}{{:helper.link(value.disabled,null, {'command' : value.command, 'activate' : value.act ? 0 : 1}, !value.active ? (value.danger ? 'redButton' : 'selected') : null)}}
    + + +
    +
    + Main power is + {{if data.main_power_loss == 0}} + online + {{else data.main_power_loss == -1}} + offline + {{else}} + offline for {{:data.main_power_loss}} second{{:data.main_power_loss == 1 ? '' : 's'}} + {{/if}}. +
    +
    + {{:helper.link(data.main_power_loss ? 'Disabled' : 'Disable', null, {'command' : 'main_power'}, data.main_power_loss == 0 ? null : 'disabled', data.main_power_loss == 0 ? 'redButton' : null)}} +
    +
    + +
    +
    + Backup power is + {{if data.backup_power_loss == 0}} + online + {{else data.backup_power_loss == -1}} + offline + {{else}} + offline for {{:data.backup_power_loss}} second{{:data.backup_power_loss == 1 ? '' : 's'}} + {{/if}}. +
    +
    + {{:helper.link(data.backup_power_loss ? 'Disabled' : 'Disable', null, {'command' : 'backup_power'}, data.backup_power_loss == 0 ? null : 'disabled', data.backup_power_loss == 0 ? 'redButton' : null)}} +
    +
    + +
    +
    + Electrified Status: +
    +
    + {{:helper.link('Offline' , null, {'command' : 'electrify_permanently', 'activate' : "0" }, data.electrified == 0 ? 'selected' : null)}} + {{:helper.link(data.electrified <= 0 ? 'Temporary (30s)' : 'Temporary (' + data.electrified +'s)', null, {'command' : 'electrify_temporary', 'activate' : "1"}, data.electrified > 0 ? 'redButton' : null)}} + {{:helper.link('Permanent', null, {'command' : 'electrify_permanently', 'activate' : "1"}, data.electrified == -1 ? 'redButton' : null)}} +
    +
    + +
    + + + {{for data.commands}} + + + + + + {{/for}} +
    {{:value.name}}:{{:helper.link(value.enabled, null, {'command' : value.command, 'activate' : value.act ? 1 : 0}, value.active ? 'selected' : null)}}{{:helper.link(value.disabled,null, {'command' : value.command, 'activate' : value.act ? 0 : 1}, !value.active ? (value.danger ? 'redButton' : 'selected') : null)}}
    diff --git a/nano/templates/merc_blast_door_control.tmpl b/nano/templates/merc_blast_door_control.tmpl index ec323ce081..bd74a42e20 100644 --- a/nano/templates/merc_blast_door_control.tmpl +++ b/nano/templates/merc_blast_door_control.tmpl @@ -1,23 +1,23 @@ -

    Shuttle Blast Door Control

    - -
    - {{:helper.link('Open all doors', 'radio-on', {'cartridge_topic' : 1, 'all_blast_doors' : "open"})}} - {{:helper.link('Close all doors', 'radio-off', {'cartridge_topic' : 1, 'all_blast_doors' : "close"})}} -
    -
    - {{:helper.link('Scan for doors', 'refresh', {'cartridge_topic' : 1, 'scan_blast_doors' : 1})}} -
    - -{{for data.blast_door}} -
    -
    - {{:value.name}} #{{:index}} -
    -
    - {{:helper.link('On', 'radio-on', {'cartridge_topic' : 1, 'toggle_blast_door' : value.ref}, value.open ? 'selected' : null)}} - {{:helper.link('Off', 'radio-off', {'cartridge_topic' : 1, 'toggle_blast_door' : value.ref}, value.open ? null : 'selected')}} -
    -
    -{{empty}} -

    No doors detected!

    +

    Shuttle Blast Door Control

    + +
    + {{:helper.link('Open all doors', 'radio-on', {'cartridge_topic' : 1, 'all_blast_doors' : "open"})}} + {{:helper.link('Close all doors', 'radio-off', {'cartridge_topic' : 1, 'all_blast_doors' : "close"})}} +
    +
    + {{:helper.link('Scan for doors', 'refresh', {'cartridge_topic' : 1, 'scan_blast_doors' : 1})}} +
    + +{{for data.blast_door}} +
    +
    + {{:value.name}} #{{:index}} +
    +
    + {{:helper.link('On', 'radio-on', {'cartridge_topic' : 1, 'toggle_blast_door' : value.ref}, value.open ? 'selected' : null)}} + {{:helper.link('Off', 'radio-off', {'cartridge_topic' : 1, 'toggle_blast_door' : value.ref}, value.open ? null : 'selected')}} +
    +
    +{{empty}} +

    No doors detected!

    {{/for}} \ No newline at end of file diff --git a/nano/templates/photocopier.tmpl b/nano/templates/photocopier.tmpl index 9ced6b63d1..99442fa32a 100644 --- a/nano/templates/photocopier.tmpl +++ b/nano/templates/photocopier.tmpl @@ -1,45 +1,45 @@ - - -{{if data.copyItem || data.assPresent}} -
    - {{:helper.link('Remove Item', 'eject', {'remove' : 1})}} - {{if data.toner}} - {{:helper.link('Copy', 'copy', {'copy' : 1})}} -
    -
    - Printing: -
    -
    -
    - {{:helper.link('-', null, {'min' : 1}, data.copies == 1 ? 'linkOff' : null)}} -
    {{:data.copies}}
    - {{:helper.link('+', null, {'add' : 1}, data.copies == data.maxCopies ? 'linkOff' : null)}} -
    -
    -
    -
    -
    -
    Current toner level:
    -
    {{:data.toner}}u
    -
    - {{else}} - Please insert a new toner cartridge! - {{/if}} -
    -{{else data.toner}} -

    Please insert something to copy.

    - {{if data.isSilicon}} - {{:helper.link('Print photo from database', 'image', {'aipic' : 1})}} - {{/if}} -
    -
    Current toner level:
    -
    {{:data.toner}}u
    -
    -{{else}} -
    - Please insert a new toner cartridge! -
    + + +{{if data.copyItem || data.assPresent}} +
    + {{:helper.link('Remove Item', 'eject', {'remove' : 1})}} + {{if data.toner}} + {{:helper.link('Copy', 'copy', {'copy' : 1})}} +
    +
    + Printing: +
    +
    +
    + {{:helper.link('-', null, {'min' : 1}, data.copies == 1 ? 'linkOff' : null)}} +
    {{:data.copies}}
    + {{:helper.link('+', null, {'add' : 1}, data.copies == data.maxCopies ? 'linkOff' : null)}} +
    +
    +
    +
    +
    +
    Current toner level:
    +
    {{:data.toner}}u
    +
    + {{else}} + Please insert a new toner cartridge! + {{/if}} +
    +{{else data.toner}} +

    Please insert something to copy.

    + {{if data.isSilicon}} + {{:helper.link('Print photo from database', 'image', {'aipic' : 1})}} + {{/if}} +
    +
    Current toner level:
    +
    {{:data.toner}}u
    +
    +{{else}} +
    + Please insert a new toner cartridge! +
    {{/if}} \ No newline at end of file diff --git a/nano/templates/stat_display_access.tmpl b/nano/templates/stat_display_access.tmpl index 20655bb709..1f1c8e0492 100644 --- a/nano/templates/stat_display_access.tmpl +++ b/nano/templates/stat_display_access.tmpl @@ -1,57 +1,57 @@ -

    Station Status Display Interlink

    - -
    -
    - Code -
    -
    - {{:helper.link('Clear Message', 'trash', {'cartridge_topic' : "1", 'stat_display' : "blank"}, (data.stat_display.active == "blank") ? 'selected' : null)}} - {{:helper.link('Clear Alert', 'alert', {'cartridge_topic' : "1", 'choice' : "Status", 'stat_display' : "alert", 'alert' : "default"}, (data.stat_display.active == "default") ? 'selected' : null)}} -
    -
    -
    -
    - Message -
    -
    - {{:helper.link('Shuttle ETA', 'gear', {'cartridge_topic' : "1", 'stat_display' : "shuttle"}, (data.stat_display.active == "shuttle") ? 'selected' : null)}} - {{:helper.link('Set Message', 'gear', {'cartridge_topic' : "1", 'stat_display' : "message"}, (data.stat_display.active == "message") ? 'selected' : null)}} -
    -
    -
    -
    - Alert -
    -
    - {{:helper.link('Red Alert', 'alert', {'cartridge_topic' : "1", 'choice' : "Status", 'stat_display' : "alert", 'alert' : "redalert"}, (data.stat_display.active == "redalert") ? 'selected' : null)}} - {{:helper.link('Lockdown', 'caution', {'cartridge_topic' : "1", 'choice' : "Status", 'stat_display' : "alert", 'alert' : "lockdown"}, (data.stat_display.active == "lockdown") ? 'selected' : null)}} - {{:helper.link('Biohazard', 'radiation', {'cartridge_topic' : "1", 'choice' : "Status", 'stat_display' : "alert", 'alert' : "biohazard"}, (data.stat_display.active == "biohazard") ? 'selected' : null)}} -
    -
    -{{if data.stat_display.line1 != data.stat_display.active_line1 || data.stat_display.line2 != data.stat_display.active_line2}} -
    -
    - Active Message: -
    -
    - {{:data.stat_display.active_line1}}
    - {{:data.stat_display.active_line2}} -
    -
    -{{/if}} -
    -
    - Stored line 1 -
    -
    - {{:helper.link(data.stat_display.line1 + ' (set)', 'pencil', {'cartridge_topic' : "1", 'stat_display' : "setmsg", 'line' : "1"}, null, null)}} -
    -
    -
    -
    - Stored line 2 -
    -
    - {{:helper.link(data.stat_display.line2 + ' (set)', 'pencil', {'cartridge_topic' : "1", 'stat_display' : "setmsg", 'line' : "2"}, null, null)}} -
    -
    +

    Station Status Display Interlink

    + +
    +
    + Code +
    +
    + {{:helper.link('Clear Message', 'trash', {'cartridge_topic' : "1", 'stat_display' : "blank"}, (data.stat_display.active == "blank") ? 'selected' : null)}} + {{:helper.link('Clear Alert', 'alert', {'cartridge_topic' : "1", 'choice' : "Status", 'stat_display' : "alert", 'alert' : "default"}, (data.stat_display.active == "default") ? 'selected' : null)}} +
    +
    +
    +
    + Message +
    +
    + {{:helper.link('Shuttle ETA', 'gear', {'cartridge_topic' : "1", 'stat_display' : "shuttle"}, (data.stat_display.active == "shuttle") ? 'selected' : null)}} + {{:helper.link('Set Message', 'gear', {'cartridge_topic' : "1", 'stat_display' : "message"}, (data.stat_display.active == "message") ? 'selected' : null)}} +
    +
    +
    +
    + Alert +
    +
    + {{:helper.link('Red Alert', 'alert', {'cartridge_topic' : "1", 'choice' : "Status", 'stat_display' : "alert", 'alert' : "redalert"}, (data.stat_display.active == "redalert") ? 'selected' : null)}} + {{:helper.link('Lockdown', 'caution', {'cartridge_topic' : "1", 'choice' : "Status", 'stat_display' : "alert", 'alert' : "lockdown"}, (data.stat_display.active == "lockdown") ? 'selected' : null)}} + {{:helper.link('Biohazard', 'radiation', {'cartridge_topic' : "1", 'choice' : "Status", 'stat_display' : "alert", 'alert' : "biohazard"}, (data.stat_display.active == "biohazard") ? 'selected' : null)}} +
    +
    +{{if data.stat_display.line1 != data.stat_display.active_line1 || data.stat_display.line2 != data.stat_display.active_line2}} +
    +
    + Active Message: +
    +
    + {{:data.stat_display.active_line1}}
    + {{:data.stat_display.active_line2}} +
    +
    +{{/if}} +
    +
    + Stored line 1 +
    +
    + {{:helper.link(data.stat_display.line1 + ' (set)', 'pencil', {'cartridge_topic' : "1", 'stat_display' : "setmsg", 'line' : "1"}, null, null)}} +
    +
    +
    +
    + Stored line 2 +
    +
    + {{:helper.link(data.stat_display.line2 + ' (set)', 'pencil', {'cartridge_topic' : "1", 'stat_display' : "setmsg", 'line' : "2"}, null, null)}} +
    +
    diff --git a/nano/templates/turret_control.tmpl b/nano/templates/turret_control.tmpl index a529bcbb10..944f4a73d3 100644 --- a/nano/templates/turret_control.tmpl +++ b/nano/templates/turret_control.tmpl @@ -1,41 +1,41 @@ -
    -
    - Behaviour controls are {{:data.locked ? "locked" : "unlocked"}}. -
    -
    -
    -{{if data.access}} -
    -
    - Turret Status: -
    -
    - {{:helper.link('Enabled', null, {'command' : 'enable', 'value' : 1}, data.enabled ?'redButton' : null)}} - {{:helper.link('Disabled',null, {'command' : 'enable', 'value' : 0}, !data.enabled ? 'selected' : null)}} -
    -
    - - {{if data.is_lethal}} -
    -
    - Lethal Mode: -
    -
    - {{:helper.link('On', null, {'command' : 'lethal', 'value' : 1}, data.lethal ?'redButton' : null)}} - {{:helper.link('Off',null, {'command' : 'lethal', 'value' : 0}, !data.lethal ? 'selected' : null)}} -
    -
    - {{/if}} - - {{for data.settings}} -
    -
    - {{:value.category}} -
    -
    - {{:helper.link('On', null, {'command' : value.setting, 'value' : 1}, value.value ? 'selected' : null)}} - {{:helper.link('Off',null, {'command' : value.setting, 'value' : 0}, !value.value ? 'selected' : null)}} -
    -
    - {{/for}} -{{/if}} +
    +
    + Behaviour controls are {{:data.locked ? "locked" : "unlocked"}}. +
    +
    +
    +{{if data.access}} +
    +
    + Turret Status: +
    +
    + {{:helper.link('Enabled', null, {'command' : 'enable', 'value' : 1}, data.enabled ?'redButton' : null)}} + {{:helper.link('Disabled',null, {'command' : 'enable', 'value' : 0}, !data.enabled ? 'selected' : null)}} +
    +
    + + {{if data.is_lethal}} +
    +
    + Lethal Mode: +
    +
    + {{:helper.link('On', null, {'command' : 'lethal', 'value' : 1}, data.lethal ?'redButton' : null)}} + {{:helper.link('Off',null, {'command' : 'lethal', 'value' : 0}, !data.lethal ? 'selected' : null)}} +
    +
    + {{/if}} + + {{for data.settings}} +
    +
    + {{:value.category}} +
    +
    + {{:helper.link('On', null, {'command' : value.setting, 'value' : 1}, value.value ? 'selected' : null)}} + {{:helper.link('Off',null, {'command' : value.setting, 'value' : 0}, !value.value ? 'selected' : null)}} +
    +
    + {{/for}} +{{/if}} diff --git a/nano/templates/uplink.tmpl b/nano/templates/uplink.tmpl index 0773883d70..10991da754 100644 --- a/nano/templates/uplink.tmpl +++ b/nano/templates/uplink.tmpl @@ -1,177 +1,177 @@ - - -{{:helper.syndicateMode()}} - - - -

    {{:data.welcome}}

    -
    -
    -
    - Functions: -
    -
    -
    - {{:helper.link('Request Items', 'gear', {'menu' : 0}, null, 'fixedLeftWider')}} - {{:helper.link('Exploitable Information', 'gear', {'menu' : 2}, null, 'fixedLeftWider')}} -
    -
    - {{:helper.link('Return', 'arrowreturn-1-w', {'return' : 1}, null, 'fixedLeft')}} - {{:helper.link('Close', 'gear', {'lock' : "1"}, null, 'fixedLeft')}} -
    -
    -
    -
    - -
    -
    - Tele-Crystals: -
    -
    - {{:data.crystals}} -
    -
    - - -{{if data.menu == 0}} - {{if data.discount_amount < 100}} -
    -
    - Currently discounted: -
    -
    - {{:data.discount_name}} - {{:data.discount_amount}}% off. Offer will expire at: {{:data.offer_expiry}} -
    -
    - {{/if}} - -
    -
    Categories
    - {{for data.categories}} -
    - {{:helper.link(value.name, 'gear', {'category' : value.ref}, (value.name == data.current_category) ? 'categoryActive' : '', 'category')}} -
    - {{/for}} -
    - -
    -
    - Request Items -
    -
    -
    -
    - {{for data.items}} -
    -
    - -
    {{:value.cost}} points
    -
    -
    - {{/for}} -
    -
    -
    -
    - -{{else data.menu == 2}} -

    Information Record List:

    -
    -
    - Select a Record -
    -
    - {{for data.exploit_records}} -
    - {{:helper.link(value.Name, 'gear', {'menu' : 21, 'id' : value.id}, null, null)}} -
    - {{/for}} -{{else data.menu == 21}} -

    Information Record:

    -
    -
    -
    -
    - {{if data.exploit_exists == 1}} - Name: {{:data.exploit.name}}
    - Sex: {{:data.exploit.sex}}
    - Species: {{:data.exploit.species}}
    - Age: {{:data.exploit.age}}
    - Rank: {{:data.exploit.rank}}
    - Home System: {{:data.exploit.home_system}}
    - Citizenship: {{:data.exploit.citizenship}}
    - Faction: {{:data.exploit.faction}}
    - Religion: {{:data.exploit.religion}}
    - Fingerprint: {{:data.exploit.fingerprint}}
    - Other Affiliation: {{:data.exploit.antagfaction}}
    - -
    Acquired Information:
    - Notes:
    {{:data.exploit.nanoui_exploit_record}}

    - {{else}} - - No exploitative information acquired! -
    -
    -
    - {{/if}} -
    -
    -
    -{{/if}} + + +{{:helper.syndicateMode()}} + + + +

    {{:data.welcome}}

    +
    +
    +
    + Functions: +
    +
    +
    + {{:helper.link('Request Items', 'gear', {'menu' : 0}, null, 'fixedLeftWider')}} + {{:helper.link('Exploitable Information', 'gear', {'menu' : 2}, null, 'fixedLeftWider')}} +
    +
    + {{:helper.link('Return', 'arrowreturn-1-w', {'return' : 1}, null, 'fixedLeft')}} + {{:helper.link('Close', 'gear', {'lock' : "1"}, null, 'fixedLeft')}} +
    +
    +
    +
    + +
    +
    + Tele-Crystals: +
    +
    + {{:data.crystals}} +
    +
    + + +{{if data.menu == 0}} + {{if data.discount_amount < 100}} +
    +
    + Currently discounted: +
    +
    + {{:data.discount_name}} - {{:data.discount_amount}}% off. Offer will expire at: {{:data.offer_expiry}} +
    +
    + {{/if}} + +
    +
    Categories
    + {{for data.categories}} +
    + {{:helper.link(value.name, 'gear', {'category' : value.ref}, (value.name == data.current_category) ? 'categoryActive' : '', 'category')}} +
    + {{/for}} +
    + +
    +
    + Request Items +
    +
    +
    +
    + {{for data.items}} +
    +
    + +
    {{:value.cost}} points
    +
    +
    + {{/for}} +
    +
    +
    +
    + +{{else data.menu == 2}} +

    Information Record List:

    +
    +
    + Select a Record +
    +
    + {{for data.exploit_records}} +
    + {{:helper.link(value.Name, 'gear', {'menu' : 21, 'id' : value.id}, null, null)}} +
    + {{/for}} +{{else data.menu == 21}} +

    Information Record:

    +
    +
    +
    +
    + {{if data.exploit_exists == 1}} + Name: {{:data.exploit.name}}
    + Sex: {{:data.exploit.sex}}
    + Species: {{:data.exploit.species}}
    + Age: {{:data.exploit.age}}
    + Rank: {{:data.exploit.rank}}
    + Home System: {{:data.exploit.home_system}}
    + Citizenship: {{:data.exploit.citizenship}}
    + Faction: {{:data.exploit.faction}}
    + Religion: {{:data.exploit.religion}}
    + Fingerprint: {{:data.exploit.fingerprint}}
    + Other Affiliation: {{:data.exploit.antagfaction}}
    + +
    Acquired Information:
    + Notes:
    {{:data.exploit.nanoui_exploit_record}}

    + {{else}} + + No exploitative information acquired! +
    +
    +
    + {{/if}} +
    +
    +
    +{{/if}} diff --git a/sound/items/drop/generic1.ogg b/sound/items/drop/generic1.ogg new file mode 100644 index 0000000000..c2195b1e24 Binary files /dev/null and b/sound/items/drop/generic1.ogg differ diff --git a/sound/items/drop/generic2.ogg b/sound/items/drop/generic2.ogg new file mode 100644 index 0000000000..ac0bd3710f Binary files /dev/null and b/sound/items/drop/generic2.ogg differ diff --git a/sound/items/pickup/clothing.ogg b/sound/items/pickup/clothing.ogg new file mode 100644 index 0000000000..568fe73341 Binary files /dev/null and b/sound/items/pickup/clothing.ogg differ diff --git a/sound/items/pickup/generic1.ogg b/sound/items/pickup/generic1.ogg new file mode 100644 index 0000000000..64f37c6dd9 Binary files /dev/null and b/sound/items/pickup/generic1.ogg differ diff --git a/sound/items/pickup/generic2.ogg b/sound/items/pickup/generic2.ogg new file mode 100644 index 0000000000..57092778f2 Binary files /dev/null and b/sound/items/pickup/generic2.ogg differ diff --git a/sound/items/pickup/generic3.ogg b/sound/items/pickup/generic3.ogg new file mode 100644 index 0000000000..be46e77242 Binary files /dev/null and b/sound/items/pickup/generic3.ogg differ diff --git a/sound/items/pickup/soda.ogg b/sound/items/pickup/soda.ogg index f19a06ec75..5a342af320 100644 Binary files a/sound/items/pickup/soda.ogg and b/sound/items/pickup/soda.ogg differ diff --git a/sound/voice/complionator/asshole.ogg b/sound/voice/complionator/asshole.ogg new file mode 100644 index 0000000000..9ee40942c4 Binary files /dev/null and b/sound/voice/complionator/asshole.ogg differ diff --git a/sound/voice/complionator/bash.ogg b/sound/voice/complionator/bash.ogg new file mode 100644 index 0000000000..e79a2cd1e1 Binary files /dev/null and b/sound/voice/complionator/bash.ogg differ diff --git a/sound/voice/complionator/bobby.ogg b/sound/voice/complionator/bobby.ogg new file mode 100644 index 0000000000..4bc8f8df94 Binary files /dev/null and b/sound/voice/complionator/bobby.ogg differ diff --git a/sound/voice/complionator/compliance.ogg b/sound/voice/complionator/compliance.ogg new file mode 100644 index 0000000000..fcfb608202 Binary files /dev/null and b/sound/voice/complionator/compliance.ogg differ diff --git a/sound/voice/complionator/dontmove.ogg b/sound/voice/complionator/dontmove.ogg new file mode 100644 index 0000000000..09cefea9d6 Binary files /dev/null and b/sound/voice/complionator/dontmove.ogg differ diff --git a/sound/voice/complionator/dredd.ogg b/sound/voice/complionator/dredd.ogg new file mode 100644 index 0000000000..ab434dbfde Binary files /dev/null and b/sound/voice/complionator/dredd.ogg differ diff --git a/sound/voice/complionator/floor.ogg b/sound/voice/complionator/floor.ogg new file mode 100644 index 0000000000..996dd0f54a Binary files /dev/null and b/sound/voice/complionator/floor.ogg differ diff --git a/sound/voice/complionator/freeze.ogg b/sound/voice/complionator/freeze.ogg new file mode 100644 index 0000000000..d4224be839 Binary files /dev/null and b/sound/voice/complionator/freeze.ogg differ diff --git a/sound/voice/complionator/god.ogg b/sound/voice/complionator/god.ogg new file mode 100644 index 0000000000..8e1a54d268 Binary files /dev/null and b/sound/voice/complionator/god.ogg differ diff --git a/sound/voice/complionator/halt.ogg b/sound/voice/complionator/halt.ogg new file mode 100644 index 0000000000..81563b928f Binary files /dev/null and b/sound/voice/complionator/halt.ogg differ diff --git a/sound/voice/complionator/harry.ogg b/sound/voice/complionator/harry.ogg new file mode 100644 index 0000000000..eae132675e Binary files /dev/null and b/sound/voice/complionator/harry.ogg differ diff --git a/sound/voice/complionator/imperial.ogg b/sound/voice/complionator/imperial.ogg new file mode 100644 index 0000000000..903cf1197c Binary files /dev/null and b/sound/voice/complionator/imperial.ogg differ diff --git a/sound/voice/complionator/justice.ogg b/sound/voice/complionator/justice.ogg new file mode 100644 index 0000000000..2aef43b150 Binary files /dev/null and b/sound/voice/complionator/justice.ogg differ diff --git a/sound/voice/complionator/robocop.ogg b/sound/voice/complionator/robocop.ogg new file mode 100644 index 0000000000..4dec421ed0 Binary files /dev/null and b/sound/voice/complionator/robocop.ogg differ diff --git a/sound/voice/complionator/running.ogg b/sound/voice/complionator/running.ogg new file mode 100644 index 0000000000..3711ce6ccf Binary files /dev/null and b/sound/voice/complionator/running.ogg differ diff --git a/sound/voice/complionator/shutup.ogg b/sound/voice/complionator/shutup.ogg new file mode 100644 index 0000000000..ecd2b02015 Binary files /dev/null and b/sound/voice/complionator/shutup.ogg differ diff --git a/sound/voice/complionator/stfu.ogg b/sound/voice/complionator/stfu.ogg new file mode 100644 index 0000000000..9c3fcf675b Binary files /dev/null and b/sound/voice/complionator/stfu.ogg differ diff --git a/sound/voice/complionator/super.ogg b/sound/voice/complionator/super.ogg new file mode 100644 index 0000000000..8bae406dea Binary files /dev/null and b/sound/voice/complionator/super.ogg differ diff --git a/tgui/packages/common/string.js b/tgui/packages/common/string.js index a3da0885a1..405693a0d2 100644 --- a/tgui/packages/common/string.js +++ b/tgui/packages/common/string.js @@ -120,10 +120,11 @@ export const decodeHtmlEntities = str => { if (!str) { return str; } - const translate_re = /&(nbsp|amp|quot|lt|gt|apos|trade);/g; + const translate_re = /&(nbsp|amp|deg|quot|lt|gt|apos|trade);/g; const translate = { nbsp: ' ', amp: '&', + deg: '°', quot: '"', lt: '<', gt: '>', diff --git a/tgui/packages/tgui/components/Box.js b/tgui/packages/tgui/components/Box.js index a53fa1e8fd..31bade2634 100644 --- a/tgui/packages/tgui/components/Box.js +++ b/tgui/packages/tgui/components/Box.js @@ -104,6 +104,7 @@ const styleMapperByPropName = { verticalAlign: mapRawPropTo('vertical-align'), textTransform: mapRawPropTo('text-transform'), wordWrap: mapRawPropTo('word-wrap'), + unselectable: mapRawPropTo('unselectable'), // Boolean props inline: mapBooleanPropTo('display', 'inline-block'), bold: mapBooleanPropTo('font-weight', 'bold'), diff --git a/tgui/packages/tgui/components/Button.js b/tgui/packages/tgui/components/Button.js index ced7bd13bd..876435c892 100644 --- a/tgui/packages/tgui/components/Button.js +++ b/tgui/packages/tgui/components/Button.js @@ -20,6 +20,10 @@ export const Button = props => { className, fluid, icon, + iconRotation, + iconSpin, + iconColor, + iconSize, color, disabled, selected, @@ -27,11 +31,9 @@ export const Button = props => { tooltipPosition, tooltipScale, ellipsis, + compact, + circular, content, - iconRotation, - iconSpin, - iconColor, - iconSize, children, onclick, onClick, @@ -57,6 +59,8 @@ export const Button = props => { selected && 'Button--selected', hasContent && 'Button--hasContent', ellipsis && 'Button--ellipsis', + circular && 'Button--circular', + compact && 'Button--compact', (color && typeof color === 'string') ? 'Button--color--' + color : 'Button--color--default', diff --git a/tgui/packages/tgui/components/NanoMap.js b/tgui/packages/tgui/components/NanoMap.js index 261fb8b1d3..2d7f969890 100644 --- a/tgui/packages/tgui/components/NanoMap.js +++ b/tgui/packages/tgui/components/NanoMap.js @@ -1,38 +1,44 @@ -import { Box, Icon, Tooltip } from '.'; import { Component } from 'inferno'; +import { Box, Button, Icon, Tooltip, LabeledList, Slider } from '.'; import { useBackend } from "../backend"; -import { resolveAsset } from '../assets'; -import { logger } from '../logging'; + +const pauseEvent = e => { + if (e.stopPropagation) { e.stopPropagation(); } + if (e.preventDefault) { e.preventDefault(); } + e.cancelBubble = true; + e.returnValue = false; + return false; +}; export class NanoMap extends Component { constructor(props) { super(props); // Auto center based on window size + const Xcenter = (window.innerWidth / 2) - 256; + const Ycenter = (window.innerHeight / 2) - 256; + this.state = { - offsetX: 0, - offsetY: 0, + offsetX: Xcenter, + offsetY: Ycenter, transform: 'none', dragging: false, originX: null, originY: null, + zoom: 1, }; + // Dragging this.handleDragStart = e => { - document.body.style['pointer-events'] = 'none'; this.ref = e.target; this.setState({ dragging: false, originX: e.screenX, originY: e.screenY, }); - this.timer = setTimeout(() => { - this.setState({ - dragging: true, - }); - }, 250); document.addEventListener('mousemove', this.handleDragMove); document.addEventListener('mouseup', this.handleDragEnd); + pauseEvent(e); }; this.handleDragMove = e => { @@ -41,8 +47,8 @@ export class NanoMap extends Component { const newOffsetX = e.screenX - state.originX; const newOffsetY = e.screenY - state.originY; if (prevState.dragging) { - state.offsetX += (newOffsetX / this.props.zoom); - state.offsetY += (newOffsetY / this.props.zoom); + state.offsetX += newOffsetX; + state.offsetY += newOffsetY; state.originX = e.screenX; state.originY = e.screenY; } else { @@ -50,11 +56,10 @@ export class NanoMap extends Component { } return state; }); + pauseEvent(e); }; this.handleDragEnd = e => { - document.body.style['pointer-events'] = 'auto'; - clearTimeout(this.timer); this.setState({ dragging: false, originX: null, @@ -62,28 +67,54 @@ export class NanoMap extends Component { }); document.removeEventListener('mousemove', this.handleDragMove); document.removeEventListener('mouseup', this.handleDragEnd); + pauseEvent(e); }; + + this.handleZoom = (_e, value) => { + this.setState(state => { + const newZoom = Math.min(Math.max(value, 1), 8); + let zoomDiff = (newZoom - state.zoom) * 1.5; + state.zoom = newZoom; + + let newOffsetX = state.offsetX - 262 * zoomDiff; + if (newOffsetX < -500) { newOffsetX = -500; } + if (newOffsetX > 500) { newOffsetX = 500; } + + let newOffsetY = state.offsetY - 256 * zoomDiff; + if (newOffsetY < -200) { newOffsetY = -200; } + if (newOffsetY > 200) { newOffsetY = 200; } + + state.offsetX = newOffsetX; + state.offsetY = newOffsetY; + if (props.onZoom) { + props.onZoom(state.zoom); + } + return state; + }); + }; + } render() { const { config } = useBackend(this.context); - const { offsetX, offsetY } = this.state; - const { children, zoom, reset } = this.props; + const { dragging, offsetX, offsetY, zoom = 1 } = this.state; + const { children } = this.props; - let matrix - = `matrix(${zoom}, 0, 0, ${zoom}, ${offsetX * zoom}, ${offsetY * zoom})`; - + const mapUrl = config.map + "_nanomap_z" + config.mapZLevel + ".png"; + // (x * zoom), x Needs to be double the turf- map size. (for virgo, 140x140) + const mapSize = (280 * zoom) + 'px'; const newStyle = { - width: '560px', - height: '560px', + width: mapSize, + height: mapSize, + "margin-top": offsetY + "px", + "margin-left": offsetX + "px", "overflow": "hidden", "position": "relative", - "padding": "0px", - "background-image": - "url("+config.map+"_nanomap_z"+config.mapZLevel+".png)", + "background-image": "url(" + mapUrl + ")", "background-size": "cover", + "background-repeat": "no-repeat", "text-align": "center", - "transform": matrix, + "cursor": dragging ? "move" : "auto", }; return ( @@ -96,6 +127,7 @@ export class NanoMap extends Component { {children} + ); } @@ -105,31 +137,73 @@ const NanoMapMarker = (props, context) => { const { x, y, - zoom, + zoom = 1, icon, tooltip, color, onClick, } = props; - const rx = (x * 4) - 5; - const ry = (y * 4) - 4; + const handleOnClick = e => { + pauseEvent(e); + onClick(e); + }; + + const rx = ((x * 2 * zoom) - zoom) - 3; + const ry = ((y * 2 * zoom) - zoom) - 3; return ( - - - - +
    + + + + +
    ); }; NanoMap.Marker = NanoMapMarker; + +const NanoMapZoomer = (props, context) => { + const { act, config, data } = useBackend(context); + return ( + + + + v + "x"} + value={props.zoom} + onDrag={(e, v) => props.onZoom(e, v)} + /> + + + {data.map_levels + .sort((a, b) => Number(a) - Number(b)) + .map(level => ( + + + + + + + +
    + {items.map((item, i) => #{i+1}: {item})} +
    + + ) || ( +
    + No items inserted. +
    + )} + + + ); +}; \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/CommunicationsConsole.js b/tgui/packages/tgui/interfaces/CommunicationsConsole.js new file mode 100644 index 0000000000..d76abba47d --- /dev/null +++ b/tgui/packages/tgui/interfaces/CommunicationsConsole.js @@ -0,0 +1,347 @@ +import { Fragment } from 'inferno'; +import { useBackend } from '../backend'; +import { Button, LabeledList, Box, Section } from '../components'; +import { Window } from '../layouts'; + +export const CommunicationsConsole = (props, context) => { + return ( + + + + + + ); +}; + +export const CommunicationsConsoleContent = (props, context) => { + const { act, data } = useBackend(context); + + const { + menu_state, + } = data; + + let mainTemplate = ( + + ERRROR. Unknown menu_state: {menu_state} + Please report this to NT Technical Support. + + ); + + // 1 = main screen + if (menu_state === 1) { + mainTemplate = ; + } else if (menu_state === 2) { + // 2 = status screen + mainTemplate = ; + } else if (menu_state === 3) { + // 3 = messages screen + mainTemplate = ; + } + + return ( + + + {mainTemplate} + + ); +}; + +const CommunicationsConsoleMain = (props, context) => { + const { act, data } = useBackend(context); + + const { + messages, + msg_cooldown, + emagged, + cc_cooldown, + str_security_level, + levels, + authmax, + security_level, + security_level_color, + authenticated, + atcsquelch, + boss_short, + } = data; + + let reportText = "View (" + messages.length + ")"; + let announceText = "Make Priority Announcement"; + if (msg_cooldown > 0) { + announceText += " (" + msg_cooldown + "s)"; + } + let ccMessageText = emagged ? "Message [UNKNOWN]" : "Message " + boss_short; + if (cc_cooldown > 0) { + ccMessageText += " (" + cc_cooldown + "s)"; + } + + let alertLevelText = str_security_level; + let alertLevelButtons = levels.map(slevel => { + return ( + + + {app.module} + + + ))} + + ); +}; + +TabToTemplate[HOMETAB] = ; + +/* Phone tab, provides a phone interface! */ +const PhoneTab = (props, context) => { + const { act, data } = useBackend(context); + + const { + targetAddress, + voice_mobs, + communicating, + requestsReceived, + invitesSent, + video_comm, + } = data; + + return ( +
    + + + + + act("write_target_address", { val: val })} /> + + +
    +
    + {!!communicating.length && ( + + {communicating.map(comm => ( + + + {decodeHtmlEntities(comm.name)} + + +
    + ) || ( + + No connections + + )} +
    +
    + {!!requestsReceived.length && ( + + {requestsReceived.map(request => ( + + {decodeHtmlEntities(request.address)} + +
    +
    + {!!invitesSent.length && ( + + {invitesSent.map(invite => ( + + {decodeHtmlEntities(invite.address)} + +
    + + + ); +}; + +// Subtemplate +const NumberPad = (props, context) => { + const { act, data } = useBackend(context); + + const { + targetAddress, + } = data; + + const validCharacters = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"]; + + let buttonArray = validCharacters.map(char => ( + + + Dial + + + {/* Message */} + + + + Message + + + {/* Hang Up */} + + + + Hang Up + + + + + + ); +}; + +TabToTemplate[PHONTAB] = ; + +/* Contacts */ +const ContactsTab = (props, context) => { + const { act, data } = useBackend(context); + + const { + knownDevices, + } = data; + + return ( +
    + {knownDevices.length && ( + + {knownDevices.map(device => ( + + + {decodeHtmlEntities(device.name)} + + + {device.address} + +
    + ) || ( + + No devices detected on your local NTNet region. + + )} +
    + ); +}; + +TabToTemplate[CONTTAB] = ; + +/* Messaging */ +const MessagingTab = (props, context) => { + const { act, data } = useBackend(context); + + const { + imContacts, + } = data; + + return ( +
    + {imContacts.length && ( + + {imContacts.map(device => ( + + + {decodeHtmlEntities(device.name)}: + + + {device.address} + +
    + ) || ( + + You haven't sent any messages yet. +
    + ); +}; + +TabToTemplate[MESSTAB] = ; + +/* Actual messaging conversation */ +const IsIMOurs = (im, targetAddress) => { + return im.address !== targetAddress; +}; + +const enforceLengthLimit = (prefix, name, length) => { + if ((prefix + name).length > length) { + if (name.length > length) { + return name.slice(0, length) + "..."; + } + return name; + } + return prefix + name; +}; + +const MessagingThreadTab = (props, context) => { + const { act, data } = useBackend(context); + + const { + targetAddressName, + targetAddress, + imList, + } = data; + + const [clipboardMode, setClipboardMode] = useLocalState(context, 'clipboardMode', false); + + if (clipboardMode) { + return ( +
    + {enforceLengthLimit("Conversation with ", decodeHtmlEntities(targetAddressName), 30)} + + )} + buttons={ +
    + ); + } + + return ( +
    + {enforceLengthLimit("Conversation with ", decodeHtmlEntities(targetAddressName), 30)} + + )} + buttons={ +
    + ); +}; + +TabToTemplate[MESSSUBTAB] = ; + +/* News */ +const NewsTab = (props, context) => { + const { act, data } = useBackend(context); + + const { + feeds, + target_feed, + } = data; + + return ( +
    + {!feeds.length && ( + + Error: No newsfeeds available. Please try again later. + + ) || target_feed && ( + + ) || ( + + )} +
    + ); +}; + +const NewsTargetFeed = (props, context) => { + const { act, data } = useBackend(context); + + const { + target_feed, + } = data; + + return ( +
    act("newsfeed", { newsfeed: null })} /> + }> + {target_feed.messages.map(message => ( +
    + - {decodeHtmlEntities(message.body)} + {!!message.img && ( + + + {decodeHtmlEntities(message.caption) || null} + + )} + + [{message.message_type} by {decodeHtmlEntities(message.author)} - {message.time_stamp}] + +
    + ))} +
    + ); +}; + +const NewsFeed = (props, context) => { + const { act, data } = useBackend(context); + + const { + feeds, + latest_news, + } = data; + + return ( + +
    +
    + {latest_news.map(news => ( + +
    + {decodeHtmlEntities(news.channel)} +
    + - {decodeHtmlEntities(news.body)} + {!!news.img && ( + + [image omitted, view story for more details] + {news.caption || null} + + )} + + [{news.message_type} by {news.author} - {news.time_stamp}] + +
    + ))} +
    +
    +
    + {feeds.map(feed => ( +
    +
    + ); +}; + +TabToTemplate[NEWSTAB] = ; + +/* Note Keeper */ +const NoteTab = (props, context) => { + const { act, data } = useBackend(context); + + const { + note, + } = data; + + return ( +
    act("edit")} + content="Edit Notes" /> + }> +
    + {note} +
    +
    + ); +}; + +TabToTemplate[NOTETAB] = ; + +/* Weather App */ +const getItemColor = (value, min2, min1, max1, max2) => { + if (value < min2) { + return "bad"; + } else if (value < min1) { + return "average"; + } else if (value > max1) { + return "average"; + } else if (value > max2) { + return "bad"; + } + return "good"; +}; + +const WeatherTab = (props, context) => { + const { act, data } = useBackend(context); + + const { + aircontents, + weather, + } = data; + + return ( +
    +
    + + {filter( + i => (i.val !== "0") || i.entry === "Pressure" || i.entry === "Temperature" + )(aircontents) + .map(item => ( + + {item.val}{decodeHtmlEntities(item.units)} + + ))} + +
    +
    + {!!weather.length && ( + + {weather.map(wr => ( + + + + {wr.Time} + + + {toTitleCase(wr.Weather)} + + + Current: {wr.Temperature.toFixed()}°C + | High: {wr.High.toFixed()}°C + | Low: {wr.Low.toFixed()}°C + + + {wr.WindDir} + + + {wr.WindSpeed} + + + {decodeHtmlEntities(wr.Forecast)} + + + + ))} + + ) || ( + + No weather reports available. Please check back later. + + )} +
    +
    + ); +}; + +TabToTemplate[WTHRTAB] = ; + +/* Crew Manifest */ +// Lol just steal it from the existing template +TabToTemplate[MANITAB] = ; + +/* Settings */ +const SettingsTab = (props, context) => { + const { act, data } = useBackend(context); + + const { + owner, + occupation, + connectionStatus, + address, + visible, + ring, + } = data; + + return ( +
    + + +
    + ); +}; + +TabToTemplate[SETTTAB] = ; \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/ComputerFabricator.js b/tgui/packages/tgui/interfaces/ComputerFabricator.js new file mode 100644 index 0000000000..54baebaf23 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ComputerFabricator.js @@ -0,0 +1,398 @@ +import { multiline } from 'common/string'; +import { Fragment } from 'inferno'; +import { useBackend } from '../backend'; +import { Box, Button, Grid, Section, Table, Tooltip } from '../components'; +import { Window } from '../layouts'; + +export const ComputerFabricator = (props, context) => { + const { act, data } = useBackend(context); + return ( + + +
    + Your perfect device, only three steps away... +
    + {data.state !== 0 && ( + +
    + ); + } + + return ( + + + + + + + + {content.progressText[1]} + + + + + ); + })} +
    + + + + ); +}; \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/CrewManifest.js b/tgui/packages/tgui/interfaces/CrewManifest.js new file mode 100644 index 0000000000..080968d086 --- /dev/null +++ b/tgui/packages/tgui/interfaces/CrewManifest.js @@ -0,0 +1,68 @@ +import { useBackend } from "../backend"; +import { Box, Section, Table } from "../components"; +import { Window } from "../layouts"; +import { COLORS } from "../constants"; +import { decodeHtmlEntities } from "common/string"; + +/* + * Shared by the following templates (and used individually too) + * - Communicator.js + * - IdentificationComputer.js + * - pda/pda_manifest.js + * In order to fuel this UI, you must use the following code in your ui_data (or static data, doesn't really matter) + * ```dm +if(data_core) + data_core.get_manifest_list() +data["manifest"] = PDA_Manifest + * ``` + */ + +export const CrewManifest = (props, context) => { + return ( + + + + + + ); +}; + +export const CrewManifestContent = (props, context) => { + const { act, data } = useBackend(context); + + const { + manifest, + } = data; + + return ( +
    + {manifest.map(cat => !!cat.elems.length && ( +
    + + {cat.cat} + + + )} + key={cat.cat} + level={2}> + + + Name + Rank + Active + + {cat.elems.map(person => ( + + {decodeHtmlEntities(person.name)} + {person.rank} + {person.active} + + ))} +
    +
    + ))} +
    + ); +}; \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/CrewMonitor.js b/tgui/packages/tgui/interfaces/CrewMonitor.js index e8372502e3..62d9774169 100644 --- a/tgui/packages/tgui/interfaces/CrewMonitor.js +++ b/tgui/packages/tgui/interfaces/CrewMonitor.js @@ -3,9 +3,28 @@ import { flow } from 'common/fp'; import { useBackend, useLocalState } from "../backend"; import { Window } from "../layouts"; import { NanoMap, Box, Table, Button, Tabs, Icon, NumberInput } from "../components"; -import { TableCell } from '../components/Table'; import { Fragment } from 'inferno'; +const getStatText = cm => { + if (cm.dead) { + return "Deceased"; + } + if (parseInt(cm.stat, 10) === 1) { // Unconscious + return "Unconscious"; + } + return "Living"; +}; + +const getStatColor = cm => { + if (cm.dead) { + return "red"; + } + if (parseInt(cm.stat, 10) === 1) { // Unconscious + return "orange"; + } + return "green"; +}; + export const CrewMonitor = () => { return ( { sortBy(cm => cm?.realZ), ])(data.crewmembers || []); - const [ - mapZoom, - setZoom, - ] = useLocalState(context, 'number', 1); + const [zoom, setZoom] = useLocalState(context, 'zoom', 1); + let body; // Data view if (tabIndex === 0) { @@ -51,14 +68,14 @@ export const CrewMonitorContent = (props, context) => { {crew.map(cm => ( - - + + {cm.name} ({cm.assignment}) - - + + - {cm.dead ? 'Deceased' : 'Living'} + color={getStatColor(cm)}> + {getStatText(cm)} {cm.sensor_type >= 2 ? ( @@ -85,8 +102,8 @@ export const CrewMonitorContent = (props, context) => { {')'} ) : null} - - + + {cm.sensor_type === 3 ? ( data.isAI ? ( + }> + {items.length && items.map(item => ( + + )) || ( + + No items stored. + + )} + + ); +}; \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/CryoStorageVr.js b/tgui/packages/tgui/interfaces/CryoStorageVr.js new file mode 100644 index 0000000000..0fa51aca5f --- /dev/null +++ b/tgui/packages/tgui/interfaces/CryoStorageVr.js @@ -0,0 +1,57 @@ +import { useBackend, useLocalState } from "../backend"; +import { Box, Button, Section, Tabs, NoticeBox } from "../components"; +import { Window } from "../layouts"; +import { CryoStorageCrew } from "./CryoStorage"; + +export const CryoStorageVr = (props, context) => { + const { act, data } = useBackend(context); + + const { + real_name, + allow_items, + } = data; + + const [tab, setTab] = useLocalState(context, "tab", 0); + + return ( + + + + setTab(0)}> + Crew + + {!!allow_items && ( + setTab(1)}> + Items + + )} + + Welcome, {real_name}. + {tab === 0 && } + {!!allow_items && tab === 1 && } + + + ); +}; + +export const CryoStorageItemsVr = (props, context) => { + const { act, data } = useBackend(context); + + const { + items, + } = data; + + return ( +
    + {items.length && items.map(item => {item}) || ( + + No items stored. + + )} +
    + ); +}; \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/Fax.js b/tgui/packages/tgui/interfaces/Fax.js new file mode 100644 index 0000000000..e3c8a313b0 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Fax.js @@ -0,0 +1,113 @@ +import { Fragment } from 'inferno'; +import { useBackend } from "../backend"; +import { Box, Button, Collapsible, Icon, Input, LabeledList, NoticeBox, Section, Tabs } from "../components"; +import { Window } from "../layouts"; +import { LoginInfo } from './common/LoginInfo'; +import { LoginScreen } from './common/LoginScreen'; + +export const Fax = (props, context) => { + const { data } = useBackend(context); + + const { + authenticated, + } = data; + + if (!authenticated) { + return ( + + + + + + + ); + } + + return ( + + + + + + + + ); +}; + +export const FaxContent = (props, context) => { + const { act, data } = useBackend(context); + + const { + bossName, + copyItem, + cooldown, + destination, + } = data; + + return ( +
    + {!!cooldown && ( + + Transmitter arrays realigning. Please stand by. + + )} + + + {bossName} Quantum Entanglement Network + + + {copyItem && ( + + + + {copyItem} + + +
    + ); +}; + +const RemoveItem = (props, context) => { + const { act, data } = useBackend(context); + + const { + copyItem, + } = data; + + if (!copyItem) { + return null; + } + + return ( + + + + )} +
    + + + {safetyDisabled ? DISABLED : ENABLED} + + + + + +
    + +
    + ); +}; \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/ICAssembly.js b/tgui/packages/tgui/interfaces/ICAssembly.js index bf621880ad..d9dcde7236 100644 --- a/tgui/packages/tgui/interfaces/ICAssembly.js +++ b/tgui/packages/tgui/interfaces/ICAssembly.js @@ -22,8 +22,8 @@ export const ICAssembly = (props, context) => { } = data; return ( - - + +
    diff --git a/tgui/packages/tgui/interfaces/IDCard.js b/tgui/packages/tgui/interfaces/IDCard.js index 9883fbc88d..fc28fb08a4 100644 --- a/tgui/packages/tgui/interfaces/IDCard.js +++ b/tgui/packages/tgui/interfaces/IDCard.js @@ -2,122 +2,7 @@ import { Box, Flex, LabeledList, Section, Icon } from "../components"; import { useBackend } from "../backend"; import { Window } from "../layouts"; import { Fragment } from "inferno"; - -const rank2icon = { - // Command - 'Colony Director': 'user-tie', - 'Site Manager': 'user-tie', - 'Overseer': 'user-tie', - 'Head of Personnel': 'briefcase', - 'Crew Resources Officer': 'briefcase', - 'Deputy Director': 'briefcase', - 'Command Secretary': 'user-tie', - // Security - 'Head of Security': 'user-shield', - 'Security Commander': 'user-shield', - 'Chief of Security': 'user-shield', - 'Warden': ['city', 'shield-alt'], - 'Detective': 'search', - 'Forensic Technician': 'search', - 'Security Officer': 'user-shield', - 'Junior Officer': 'user-shield', - // Engineering - 'Chief Engineer': 'toolbox', - 'Atmospheric Technician': 'wind', - 'Station Engineer': 'toolbox', - 'Maintenance Technician': 'wrench', - 'Engine Technician': 'toolbox', - 'Electrician': 'toolbox', - // Medical - 'Chief Medical Officer': 'user-md', - 'Chemist': 'mortar-pestle', - 'Pharmacist': 'mortar-pestle', - 'Medical Doctor': 'user-md', - 'Surgeon': 'user-md', - 'Emergency Physician': 'user-md', - 'Nurse': 'user-md', - 'Virologist': 'disease', - 'Paramedic': 'ambulance', - 'Emergency Medical Technician': 'ambulance', - 'Psychiatrist': 'couch', - 'Psychologist': 'couch', - // Science - 'Research Director': 'user-graduate', - 'Research Supervisor': 'user-graduate', - 'Roboticist': 'robot', - 'Biomechanical Engineer': ['wrench', 'heartbeat'], - 'Mechatronic Engineer': 'wrench', - 'Scientist': 'flask', - 'Xenoarchaeologist': 'flask', - 'Anomalist': 'flask', - 'Phoron Researcher': 'flask', - 'Circuit Designer': 'car-battery', - 'Xenobiologist': 'meteor', - 'Xenobotanist': ['biohazard', 'seedling'], - // Cargo - 'Quartermaster': 'box-open', - 'Supply Chief': 'warehouse', - 'Cargo Technician': 'box-open', - 'Shaft Miner': 'hard-hat', - 'Drill Technician': 'hard-hat', - // Exploration - 'Pathfinder': 'binoculars', - 'Explorer': 'user-astronaut', - 'Field Medic': ['user-md', 'user-astronaut'], - 'Pilot': 'space-shuttle', - // Civvies - 'Bartender': 'glass-martini', - 'Barista': 'coffee', - 'Botanist': 'leaf', - 'Gardener': 'leaf', - 'Chaplain': 'place-of-worship', - 'Counselor': 'couch', - 'Chef': 'utensils', - 'Cook': 'utensils', - 'Entertainer': 'smile-beam', - 'Performer': 'smile-beam', - 'Musician': 'guitar', - 'Stagehand': 'smile-beam', - // All of the interns - 'Intern': 'school', - 'Apprentice Engineer': ['school', 'wrench'], - 'Medical Intern': ['school', 'user-md'], - 'Lab Assistant': ['school', 'flask'], - 'Security Cadet': ['school', 'shield-alt'], - 'Jr. Cargo Tech': ['school', 'box'], - 'Jr. Explorer': ['school', 'user-astronaut'], - 'Server': ['school', 'utensils'], - // Back to civvies - 'Internal Affairs Agent': 'balance-scale', - 'Janitor': 'broom', - 'Custodian': 'broom', - 'Sanitation Technician': 'hand-sparkles', - 'Maid': 'broom', - 'Librarian': 'book', - 'Journalist': 'newspaper', - 'Writer': 'book', - 'Historian': 'chalkboard-teacher', - 'Professor': 'chalkboard-teacher', - 'Visitor': 'user', - // Special roles - 'Emergency Responder': 'fighter-jet', -}; -const RankIcon = (props, context) => { - const { - rank, - } = props; - - let rankObj = rank2icon[rank]; - if (typeof rankObj === "string") { - return ; - } else if (Array.isArray(rankObj)) { - return rankObj.map(icon => ( - - )); - } else { - return ; - } -}; +import { RankIcon } from "./common/RankIcon"; export const IDCard = (props, context) => { const { data } = useBackend(context); diff --git a/tgui/packages/tgui/interfaces/IdentificationComputer.js b/tgui/packages/tgui/interfaces/IdentificationComputer.js new file mode 100644 index 0000000000..0bfee7333e --- /dev/null +++ b/tgui/packages/tgui/interfaces/IdentificationComputer.js @@ -0,0 +1,237 @@ +import { sortBy } from 'common/collections'; +import { Fragment } from 'inferno'; +import { useBackend } from "../backend"; +import { Box, Button, Flex, Input, LabeledList, Section, Table, Tabs } from "../components"; +import { Window } from "../layouts"; +import { decodeHtmlEntities } from 'common/string'; +import { COLORS } from "../constants"; +import { CrewManifestContent } from './CrewManifest'; + +export const IdentificationComputer = (props, context) => { + const { act, data } = useBackend(context); + + return ( + + + + + + ); +}; + +export const IdentificationComputerContent = (props, context) => { + const { act, data } = useBackend(context); + + const { + ntos, + } = props; + + const { + mode, + has_modify, + printing, + } = data; + + let body = ; + if (ntos && !data.have_id_slot) { + body = ; + } else if (printing) { + body = ; + } else if (mode === 1) { + body = ; + } + + return ( + + + {(!ntos || !!data.have_id_slot) && ( + act("mode", { "mode_target": 0 })}> + Access Modification + + )} + act("mode", { "mode_target": 1 })}> + Crew Manifest + + {!ntos || !!data.have_printer && ( + act("print")} disabled={!mode && !has_modify} color=""> + Print + + )} + + {body} + + ); +}; + +export const IdentificationComputerPrinting = (props, context) => { + return ( +
    + Please wait... +
    + ); +}; + +export const IdentificationComputerAccessModification = (props, context) => { + const { act, data } = useBackend(context); + + const { + ntos, + } = props; + + const { + station_name, + target_name, + target_owner, + scan_name, + authenticated, + has_modify, + account_number, + centcom_access, + all_centcom_access, + regions, + id_rank, + departments, + } = data; + + return ( +
    + {!authenticated && ( + + Please insert the IDs into the terminal to proceed. + + )} + + + + + ))} +
    + ) || ( +
    + +
    + )} + + )} +
    + ); +}; + +export const IdentificationComputerRegions = (props, context) => { + const { act, data } = useBackend(context); + + const { + actName, + } = props; + + const { + regions, + } = data; + + return ( + + {sortBy(r => r.name)(regions).map(region => ( + +
    + {sortBy(a => a.desc)(region.accesses).map(access => ( + + + + ))} +
    +
    + ))} +
    + ); +}; diff --git a/tgui/packages/tgui/interfaces/JanitorCart.js b/tgui/packages/tgui/interfaces/JanitorCart.js new file mode 100644 index 0000000000..ec95c33414 --- /dev/null +++ b/tgui/packages/tgui/interfaces/JanitorCart.js @@ -0,0 +1,158 @@ +import { round } from 'common/math'; +import { Fragment } from 'inferno'; +import { useBackend } from "../backend"; +import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../components"; +import { Window } from "../layouts"; + +export const JanitorCart = (props, context) => { + const { act, data } = useBackend(context); + + const { + mybag, + mybucket, + mymop, + myspray, + myreplacer, + signs, + icons, + } = data; + + return ( + + + + + + + + + + + ); +}; + +const iconkeysToIcons = { + "mybag": "trash", + "mybucket": "fill", + "mymop": "broom", + "myspray": "spray-can", + "myreplacer": "lightbulb", + "signs": "sign", +}; + +const JanicartIcon = (props, context) => { + const { data } = useBackend(context); + + const { + iconkey, + } = props; + + const { + icons, + } = data; + + if (iconkey in icons) { + return ( + + ); + } + + return ( + + ); +}; \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/Jukebox.js b/tgui/packages/tgui/interfaces/Jukebox.js new file mode 100644 index 0000000000..b9eac0520b --- /dev/null +++ b/tgui/packages/tgui/interfaces/Jukebox.js @@ -0,0 +1,117 @@ +import { round } from 'common/math'; +import { sortBy } from 'common/collections'; +import { useBackend } from "../backend"; +import { Box, Button, LabeledList, ProgressBar, Section, Slider } from "../components"; +import { Window } from "../layouts"; + +export const Jukebox = (props, context) => { + const { act, data } = useBackend(context); + + const { + playing, + loop_mode, + volume, + current_track_ref, + current_track, + percent, + tracks, + } = data; + + return ( + + +
    + + + {playing && current_track && ( + + {current_track.title} by {current_track.artist || "Unkown"} + + ) || ( + + Stopped + + )} + + + + + + + + + + + + + + + + round(val * 100, 1) + "%"} + onChange={(e, val) => act("volume", { val: round(val, 2) })} /> + + +
    +
    + {tracks.length && sortBy(a => a.title)(tracks).map(track => ( + + )) || ( + + Error: No songs loaded. + + )} +
    +
    +
    + ); +}; \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/LookingGlass.js b/tgui/packages/tgui/interfaces/LookingGlass.js new file mode 100644 index 0000000000..f7a1578950 --- /dev/null +++ b/tgui/packages/tgui/interfaces/LookingGlass.js @@ -0,0 +1,60 @@ +import { round } from 'common/math'; +import { Fragment } from 'inferno'; +import { useBackend } from "../backend"; +import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../components"; +import { Window } from "../layouts"; + +export const LookingGlass = (props, context) => { + const { act, data } = useBackend(context); + + const { + supportedPrograms, + currentProgram, + immersion, + gravity, + } = data; + + let height = Math.min(180 + (supportedPrograms.length * 23), 600); + + return ( + + +
    + {supportedPrograms.map(program => ( + + ))} +
    +
    + + + + + + + + +
    +
    +
    + ); +}; \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/MedicalRecords.js b/tgui/packages/tgui/interfaces/MedicalRecords.js index c5da8480b5..7af94c3501 100644 --- a/tgui/packages/tgui/interfaces/MedicalRecords.js +++ b/tgui/packages/tgui/interfaces/MedicalRecords.js @@ -231,7 +231,7 @@ const MedicalRecordsViewGeneral = (_properties, context) => { {general.fields.map((field, i) => ( - {field.value} + {field.value.split("\n").map(m => {m})} {!!field.edit && ( + + + }> + + {items.map(item => ( + + {item.amt} {item.extra} + + ))} + + + ) || ( +
    + + {config.title} is empty. + +
    + )} +
    +
    + ); +}; \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/NIF.js b/tgui/packages/tgui/interfaces/NIF.js new file mode 100644 index 0000000000..f1029abccf --- /dev/null +++ b/tgui/packages/tgui/interfaces/NIF.js @@ -0,0 +1,255 @@ +import { round } from 'common/math'; +import { Fragment } from 'inferno'; +import { useBackend, useLocalState } from "../backend"; +import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Modal, Section, Dropdown, AnimatedNumber, NoticeBox, Table } from "../components"; +import { Window } from "../layouts"; + +const NIF_WORKING = 0; +const NIF_POWFAIL = 1; +const NIF_TEMPFAIL = 2; +const NIF_INSTALLING = 3; +const NIF_PREINSTALL = 4; + +const validThemes = [ + "abductor", + "cardtable", + "hackerman", + "malfunction", + "ntos", + "paper", + "retro", + "syndicate", +]; + +export const NIF = (props, context) => { + const { act, config, data } = useBackend(context); + + const { + theme, + last_notification, + } = data; + + const [settingsOpen, setSettingsOpen] = useLocalState(context, "settingsOpen", false); + const [viewingModule, setViewing] = useLocalState(context, "viewingModule", null); + + return ( + + + {!!last_notification && ( + + + + {last_notification} + +
    +
    + )} + {!!viewingModule && ( + +
    + { + act("uninstall", { module: viewingModule.ref }); + setViewing(null); + }} /> +
    +
    + )} +
    setSettingsOpen(!settingsOpen)} /> + }> + {settingsOpen && || } +
    +
    +
    + ); +}; + +const getNifCondition = (nif_stat, nif_percent) => { + switch (nif_stat) { + case NIF_WORKING: + if (nif_percent < 25) { + return "Service Needed Soon"; + } else { + return "Operating Normally"; + } + break; + case NIF_POWFAIL: + return "Insufficient Energy!"; + break; + case NIF_TEMPFAIL: + return "System Failure!"; + break; + case NIF_INSTALLING: + return "Adapting To User"; + break; + } + return "Unknown"; +}; + +const getNutritionText = (nutrition, isSynthetic) => { + if (isSynthetic) { + if (nutrition >= 450) { + return "Overcharged"; + } else if (nutrition >= 250) { + return "Good Charge"; + } + return "Low Charge"; + } + + if (nutrition >= 250) { + return "NIF Power Requirement met."; + } else if (nutrition >= 150) { + return "Fluctuations in available power."; + } + return "Power failure imminent."; +}; + +const NIFMain = (props, context) => { + const { act, config, data } = useBackend(context); + + const { + nif_percent, + nif_stat, + last_notification, + nutrition, + isSynthetic, + modules, + } = data; + + const { + setViewing, + } = props; + + return ( + + + + + {getNifCondition(nif_stat, nif_percent)} (%) + + + + + {getNutritionText(nutrition, isSynthetic)} + + + +
    + + {modules.map(module => ( + + act("uninstall", { module: module.ref })} /> +
    +
    + ); +}; + +const NIFSettings = (props, context) => { + const { act, data } = useBackend(context); + + const { + theme, + } = data; + + return ( + + + act("setTheme", { theme: val })} /> + + + ); +}; \ No newline at end of file diff --git a/tgui/packages/tgui/interfaces/Newscaster.js b/tgui/packages/tgui/interfaces/Newscaster.js new file mode 100644 index 0000000000..3caf6a80d1 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Newscaster.js @@ -0,0 +1,570 @@ +import { decodeHtmlEntities } from 'common/string'; +import { Fragment } from 'inferno'; +import { useBackend, useSharedState } from "../backend"; +import { Box, Button, Flex, Icon, LabeledList, Input, ProgressBar, Section, NoticeBox } from "../components"; +import { Window } from "../layouts"; +import { TemporaryNotice } from './common/TemporaryNotice'; + +const NEWSCASTER_SCREEN_MAIN = "Main Menu"; +const NEWSCASTER_SCREEN_NEWCHANNEL = "New Channel"; +const NEWSCASTER_SCREEN_VIEWLIST = "View List"; +const NEWSCASTER_SCREEN_NEWSTORY = "New Story"; +const NEWSCASTER_SCREEN_PRINT = "Print"; +const NEWSCASTER_SCREEN_NEWWANTED = "New Wanted"; +const NEWSCASTER_SCREEN_VIEWWANTED = "View Wanted"; +const NEWSCASTER_SCREEN_SELECTEDCHANNEL = "View Selected Channel"; + +export const Newscaster = (props, context) => { + const { act, data } = useBackend(context); + + const { + screen, + user, + } = data; + + return ( + + + + + + + ); +}; + +const NewscasterContent = (props, context) => { + const { act, data } = useBackend(context); + + const { + user, + } = data; + + const [screen, setScreen] = useSharedState(context, "screen", NEWSCASTER_SCREEN_MAIN); + let Template = screenToTemplate[screen]; + + return ( + +