diff --git a/.gitattributes b/.gitattributes index c5587f6042..6f1fee8150 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,12 @@ +## Enforce text mode and LF line breaks +*.cjs text eol=lf +*.css text eol=lf +*.js text eol=lf +*.jsx text eol=lf +*.scss text eol=lf +*.ts text eol=lf +*.tsx text eol=lf + ## Enforce binary mode *.dll binary *.exe binary diff --git a/.gitignore b/.gitignore index a18ba4a703..9140a7c159 100644 --- a/.gitignore +++ b/.gitignore @@ -11,10 +11,12 @@ vchat.db* *.before *.pyc *.pid -data -data/ cfg/ +#Ignore everything in datafolder and subdirectories +/data/**/* +/tmp/**/* + #Visual studio stuff *.vscode/* !/.vscode/launch.json diff --git a/code/__defines/chat.dm b/code/__defines/chat.dm new file mode 100644 index 0000000000..37624e1f4d --- /dev/null +++ b/code/__defines/chat.dm @@ -0,0 +1,26 @@ +/*! + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + +#define MESSAGE_TYPE_SYSTEM "system" +#define MESSAGE_TYPE_LOCALCHAT "localchat" +#define MESSAGE_TYPE_PLOCALCHAT "plocalchat" +#define MESSAGE_TYPE_RADIO "radio" +#define MESSAGE_TYPE_NIF "nif" +#define MESSAGE_TYPE_INFO "info" +#define MESSAGE_TYPE_WARNING "warning" +#define MESSAGE_TYPE_DEADCHAT "deadchat" +#define MESSAGE_TYPE_OOC "ooc" +#define MESSAGE_TYPE_LOOC "looc" +#define MESSAGE_TYPE_ADMINPM "adminpm" +#define MESSAGE_TYPE_MENTORPM "mentorpm" +#define MESSAGE_TYPE_COMBAT "combat" +#define MESSAGE_TYPE_ADMINCHAT "adminchat" +#define MESSAGE_TYPE_PRAYER "prayer" +#define MESSAGE_TYPE_MODCHAT "modchat" +#define MESSAGE_TYPE_RLOOC "rlooc" +#define MESSAGE_TYPE_EVENTCHAT "eventchat" +#define MESSAGE_TYPE_ADMINLOG "adminlog" +#define MESSAGE_TYPE_ATTACKLOG "attacklog" +#define MESSAGE_TYPE_DEBUG "debug" diff --git a/code/__defines/logging.dm b/code/__defines/logging.dm new file mode 100644 index 0000000000..07a121d9bb --- /dev/null +++ b/code/__defines/logging.dm @@ -0,0 +1,2 @@ +#define SEND_TEXT(target, text) DIRECT_OUTPUT(target, text) +#define WRITE_FILE(file, text) DIRECT_OUTPUT(file, text) diff --git a/code/__defines/mobs_vr.dm b/code/__defines/mobs_vr.dm index 23e0b405cd..52e8d86525 100644 --- a/code/__defines/mobs_vr.dm +++ b/code/__defines/mobs_vr.dm @@ -50,3 +50,7 @@ #define SELECTS_BODYTYPE_FALSE 0 #define SELECTS_BODYTYPE_CUSTOM 1 #define SELECTS_BODYTYPE_SHAPESHIFTER 2 + +#define MARKING_NONDIGI_ONLY (1 << 0) +#define MARKING_DIGITIGRADE_ONLY (1 << 1) +#define MARKING_ALL_LEGS MARKING_NONDIGI_ONLY|MARKING_DIGITIGRADE_ONLY diff --git a/code/__defines/span_vr.dm b/code/__defines/span_vr.dm index ed4072b31f..549098f2d8 100644 --- a/code/__defines/span_vr.dm +++ b/code/__defines/span_vr.dm @@ -29,7 +29,7 @@ #define span_emote(str) ("" + str + "") -#define span_emote_subtle(str) ("" + str + "") +#define span_emote_subtle(str) ("" + str + "") #define span_attack(str) ("" + str + "") #define span_moderate(str) ("" + str + "") @@ -87,4 +87,4 @@ #define span_red(str) ("" + str + "") #define span_orange(str) ("" + str + "") #define span_blue(str) ("" + str + "") -#define span_green(str) ("" + str + "") \ No newline at end of file +#define span_green(str) ("" + str + "") diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index 1500ebb504..6474a946ef 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -49,6 +49,26 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_GAME, RUNLEVEL_POSTGAME) #define RUNLEVEL_FLAG_TO_INDEX(flag) (log(2, flag) + 1) // Convert from the runlevel bitfield constants to index in runlevel_flags list +//! ### SS initialization hints +/** + * Negative values incidate a failure or warning of some kind, positive are good. + * 0 and 1 are unused so that TRUE and FALSE are guarenteed to be invalid values. + */ + +/// Subsystem failed to initialize entirely. Print a warning, log, and disable firing. +#define SS_INIT_FAILURE -2 + +/// The default return value which must be overriden. Will succeed with a warning. +#define SS_INIT_NONE -1 + +/// Subsystem initialized sucessfully. +#define SS_INIT_SUCCESS 2 + +/// Successful, but don't print anything. Useful if subsystem was disabled. +#define SS_INIT_NO_NEED 3 + +//! ### SS initialization load orders + // Subsystem init_order, from highest priority to lowest priority // Subsystems shutdown in the reverse of the order they initialize in // The numbers just define the ordering, they are meaningless otherwise. @@ -104,6 +124,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define FIRE_PRIORITY_ORBIT 7 #define FIRE_PRIORITY_VOTE 8 #define FIRE_PRIORITY_INSTRUMENTS 9 +#define FIRE_PRIORITY_PING 10 #define FIRE_PRIORITY_AI 10 #define FIRE_PRIORITY_GARBAGE 15 #define FIRE_PRIORITY_ALARM 20 diff --git a/code/__defines/tgui.dm b/code/__defines/tgui.dm index 1215382ce7..96664cf2b3 100644 --- a/code/__defines/tgui.dm +++ b/code/__defines/tgui.dm @@ -4,9 +4,9 @@ #define TGUI_WINDOW_HARD_LIMIT 9 /// Maximum ping timeout allowed to detect zombie windows -#define TGUI_PING_TIMEOUT 4 SECONDS +#define TGUI_PING_TIMEOUT (4 SECONDS) /// Used for rate-limiting to prevent DoS by excessively refreshing a TGUI window -#define TGUI_REFRESH_FULL_UPDATE_COOLDOWN 5 SECONDS +#define TGUI_REFRESH_FULL_UPDATE_COOLDOWN (1 SECONDS) /// Window does not exist #define TGUI_WINDOW_CLOSED 0 @@ -36,4 +36,4 @@ #define TGUI_MODAL_OPEN 1 #define TGUI_MODAL_DELEGATE 2 #define TGUI_MODAL_ANSWER 3 -#define TGUI_MODAL_CLOSE 4 \ No newline at end of file +#define TGUI_MODAL_CLOSE 4 diff --git a/code/_global_vars/_regexes.dm b/code/_global_vars/_regexes.dm new file mode 100644 index 0000000000..7e9ea99d1f --- /dev/null +++ b/code/_global_vars/_regexes.dm @@ -0,0 +1,2 @@ +//These are a bunch of regex datums for use /((any|every|no|some|head|foot)where(wolf)?\sand\s)+(\.[\.\s]+\s?where\?)?/i +GLOBAL_DATUM_INIT(is_http_protocol, /regex, regex("^https?://")) diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm index 95b7758922..e25c0652a9 100644 --- a/code/_helpers/global_lists.dm +++ b/code/_helpers/global_lists.dm @@ -54,7 +54,7 @@ var/datum/category_collection/underwear/global_underwear = new() //Backpacks var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Alt", "Messenger Bag", "Sports Bag", "Strapless Satchel") //VOREStation edit -var/global/list/pdachoicelist = list("Default", "Slim", "Old", "Rugged", "Holographic", "Wrist-Bound", "Slider") +var/global/list/pdachoicelist = list("Default", "Slim", "Old", "Rugged", "Holographic", "Wrist-Bound","Slider", "Vintage") var/global/list/exclude_jobs = list(/datum/job/ai,/datum/job/cyborg) // Visual nets diff --git a/code/_helpers/logging.dm b/code/_helpers/logging.dm index 9e3a7addb8..737b00a7d0 100644 --- a/code/_helpers/logging.dm +++ b/code/_helpers/logging.dm @@ -163,10 +163,6 @@ if(Debug2) WRITE_LOG(diary, "TOPIC: [text]") -/proc/log_href(text) - // Configs are checked by caller - WRITE_LOG(href_logfile, "HREF: [text]") - /proc/log_unit_test(text) to_world_log("## UNIT_TEST: [text]") @@ -176,22 +172,6 @@ #define log_reftracker(msg) #endif -/proc/log_tgui(user_or_client, text) - if(!text) - stack_trace("Pointless log_tgui message") - return - var/entry = "" - if(!user_or_client) - entry += "no user" - else if(istype(user_or_client, /mob)) - var/mob/user = user_or_client - entry += "[user.ckey] (as [user])" - else if(istype(user_or_client, /client)) - var/client/client = user_or_client - entry += "[client.ckey]" - entry += ":\n[text]" - WRITE_LOG(diary, entry) - /proc/log_asset(text) WRITE_LOG(diary, "ASSET: [text]") diff --git a/code/_helpers/logging/ui.dm b/code/_helpers/logging/ui.dm new file mode 100644 index 0000000000..ed6a0b6588 --- /dev/null +++ b/code/_helpers/logging/ui.dm @@ -0,0 +1,36 @@ +/proc/log_href(text) + //WRITE_LOG(GLOB.world_href_log, "HREF: [text]") + WRITE_LOG(href_logfile, "HREF: [text]") + +/** + * Appends a tgui-related log entry. All arguments are optional. + */ +/proc/log_tgui(user, message, context, + datum/tgui_window/window, + datum/src_object) + var/entry = "" + // Insert user info + if(!user) + entry += "" + else if(istype(user, /mob)) + var/mob/mob = user + entry += "[mob.ckey] (as [mob] at [mob.x],[mob.y],[mob.z])" + else if(istype(user, /client)) + var/client/client = user + entry += "[client.ckey]" + // Insert context + if(context) + entry += " in [context]" + else if(window) + entry += " in [window.id]" + // Resolve src_object + if(!src_object && window?.locked_by) + src_object = window.locked_by.src_object + // Insert src_object info + if(src_object) + entry += "\nUsing: [src_object.type] [REF(src_object)]" + // Insert message + if(message) + entry += "\n[message]" + //WRITE_LOG(GLOB.tgui_log, entry) + WRITE_LOG(diary, entry) diff --git a/code/datums/supplypacks/hospitality_vr.dm b/code/datums/supplypacks/hospitality_vr.dm index da65a8760a..ceb35b6c5d 100644 --- a/code/datums/supplypacks/hospitality_vr.dm +++ b/code/datums/supplypacks/hospitality_vr.dm @@ -91,9 +91,32 @@ /datum/supply_pack/randomised/hospitality/jaffacake contains = list( - /obj/item/weapon/storage/box/jaffacake = 10 + /obj/item/weapon/storage/box/jaffacake, + /obj/item/weapon/storage/box/jaffacake, + /obj/item/weapon/storage/box/jaffacake, + /obj/item/weapon/storage/box/jaffacake, + /obj/item/weapon/storage/box/jaffacake, + /obj/item/weapon/storage/box/jaffacake, + /obj/item/weapon/storage/box/jaffacake, + /obj/item/weapon/storage/box/jaffacake, + /obj/item/weapon/storage/box/jaffacake, + /obj/item/weapon/storage/box/jaffacake ) name = "Desatti jaffa cake crate" cost = 25 containertype = /obj/structure/closet/crate/freezer containername = "Desatti jaffa cake crate" + +/datum/supply_pack/randomised/hospitality/sweets + num_contained = 5 + contains = list( + /obj/item/weapon/storage/box/jaffacake, + /obj/item/weapon/storage/box/winegum, + /obj/item/weapon/storage/box/saucer, + /obj/item/weapon/storage/box/shrimpsandbananas, + /obj/item/weapon/storage/box/rhubarbcustard + ) + name = "Sweets crate" + cost = 25 + containertype = /obj/structure/closet/crate/freezer + containername = "Sweets crate" diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm index 791524d221..e7f7c4f550 100644 --- a/code/game/dna/dna2.dm +++ b/code/game/dna/dna2.dm @@ -120,6 +120,7 @@ var/global/list/datum/dna/gene/dna_genes[0] var/custom_exclaim var/list/custom_heat = list() var/list/custom_cold = list() + var/digitigrade = 0 //0, Not FALSE, for future use as indicator for digitigrade types // VOREStation // New stuff @@ -148,6 +149,7 @@ var/global/list/datum/dna/gene/dna_genes[0] new_dna.custom_exclaim=custom_exclaim //VOREStaton Edit new_dna.custom_heat=custom_heat //VOREStation Edit new_dna.custom_cold=custom_cold //VOREStation Edit + new_dna.digitigrade=src.digitigrade //VOREStation Edit var/list/body_markings_genetic = (body_markings - body_marking_nopersist_list) new_dna.body_markings=body_markings_genetic.Copy() for(var/b=1;b<=DNA_SE_LENGTH;b++) @@ -222,6 +224,7 @@ var/global/list/datum/dna/gene/dna_genes[0] src.custom_exclaim = character.custom_exclaim src.custom_heat = character.custom_heat src.custom_cold = character.custom_cold + src.digitigrade = character.digitigrade // +1 to account for the none-of-the-above possibility SetUIValueRange(DNA_UI_EAR_STYLE, ear_style + 1, ear_styles_list.len + 1, 1) diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 2a79c6aaac..474ef45c6b 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -86,9 +86,9 @@ /obj/item/borg/upgrade/vtec/action(var/mob/living/silicon/robot/R) if(..()) return 0 - if(R.speed == -1) + if(R.speed == -1 || (/mob/living/silicon/robot/proc/toggle_vtec in R.verbs)) return 0 - + R.verbs += /mob/living/silicon/robot/proc/toggle_vtec R.speed-- return 1 @@ -214,4 +214,4 @@ R.add_language(LANGUAGE_TERMINUS, 1) R.add_language(LANGUAGE_ZADDAT, 1) - return 1 \ No newline at end of file + return 1 diff --git a/code/game/objects/items/robot/robot_upgrades_vr.dm b/code/game/objects/items/robot/robot_upgrades_vr.dm index f034fbba59..4b80bdc03e 100644 --- a/code/game/objects/items/robot/robot_upgrades_vr.dm +++ b/code/game/objects/items/robot/robot_upgrades_vr.dm @@ -90,6 +90,43 @@ T.upgraded_capacity = TRUE return 1 +//adds the capability to ingest items to the sleeper modules as optional upgrade +/obj/item/borg/upgrade/bellycapupgrade + name = "robohound capability expansion module" + desc = "Used to enable a robohound's sleeper to ingest items. This only affects sleepers, and has no effect on compactor bellies. Can only be applied once." + icon_state = "cyborg_upgrade2" + item_state = "cyborg_upgrade" + require_module = 1 + +/obj/item/borg/upgrade/bellycapupgrade/action(var/mob/living/silicon/robot/R) + if(..()) return 0 + + if(!R.module)//can work + to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") + to_chat(usr, "There's no mounting point for the module!") + return 0 + + var/obj/item/device/dogborg/sleeper/T = locate() in R.module + if(!T) + T = locate() in R.module.contents + if(!T) + T = locate() in R.module.modules + if(!T) + to_chat(usr, "This robot has had its processor removed!") + return 0 + + if(T.compactor)// == TRUE, the belly unit is a compactor and no sleeper unit already + to_chat(R, "Maximum capability achieved for this hardpoint!") + to_chat(usr, "There's no room for another capability upgrade!") + return 0 + else + var/X = T.max_item_count*2 //double the capacity from 1 to 2 to allow sleepers to store some items, at most 4 with both upgrades + T.max_item_count = X //I couldn't do T = maxitem*2 for some reason. + to_chat(R, "Internal capability upgraded.") + to_chat(usr, "Internal capability upgraded.") + T.compactor = TRUE + return 1 + //Advanced RPED /obj/item/borg/upgrade/advrped name = "Advanced Rapid Part Exchange Device" @@ -202,4 +239,4 @@ if(T) to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") to_chat(usr, "There's no mounting point for the module!") - return 0 \ No newline at end of file + return 0 diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm index 9b6ba7b992..ba98a00251 100644 --- a/code/game/objects/items/trash.dm +++ b/code/game/objects/items/trash.dm @@ -445,6 +445,10 @@ name = "scotch egg packaging" icon_state = "scotchegg" +/obj/item/trash/porkpie + name = "pork pie packaging" + icon_state = "porkpie" + //Candy Bars (1-10) /obj/item/trash/candy/cb01 name = "\improper Tau Ceti Bar wrapper" diff --git a/code/game/objects/items/trash_vr.dm b/code/game/objects/items/trash_vr.dm index 08fbdda5b6..4a50236a62 100644 --- a/code/game/objects/items/trash_vr.dm +++ b/code/game/objects/items/trash_vr.dm @@ -95,4 +95,14 @@ /obj/item/trash/ratpacktaco name = "\improper Prepackaged Meal Tray" icon = 'icons/obj/trash_vr.dmi' - icon_state = "altevian_pack_taco-trash" \ No newline at end of file + icon_state = "altevian_pack_taco-trash" + +/obj/item/trash/ratpackcake + name = "\improper Prepackaged Meal Tray" + icon = 'icons/obj/trash_vr.dmi' + icon_state = "altevian_pack_cake-trash" + +/obj/item/trash/ratpackmeat + name = "\improper Prepackaged Meal Tray" + icon = 'icons/obj/trash_vr.dmi' + icon_state = "altevian_pack_meat-trash" \ No newline at end of file diff --git a/code/game/objects/items/weapons/grenades/confetti.dm b/code/game/objects/items/weapons/grenades/confetti.dm new file mode 100644 index 0000000000..a2e5559d91 --- /dev/null +++ b/code/game/objects/items/weapons/grenades/confetti.dm @@ -0,0 +1,51 @@ +/obj/item/weapon/grenade/confetti + desc = "It is set to detonate in 2 seconds. These party grenades will make everyone jump with joy (or fright)!" + name = "grenatti" + icon = 'icons/obj/grenade.dmi' + icon_state = "grenade" + det_time = 20 + item_state = "grenade" + slot_flags = SLOT_BELT + var/datum/effect/effect/system/confetti_spread + var/confetti_strength = 8 + +/obj/item/weapon/grenade/confetti/New() + ..() + src.confetti_spread = new /datum/effect/effect/system/confetti_spread() + src.confetti_spread.attach(src) + +/obj/item/weapon/grenade/confetti/Destroy() + qdel(confetti_spread) + confetti_spread = null + return ..() + +/obj/item/weapon/grenade/confetti/detonate() //Find a good confetti firework or pop sound effect later + playsound(src.loc, 'sound/effects/snap.ogg', 50, 1, -3) + src.confetti_spread.set_up(10, 0, usr.loc) + spawn(0) + for(var/i = 1 to confetti_strength) + src.confetti_spread.start() + sleep(10) + qdel(src) + + return + +/obj/item/weapon/grenade/confetti/party_ball //Intended to be used only with the confetti cannon. + name = "party ball" + desc = "Full of !!FUN!!" + icon = 'icons/obj/grenade.dmi' + icon_state = "party_ball" + confetti_strength = 2 + det_time = 1 + throwforce = 0 //Confetti cannon is only fun to shoot at people if it deals no damage. + +/obj/item/weapon/grenade/confetti/party_ball/detonate() //Could condense this by making the sound a variable in the parent but I'm lazy. + playsound(src.loc, 'sound/effects/confetti_ball.ogg', 50, 1, -3) + src.confetti_spread.set_up(10, 0, usr.loc) + spawn(0) + for(var/i = 1 to confetti_strength) + src.confetti_spread.start() + sleep(10) + qdel(src) + + return \ No newline at end of file diff --git a/code/game/objects/items/weapons/id cards/cards.dm b/code/game/objects/items/weapons/id cards/cards.dm index 260eff8539..c02213078b 100644 --- a/code/game/objects/items/weapons/id cards/cards.dm +++ b/code/game/objects/items/weapons/id cards/cards.dm @@ -136,3 +136,29 @@ uses = CEILING(uses, 1) //Ensures no decimal uses nonsense, rounds up to be nice to_chat(usr, "You add \the [O] to \the [src]. Increasing the uses of \the [src] to [uses].") qdel(O) + + +/obj/item/weapon/card/emag/borg + uses = 12 + var/burnt_out = FALSE + +/obj/item/weapon/card/emag/borg/afterattack(atom/A, mob/user, proximity, var/click_parameters) + if(!proximity || burnt_out) return + var/used_uses = A.emag_act(uses, user, src) + if(used_uses < 0) + return ..(A, user, proximity, click_parameters) + + uses -= used_uses + A.add_fingerprint(user) + //Vorestation Edit: Because some things (read lift doors) don't get emagged + if(used_uses) + log_and_message_admins("emagged \an [A].") + else + log_and_message_admins("attempted to emag \an [A].") + // Vorestation Edit: End of Edit + + if(uses<1) + user.visible_message("\The [src] fizzles and sparks - it seems it's been used once too often, and is now spent.") + burnt_out = TRUE + + return 1 \ No newline at end of file diff --git a/code/game/objects/random/mapping.dm b/code/game/objects/random/mapping.dm index b8ff810fe2..788ee12ba2 100644 --- a/code/game/objects/random/mapping.dm +++ b/code/game/objects/random/mapping.dm @@ -84,7 +84,8 @@ prob(5);/obj/machinery/vending/sovietsoda, prob(5);/obj/machinery/vending/sovietvend, prob(5);/obj/machinery/vending/radren, - prob(3);/obj/machinery/vending/altevian) //VOREStation Edit End + prob(3);/obj/machinery/vending/altevian, + prob(5);/obj/machinery/vending/desatti) //VOREStation Edit End /obj/random/vendorfood //Random food vendors for station use name = "random snack vending machine" @@ -98,7 +99,8 @@ /obj/machinery/vending/sol, /obj/machinery/vending/snix, /obj/machinery/vending/snlvend, - /obj/machinery/vending/altevian) + /obj/machinery/vending/altevian, + /obj/machinery/vending/desatti) /obj/random/vendordrink //Random drink vendors for station use name = "random drink vending machine" diff --git a/code/game/objects/structures/crates_lockers/closets/l3closet.dm b/code/game/objects/structures/crates_lockers/closets/l3closet.dm index c592c3e69f..e1c551b551 100644 --- a/code/game/objects/structures/crates_lockers/closets/l3closet.dm +++ b/code/game/objects/structures/crates_lockers/closets/l3closet.dm @@ -44,7 +44,8 @@ starts_with = list( /obj/item/clothing/suit/bio_suit/scientist, - /obj/item/clothing/head/bio_hood/scientist) + /obj/item/clothing/head/bio_hood/scientist, + /obj/item/weapon/storage/bag/xeno = 1) /obj/structure/closet/l3closet/scientist/double starts_with = list( diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm index 36c5c67200..acbd82a348 100644 --- a/code/modules/asset_cache/asset_list_items.dm +++ b/code/modules/asset_cache/asset_list_items.dm @@ -1,13 +1,4 @@ //DEFINITIONS FOR ASSET DATUMS START HERE. - -/datum/asset/simple/tgui - // keep_local_name = TRUE - assets = list( - "tgui.bundle.js" = file("tgui/public/tgui.bundle.js"), - "tgui.bundle.css" = file("tgui/public/tgui.bundle.css"), - ) - - /datum/asset/simple/headers assets = list( "alarm_green.gif" = 'icons/program_icons/alarm_green.gif', @@ -154,11 +145,6 @@ // /datum/asset/simple/fontawesome // ) -/datum/asset/simple/jquery - assets = list( - "jquery.min.js" = 'code/modules/tooltip/jquery.min.js', - ) - // /datum/asset/simple/goonchat // assets = list( // "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js', @@ -167,24 +153,6 @@ // "browserOutput_white.css" = 'code/modules/goonchat/browserassets/css/browserOutput_white.css', // ) -/datum/asset/simple/fontawesome - assets = list( - "fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot', - "fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff', - "fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot', - "fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff', - "font-awesome.css" = 'html/font-awesome/css/all.min.css', - "v4shim.css" = 'html/font-awesome/css/v4-shims.min.css' - ) - -/datum/asset/simple/tgfont - assets = list( - "tgfont.eot" = file("tgui/packages/tgfont/dist/tgfont.eot"), - "tgfont.woff2" = file("tgui/packages/tgfont/dist/tgfont.woff2"), - "tgfont.css" = file("tgui/packages/tgfont/dist/tgfont.css"), - ) - - // /datum/asset/spritesheet/goonchat // name = "chat" diff --git a/code/modules/asset_cache/assets/fontawesome.dm b/code/modules/asset_cache/assets/fontawesome.dm new file mode 100644 index 0000000000..72af739f4e --- /dev/null +++ b/code/modules/asset_cache/assets/fontawesome.dm @@ -0,0 +1,9 @@ +/datum/asset/simple/fontawesome + assets = list( + "fa-regular-400.eot" = 'html/font-awesome/webfonts/fa-regular-400.eot', + "fa-regular-400.woff" = 'html/font-awesome/webfonts/fa-regular-400.woff', + "fa-solid-900.eot" = 'html/font-awesome/webfonts/fa-solid-900.eot', + "fa-solid-900.woff" = 'html/font-awesome/webfonts/fa-solid-900.woff', + "font-awesome.css" = 'html/font-awesome/css/all.min.css', + "v4shim.css" = 'html/font-awesome/css/v4-shims.min.css' + ) diff --git a/code/modules/asset_cache/assets/jquery.dm b/code/modules/asset_cache/assets/jquery.dm new file mode 100644 index 0000000000..2a28293fbb --- /dev/null +++ b/code/modules/asset_cache/assets/jquery.dm @@ -0,0 +1,4 @@ +/datum/asset/simple/jquery + assets = list( + "jquery.min.js" = 'code/modules/tooltip/jquery.min.js', + ) diff --git a/code/modules/asset_cache/assets/tgfont.dm b/code/modules/asset_cache/assets/tgfont.dm new file mode 100644 index 0000000000..48db3e4e67 --- /dev/null +++ b/code/modules/asset_cache/assets/tgfont.dm @@ -0,0 +1,6 @@ +/datum/asset/simple/tgfont + assets = list( + "tgfont.eot" = file("tgui/packages/tgfont/dist/tgfont.eot"), + "tgfont.woff2" = file("tgui/packages/tgfont/dist/tgfont.woff2"), + "tgfont.css" = file("tgui/packages/tgfont/dist/tgfont.css"), + ) diff --git a/code/modules/asset_cache/assets/tgui.dm b/code/modules/asset_cache/assets/tgui.dm new file mode 100644 index 0000000000..6874c24eea --- /dev/null +++ b/code/modules/asset_cache/assets/tgui.dm @@ -0,0 +1,15 @@ +/datum/asset/simple/tgui + // keep_local_name = TRUE + assets = list( + "tgui.bundle.js" = file("tgui/public/tgui.bundle.js"), + "tgui.bundle.css" = file("tgui/public/tgui.bundle.css"), + ) + +/* Comment will be removed in later part +/datum/asset/simple/tgui_panel + // keep_local_name = TRUE + assets = list( + "tgui-panel.bundle.js" = file("tgui/public/tgui-panel.bundle.js"), + "tgui-panel.bundle.css" = file("tgui/public/tgui-panel.bundle.css"), + ) +*/ diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm index 292655377f..7bfbf51a03 100644 --- a/code/modules/client/client defines.dm +++ b/code/modules/client/client defines.dm @@ -1,11 +1,42 @@ +/** + * Client datum + * + * A datum that is created whenever a user joins a BYOND world, one will exist for every active connected + * player + * + * when they first connect, this client object is created and [/client/New] is called + * + * When they disconnect, this client object is deleted and [/client/Del] is called + * + * All client topic calls go through [/client/Topic] first, so a lot of our specialised + * topic handling starts here + */ /client - ////////////////////// - //BLACK MAGIC THINGS// - ////////////////////// + /** + * This line makes clients parent type be a datum + * + * By default in byond if you define a proc on datums, that proc will exist on nearly every single type + * from icons to images to atoms to mobs to objs to turfs to areas, it won't however, appear on client + * + * instead by default they act like their own independent type so while you can do isdatum(icon) + * and have it return true, you can't do isdatum(client), it will always return false. + * + * This makes writing oo code hard, when you have to consider this extra special case + * + * This line prevents that, and has never appeared to cause any ill effects, while saving us an extra + * pain to think about + * + * This line is widely considered black fucking magic, and the fact it works is a puzzle to everyone + * involved, including the current engine developer, lummox + * + * If you are a future developer and the engine source is now available and you can explain why this + * is the way it is, please do update this comment + */ parent_type = /datum //////////////// //ADMIN THINGS// //////////////// + ///Contains admin info. Null if client is not an admin. var/datum/admins/holder = null var/datum/admins/deadmin_holder = null var/buildmode = 0 @@ -18,6 +49,7 @@ ///////// //OTHER// ///////// + ///Player preferences datum for the client var/datum/preferences/prefs = null var/moving = null var/adminobs = null diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index 9ed4d03b66..084b3ff437 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -153,6 +153,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O S["r_wing3"] >> pref.r_wing3 S["g_wing3"] >> pref.g_wing3 S["b_wing3"] >> pref.b_wing3 + S["digitigrade"] >> pref.digitigrade S["Wingdings"] >> pref.wingdings //YWadd start S["colorblind_mono"] >> pref.colorblind_mono S["colorblind_vulp"] >> pref.colorblind_vulp @@ -222,6 +223,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O S["r_wing3"] << pref.r_wing3 S["g_wing3"] << pref.g_wing3 S["b_wing3"] << pref.b_wing3 + S["digitigrade"] << pref.digitigrade S["Wingdings"] << pref.wingdings //YWadd start S["colorblind_mono"] << pref.colorblind_mono S["colorblind_vulp"] << pref.colorblind_vulp @@ -291,6 +293,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.r_wing3 = sanitize_integer(pref.r_wing3, 0, 255, initial(pref.r_wing3)) pref.g_wing3 = sanitize_integer(pref.g_wing3, 0, 255, initial(pref.g_wing3)) pref.b_wing3 = sanitize_integer(pref.b_wing3, 0, 255, initial(pref.b_wing3)) + pref.digitigrade = sanitize_integer(pref.digitigrade, 0, 1, initial(pref.digitigrade)) pref.sanitize_body_styles() @@ -324,6 +327,16 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O character.g_synth = pref.g_synth character.b_synth = pref.b_synth character.synth_markings = pref.synth_markings + if(character.species.digi_allowed) + character.digitigrade = pref.digitigrade + else + character.digitigrade = 0 + + //sanity check + if(character.digitigrade == null) + character.digitigrade = 0 + pref.digitigrade = 0 + //YWadd START if(pref.species == "Grey")//YWadd START character.wingdings = pref.wingdings @@ -602,6 +615,9 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O . += "
Body Color
" . += "Change Color [color_square(pref.r_skin, pref.g_skin, pref.b_skin)]
" + if(mob_species.digi_allowed) + . += "
Digitigrade?: [pref.digitigrade ? "Yes" : "No"]
" + . += "

Genetics Settings

" var/list/ear_styles = pref.get_available_styles(global.ear_styles_list) @@ -822,6 +838,11 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.b_facial = hex2num(copytext(new_facial, 6, 8)) return TOPIC_REFRESH_UPDATE_PREVIEW + if(href_list["digitigrade"]) + pref.digitigrade = !pref.digitigrade + + return TOPIC_REFRESH_UPDATE_PREVIEW + else if(href_list["eye_color"]) if(!has_flag(mob_species, HAS_EYE_COLOR)) return TOPIC_NOACTION diff --git a/code/modules/client/preference_setup/general/04_equipment.dm b/code/modules/client/preference_setup/general/04_equipment.dm index c2cdf0b244..6d58301ba5 100644 --- a/code/modules/client/preference_setup/general/04_equipment.dm +++ b/code/modules/client/preference_setup/general/04_equipment.dm @@ -1,159 +1,159 @@ -/datum/preferences - var/list/all_underwear - var/list/all_underwear_metadata - -/datum/category_item/player_setup_item/general/equipment - name = "Clothing" - sort_order = 4 - -/datum/category_item/player_setup_item/general/equipment/load_character(var/savefile/S) - S["all_underwear"] >> pref.all_underwear - S["all_underwear_metadata"] >> pref.all_underwear_metadata - S["backbag"] >> pref.backbag - S["pdachoice"] >> pref.pdachoice - S["communicator_visibility"] >> pref.communicator_visibility - S["ttone"] >> pref.ttone //YW Edit - -/datum/category_item/player_setup_item/general/equipment/save_character(var/savefile/S) - S["all_underwear"] << pref.all_underwear - S["all_underwear_metadata"] << pref.all_underwear_metadata - S["backbag"] << pref.backbag - S["pdachoice"] << pref.pdachoice - S["communicator_visibility"] << pref.communicator_visibility - S["ttone"] << pref.ttone // YW EDIT - -// Moved from /datum/preferences/proc/copy_to() -/datum/category_item/player_setup_item/general/equipment/copy_to_mob(var/mob/living/carbon/human/character) - character.all_underwear.Cut() - character.all_underwear_metadata.Cut() - - for(var/underwear_category_name in pref.all_underwear) - var/datum/category_group/underwear/underwear_category = global_underwear.categories_by_name[underwear_category_name] - if(underwear_category) - var/underwear_item_name = pref.all_underwear[underwear_category_name] - character.all_underwear[underwear_category_name] = underwear_category.items_by_name[underwear_item_name] - if(pref.all_underwear_metadata[underwear_category_name]) - character.all_underwear_metadata[underwear_category_name] = pref.all_underwear_metadata[underwear_category_name] - else - pref.all_underwear -= underwear_category_name - - // TODO - Looks like this is duplicating the work of sanitize_character() if so, remove - if(pref.backbag > backbaglist.len || pref.backbag < 1) - pref.backbag = 2 //Same as above - character.backbag = pref.backbag - - if(pref.pdachoice > 7 || pref.pdachoice < 1) - pref.pdachoice = 1 - character.pdachoice = pref.pdachoice - -/datum/category_item/player_setup_item/general/equipment/sanitize_character() - if(!islist(pref.gear)) pref.gear = list() - - if(!istype(pref.all_underwear)) - pref.all_underwear = list() - - for(var/datum/category_group/underwear/WRC in global_underwear.categories) - for(var/datum/category_item/underwear/WRI in WRC.items) - if(WRI.is_default(pref.identifying_gender ? pref.identifying_gender : MALE)) - pref.all_underwear[WRC.name] = WRI.name - break - - if(!istype(pref.all_underwear_metadata)) - pref.all_underwear_metadata = list() - - for(var/underwear_category in pref.all_underwear) - var/datum/category_group/underwear/UWC = global_underwear.categories_by_name[underwear_category] - if(!UWC) - pref.all_underwear -= underwear_category - else - var/datum/category_item/underwear/UWI = UWC.items_by_name[pref.all_underwear[underwear_category]] - if(!UWI) - pref.all_underwear -= underwear_category - - for(var/underwear_metadata in pref.all_underwear_metadata) - if(!(underwear_metadata in pref.all_underwear)) - pref.all_underwear_metadata -= underwear_metadata - pref.backbag = sanitize_integer(pref.backbag, 1, backbaglist.len, initial(pref.backbag)) - pref.pdachoice = sanitize_integer(pref.pdachoice, 1, pdachoicelist.len, initial(pref.pdachoice)) - pref.ttone = sanitize(pref.ttone, 20)//YW Edit - -/datum/category_item/player_setup_item/general/equipment/content() - . = list() - . += "Equipment:
" - for(var/datum/category_group/underwear/UWC in global_underwear.categories) - var/item_name = pref.all_underwear[UWC.name] ? pref.all_underwear[UWC.name] : "None" - . += "[UWC.name]: [item_name]" - var/datum/category_item/underwear/UWI = UWC.items_by_name[item_name] - if(UWI) - for(var/datum/gear_tweak/gt in UWI.tweaks) - . += " [gt.get_contents(get_metadata(UWC.name, gt))]" - - . += "
" - . += "Backpack Type: [backbaglist[pref.backbag]]
" - . += "PDA Type: [pdachoicelist[pref.pdachoice]]
" - . += "Communicator Visibility: [(pref.communicator_visibility) ? "Yes" : "No"]
" - . += "Ringtone (leave blank for job default): [pref.ttone]
" //YW EDIT - - return jointext(.,null) - -/datum/category_item/player_setup_item/general/equipment/proc/get_metadata(var/underwear_category, var/datum/gear_tweak/gt) - var/metadata = pref.all_underwear_metadata[underwear_category] - if(!metadata) - metadata = list() - pref.all_underwear_metadata[underwear_category] = metadata - - var/tweak_data = metadata["[gt]"] - if(!tweak_data) - tweak_data = gt.get_default() - metadata["[gt]"] = tweak_data - return tweak_data - -/datum/category_item/player_setup_item/general/equipment/proc/set_metadata(var/underwear_category, var/datum/gear_tweak/gt, var/new_metadata) - var/list/metadata = pref.all_underwear_metadata[underwear_category] - metadata["[gt]"] = new_metadata - - -/datum/category_item/player_setup_item/general/equipment/OnTopic(var/href,var/list/href_list, var/mob/user) - if(href_list["change_backpack"]) - var/new_backbag = tgui_input_list(user, "Choose your character's style of bag:", "Character Preference", backbaglist, backbaglist[pref.backbag]) - if(!isnull(new_backbag) && CanUseTopic(user)) - pref.backbag = backbaglist.Find(new_backbag) - return TOPIC_REFRESH_UPDATE_PREVIEW - - else if(href_list["change_pda"]) - var/new_pdachoice = tgui_input_list(user, "Choose your character's style of PDA:", "Character Preference", pdachoicelist, pdachoicelist[pref.pdachoice]) - if(!isnull(new_pdachoice) && CanUseTopic(user)) - pref.pdachoice = pdachoicelist.Find(new_pdachoice) - return TOPIC_REFRESH - - else if(href_list["change_underwear"]) - var/datum/category_group/underwear/UWC = global_underwear.categories_by_name[href_list["change_underwear"]] - if(!UWC) - return - var/datum/category_item/underwear/selected_underwear = tgui_input_list(user, "Choose underwear:", "Character Preference", UWC.items, pref.all_underwear[UWC.name]) - if(selected_underwear && CanUseTopic(user)) - pref.all_underwear[UWC.name] = selected_underwear.name - return TOPIC_REFRESH_UPDATE_PREVIEW - - else if(href_list["underwear"] && href_list["tweak"]) - var/underwear = href_list["underwear"] - if(!(underwear in pref.all_underwear)) - return TOPIC_NOACTION - var/datum/gear_tweak/gt = locate(href_list["tweak"]) - if(!gt) - return TOPIC_NOACTION - var/new_metadata = gt.get_metadata(usr, get_metadata(underwear, gt)) - if(new_metadata) - set_metadata(underwear, gt, new_metadata) - return TOPIC_REFRESH_UPDATE_PREVIEW - else if(href_list["toggle_comm_visibility"]) - if(CanUseTopic(user)) - pref.communicator_visibility = !pref.communicator_visibility - return TOPIC_REFRESH - else if(href_list["set_ttone"]) //Start of YW EDIT - if(CanUseTopic(user)) - pref.ttone = sanitize(input(user, "Please enter a new ringtone.", "Character Preference") as null|text, 20) - return TOPIC_REFRESH //End of YW EDIT - - - return ..() +/datum/preferences + var/list/all_underwear + var/list/all_underwear_metadata + +/datum/category_item/player_setup_item/general/equipment + name = "Clothing" + sort_order = 4 + +/datum/category_item/player_setup_item/general/equipment/load_character(var/savefile/S) + S["all_underwear"] >> pref.all_underwear + S["all_underwear_metadata"] >> pref.all_underwear_metadata + S["backbag"] >> pref.backbag + S["pdachoice"] >> pref.pdachoice + S["communicator_visibility"] >> pref.communicator_visibility + S["ttone"] >> pref.ttone //YW Edit + +/datum/category_item/player_setup_item/general/equipment/save_character(var/savefile/S) + S["all_underwear"] << pref.all_underwear + S["all_underwear_metadata"] << pref.all_underwear_metadata + S["backbag"] << pref.backbag + S["pdachoice"] << pref.pdachoice + S["communicator_visibility"] << pref.communicator_visibility + S["ttone"] << pref.ttone // YW EDIT + +// Moved from /datum/preferences/proc/copy_to() +/datum/category_item/player_setup_item/general/equipment/copy_to_mob(var/mob/living/carbon/human/character) + character.all_underwear.Cut() + character.all_underwear_metadata.Cut() + + for(var/underwear_category_name in pref.all_underwear) + var/datum/category_group/underwear/underwear_category = global_underwear.categories_by_name[underwear_category_name] + if(underwear_category) + var/underwear_item_name = pref.all_underwear[underwear_category_name] + character.all_underwear[underwear_category_name] = underwear_category.items_by_name[underwear_item_name] + if(pref.all_underwear_metadata[underwear_category_name]) + character.all_underwear_metadata[underwear_category_name] = pref.all_underwear_metadata[underwear_category_name] + else + pref.all_underwear -= underwear_category_name + + // TODO - Looks like this is duplicating the work of sanitize_character() if so, remove + if(pref.backbag > backbaglist.len || pref.backbag < 1) + pref.backbag = 2 //Same as above + character.backbag = pref.backbag + + if(pref.pdachoice > 8 || pref.pdachoice < 1) + pref.pdachoice = 1 + character.pdachoice = pref.pdachoice + +/datum/category_item/player_setup_item/general/equipment/sanitize_character() + if(!islist(pref.gear)) pref.gear = list() + + if(!istype(pref.all_underwear)) + pref.all_underwear = list() + + for(var/datum/category_group/underwear/WRC in global_underwear.categories) + for(var/datum/category_item/underwear/WRI in WRC.items) + if(WRI.is_default(pref.identifying_gender ? pref.identifying_gender : MALE)) + pref.all_underwear[WRC.name] = WRI.name + break + + if(!istype(pref.all_underwear_metadata)) + pref.all_underwear_metadata = list() + + for(var/underwear_category in pref.all_underwear) + var/datum/category_group/underwear/UWC = global_underwear.categories_by_name[underwear_category] + if(!UWC) + pref.all_underwear -= underwear_category + else + var/datum/category_item/underwear/UWI = UWC.items_by_name[pref.all_underwear[underwear_category]] + if(!UWI) + pref.all_underwear -= underwear_category + + for(var/underwear_metadata in pref.all_underwear_metadata) + if(!(underwear_metadata in pref.all_underwear)) + pref.all_underwear_metadata -= underwear_metadata + pref.backbag = sanitize_integer(pref.backbag, 1, backbaglist.len, initial(pref.backbag)) + pref.pdachoice = sanitize_integer(pref.pdachoice, 1, pdachoicelist.len, initial(pref.pdachoice)) + pref.ttone = sanitize(pref.ttone, 20)//YW Edit + +/datum/category_item/player_setup_item/general/equipment/content() + . = list() + . += "Equipment:
" + for(var/datum/category_group/underwear/UWC in global_underwear.categories) + var/item_name = pref.all_underwear[UWC.name] ? pref.all_underwear[UWC.name] : "None" + . += "[UWC.name]: [item_name]" + var/datum/category_item/underwear/UWI = UWC.items_by_name[item_name] + if(UWI) + for(var/datum/gear_tweak/gt in UWI.tweaks) + . += " [gt.get_contents(get_metadata(UWC.name, gt))]" + + . += "
" + . += "Backpack Type: [backbaglist[pref.backbag]]
" + . += "PDA Type: [pdachoicelist[pref.pdachoice]]
" + . += "Communicator Visibility: [(pref.communicator_visibility) ? "Yes" : "No"]
" + . += "Ringtone (leave blank for job default): [pref.ttone]
" //YW EDIT + + return jointext(.,null) + +/datum/category_item/player_setup_item/general/equipment/proc/get_metadata(var/underwear_category, var/datum/gear_tweak/gt) + var/metadata = pref.all_underwear_metadata[underwear_category] + if(!metadata) + metadata = list() + pref.all_underwear_metadata[underwear_category] = metadata + + var/tweak_data = metadata["[gt]"] + if(!tweak_data) + tweak_data = gt.get_default() + metadata["[gt]"] = tweak_data + return tweak_data + +/datum/category_item/player_setup_item/general/equipment/proc/set_metadata(var/underwear_category, var/datum/gear_tweak/gt, var/new_metadata) + var/list/metadata = pref.all_underwear_metadata[underwear_category] + metadata["[gt]"] = new_metadata + + +/datum/category_item/player_setup_item/general/equipment/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["change_backpack"]) + var/new_backbag = tgui_input_list(user, "Choose your character's style of bag:", "Character Preference", backbaglist, backbaglist[pref.backbag]) + if(!isnull(new_backbag) && CanUseTopic(user)) + pref.backbag = backbaglist.Find(new_backbag) + return TOPIC_REFRESH_UPDATE_PREVIEW + + else if(href_list["change_pda"]) + var/new_pdachoice = tgui_input_list(user, "Choose your character's style of PDA:", "Character Preference", pdachoicelist, pdachoicelist[pref.pdachoice]) + if(!isnull(new_pdachoice) && CanUseTopic(user)) + pref.pdachoice = pdachoicelist.Find(new_pdachoice) + return TOPIC_REFRESH + + else if(href_list["change_underwear"]) + var/datum/category_group/underwear/UWC = global_underwear.categories_by_name[href_list["change_underwear"]] + if(!UWC) + return + var/datum/category_item/underwear/selected_underwear = tgui_input_list(user, "Choose underwear:", "Character Preference", UWC.items, pref.all_underwear[UWC.name]) + if(selected_underwear && CanUseTopic(user)) + pref.all_underwear[UWC.name] = selected_underwear.name + return TOPIC_REFRESH_UPDATE_PREVIEW + + else if(href_list["underwear"] && href_list["tweak"]) + var/underwear = href_list["underwear"] + if(!(underwear in pref.all_underwear)) + return TOPIC_NOACTION + var/datum/gear_tweak/gt = locate(href_list["tweak"]) + if(!gt) + return TOPIC_NOACTION + var/new_metadata = gt.get_metadata(usr, get_metadata(underwear, gt)) + if(new_metadata) + set_metadata(underwear, gt, new_metadata) + return TOPIC_REFRESH_UPDATE_PREVIEW + else if(href_list["toggle_comm_visibility"]) + if(CanUseTopic(user)) + pref.communicator_visibility = !pref.communicator_visibility + return TOPIC_REFRESH + else if(href_list["set_ttone"]) //Start of YW EDIT + if(CanUseTopic(user)) + pref.ttone = sanitize(input(user, "Please enter a new ringtone.", "Character Preference") as null|text, 20) + return TOPIC_REFRESH //End of YW EDIT + + + return ..() diff --git a/code/modules/client/preference_setup/vore/02_size.dm b/code/modules/client/preference_setup/vore/02_size.dm index c3e386cb4c..e1a77d2883 100644 --- a/code/modules/client/preference_setup/vore/02_size.dm +++ b/code/modules/client/preference_setup/vore/02_size.dm @@ -14,6 +14,7 @@ var/weight_gain = 100 // Weight gain rate. var/weight_loss = 50 // Weight loss rate. var/fuzzy = 0 // Preference toggle for sharp/fuzzy icon. Default sharp. + var/offset_override = FALSE var/voice_freq = 0 var/voice_sound = "beep-boop" var/custom_speech_bubble = "default" @@ -29,6 +30,7 @@ S["weight_gain"] >> pref.weight_gain S["weight_loss"] >> pref.weight_loss S["fuzzy"] >> pref.fuzzy + S["offset_override"] >> pref.offset_override S["voice_freq"] >> pref.voice_freq S["voice_sound"] >> pref.voice_sound S["custom_speech_bubble"] >> pref.custom_speech_bubble @@ -39,6 +41,7 @@ S["weight_gain"] << pref.weight_gain S["weight_loss"] << pref.weight_loss S["fuzzy"] << pref.fuzzy + S["offset_override"] << pref.offset_override S["voice_freq"] << pref.voice_freq S["voice_sound"] << pref.voice_sound S["custom_speech_bubble"] << pref.custom_speech_bubble @@ -48,6 +51,7 @@ pref.weight_gain = sanitize_integer(pref.weight_gain, WEIGHT_CHANGE_MIN, WEIGHT_CHANGE_MAX, initial(pref.weight_gain)) pref.weight_loss = sanitize_integer(pref.weight_loss, WEIGHT_CHANGE_MIN, WEIGHT_CHANGE_MAX, initial(pref.weight_loss)) pref.fuzzy = sanitize_integer(pref.fuzzy, 0, 1, initial(pref.fuzzy)) + pref.offset_override = sanitize_integer(pref.offset_override, 0, 1, initial(pref.offset_override)) if(pref.voice_freq != 0) pref.voice_freq = sanitize_integer(pref.voice_freq, MIN_VOICE_FREQ, MAX_VOICE_FREQ, initial(pref.fuzzy)) if(pref.size_multiplier == null || pref.size_multiplier < RESIZE_TINY || pref.size_multiplier > RESIZE_HUGE) @@ -60,6 +64,7 @@ character.weight_gain = pref.weight_gain character.weight_loss = pref.weight_loss character.fuzzy = pref.fuzzy + character.offset_override = pref.offset_override character.voice_freq = pref.voice_freq character.resize(pref.size_multiplier, animate = FALSE, ignore_prefs = TRUE) if(!pref.voice_sound) @@ -100,6 +105,7 @@ . += "
" . += "Scale: [round(pref.size_multiplier*100)]%
" . += "Scaled Appearance: [pref.fuzzy ? "Fuzzy" : "Sharp"]
" + . += "Scaling Center: [pref.offset_override ? "Odd" : "Even"]
" . += "Voice Frequency: [pref.voice_freq]
" . += "Voice Sounds: [pref.voice_sound]
" . += "Test Selected Voice
" @@ -124,6 +130,10 @@ pref.fuzzy = pref.fuzzy ? 0 : 1; return TOPIC_REFRESH_UPDATE_PREVIEW + else if(href_list["toggle_offset_override"]) + pref.offset_override = pref.offset_override ? 0 : 1; + return TOPIC_REFRESH_UPDATE_PREVIEW + else if(href_list["weight"]) var/new_weight = tgui_input_number(user, "Choose your character's relative body weight.\n\ This measurement should be set relative to a normal 5'10'' person's body and not the actual size of your character.\n\ diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 1801ddf95d..5c7361b761 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -82,6 +82,7 @@ var/list/preferences_datums = list() var/g_synth //Same as above var/b_synth //Same as above var/synth_markings = 1 //Enable/disable markings on synth parts. //VOREStation Edit - 1 by default + var/digitigrade = 0 //Some faction information. var/home_system = "Unset" //Current home or residence. diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index d72700444f..72476e78a9 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -23,6 +23,10 @@ var/polychromic = FALSE //VOREStation edit + var/update_icon_define_orig = null // temp storage for original update_icon_define (if it exists) + var/update_icon_define_digi = null // dmi used for the digi sprites + var/fit_for_digi = FALSE // flag for if clothing has already been reskinned to digitigrade + //Updates the icons of the mob wearing the clothing item, if any. /obj/item/clothing/proc/update_clothing_icon() return @@ -622,6 +626,8 @@ drop_sound = 'sound/items/drop/shoes.ogg' pickup_sound = 'sound/items/pickup/shoes.ogg' + update_icon_define_digi = "icons/inventory/feet/mob_digi.dmi" + /obj/item/clothing/shoes/proc/draw_knife() set name = "Draw Boot Knife" set desc = "Pull out your boot knife." @@ -746,6 +752,8 @@ valid_accessory_slots = (ACCESSORY_SLOT_OVER | ACCESSORY_SLOT_ARMBAND) restricted_accessory_slots = (ACCESSORY_SLOT_ARMBAND) + update_icon_define_digi = "icons/inventory/suit/mob_digi.dmi" + /obj/item/clothing/suit/update_clothing_icon() if (ismob(src.loc)) var/mob/M = src.loc @@ -856,6 +864,8 @@ var/icon/rolled_down_icon = 'icons/inventory/uniform/mob_rolled_down.dmi' var/icon/rolled_down_sleeves_icon = 'icons/inventory/uniform/mob_sleeves_rolled.dmi' + update_icon_define_digi = "icons/inventory/uniform/mob_digi.dmi" + /obj/item/clothing/under/attack_hand(var/mob/user) if(LAZYLEN(accessories)) ..() @@ -1061,3 +1071,49 @@ M.forceMove(get_turf(src)) return ..() //Vorestation edit end + +/obj/item/clothing/proc/handle_digitigrade(var/mob/user) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + + // if digitigrade-use flag is set + if(H.digitigrade) + + // Don't reset if already set + if(!fit_for_digi) + fit_for_digi = TRUE // set flag even if no icon_state exists, so we don't repeat checks + + //if update_icon_define is already set to something, place it in a var to hold it temporarily + if(update_icon_define) + update_icon_define_orig = update_icon_define + + // only override icon if a corresponding digitigrade replacement icon_state exists + // otherwise, keep the old non-digi icon_define (or nothing) + if(icon_state && icon_states(update_icon_define_digi).Find(icon_state)) + update_icon_define = update_icon_define_digi + + + // if not-digitigrade, only act if the clothing was previously fit for a digitigrade char + else + if(fit_for_digi) + fit_for_digi = FALSE + + //either reset update_icon_define to it's old value + // or reset update_icon_define to null + if(update_icon_define_orig) + update_icon_define = update_icon_define_orig + update_icon_define_orig = null + else + update_icon_define = null + +/obj/item/clothing/shoes/equipped(var/mob/user, var/slot) + . = ..() + handle_digitigrade(user) + +/obj/item/clothing/suit/equipped(var/mob/user, var/slot) + . = ..() + handle_digitigrade(user) + +/obj/item/clothing/under/equipped(var/mob/user, var/slot) + . = ..() + handle_digitigrade(user) diff --git a/code/modules/economy/vending_machines_vr.dm b/code/modules/economy/vending_machines_vr.dm index 9986a4c7fb..05da4f8f3b 100644 --- a/code/modules/economy/vending_machines_vr.dm +++ b/code/modules/economy/vending_machines_vr.dm @@ -3525,6 +3525,7 @@ /obj/item/weapon/reagent_containers/food/snacks/ratpackcheese = 8, /obj/item/weapon/reagent_containers/food/snacks/ratpackramen = 8, /obj/item/weapon/reagent_containers/food/snacks/ratpacktaco = 8, + /obj/item/weapon/reagent_containers/food/snacks/ratpackcake = 8, /obj/item/weapon/reagent_containers/food/snacks/ratpackturkey = 2) prices = list(/obj/item/weapon/reagent_containers/food/snacks/ratprotein = 8, @@ -3535,4 +3536,37 @@ /obj/item/weapon/reagent_containers/food/snacks/ratpackcheese = 10, /obj/item/weapon/reagent_containers/food/snacks/ratpackramen = 10, /obj/item/weapon/reagent_containers/food/snacks/ratpacktaco = 10, + /obj/item/weapon/reagent_containers/food/snacks/ratpackcake = 10, /obj/item/weapon/reagent_containers/food/snacks/ratpackturkey = 200) + +/obj/machinery/vending/desatti + name = "Desatti Catering" + desc = "A vending machine from Desatti Catering, stocking traditional Sol snacks. Like the good ol' days, apparently." + icon = 'icons/obj/vending_vr.dmi' + icon_state = "desatti" + product_slogans = "Keep calm and eat Desatti!;Don't be a smeg head, tuck in!;Go'an. 'Ave a cheeky nosh.;TAKE A BUTCHERS AT THIS!" + product_ads = "Jaffa cakes are legally cakes!;Real synthetic processed pork!;What flavour could the shrimps really be!?;Tea recommended with every biscuit purchase!" + products = list(/obj/item/weapon/storage/box/jaffacake = 15, + /obj/item/weapon/storage/box/winegum = 15, + /obj/item/weapon/storage/box/saucer = 15, + /obj/item/weapon/storage/box/shrimpsandbananas = 15, + /obj/item/weapon/storage/box/rhubarbcustard = 10, + /obj/item/weapon/storage/box/custardcream = 10, + /obj/item/weapon/storage/box/bourbon = 10, + /obj/item/weapon/reagent_containers/food/snacks/packaged/sausageroll= 8, + /obj/item/weapon/reagent_containers/food/snacks/packaged/pasty = 8, + /obj/item/weapon/reagent_containers/food/snacks/packaged/scotchegg = 8, + /obj/item/weapon/reagent_containers/food/snacks/packaged/porkpie = 8) + + prices = list(/obj/item/weapon/storage/box/jaffacake = 8, + /obj/item/weapon/storage/box/winegum = 8, + /obj/item/weapon/storage/box/saucer = 8, + /obj/item/weapon/storage/box/shrimpsandbananas = 8, + /obj/item/weapon/storage/box/rhubarbcustard = 8, + /obj/item/weapon/storage/box/custardcream = 8, + /obj/item/weapon/storage/box/bourbon = 8, + /obj/item/weapon/reagent_containers/food/snacks/packaged/sausageroll = 10, + /obj/item/weapon/reagent_containers/food/snacks/packaged/pasty = 10, + /obj/item/weapon/reagent_containers/food/snacks/packaged/scotchegg = 10, + /obj/item/weapon/reagent_containers/food/snacks/packaged/porkpie = 10 + ) diff --git a/code/modules/food/food/snacks.dm b/code/modules/food/food/snacks.dm index 4cab6810e6..5317d03b92 100644 --- a/code/modules/food/food/snacks.dm +++ b/code/modules/food/food/snacks.dm @@ -948,10 +948,6 @@ nutriment_desc = list("turkey" = 3, "tofu" = 5, "goeyness" = 4) bitesize = 3 -/obj/item/weapon/reagent_containers/food/snacks/tofurkey/Initialize() - . = ..() - reagents.add_reagent("stoxin", 3) - /obj/item/weapon/reagent_containers/food/snacks/stuffing name = "Stuffing" desc = "Moist, peppery breadcrumbs for filling the body cavities of dead birds. Dig in!" @@ -2422,6 +2418,7 @@ filling_color = "#785210" center_of_mass = list("x"=16, "y"=8) bitesize = 5 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/meatballsoup/Initialize() . = ..() @@ -2434,6 +2431,7 @@ icon_state = "slimesoup" //nonexistant? - 3/1/2020 FIXED. roro's live on. - 7/14/2020 - The fuck are you smoking, roro's is stupid, name it slimesoup so it's clear wtf it is. filling_color = "#C4DBA0" bitesize = 5 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/slimesoup/Initialize() . = ..() @@ -2447,6 +2445,7 @@ filling_color = "#FF0000" center_of_mass = list("x"=16, "y"=7) bitesize = 5 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/bloodsoup/Initialize() . = ..() @@ -2463,6 +2462,7 @@ nutriment_amt = 4 nutriment_desc = list("salt" = 1, "the worst joke" = 3) bitesize = 5 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/clownstears/Initialize() . = ..() @@ -2478,6 +2478,7 @@ center_of_mass = list("x"=16, "y"=8) nutriment_desc = list("carrot" = 2, "corn" = 2, "eggplant" = 2, "potato" = 2) bitesize = 5 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/vegetablesoup/Initialize() . = ..() @@ -2493,6 +2494,7 @@ nutriment_amt = 8 nutriment_desc = list("salad" = 4, "egg" = 2, "potato" = 2) bitesize = 5 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/nettlesoup/Initialize() . = ..() @@ -2509,6 +2511,7 @@ nutriment_amt = 1 nutriment_desc = list("backwash" = 1) bitesize = 5 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/mysterysoup/Initialize() . = ..() @@ -2557,6 +2560,7 @@ filling_color = "#D1F4FF" center_of_mass = list("x"=16, "y"=11) bitesize = 5 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/wishsoup/Initialize() . = ..() @@ -2573,6 +2577,7 @@ filling_color = "#D92929" center_of_mass = list("x"=16, "y"=7) bitesize = 3 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/tomatosoup/Initialize() . = ..() @@ -2586,6 +2591,7 @@ filling_color = "#E386BF" center_of_mass = list("x"=17, "y"=10) bitesize = 3 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/mushroomsoup/Initialize() . = ..() @@ -2599,6 +2605,7 @@ filling_color = "#FAC9FF" center_of_mass = list("x"=15, "y"=8) bitesize = 3 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/beetsoup/Initialize() . = ..() @@ -2613,6 +2620,7 @@ filling_color = "#E0C367" center_of_mass = list("x"=16, "y"=7) bitesize = 3 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/soup/onion/Initialize() . = ..() @@ -2641,6 +2649,7 @@ drop_sound = 'sound/items/drop/shovel.ogg' pickup_sound = 'sound/items/pickup/shovel.ogg' bitesize = 10 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/stew/Initialize() . = ..() @@ -2659,6 +2668,7 @@ nutriment_desc = list("hearty stew" = 6) center_of_mass = list("x"=16, "y"=5) bitesize = 6 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/bearstew/Initialize() . = ..() @@ -2679,6 +2689,7 @@ nutriment_amt = 3 nutriment_desc = list("chilli peppers" = 3) bitesize = 5 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/hotchili/Initialize() . = ..() @@ -2696,6 +2707,7 @@ nutriment_amt = 3 nutriment_desc = list("ice peppers" = 3) bitesize = 5 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/coldchili/Initialize() . = ..() @@ -2715,6 +2727,7 @@ nutriment_desc = list("dark, hearty chili" = 3) center_of_mass = list("x"=15, "y"=9) bitesize = 6 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/bearchili/Initialize() . = ..() @@ -4262,6 +4275,7 @@ nutriment_amt = 20 nutriment_desc = list("chalk" = 6) bitesize = 4 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/liquidfood/Initialize() . = ..() @@ -4276,6 +4290,7 @@ survivalfood = TRUE center_of_mass = list("x"=16, "y"=15) bitesize = 4 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/liquidprotein/Initialize() . = ..() @@ -4291,6 +4306,7 @@ survivalfood = TRUE center_of_mass = list("x"=16, "y"=15) bitesize = 4 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/liquidvitamin/Initialize() . = ..() diff --git a/code/modules/food/food/snacks_vr.dm b/code/modules/food/food/snacks_vr.dm index f9125284fa..9d43943d42 100644 --- a/code/modules/food/food/snacks_vr.dm +++ b/code/modules/food/food/snacks_vr.dm @@ -33,6 +33,7 @@ trash = /obj/item/trash/snack_bowl nutriment_amt = 6 nutriment_desc = list("meat" = 2, "vegetables" = 2, "seasoning" = 5) + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/goulash/Initialize() . = ..() @@ -128,6 +129,7 @@ trash = /obj/item/trash/asian_bowl nutriment_amt = 6 nutriment_desc = list("spicyness" = 4, "sourness" = 4, "tofu" = 1) + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/hotandsoursoup/Initialize() . = ..() @@ -142,6 +144,7 @@ trash = /obj/item/trash/asian_bowl nutriment_amt = 6 nutriment_desc = list("fried egg" = 2, "egg noodles" = 4) + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/kitsuneudon/Initialize() . = ..() @@ -583,6 +586,7 @@ nutriment_amt = 8 nutriment_desc = list("soy" = 8) bitesize = 4 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/milosoup/Initialize() . = ..() @@ -596,6 +600,7 @@ filling_color = "#E0C367" center_of_mass = list("x"=16, "y"=7) bitesize = 3 + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/onionsoup/Initialize() . = ..() @@ -808,6 +813,7 @@ trash = /obj/item/trash/ratjuice nutriment_amt = 2 nutriment_desc = list("essence of steak" = 6) + eating_sound = 'sound/items/drink.ogg' /obj/item/weapon/reagent_containers/food/snacks/ratliquid/Initialize() . = ..() @@ -913,6 +919,30 @@ nutriment_amt = 2 nutriment_desc = list("salsa sauce" = 2, "meat chunks" = 4, "cheese" = 3) +/obj/item/weapon/reagent_containers/food/snacks/ratpackcake + name = "Instant Sweet Celebration" + desc = "A compressed sweet treat in one easy container. The label states that it's a slice of vanilla cake." + icon = 'icons/obj/food_vr.dmi' + icon_state = "altevian_pack_cake" + package_open_state = "altevian_pack_cake-open" + package_opening_state = "altevian_pack_cake-opening" + package = TRUE + trash = /obj/item/trash/ratpackcake + nutriment_amt = 2 + nutriment_desc = list("nice mix of vanilla and sugar" = 5) + +/obj/item/weapon/reagent_containers/food/snacks/ratpackmeat + name = "unmarked compression package" + desc = "This package looks familiar to the compression packs commonly seen from the Altevians. However, it looks to be unfinished or a possible test product that somehow ended up in your hands." + icon = 'icons/obj/food_vr.dmi' + icon_state = "altevian_pack_meat" + package_open_state = "altevian_pack_meat-open" + package_opening_state = "altevian_pack_meat-opening" + package = TRUE + trash = /obj/item/trash/ratpackmeat + nutriment_amt = 2 + nutriment_desc = list("synthetic meat" = 6) + //desatti snacks @@ -925,6 +955,10 @@ bitesize = 2 nutriment_desc = list("chocolate" = 2, "orange" = 4, "cake" = 3) +/obj/item/weapon/reagent_containers/food/snacks/bourbon/Initialize() + . = ..() + reagents.add_reagent("coco", 2) + /obj/item/weapon/storage/box/jaffacake //This is kinda like the donut box. name = "Desatti Jaffa Cakes" desc = "A box full of desatti brand jaffa cakes, with twelve in a pack!" @@ -998,6 +1032,10 @@ nutriment_amt = 4 nutriment_desc = list("pastry" = 5, "meat" = 5, "onion" = 2, "potato" = 3) +/obj/item/weapon/reagent_containers/food/snacks/packaged/pasty/Initialize() + . = ..() + reagents.add_reagent("protein", 2) + /obj/item/weapon/reagent_containers/food/snacks/saucer name = "Sherbert Saucer" desc = "A small saucer shaped piece of rice paper filled with sugar." @@ -1073,6 +1111,10 @@ ) foldable = null +/obj/item/weapon/reagent_containers/food/snacks/bourbon/Initialize() + . = ..() + reagents.add_reagent("coco", 2) + /obj/item/weapon/reagent_containers/food/snacks/packaged/sausageroll name = "Sausage Roll" icon_state = "sausageroll" @@ -1082,6 +1124,10 @@ nutriment_amt = 3 nutriment_desc = list("pastry" = 5, "meat" = 5) +/obj/item/weapon/reagent_containers/food/snacks/packaged/sausageroll/Initialize() + . = ..() + reagents.add_reagent("protein", 2) + /obj/item/weapon/reagent_containers/food/snacks/packaged/scotchegg name = "Scotch Egg" icon_state = "scotchegg" @@ -1091,6 +1137,10 @@ nutriment_amt = 3 nutriment_desc = list("egg" = 5, "meat" = 5, "bread" = 2) +/obj/item/weapon/reagent_containers/food/snacks/packaged/scotchegg/Initialize() + . = ..() + reagents.add_reagent("protein", 2) + /obj/item/weapon/reagent_containers/food/snacks/foam_banana name = "Foam Banana" desc = "A small vaguely banana shaped sweet with a foam-like texture." @@ -1125,3 +1175,45 @@ /obj/item/weapon/reagent_containers/food/snacks/foam_shrimp = 10 ) foldable = null + +/obj/item/weapon/reagent_containers/food/snacks/rhubarbcustard + name = "Rhubarb and Custard Sweet" + desc = "A small pink and yellow boiled sweet." + icon = 'icons/obj/food_snacks.dmi' + icon_state = "rhubarbcustard_1" + w_class = ITEMSIZE_TINY + nutriment_amt = 1 + bitesize = 2 + nutriment_desc = list("sugar" = 5, "rhubarb" = 2, "custard" = 2) + var/list/color_options = list("rhubarbcustard_1","rhubarbcustard_2") + +/obj/item/weapon/reagent_containers/food/snacks/rhubarbcustard/Initialize() + . = ..() + icon_state = pick(color_options) + +/obj/item/weapon/storage/box/rhubarbcustard //This is kinda like the donut box. + name = "Desatti Rhubarb and Custards" + desc = "A pack of rhubarb and custard boiled sweets, the taste combination might sound usual, but they insist it's actually kind of okay!" + icon = 'icons/obj/food_snacks.dmi' + icon_state = "rhubarbcustard_pack" + var/icon_base = "rhubarbcustard_pack" + var/startswith = 15 + max_storage_space = ITEMSIZE_COST_TINY * 15 + can_hold = list(/obj/item/weapon/reagent_containers/food/snacks/rhubarbcustard) + starts_with = list( + /obj/item/weapon/reagent_containers/food/snacks/rhubarbcustard = 15, + ) + foldable = null + +/obj/item/weapon/reagent_containers/food/snacks/packaged/porkpie + name = "Pork Pie" + icon_state = "porkpie" + desc = "A pre-packaged pork pie with Desatti Catering branding. Claims to contain real meat covered in pastry!" + package_trash = /obj/item/trash/porkpie + package_open_state = "porkpie_open" + nutriment_amt = 3 + nutriment_desc = list("pastry" = 5, "meat" = 5) + +/obj/item/weapon/reagent_containers/food/snacks/packaged/porkpie/Initialize() + . = ..() + reagents.add_reagent("protein", 2) diff --git a/code/modules/gamemaster/event2/events/medical/virus.dm b/code/modules/gamemaster/event2/events/medical/virus.dm index 58791d2ad1..2b3ada5cf9 100644 --- a/code/modules/gamemaster/event2/events/medical/virus.dm +++ b/code/modules/gamemaster/event2/events/medical/virus.dm @@ -44,7 +44,7 @@ /datum/event2/event/virus/set_up() for(var/mob/living/carbon/human/H in player_list) - if(H.client && !H.isSynthetic() && H.stat != DEAD && !player_is_antag(H.mind)) + if(H.client && !H.isSynthetic() && H.stat != DEAD && !player_is_antag(H.mind) && !isbelly(H.loc)) candidates += H candidates = shuffle(candidates) diff --git a/code/modules/materials/materials/organic/wood.dm b/code/modules/materials/materials/organic/wood.dm index b91bb381ac..114caef9dc 100644 --- a/code/modules/materials/materials/organic/wood.dm +++ b/code/modules/materials/materials/organic/wood.dm @@ -79,6 +79,7 @@ /datum/material/wood/hardwood/generate_recipes() ..() + recipes += new /datum/stack_recipe("parquet wood floor tile", /obj/item/stack/tile/wood/parquet, 1, 4, 20, pass_stack_color = FALSE) for(var/datum/stack_recipe/r_recipe in recipes) if(r_recipe.title == "wood floor tile") recipes -= r_recipe diff --git a/code/modules/mob/dead/corpse.dm b/code/modules/mob/dead/corpse.dm index 2e70945e1e..8a8756ffd2 100644 --- a/code/modules/mob/dead/corpse.dm +++ b/code/modules/mob/dead/corpse.dm @@ -107,7 +107,6 @@ M.real_name = generateCorpseName() M.set_stat(DEAD) //Kills the new mob if(corpsesynthtype > 0) - to_world("Synth") if(!corpsesynthbrand) corpsesynthbrand = "Unbranded" for(var/obj/item/organ/external/O in M.organs) @@ -250,4 +249,4 @@ corpsehelmet = /obj/item/clothing/head/bearpelt /obj/effect/landmark/mobcorpse/russian/ranged - corpsehelmet = /obj/item/clothing/head/ushanka \ No newline at end of file + corpsehelmet = /obj/item/clothing/head/ushanka diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index a2962591aa..8f2847da11 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1247,6 +1247,8 @@ maxHealth = species.total_health hunger_rate = species.hunger_factor //VOREStation Add + center_offset = species.center_offset + if(LAZYLEN(descriptors)) descriptors = null diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 4b2236218e..a3be484060 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -36,6 +36,8 @@ var/b_synth //Same as above var/synth_markings = 0 //Enables/disables markings on synth parts. + var/digitigrade = 0 // 0 = no digi, 1 = default, 2+ = digi styles... (Not used yet) + //var/size_multiplier = 1 //multiplier for the mob's icon size //VOREStation Edit (Moved to /mob/living) var/damage_multiplier = 1 //multiplies melee combat damage var/icon_update = 1 //whether icon updating shall take place diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index fec724dae2..e7722cff39 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -61,6 +61,9 @@ var/min_age = 17 var/max_age = 70 + var/icodigi = 'icons/mob/human_races/r_digi.dmi' + var/digi_allowed = FALSE + // Language/culture vars. var/default_language = LANGUAGE_GALCOM // Default language is used when 'say' is used without modifiers. var/language = LANGUAGE_GALCOM // Default racial language, if any. diff --git a/code/modules/mob/living/carbon/human/species/species_vr.dm b/code/modules/mob/living/carbon/human/species/species_vr.dm index 4199dba6f3..3aa0e5799d 100644 --- a/code/modules/mob/living/carbon/human/species/species_vr.dm +++ b/code/modules/mob/living/carbon/human/species/species_vr.dm @@ -38,6 +38,7 @@ var/micro_size_mod = 0 // How different is our size for interactions that involve us being small? var/macro_size_mod = 0 // How different is our size for interactions that involve us being big? var/digestion_nutrition_modifier = 1 + var/center_offset = 0.5 var/can_climb = FALSE var/climbing_delay = 1.5 // We climb with a quarter delay diff --git a/code/modules/mob/living/carbon/human/species/station/blank_vr.dm b/code/modules/mob/living/carbon/human/species/station/blank_vr.dm index f1a261e26e..6770386fbd 100644 --- a/code/modules/mob/living/carbon/human/species/station/blank_vr.dm +++ b/code/modules/mob/living/carbon/human/species/station/blank_vr.dm @@ -8,6 +8,7 @@ name_plural = "Custom" selects_bodytype = SELECTS_BODYTYPE_CUSTOM base_species = SPECIES_HUMAN + digi_allowed = TRUE unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/punch, /datum/unarmed_attack/bite) diff --git a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm index 6935c7701c..eb04f2d6de 100755 --- a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm +++ b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm @@ -13,6 +13,7 @@ selects_bodytype = SELECTS_BODYTYPE_SHAPESHIFTER base_species = SPECIES_HUMAN + digi_allowed = TRUE blood_color = "#505050" //This is the same as the 80,80,80 below, but in hex flesh_color = "#505050" diff --git a/code/modules/mob/living/carbon/human/species/station/station.dm b/code/modules/mob/living/carbon/human/species/station/station.dm index 92aa7c7783..1e1a32d94b 100644 --- a/code/modules/mob/living/carbon/human/species/station/station.dm +++ b/code/modules/mob/living/carbon/human/species/station/station.dm @@ -73,6 +73,7 @@ health_hud_intensity = 2.5 chem_strength_alcohol = 0.75 throwforce_absorb_threshold = 10 + digi_allowed = TRUE min_age = 32 max_age = 260 @@ -198,6 +199,7 @@ species_language = LANGUAGE_SIIK health_hud_intensity = 2.5 chem_strength_alcohol = 1.25 + digi_allowed = TRUE min_age = 18 max_age = 110 diff --git a/code/modules/mob/living/carbon/human/species/station/station_special_vr.dm b/code/modules/mob/living/carbon/human/species/station/station_special_vr.dm index b6182b9ede..9a69828501 100644 --- a/code/modules/mob/living/carbon/human/species/station/station_special_vr.dm +++ b/code/modules/mob/living/carbon/human/species/station/station_special_vr.dm @@ -16,6 +16,7 @@ burn_mod = 1.15 //As vulnerable to burn as a Tajara. base_species = "Xenochimera" selects_bodytype = SELECTS_BODYTYPE_CUSTOM + digi_allowed = TRUE num_alternate_languages = 3 species_language = null @@ -332,6 +333,7 @@ brute_mod = 0.8 //20% brute damage reduction burn_mod = 1.15 //15% burn damage increase. They're spiders. Aerosol can+lighter = dead spiders. throwforce_absorb_threshold = 10 + digi_allowed = TRUE num_alternate_languages = 3 species_language = LANGUAGE_VESPINAE diff --git a/code/modules/mob/living/carbon/human/species/station/station_vr.dm b/code/modules/mob/living/carbon/human/species/station/station_vr.dm index d153921823..bceebe85f3 100644 --- a/code/modules/mob/living/carbon/human/species/station/station_vr.dm +++ b/code/modules/mob/living/carbon/human/species/station/station_vr.dm @@ -17,6 +17,7 @@ species_language = LANGUAGE_SAGARU color_mult = 1 inherent_verbs = list(/mob/living/carbon/human/proc/tie_hair) + digi_allowed = TRUE min_age = 18 max_age = 110 @@ -85,7 +86,8 @@ assisted_langs = list(LANGUAGE_EAL, LANGUAGE_ROOTLOCAL, LANGUAGE_ROOTGLOBAL, LANGUAGE_VOX, LANGUAGE_PROMETHEAN) inherent_verbs = list(/mob/living/carbon/human/proc/tie_hair, /mob/living/carbon/human/proc/water_stealth, /mob/living/carbon/human/proc/underwater_devour) min_age = 18 - max_age = 110 + max_age = 110 // YW EDIT: 110 + digi_allowed = TRUE blurb = "The Akula are a species of amphibious humanoids like the Skrell, but have an appearance very similar to that of a shark. \ They were first discovered as a primitive race of underwater dwelling tribal creatures by the Skrell. At first they were not believed \ @@ -137,7 +139,8 @@ /mob/living/proc/start_wings_hovering, /mob/living/carbon/human/proc/tie_hair) min_age = 18 - max_age = 110 + max_age = 110 // YW EDIT: 110 + digi_allowed = TRUE blurb = "Nevreans are a race of avian and dinosaur-like creatures living on Tal. They belong to a group of races that hails from Eltus, \ in the Vilous system. Unlike sergals whom they share a star system with, their species is a very peaceful one. They possess remarkable \ @@ -180,6 +183,7 @@ inherent_verbs = list(/mob/living/carbon/human/proc/lick_wounds, /mob/living/proc/shred_limb, /mob/living/carbon/human/proc/tie_hair) + digi_allowed = TRUE min_age = 18 max_age = 110 @@ -237,6 +241,7 @@ color_mult = 1 inherent_verbs = list(/mob/living/carbon/human/proc/lick_wounds, /mob/living/carbon/human/proc/tie_hair) + digi_allowed = TRUE wikilink="https://yawn.izac.live/Vulpkanin" //YW EDIT: Wiki @@ -402,6 +407,7 @@ color_mult = 1 genders = list(MALE, FEMALE, PLURAL, NEUTER) inherent_verbs = list(/mob/living/proc/flying_toggle,/mob/living/proc/flying_vore_toggle,/mob/living/proc/start_wings_hovering,/mob/living/carbon/human/proc/tie_hair) + digi_allowed = TRUE min_age = 18 max_age = 80 @@ -443,6 +449,7 @@ taken to calling these creatures 'Shadekin', and the name has generally stuck and spread. " //TODO: Something more fitting for black-eyes wikilink = "https://wiki.vore-station.net/Shadekin" catalogue_data = list(/datum/category_item/catalogue/fauna/shadekin) + digi_allowed = TRUE language = LANGUAGE_SHADEKIN name_language = LANGUAGE_SHADEKIN @@ -552,6 +559,7 @@ name_language = LANGUAGE_TERMINUS species_language = LANGUAGE_TERMINUS inherent_verbs = list(/mob/living/carbon/human/proc/lick_wounds,/mob/living/proc/shred_limb,/mob/living/carbon/human/proc/tie_hair) + digi_allowed = TRUE min_age = 18 max_age = 80 @@ -583,6 +591,7 @@ darksight = 4 //Better hunters in the dark. hunger_factor = 0.1 //In exchange, they get hungry a tad faster. num_alternate_languages = 3 + digi_allowed = TRUE min_age = 18 max_age = 80 @@ -622,6 +631,7 @@ name_language = null color_mult = 1 inherent_verbs = list(/mob/living/carbon/human/proc/tie_hair) + digi_allowed = TRUE min_age = 18 max_age = 80 diff --git a/code/modules/mob/living/carbon/human/species/station/teshari.dm b/code/modules/mob/living/carbon/human/species/station/teshari.dm index 7bf4b52c42..df8cc92525 100644 --- a/code/modules/mob/living/carbon/human/species/station/teshari.dm +++ b/code/modules/mob/living/carbon/human/species/station/teshari.dm @@ -28,6 +28,7 @@ female_cough_sounds = list('sound/effects/mob_effects/tesharicougha.ogg','sound/effects/mob_effects/tesharicoughb.ogg') male_sneeze_sound = 'sound/effects/mob_effects/tesharisneeze.ogg' female_sneeze_sound = 'sound/effects/mob_effects/tesharisneeze.ogg' + center_offset = 0 blood_color = "#D514F7" flesh_color = "#5F7BB0" diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 74eed4ebfc..04fe9dd2cf 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -117,7 +117,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() //Do any species specific layering updates, such as when hiding. update_icon_special() -/mob/living/carbon/human/update_transform() +/mob/living/carbon/human/update_transform(var/instant = FALSE) /* VOREStation Edit START // First, get the correct size. var/desired_scale_x = icon_scale_x @@ -136,6 +136,9 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() var/desired_scale_y = size_multiplier * icon_scale_y desired_scale_x *= species.icon_scale_x desired_scale_y *= species.icon_scale_y + var/cent_offset = species.center_offset + if(fuzzy || offset_override || dir == EAST || dir == WEST) + cent_offset = 0 vis_height = species.icon_height appearance_flags |= PIXEL_SCALE if(fuzzy) @@ -165,15 +168,19 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() else M.Translate(1,-6) M.Scale(desired_scale_y, desired_scale_x) + M.Translate(cent_offset * desired_scale_x, (vis_height/2)*(desired_scale_y-1)) layer = MOB_LAYER -0.01 // Fix for a byond bug where turf entry order no longer matters else M.Scale(desired_scale_x, desired_scale_y)//VOREStation Edit - M.Translate(0, (vis_height/2)*(desired_scale_y-1)) //VOREStation edit + M.Translate(cent_offset * desired_scale_x, (vis_height/2)*(desired_scale_y-1)) if(tail_style?.can_loaf) // VOREStation Edit: Taur Loafing update_tail_showing() // VOREStation Edit: Taur Loafing layer = MOB_LAYER // Fix for a byond bug where turf entry order no longer matters - animate(src, transform = M, time = anim_time) + if(instant) + transform = M + else + animate(src, transform = M, time = anim_time) update_icon_special() //May contain transform-altering things //DAMAGE OVERLAYS @@ -312,6 +319,9 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() if(tail_style.clip_mask) //VOREStation Edit. icon_key += tail_style.clip_mask_state + if(digitigrade && (part.organ_tag == BP_R_LEG || part.organ_tag == BP_L_LEG || part.organ_tag == BP_R_FOOT || part.organ_tag == BP_L_FOOT)) + icon_key += "_digi" + if(tail_style) pixel_x = tail_style.mob_offset_x pixel_y = tail_style.mob_offset_y @@ -797,6 +807,14 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() if(istype(foot) && foot.is_hidden_by_sprite_accessory(clothing_only = TRUE)) //If either foot is hidden by the tail, don't render footwear. return + var/obj/item/clothing/shoes/shoe = shoes + var/shoe_sprite + + if(istype(shoe) && !isnull(shoe.update_icon_define)) + shoe_sprite = shoe.update_icon_define + else + shoe_sprite = INV_FEET_DEF_ICON + //Allow for shoe layer toggle nonsense var/shoe_layer = SHOES_LAYER if(istype(shoes, /obj/item/clothing/shoes)) @@ -805,7 +823,7 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() shoe_layer = SHOES_LAYER_ALT //NB: the use of a var for the layer on this one - overlays_standing[shoe_layer] = shoes.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_shoes_str, default_icon = INV_FEET_DEF_ICON, default_layer = shoe_layer) + overlays_standing[shoe_layer] = shoes.make_worn_icon(body_type = species.get_bodytype(src), slot_name = slot_shoes_str, default_icon = shoe_sprite, default_layer = shoe_layer) apply_layer(SHOES_LAYER) apply_layer(SHOES_LAYER_ALT) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 82f2064a42..a959c635ed 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1010,15 +1010,18 @@ if(!isnull(M.icon_scale_y_percent)) . *= M.icon_scale_y_percent -/mob/living/update_transform() +/mob/living/update_transform(var/instant = FALSE) // First, get the correct size. var/desired_scale_x = size_multiplier * icon_scale_x //VOREStation edit var/desired_scale_y = size_multiplier * icon_scale_y //VOREStation edit + var/cent_offset = center_offset // Now for the regular stuff. + if(fuzzy || offset_override || dir == EAST || dir == WEST) + cent_offset = 0 var/matrix/M = matrix() M.Scale(desired_scale_x, desired_scale_y) - M.Translate(0, (vis_height/2)*(desired_scale_y-1)) //VOREStation edit + M.Translate(cent_offset * desired_scale_x, (vis_height/2)*(desired_scale_y-1)) src.transform = M //VOREStation edit handle_status_indicators() @@ -1301,3 +1304,8 @@ icon = 'icons/mob/screen/midnight.dmi' icon_state = "character" screen_loc = ui_smallquad + +/mob/living/set_dir(var/new_dir) + . = ..() + if(size_multiplier != 1 || icon_scale_x != 1 && center_offset > 0) + update_transform(TRUE) diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm index d6aec7d322..927fc4a511 100644 --- a/code/modules/mob/living/login.dm +++ b/code/modules/mob/living/login.dm @@ -19,6 +19,7 @@ verbs |= /mob/living/proc/lick verbs |= /mob/living/proc/smell verbs |= /mob/living/proc/switch_scaling + verbs |= /mob/living/proc/center_offset if(!no_vore) verbs |= /mob/living/proc/vorebelly_printout diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm index 430747add5..50c0323f7c 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm @@ -379,7 +379,7 @@ else if(istype(target,/obj/machinery/power/apc)) var/obj/machinery/power/apc/A = target if(A.opened) - if(A.cell) + if(A.cell && is_type_in_list(A.cell, can_hold)) wrapped = A.cell @@ -396,7 +396,7 @@ else if(istype(target,/mob/living/silicon/robot)) var/mob/living/silicon/robot/A = target if(A.opened) - if(A.cell) + if(A.cell && is_type_in_list(A.cell, can_hold)) wrapped = A.cell diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 52d676081d..05ce14c916 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -476,6 +476,16 @@ else stat(null, text("No Cell Inserted!")) +// function to toggle VTEC once installed +/mob/living/silicon/robot/proc/toggle_vtec() + set name = "Toggle VTEC" + set category = "Abilities" + if(speed == -1) + to_chat(src, "VTEC module disabled.") + speed = 0 + else + to_chat(src, "VTEC module enabled.") + speed = -1 // update the status screen display /mob/living/silicon/robot/Stat() @@ -895,7 +905,7 @@ if(LAZYLEN(vore_selected.contents) > 0) for(var/borgfood in vore_selected.contents) //"inspired" (kinda copied) from Chompstation's belly fullness system's procs if(istype(borgfood, /mob/living)) - if(vore_selected.belly_item_mult <= 0) //If mobs dont contribute, dont calculate further + if(vore_selected.belly_mob_mult <= 0) //If mobs dont contribute, dont calculate further continue var/mob/living/prey = borgfood //typecast to living belly_size += (prey.size_multiplier / size_multiplier) / vore_selected.belly_mob_mult //Smaller prey are less filling to larger bellies @@ -928,7 +938,7 @@ if(belly_size > 0) //Borgs probably only have 1 belly size. but here's support for larger ones if that changes. if(resting && sprite_datum.has_vore_belly_resting_sprites) add_overlay(sprite_datum.get_belly_resting_overlay(src, belly_size)) - else + else if(!resting) add_overlay(sprite_datum.get_belly_overlay(src, belly_size)) sprite_datum.handle_extra_icon_updates(src) // Various equipment-based sprites go here. diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm index 6501297c3e..1124c4cfc2 100644 --- a/code/modules/mob/living/silicon/robot/robot_items.dm +++ b/code/modules/mob/living/silicon/robot/robot_items.dm @@ -316,8 +316,8 @@ //TODO: Add prewritten forms to dispense when you work out a good way to store the strings. /obj/item/weapon/form_printer - //name = "paperwork printer" - name = "paper dispenser" + name = "paperwork printer" + //name = "paper dispenser" icon = 'icons/obj/bureaucracy.dmi' icon_state = "paper_bin1" item_icons = list( @@ -341,9 +341,241 @@ deploy_paper(get_turf(src)) /obj/item/weapon/form_printer/proc/deploy_paper(var/turf/T) - T.visible_message("\The [src.loc] dispenses a sheet of crisp white paper.") - new /obj/item/weapon/paper(T) + var/choice = tgui_alert(usr, "Would you like dispense and empty page or print a form?", "Dispense", list("Paper","Form")) + if(!choice || choice == "Cancel") + return + switch(choice) + if("Paper") + T.visible_message("\The [src.loc] dispenses a sheet of crisp white paper.") + new /obj/item/weapon/paper(T) + if ("Form") + var/list/content = print_form() + if(!content) + to_chat(usr, "No form for this category found in central network. Central is advising employees to upload new forms whenever possible.") + return + T.visible_message("\The [src.loc] dispenses an official form to fill.") + new /obj/item/weapon/paper(T, content[1], content[2]) +/obj/item/weapon/form_printer/proc/print_form() + var/list/paper_forms = list("Empty", "Command", "Security", "Supply", "Science", "Medical", "Engineering", "Service", "Exploration", "Event", "Other", "Mercenary") + var/list/command_paper_forms = list("COM-0002: Dismissal Order", "COM-0003: Job Change Request", "COM-0004: ID Replacement Request", "COM-0005: Access Change Order", "COM-0006: Formal Complaint", "COM-0009: Visitor Permit", "COM-0012: Personnel Request Form") + var/list/security_paper_forms = list("SEC-1001: Shift-Start Checklist", "SEC-1002: Patrol Assignment Sheet", "SEC-1003: Incident Report", "SEC-1004: Arrest Report", "SEC-1005: Arrest Warrant", "SEC-1006: Search Warrant", "SEC-1007: Forensics Investigation Report", "SEC-1008: Interrogation Report", "SEC-1009: Witness Statement", "SEC-1010: Armory Inventory", "SEC-1011: Armory Equipment Request", "SEC-1012: Armory Equipment Deployment", "SEC-1013: Weapon Permit", "SEC-1014: Injunction") + var/list/supply_paper_forms = list("SUP-2001: Delivery of Goods", "SUP-2002: Delivery of Resources", "SUP-2003: Material Stock") + var/list/science_paper_forms = list("SCI-3003: Cyborg / Robot Inspection", "SCI-3004: Cyborg / Robot Upgrades", "SCI-3009: Xenoflora Genetics Report") + var/list/medical_paper_forms = list("MED-4001: Death Certificate", "MED-4002: Prescription", "MED-4003: Against Medical Advice", "MED-4004: Cyborgification Contract", "MED-4005: Mental Health Patient Intake", "MED-4006: NIF Surgery", "MED-4007: Psychiatric Evaluation") + var/list/engineering_paper_forms = list("ENG-5001: Building Permit") + var/list/service_paper_forms = list() + var/list/exploration_paper_forms = list() + var/list/event_paper_forms = list() + var/list/other_paper_forms = list("OTHR-9001: Emergency Transmission", "OTHR-9032: Ownership Transfer") + var/list/mercenary_paper_forms = list("MERC-?071: Mercenary Request") + + var/list/split = list() + var/papertype = tgui_input_list(usr, "What kind of form do you want to print?", "Department", paper_forms) + if(!papertype || papertype == "Cancel") + return + switch(papertype) + if ("Empty") + split = list("", "Empty form") + if("Command") + var/command_paper = tgui_input_list(usr, "What kind of command form do you want to print?", "Form", command_paper_forms) + if(!command_paper || command_paper == "Cancel") + return + split = splittext(command_paper, ": ") + if("Security") + var/security_paper = tgui_input_list(usr, "What kind of security form do you want to print?", "Form", security_paper_forms) + if(!security_paper || security_paper == "Cancel") + return + split = splittext(security_paper, ": ") + if("Supply") + var/supply_paper = tgui_input_list(usr, "What kind of supply form do you want to print?", "Form", supply_paper_forms) + if(!supply_paper || supply_paper == "Cancel") + return + split = splittext(supply_paper, ": ") + if("Science") + var/science_paper = tgui_input_list(usr, "What kind of science form do you want to print?", "Form", science_paper_forms) + if(!science_paper || science_paper == "Cancel") + return + split = splittext(science_paper, ": ") + if("Medical") + var/medical_paper = tgui_input_list(usr, "What kind of medical form do you want to print?", "Form", medical_paper_forms) + if(!medical_paper || medical_paper == "Cancel") + return + split = splittext(medical_paper, ": ") + if("Engineering") + var/engineering_paper = tgui_input_list(usr, "What kind of engineering form do you want to print?", "Form", engineering_paper_forms) + if(!engineering_paper || engineering_paper == "Cancel") + return + split = splittext(engineering_paper, ": ") + if("Service") + var/service_paper = tgui_input_list(usr, "What kind of service form do you want to print?", "Form", service_paper_forms) + if(!service_paper || service_paper == "Cancel") + return + split = splittext(service_paper, ": ") + if("Exploration") + var/exploration_paper = tgui_input_list(usr, "What kind of exploration form do you want to print?", "Form", exploration_paper_forms) + if(!exploration_paper || exploration_paper == "Cancel") + return + split = splittext(exploration_paper, ": ") + if("Event") + var/event_paper = tgui_input_list(usr, "What kind of event form do you want to print?", "Form", event_paper_forms) + if(!event_paper || event_paper == "Cancel") + return + split = splittext(event_paper, ": ") + if("Other") + var/other_paper = tgui_input_list(usr, "What kind of other form do you want to print?", "Form", other_paper_forms) + if(!other_paper || other_paper == "Cancel") + return + split = splittext(other_paper, ": ") + if("Mercenary") + var/mercenary_paper = tgui_input_list(usr, "What kind of mercenary form do you want to print?", "Form", mercenary_paper_forms) + if(!mercenary_paper || mercenary_paper == "Cancel") + return + split = splittext(mercenary_paper, ": ") + else + return + return list(select_form(split[1]), split[1] + ": " + split[2]) + +/obj/item/weapon/form_printer/proc/select_form(paperid, name) + var/content = "" + var/revision = "" + switch(paperid) + //Command forms, COM-0 + if("COM-0002") + content = @{"[grid][row][cell][b]Employee:[/b] [cell][field][br][row][cell][b]Position:[/b] [cell][field][/grid][br][hr][br][b]Reason:[/b] [field][br][br][hr][grid][row][cell][list][b]Signature of relevant Head of Staff:[/b][/list][cell][list][list][list][list][list][b]Head of Personnel signature:[/b][/list][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][list][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 1.3" + if("COM-0003") + content = @{"[grid][row][cell][b]Employee:[/b] [cell][field][br][row][cell][b]Current Position:[/b] [cell][field][br][row][cell][b]Requested Position:[/b] [cell][field][/grid][br][hr][br][b]Reason:[/b] [field][br][br][hr][grid][row][cell][list][b]Employee signature[/b][/list][cell][cell][br][row][cell][list]- [field][/list][cell][cell][br][row][cell][cell][cell][br][row][cell][list][b]Transferring department head signature:[/b][cell][list][list][list][list][list][b]Receiving department head signature:[/b][/list][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][cell][list][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][/list][cell][br][row][cell][cell][cell][br][row][cell][list][b]Head of Personnel signature[/b][/list][cell][cell][br][row][cell][list]- [large][field][/large][/list][cell][cell][/grid][hr][br][list][small][*]All department heads must agree to the transfer before transfer can take place.[br][*]If the transferred has been transferred for an invalid or illegal reason, this form is immediately void and unlawful.[br][*]In the event a relevant head of staff retracts his or her approval for this transfer, this form is immediately void and unlawful.[/small][/list]"} + revision = "Revision: 1.3" + if("COM-0004") + content = @{"[grid][row][cell][b]Employee:[/b] [cell][field][br][row][cell][b]Position:[/b] [cell][field][br][row][cell][cell][br][row][cell][b]Reason:[/b] [cell][/grid][br][table][row][cell]Lost[cell][field][br][row][cell]Damaged[cell][field][/table][br][hr][grid][row][cell][list][b]Employee signature[/b][/list][cell][cell][br][row][cell][list]- [field][/list][cell][cell][br][row][cell][cell][cell][br][row][cell][list][b]Signature of relevant Head of Staff:[/b][/list][cell][list][list][list][list][list][b]Head of Personnel signature:[/b][/list][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][list][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][/list][cell][/grid][hr][br][list][small][*]ID card requests fall under the fair use policy COM-0099.[br][*]NanoTrasen withholds the right to deny and and all applications for a replacement ID, dependent on policy COM-0099.[br][*]Excessive ID loss or damage as agreed on COM-0099 is to be compensated for out of personal income and account as specified under COM-0098.[/small][/list]"} + revision = "Revision: 1.8" + if("COM-0005") + content = @{"[grid][row][cell][b]Employee:[/b] [cell][field][br][row][cell][b]Position:[/b] [cell][field][br][row][cell][cell][br][row][cell][b]Access:[/b] [cell][field][/grid][br][hr][br][b]Reason:[/b] [field][br][br][hr][grid][row][cell][list][b]Employee signature[/b][/list][cell][cell][br][row][cell][list]- [field][/list][cell][cell][br][row][cell][cell][cell][br][row][cell][list][b]Signature of relevant Head of Staff:[/b][/list][cell][list][list][list][list][list][b]Head of Personnel signature:[/b][/list][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][list][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 1.7" + if("COM-0006") + content = @{"[grid][row][cell][b]Employee:[/b] [cell][field][br][row][cell][b]Position:[/b] [cell][field][br][row][cell][b]Department Head:[/b] [cell][field][/grid][br][hr][br][b]Reason:[/b] [field][br][br][hr][grid][row][cell][list][b]Employee signature:[/b][/list][cell][list][list][list][list][list][b]Site Manager signature:[/b][/list][/list][/list][/list][/list][cell][br][row][cell][list] - [field][/list][cell][list][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 1.3" + if("COM-0009") + content = @{"[grid][row][cell][b]Visitor name:[/b] [cell][field][br][row][cell][cell][br][row][cell][b]Escort:[/b] [cell][/grid][br][table][row][cell]Required[cell][field][br][row][cell]Not Required[cell][field][/table][br][hr][br][b]Assigned Crewmember as Escort:[/b] [field][br][br][small]Leave blank if none[/small][br][hr][grid][row][cell][list][b]Authorizing Personnel:[/b][/list][cell][cell][list][list][list][list][list][b]Crewmember signature:[/b][/list][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][list][list][list][list][cell][list][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 1.5" + if("COM-0012") + content = @{"[grid][row][cell][b]Sender:[/b] [cell][field][br][row][cell][b]Position:[/b] [cell][field][/grid][br][hr][br][b]Personnel Needed:[/b][br][table][br][row][cell]Exploration[cell][field][br][row][cell]Cargo[cell][field][br][row][cell]Medical[cell][field][br][row][cell]Service[cell][field][br][row][cell]Security[cell][field][br][row][cell]Science[cell][field][br][row][cell]Engineering[cell][field][br][row][cell]Command[cell][field][br][/table][br][small]Leave blank if none[/small][br][h3]Reason:[/h3] [field][br][br][hr][grid][row][cell][list][b]Signed:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid]"} + revision = "Revision: 1.2" + //Security forms, SEC-1 + if("SEC-1001") + content = @{"The following is a checklist of actions generally considered useful or essential to perform at the start of a work shift, or as soon as possible otherwise. Please sign to the right of each item when completed. If necessary, you may put notes regarding the work item after your signature.[br][hr][center][table][br][row][cell]All secure doors inspected and maintained if necessary[cell][field][br][row][cell]All cells cleaned[cell][field][br][row][cell]Brig cleaned and repaired if necessary[cell][field][br][row][cell]Armory inventory completed (see SEC-1010)[cell][field][br][row][cell]Security records checked for important information[cell][field][br][row][cell](optional) Patrol assignments given (see SEC-1002)[cell][field][br][row][cell]Cadets/Junior Officers assigned supervising officer if necessary[cell][field][br][/table][/center][br][hr][grid][row][cell][list][b]Officer on duty signature:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid]"} + revision = "Revision: 1.1" + if("SEC-1002") + content = @{"[hr][center][small][i]This sheet is designed for the [station]. You may wish to modify it if you are working on a different facility.[/i][/small][br][table][br][row][cell][b]Location[/b][cell][b]Personnel[/b][cell][b]Job[/b][br][row][cell]Arrivals Checkpoint[cell][field][cell][field][br][row][cell]Security Reception[cell][field][cell][field][br][row][cell]Foot Patrol: Deck 1 to Deck 2[cell][field][cell][field][br][row][cell]Foot Patrol: Deck 2[cell][field][cell][field][br][row][cell]Foot Patrol: Deck 2 to Deck 3[cell][field][cell][field][br][row][cell]Vault Checkpoint[cell][field][cell][field][br][row][cell]Auxiliary Checkpoint [field][cell][field][cell][field][br][row][cell][field][cell][field][cell][field][br][/table][/center][br][hr][grid][row][cell][list][b]Signature of Head of Security:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid]"} + revision = "Revision: 1.4" + if("SEC-1003") + content = @{"[b]Location of Incident:[/b] [field][br][br][b]Persons Involved:[/b][br][small][i](V - Victim, S - Suspect, W - Witness, M - Missing, A - Arrested, RP - Reporting Person, RO - Responding Officer, D - Deceased)[/i][/small][br][list][*] [field][br][/list][br][hr][br][b]Details of Incident:[/b][br][br][field][br][br][b]Evidence of Incident:[/b][br][br][field][br][br][hr][grid][row][cell][list][b]Signature of Reporting Officer:[/b][/list][cell][cell][list][list][list][list][b]Signature of Reporting Officer's Supervisor [small](if available)[/small]:[/b][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][cell][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 1.1" + if("SEC-1004") + content = @{"[grid][row][cell][b]Location of Incident:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Suspect's Name:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Suspect's Title:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Charges Filed:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Sentence Given:[/b][cell][field][/grid][br][hr][br][b]Persons Involved:[/b][br][small][i](V - Victim, S - Suspect, W - Witness, M - Missing, A - Arrested, RP - Reporting Person, RO - Responding Officer, D - Deceased)[/i][/small][br][list][*] [field][br][/list][br][hr][br][b]Details of Incident:[/b][br][br][field][br][br][b]Evidence of Incident:[/b][br][br][field][br][br][hr][grid][row][cell][list][b]Signature of Arresting Officer:[/b][/list][cell][cell][list][list][list][list][b]Signature of Arresting Officer's Supervisor [small](if available)[/small]:[/b][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][cell][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 1.0" + if("SEC-1005") + content = @{"[hr][br]To all members of the [field] facility's security department:[br][br]A command to arrive at the security department to answer for their accused charges of [[b][field][/b]] having been given to [[b][field][/b]], and said person having failed to do so,[br][br]YOU ARE HEREBY COMMANDED to arrest said person and bring said person directly to the security department to answer for their disobedience to the aforementioned command, and also the aforementioned charges, as issued by [[b][field][/b]].[br][br][hr][br]This arrest warrant has been issued by [[b][field][/b]] [small][i](name)[/i][/small], [[b][field][/b]] [small][i](rank)[/small][/i]. This arrest warrant is not valid without the aforementioned issuer's signature and only if they have the authority to issue this arrest warrant and are doing so with due respect to the laws and policies governing this facility.[br][br][hr][grid][row][cell][list][b]Issuer's Signature:[/b][/list][cell][cell][list][list][list][list][b]Arresting Officer's Signature:[/b][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][cell][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 1.3" + if("SEC-1006") + content = @{"[hr][br]I, [[b][field][/b]], do on oath and with my authority as a member of this facility's security department, affirm that I have substantial probable cause to search:[br][br][b]LOCATION, PROPERTY, AND/OR PERSONS TO BE SEARCHED:[/b][br][br]1. [field][br][br][b]ITEMS TO BE SEIZED:[/b][br][br]For the following property, to wit:[br]1. [field][br][br][b]OFFICER'S QUALIFICATIONS[/b][br][br]I have been a member of NanoTrasen's security division for [field] years and am currently assigned to the [field] facility. [field][br][br][b]PROBABLE CAUSE[/b][br][br][i][small]Write the reason why you have probable cause to execute this search warrant.[/small][/i][br][field][br][br][hr][br]This search warrant has been reviewed for legal sufficiency by [[b][field][/b]] [small][i](name)[/i][/small], [[b][field][/b]] [small][i](rank)[/i][/small]. This search warrant is not valid without the aforementioned reviewer's signature and only if they have the authority to approve this search warrant and are doing so with due respect to the laws and policies governing this facility.[br][br][hr][grid][row][cell][list][b]Reviewer's Signature:[/b][/list][cell][cell][list][list][list][list][b]Executing Officer's Signature:[/b][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][cell][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 1.5" + if("SEC-1007") + content = @{"[grid][row][cell][b]Case Number:[/b][cell][field][/grid][br][hr][h3]Involved Personnel[/h3][small][i](V - Victim, S - Suspect, W - Witness, M - Missing, A - Arrested, RP - Reporting Person, RO - Responding Officer, D - Deceased, O - Other)[/i][/small][br][table][br][row][cell]- [b]Personnel[/b][cell]- [b]Code[/b][cell]- [b]Summary[/b][br][row][cell]- [field][cell]- [field][cell]- [field][br][row][cell]- [field][cell]- [field][cell]- [field][br][row][cell]- [field][cell]- [field][cell]- [field][br][row][cell]- [field][cell]- [field][cell]- [field][br][row][cell]- [field][cell]- [field][cell]- [field][br][/table][br][br][hr][h3]Physical Property[/h3][small][i](D - Damaged, E - Evidence, L - Lost, R - Recovered, S - Stolen, O - Other)[/i][/small][br][table][br][row][cell]- [b]Item[/b][cell]- [b]Code[/b][cell]- [b]Summary[/b][br][row][cell]- [field][cell]- [field][cell]- [field][br][row][cell]- [field][cell]- [field][cell]- [field][br][row][cell]- [field][cell]- [field][cell]- [field][br][row][cell]- [field][cell]- [field][cell]- [field][br][row][cell]- [field][cell]- [field][cell]- [field][br][/table][br][br][hr][h3]Evidence[/h3][small][i](S - Statement, P - Photo, D - Document, IP - Item/Property, F - Fibers, FP - Fingerprints, B - Blood, O - Other)[/i][/small][br][table][br][row][cell]- [b]Evidence[/b][cell]- [b]Code[/b][cell]- [b]Summary[/b][br][row][cell]- [field][cell]- [field][cell]- [field][br][row][cell]- [field][cell]- [field][cell]- [field][br][row][cell]- [field][cell]- [field][cell]- [field][br][row][cell]- [field][cell]- [field][cell]- [field][br][row][cell]- [field][cell]- [field][cell]- [field][br][/table][br][br][hr][h3]Narrative[/h3][field][br][br][hr][grid][row][cell][list][b]Signature of Reporting Detective:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid]"} + revision = "Revision: 1.1" + if("SEC-1008") + content = @{"[grid][row][cell][b]Interviewee's Name:[/b][cell][field][br][row][cell][b]Interviewee's Title:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Interrogating Officer's Name:[/b][cell][field][br][row][cell][b]Interrogating Officer's Rank:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Other Personnel Present:[/b][cell][field][br][row][cell][b]Case Number:[/b][cell][field][/grid][br][hr][h3]Interview Notes:[/h3][field][br][br][hr][small][i]A transcript of the interrogation should be attached to this report as soon as it is available.[/i][/small][br][br][grid][row][cell][list][b]Interrogating Officer's Signature:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid]"} + revision = "Revision: 1.0" + if("SEC-1009") + content = @{"[grid][row][cell][b]Witness' Name:[/b][cell][field][br][row][cell][b]Witness' Title:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Attending Officer's Name:[/b][cell][field][br][row][cell][b]Attending Officer's Title:[/b][cell][field][/grid][hr][br][b]Witness' Statement:[/b][br][br][field][br][br][small][i]I, the undersigned, affirm that the above statement is my personal account of the relevant events and is correct and true to the best of my knowledge. Knowingly providing false information could result in charges.[/i][/small][br][grid][row][cell][list][b]Witness' Signature:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid][hr][br][small][b][u]FOR SECURITY USE ONLY[/b][/u][/small][br][br][grid][row][cell][b]Case Number:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Additional Remarks:[/b][cell][field][/grid][br][grid][row][cell][list][b]Attending Officer's Signature:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid][br]"} + revision = "Revision: 1.4" + if("SEC-1010") + content = @{"[grid][row][cell][b]Time of Inspection:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Inspecting Officer:[/b][cell][field][/grid][br][hr][center][h3]Regular Armory[/h3][/center][list][*][field][br][/list][br]Miscellaneous equipment: [field][br][br][hr][center][h3]Tactical Armory[/h3][/center][list][*][field][br][/list][br]Miscellaneous equipment: [field][br][br][hr][grid][row][cell][list][b]Signature of Inspecting Officer:[/b][/list][cell][cell][list][list][list][list][b]Signature of Warden [small](if different)[/small]:[/b][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][cell][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 1.1" + if("SEC-1011") + content = @{"[grid][row][cell][b]Name of Requesting Personne:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Title of Requesting Personnel:[/b][cell][field][/grid][br][hr][br][b]Equipment Requested:[/b][br][br][field][br][br][grid][row][cell][b]Reason:[/b][cell][field][/grid][br][grid][row][cell][list][b]Signature of Requesting Personnel:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid][hr][br][grid][row][cell][b]Tequest Status [small](approved/denied)[/small]:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Reason [small](if denied)[/small]:[/b][cell][field][/grid][br][grid][row][cell][list][b]Signature of Warden [small](or stand-in signatory)[/small]:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid]"} + revision = "Revision: 1.1" + if("SEC-1012") + content = @{"[grid][row][cell][b]Name of Receiving Personnel:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Title of Receiving Personnel:[/b][cell][field][/grid][br][hr][br][b]Equipment Issued:[/b][br][br][field][br][br][hr][br][grid][row][cell][b]Name of Issuing Personnel:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Title of Issuing Personnel:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Reason:[/b][cell][field][/grid][br][hr][grid][row][cell][list][b]Signature of Receiving Personnel:[/b][/list][cell][cell][list][list][list][list][b]Signature of Issuing Personnel:[/b][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][cell][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][cell][/grid][hr][br][small][b][u]TO BE FILLED OUT UPON RETURN OF EQUIPMENT[/u][/b][/small][br][br][b]Missing and/or Damaged Items:[/b][br][br][field][br][br][grid][row][cell][list][b]Signature of Warden [small](or stand-in signatory)[/small]:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid]"} + revision = "Revision: 1.3" + if("SEC-1013") + content = @{"[grid][row][cell][b]Personnel's Name:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Weapon:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Reason:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Duration [small](max. end of shift)[/small]:[/b][cell][field][/grid][br][hr][br][b]Terms of Permit:[/b][br][br][field][br][br][hr][small][i]I have read and understand Standard Operating Procedure as pertaining to weapon permits and the above terms in which I am allowed to carry this weapon permit. I understand that the below signatories, or any security officer with probable cause, may revoke my weapon permit at any time, and I will be expected to immediately surrender my weapon and this permit to the security department upon revocation or expiration of this permit. I understand that if I am involved in any violent crime, even if the crime is not related to my weapon permit, or if I violate the terms of this weapon permit for any reason, this permit may immediately be revoked at the discretion of security personnel.[/i][/small][br][br][grid][row][cell][list][b]Personnel's Signature:[/b][/list][cell][cell][list][list][list][list][b]Permit Issuer's Signature [small](Title: [field])[/small]:[/b][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][cell][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 1.1" + if("SEC-1014") + content = @{"[grid][row][cell][b]Receiving Personnel:[/b][cell][field][/grid][br][hr][h3]Terms of Injunction[/h3][field][br][br][hr][small][i]I have read and understand the above terms of this injunction. I understand that this injunction legally forbids me from performing the above actions under any circumstances and that violating this injunction can result in my immediate arrest. If I wish to appeal this injunction, I may contact an Internal Affairs Agent to appeal my case. I understand that this injunction is valid only until the end of the shift in which it was issued unless I am notified otherwise by a Central Command Officer. My below signature constitutes acknowledgment and agreeance with all of these above statements, though it is not required to enforce this injunction.[/small][/i][br][br][grid][row][cell][list][b]Signature of Receiving Personnel:[/b][/list][cell][cell][list][list][list][list][b]Signature of Head of Security [small](or stand-in signatory):[/b][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][cell][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 1.1" + //Supply forms, SUP-2 + if("SUP-2001") + content = @{"[grid][row][cell][b]Order Number(s):[/b] [cell][field][br][row][cell][b]Shipment Destination:[/b] [cell][field][br][row][cell][b]Shipment Method:[/b] [cell][field][/grid][br][hr][br][center][b]Goods in this delivery:[/b][/center][br][list][br][*][field][br][*][field][br][*][field][br][*][field][br][*][field][br][/list][br][hr][grid][row][cell][list][b]Supply personnel signature:[/b][/list][cell][cell][list][list][list][list][b]Receiver signature:[/b][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][cell][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 1.0" + if("SUP-2002") + content = @{"[grid][row][cell][b]Shipment Number(s):[/b] [cell][field][br][row][cell][b]Shipment Destination:[/b] [cell][field][br][row][cell][b]Shipment Method:[/b] [cell][field] [/grid][br][hr][br][center][b]Material in this shipment:[/b][/center][br][list][grid][row][cell][*]Iron:[cell][field][br][row][cell][*]Steel:[cell][field][br][row][cell][*]Plasteel:[cell][field][br][row][cell][*]Durasteel[cell][field][br][row][cell][*]Glass:[cell][field][br][row][cell][*]Sandstone:[cell][field][br][row][cell][*]Uranium:[cell][field][br][row][cell][*]Phoron Crystals:[cell][field][br][row][cell][*]Gold Bars:[cell][field][br][row][cell][*]Silver Ingots:[cell][field][br][row][cell][*]Diamonds:[cell][field][br][row][cell][*]Plastic:[cell][field][br][row][cell][*]Graphite:[cell][field][br][row][cell][*]Platinum:[cell][field][br][row][cell][*]Osmium:[cell][field][br][row][cell][*]Tritium:[cell][field][br][row][cell][*]Mhydrogen:[cell][field][br][row][cell][*]Verdantium:[cell][field][br][row][cell][*]Marble:[cell][field][br][row][cell][*]Lead:[cell][field][br][row][cell][*]Titanium:[cell][field][/grid][br][/list][br][small]Leave blank or write 0 if none[/small][br][hr][grid][row][cell][list][b]Supply personnel signature:[/b][/list][cell][cell][list][list][list][list][b]Receiver signature:[/b][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][cell][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 1.4" + if("SUP-2003") + content = @{"[hr][br][center][b]Material in stock:[/b][/center][br][list][grid][row][cell][*]Iron:[cell][field][br][row][cell][*]Steel:[cell][field][br][row][cell][*]Plasteel:[cell][field][br][row][cell][*]Durasteel[cell][field][br][row][cell][*]Glass:[cell][field][br][row][cell][*]Sandstone:[cell][field][br][row][cell][*]Uranium:[cell][field][br][row][cell][*]Phoron Crystals:[cell][field][br][row][cell][*]Gold Bars:[cell][field][br][row][cell][*]Silver Ingots:[cell][field][br][row][cell][*]Diamonds:[cell][field][br][row][cell][*]Plastic:[cell][field][br][row][cell][*]Graphite:[cell][field][br][row][cell][*]Platinum:[cell][field][br][row][cell][*]Osmium:[cell][field][br][row][cell][*]Tritium:[cell][field][br][row][cell][*]Mhydrogen:[cell][field][br][row][cell][*]Verdantium:[cell][field][br][row][cell][*]Marble:[cell][field][br][row][cell][*]Lead:[cell][field][br][row][cell][*]Titanium:[cell][field][/grid][br][/list][br][small]Leave blank or write 0 if none[/small][br][hr][grid][row][cell][list][b]Supply personnel signature:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid]"} + revision = "Revision: 1.1" + //Science forms, SCI-3 + if("SCI-3003") + content = @{"[grid][row][cell][row][cell][b]Roboticist:[/b] [cell][field][br][row][cell][b]Assistant:[/b] [cell][field][/grid][br][small]Leave blank if none[/small][hr][br][grid][row][cell][row][cell][b]Cyborg / Robot:[/b] [cell][field][br][row][cell][b]Module:[/b] [cell][field][/grid][br][hr][br]The following form documents the full inspection of [[field]] as performed by [u][field][/u] in the Robotics Labratory aboard the [station] on [u][date][/u].[br][br][table][row][cell][b]General [/b][cell][center]Status[/center][cell]Comment[br][row][cell][b]- Laws [/b][cell][center][field][/center][cell][field][br][row][cell]-[cell][center]-[/center][cell]-[br][row][cell][b]Component external [/b][cell][center]-[/center][cell]-[br][row][cell][b]- Robot Endoskeleton [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Left Arm [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Right Arm [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Left Leg [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Right Leg [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Torso [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Head [/b][cell][center][field][/center][cell][field][br][row][cell]-[cell][center]-[/center][cell]-[br][row][cell][b]Component internal [/b][cell][center]-[/center][cell]-[br][row][cell][b]- Wiring [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Actuator [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Radio [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Power Cell [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Self-Diagnosis Unit [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Camera [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Binary Communication Device [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Armour Plating [/b][cell][center][field][/center][cell][field][/table][br][hr][grid][row][cell][list][b]Scientist signature:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid]"} + revision = "Revision: 1.1" + if("SCI-3004") + content = @{"[grid][row][cell][row][cell][b]Roboticist:[/b] [cell][field][br][row][cell][b]Assistant:[/b] [cell][field][/grid][br][small]Leave blank if none[/small][hr][br][grid][row][cell][row][cell][b]Cyborg / Robot:[/b] [cell][field][br][row][cell][b]Module:[/b] [cell][field][/grid][br][hr][br]The following form documents the installed upgrades into [[field]] as performed by [u][field][/u] in the Robotics Labratory aboard the [station] on [u][date][/u].[br][br][table][row][cell][b]Lawset[/b][cell][center]Status[/center][cell]Comment[br][row][cell][b]- [field][/b][cell][center][field][/center][cell][field][br][row][cell]-[cell][center]-[/center][cell]-[br][row][cell][b]General [/b][cell][center]-[/center][cell]-[br][row][cell][b]- Rename Module [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Reset Module [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Emergency Resttart Module [/b][cell][center][field][/center][cell][field][br][row][cell][b]- VTEC Module [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Advanced Health Analyzer Module [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Robohound Capacity Expansion Module [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Robohound Capability Expansion Module [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Size Alteration Module [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Size Gun Module [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Scrambled Equipment Module [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Language Module [/b][cell][center][field][/center][cell][field][br][row][cell]-[cell][center]-[/center][cell]-[br][row][cell][b]Security [/b][cell][center]-[/center][cell]-[br][row][cell][b]- Rapid Taser Cooling Module [/b][cell][center][field][/center][cell][field][br][row][cell]-[cell][center]-[/center][cell]-[br][row][cell][b]Mining [/b][cell][center]-[/center][cell]-[br][row][cell][b]- Proto-Kinetic Accelerator [/b][cell][center][field][/center][cell][field][br][row][cell][b]- Diamond Drill [/b][cell][center][field][/center][cell][field][br][row][cell]-[cell][center]-[/center][cell]-[br][row][cell][b]Science [/b][cell][center]-[/center][cell]-[br][row][cell][b]- Advanced Rapid Part Exchange Device [/b][cell][center][field][/center][cell][field][/table][br][hr][grid][row][cell][list][b]Scientist signature:[/b][/list][cell][list][list][list][list][list][b]Research Director signature [small](In case of Law Change)[/small]:[/b][/list][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][list][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][/list][cell][br][row][cell][cell][cell][br][row][cell][list][/list][cell][list][list][list][list][list][b]Second Command signature [small](In case of Law Change)[/small]:[/b][/list][/list][/list][/list][/list][cell][br][row][cell][list][/list][cell][list][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 1.4" + if("SCI-3009") + content = @{"[grid][row][cell][row][cell][b]Scientist:[/b] [cell][field][br][row][cell][b]Assistant:[/b] [cell][field] [/grid][br][small]Leave blank if none[/small][br][hr][br]The following table contains the Genetic Identifier and purpose of the Xenofloral genes as identified by [u][field][/u] in the Xenobotanical Labratory aboard the [station] on [u][date][/u].[br][br][table][cell][b]Genetic Identifier[/b][cell]Genetic Sequence[row][br][cell][b]-[field] [/b][cell][small][b]Hardiness:[/b] Endurance. Tolerance to toxins, pests, and/or weeds[/small][br][row][cell]-[b][field] [/b][cell][small][b]Vigour:[/b] How long the plant takes to mature and produce fruit. How much fruit it produces. Whether it can spread out of its tray(vine).[/small][br][row][cell]-[b][field] [/b][cell][small][b]Biochemistry:[/b] Which reagents the fruit contains; which gases the plant generates.[/small][br][row][cell][b]-[field] [/b][cell][small][b]Fruit:[/b] Whether the fruit is juicy and will splatter when thrown; whether the plant has stinging spines and will inject its reagents into anyone coming in contact with it.[/small][br][row][cell]-[b][field] [/b][cell][small][b]Diet:[/b] Whether the plant consumes gases in its environment; whether the plant is carnivorous (eats pests) or eats tray weeds; how much water and fertilizer it consumes.[/small][br][row][cell]-[b][field] [/b][cell][small][b]Metabolism:[/b] Whether the plant requires water or fertilizer. Whether it alters the ambient temperature.[/small][br][row][cell]-[b][field] [/b][cell][small][b]Environment:[/b] Plant's preferred temperature and light levels, and how much tolerance it has for changes in light level.[/small][row][cell]-[b][field] [/b][cell][small][b]Atmosphere:[/b] The plant's tolerance for changes in temperature and pressure away from its preferred levels.[/small][br][row][cell]-[b][field] [/b][cell][small][b]Output:[/b] Whether the plant produces electrical power or bioluminescent light.[/small][br][row][cell]-[b][field] [/b][cell][small][b]Appearance:[/b] The "shape" of the plant. Also affects whether it can be harvested only once or multiple times.[/small][br][row][cell]-[b][field] [/b][cell][small][b]Pigment:[/b] The color of the plant and its fruit; the color of any bioluminescence.[/small][br][row][cell][b]-[field] [/b][cell][small][b]Special:[/b] The ability to teleport the thrower or target when thrown.[/small][/table][br][hr][grid][row][cell][list][b]Scientist signature:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid]"} + revision = "Revision: 0.9" + //Medical forms, MED-4 + if("MED-4001") + content = @{"[hr][br][grid][row][cell][b]Deceased Patient's Name:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Date of Birth:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Attending Physician:[/b][cell][field][/grid][br][hr][br][grid][row][cell][b]Date of Death:[/b][cell][field][br][row][cell][b]Time of Death:[/b][cell][field][br][row][cell][b]Cause of Death:[/b][cell][field][br][row][cell][cell][br][row][cell][b]DNR/DNC Request Present:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Further Autopsy Notes:[/b][cell][field][/grid][br][hr][br][i][small]I, the undersigned, with my authority as a licensed medical practitioner, declare the aforementioned patient to have irreversibly died at the aforementioned date and time in the aforementioned manner. I affirm that all information in this death certificate is true and correct to the best of my knowledge.[/i][/small][br][br][hr][grid][row][cell][list][b]Signature of Attending Physician:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid]"} + revision = "Revision: 1.2" + if("MED-4002") + content = @{"[grid][row][cell][b]Patient Name:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Prescribing Doctor:[/b][cell][field][/grid][br][hr][br][grid][row][cell][b]Name of Prescription Medicine:[/b][cell][field][br][row][cell][b]Dosage Type & Amount:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Prescription Start Date:[/b][cell][field][br][row][cell][b]Prescription End Date:[/b][cell][field][/grid][br][hr][h3]INSTRUCTIONS:[/h3][field][br][br][grid][row][cell][b]Potential Side Effects:[/b][cell][field][br][row][cell][b]Additional Notes:[/b][cell][field][/grid][br][hr][br]Only take this medication as prescribed, according to the above instructions. Do not stop taking this medication without consulting your doctor. If you miss a dose, take it as soon as you remember unless it is close to the time of your next dose. [b]Do not take multiple doses to make up for a missed dose.[/b] If you have any questions about this medication, ask your doctor.[br][br]Keep a copy of this form with your medication so you may easily reference it.[br][hr][grid][row][cell][list][b]Signature of Patient:[/b][/list][cell][cell][list][list][list][list][b]Signature of Attending Physician:[/b][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][cell][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 1.1" + if("MED-4003") + content = @{"[grid][row][cell][b]Patient Name:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Practitioner:[/b][cell][field][/grid][br][hr][br][center]Patient has decisional capacity to refuse further medical evaluation or treatment. Sign to confirm.[/center][br][hr][br]This certified that I, [[field]], voluntarily refuse further medical evaluation and treatment at [field]. I understand that further evaluation and treatment has been recommended and I am leaving [b]against medical advice.[/b] The medical staff have explained the risks of leaving which may include the worsening of my condition, harm to a bodily function or part, [b]or even death.[/b][br][br][hr][br][b]Benefits of receiving[/b] further evaluation and treatment include, but are not limited to:[br][br][field][br][br][b]Risks of refusing[/b] further evaluation and treatment include, but are not limited to:[br][br][field][br][br][b]Alternatives[/b] to receiving further evaluation and treatment here include, but are not limited to:[br][br][field][br][br][br][grid][row][cell][list][b]Practitioner Signature:[/b][/list][cell][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid][br][hr][br][b]I understand that I may return at any time and consent to further evaluation and treatment.[/b][br][br][grid][row][cell][list][b]Signature of Patient:[/b][/list][cell][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid]"} + revision = "Revision: 1.1" + if("MED-4004") + content = @{"[hr][br][grid][row][cell][b]Patient Name:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Current Occupation:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Preferred Cyborg name:[/b][cell][field][/grid][br][hr][br]By signing this contract you will be filed for voluntary cybogification.[br][br] Lobotomy will be performed on your person and your brain will be transported, implanted and synchronized to a functional cyborg shell. You also agree to abide by NT Cyborg law and that the research department, NT, or any of its affilites are not responsible for the loss of, or damage to any of the following:[br][list][small][*]Health[br][*]Life[br][*]Posessions[br][*]Investments[br][*]Relationships[br][*]Sense of fullfillment[br][*]Fun[/small][/list][br][small]The research team withholds the privilege to, [i]at any time[/i], end the cyborg contract in question, thereby destroying the shell in the process, and consider returning the brain to a biological body.[/small][br][hr][grid][row][cell][list][b]Patient signature[/b][/list][cell][cell][br][row][cell][list]- [field][/list][cell][cell][br][row][cell][cell][cell][br][row][cell][list][b]Performing surgeon signature:[/b][cell][list][list][list][list][list][b]Performing roboticist signature:[/b][/list][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][cell][list][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][/list][cell][br][row][cell][cell][cell][br][row][cell][list][b]Head of department Signature[/b][/list][cell][cell][br][row][cell][list]- [large][field][/large][/list][cell][cell][/grid][br][small][center]-Reminder to notify subject's head of staff and security-[/small]"} + revision = "Revision: 1.2" + if("MED-4005") + content = @{"[hr][br][grid][row][cell][b]Deceased Patient's Name:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Date of Birth:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Attending Physician:[/b][cell][field][/grid][br][hr][small][i]The following questions should be filled out by the patient without supervision or direction.[/small][/i][br][br][b]List of current physical and mental ailments [small](as described by you or another healthcare professional)[/small]:[/b][br][br][field][br][br][b]List of current and prior prescription medicine usage:[/b][br][br][field][br][br][b]Why do you want to see a mental health professional?[/b][br][br][field][br][br][b]Anything else I should know about you?[/b][br][br][field][br][br][b]Are you happy to recieve hypnotherapy and/or experimental vore therapy? Please ask your therapist if unsure.[/b][br][br][field][br][br][hr][br][[b][field][/b]] is expected to be your assigned mental healthcare professional. Please note that due to the decentralization of NanoTrasen's healthcare facilities, you may visit a different professional from time to time. Please take care to keep a summary of past visits with you to help you get the best care you need.[br][br][hr][grid][row][cell][list][b]Signature of Patient:[/b][/list][cell][cell][list][list][list][list][b]Doctor Signature:[/b][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][cell][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 2.1" + if("MED-4006") + content = @{"[grid][row][cell][b]Patient Name:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Practitioner:[/b][cell][field][/grid][br][hr][br]I, [[field]] (hereafter referred to as 'the patient'), hereby grant permission for the installation of a Nanite Implant Framework (hereafter referred to as a NIF), a non-essential and invasive implantation surgical procedure. I have been informed of and recognize the risks of this procedure, and the risks of possessing an implanted NIF, outlined below.[br][hr][br]Due to the complexity of this procedure, life-threatening risks are present. A skilled surgeon will be called upon to operate the procedure. They are expected to uphold Standard Operating Procedure and all surgical procedural guidelines.[br][br]There are possible risks associated with the installation of certain NIFsoft programs as well, such as malfunction or malware.[br][br]Upon installation, there will be a half-hour calibration period while the NIF connects to neurons in the brain, during which the patient will experience the following symptoms.[br][list][br][*]Loss of sight for approximately the first five minutes of calibration.[br][*]Grainy vision after restoration of ocular functions.[br][*]Strange and unusual sensations and tingling.[br][*]Extreme full-body pain.[br][*]Headaches.[br][*]Weakness.[br][*]Intermittent fainting and loss of consciousness.[/list][br][br]The patient may be discharged after the 30-minute recovery period has passed. The patient will be notified by their NIF when the process is complete.[br][br]As the patient, you are entitled to priority medical care in the event of a surgery-related emergency, up to and including resleeving if necessary. You are also entitled to an available, surgically-trained physician of your choice for the implantation in the event you do not like the one assigned to your care.[br][hr][br]Please put a cross (X) on one of these anesthetic-like options:[br][[field]] - I want to be sedated with anesthetic gas. (Recommended for a majority of species.)[br][[field]] - I want to be sedated with medication.[br][[field]] - I want my mind to be downloaded onto a SleeveMate 3700.[br][[field]] - I do [u]not[/u] want any of the above. [b](Not recommended for most species. The surgeon may refuse to operate without anesthetic.)[/b][br][hr][small]By signing this form I agree that I have read and assessed the risks associated with owning a NIF and NIF implantation surgery and give my consent for operation of this procedure.[/small][br][grid][row][cell][list][b]Signature of Patient:[/b][/list][cell][cell][list][list][list][list][b]Practitioner Signature:[/b][/list][/list][/list][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][cell][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: 2.2" + if("MED-4007") + content = @{"[grid][row][cell][b]Patient Name:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Patient Occupation:[/b][cell][field][br][row][cell][cell][br][row][cell][b]Psychiatrist:[/b][cell][field][/grid][br][hr][br][b][u]Concerns:[/u][/b][br][br][field][br][br][b][u]Evaluation:[/u][/b][br][br][field][br][br][b][u]Conclusion:[/u][/b][br][br][field][br][br][hr][b][u]Comments:[/u][/b][br][br][field][br][br][hr][grid][row][cell][list][b]Psychiatrist Signature:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid]"} + revision = "Revision: 1.3" + //Engineering forms, ENG-5 + if("ENG-5001") + content = @{"[grid][row][cell][b]Location:[/b] [cell][field][br][row][cell][b]Purpose:[/b] [cell][field][/grid][br][hr][br]I, [[u][field][/u]] certify that I have reviewed and approved of provided blueprints. I have verified that design will be structurally sound and fall within building guidelines. I and any others participating in its construction will ensure that the blueprint will be followed.[br][br][br][b]Blueprint:[/b] [field][br][br][hr][grid][row][cell][list][b]Constructing Engineer signature:[/b][/list][cell][list][list][list][list][list][b]Chief Engineer signature:[/b][/list][/list][/list][/list][/list][cell][br][row][cell][list] - [field][/list][cell][list][list][list][list][list]- [large][field][/large][/list][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision 1.1" + //Service forms, SER-6 + //Explorer forms, EXP-7 + //Event forms, EVNT-8 + //Other forms, OTHR-9 + if("OTHR-9001") + content = @{"[grid][row][cell][b]Sender:[/b] [cell][field][br][row][cell][b]Position:[/b] [cell][field][/grid][br][hr][br][b]Message:[/b] [field][br][br][hr][grid][row][cell][list][b]Signed:[/b][/list][cell][br][row][cell][list] - [large][field][/large][/list][cell][/grid]"} + revision = "Revision: 1.0" + if("OTHR-9032") + content = @{"[b]Requested Owner:[/b] [field][br][br][hr][br][b]Hereby, I [[/b][field][b]] agree to transfer my full ownsership, including all my rights to [[/b][field][b]].[br]This contract is binding immediately after both parties have signed and valid until [[/b][field][b]].[/b][br][br]Additional Agreements: [field][br][br][hr][grid][row][cell][list][b]Property Signature:[/b][/list][cell][list][list][list][list][list][b]Owner Signature:[/b][/list][cell][br][row][cell][list]- [field][/list][cell][list][list][list][list][list]- [field][/list][cell][/grid][hr][br]The contract can only be cancelled if both parties agree.[br]At no time, a single party can revert or void this contract.[br]All changes to this form after the contract was stamped are invalidated.[br][br]"} + revision = "Revision: 1.0" + //Mercenary forms, MERC-? + if("MERC-?071") + content = @{"[b]Requested Mercenary:[/b] [field][br][br][hr][br][grid][row][cell][b]Target:[/b] [cell][field][br][row][cell][b]Reason:[/b] [cell][field][/grid][br][grid][row][cell][list][b]Vore Type:[/b][/list][cell][list][field][/list][cell][list][list][list][b]Offered Bounty:[/b][/list][/list][/list][cell][list][field][/list][cell][br][row][cell][list][b]Extra Modules:[/b][/list][cell][list][field][/list][cell][list][list][list][b]Added Module Costs:[/b][/list][/list][/list][cell][list][field][/list][cell][br][row][cell][list][b]Special Requests:[/b][/list][cell][list][field][/list][cell][list][list][list][b]Added Request Fees:[/b][/list][/list][/list][cell][list][field][/list][cell][br][row][cell][cell][cell][cell][cell][br][row][cell][cell][cell][list][list][list][b]Total Bounty:[/b][/list][cell][list][field][/list][cell][/grid][br][hr][br]All payments are to be made in full before contract fulfilment.[br]Please be aware that signed contracts can [u]not[/u] be cancelled.[br][br][hr][grid][row][cell][list][b]Commissioner signature:[/b][/list][cell][list][list][list][list][list][b]Contractor signature:[/b][/list][/list][/list][/list][/list][cell][br][row][cell][list][large] - [field][/large][/list][cell][large][list][list][list][list][list]- [field][/large][cell][/list][/list][/list][/list][/list][cell][/grid]"} + revision = "Revision: ?.?" + else + paperid = @{"[field]"} + name = @{"[field]"} + content = @{"[field]"} + revision = @{"[field]"} + return create_form(paperid, name, content, revision) + +/obj/item/weapon/form_printer/proc/create_form(paperid, name, content, revision) + var/header = "\[center]\[br]\[small]" + paperid + "\[/small]\[br]\[h1]\[u]" + name + "\[/u]\[/h1]\[br]\[logo]\[br]\[br]\[station]\[br]\[/center]\[br]\[hr]\[br]\[b]Station Time:\[/b] \[date], \[time]\[br]\[br]" + var/footer = "\[hr]\[br]\[center]\[small]Stamp here.\[/small]\[/center]\[br]\[small]" + revision + "\[/small]" + return header + content + footer //Personal shielding for the combat module. /obj/item/borg/combat/shield diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station.dm b/code/modules/mob/living/silicon/robot/robot_modules/station.dm index d75fc6b642..0c4ac258c0 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules/station.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules/station.dm @@ -758,10 +758,10 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/weapon/gun/energy/laser/mounted(src) src.modules += new /obj/item/weapon/gun/energy/taser/mounted/cyborg/ertgun(src) src.modules += new /obj/item/weapon/pickaxe/plasmacutter/borg(src) - src.modules += new /obj/item/weapon/combat_borgblade + src.modules += new /obj/item/weapon/combat_borgblade(src) src.modules += new /obj/item/borg/combat/shield(src) src.modules += new /obj/item/borg/combat/mobility(src) - src.modules += new /obj/item/weapon/borg_combat_shocker + src.modules += new /obj/item/weapon/borg_combat_shocker(src) src.modules += new /obj/item/device/ticket_printer(src) src.emag += new /obj/item/weapon/gun/energy/lasercannon/mounted(src) diff --git a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm index bc608343f7..d87b6eaec3 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm @@ -36,7 +36,8 @@ src.modules += jetpack robot.internals = jetpack - id = robot.idcard + var/obj/id = robot.idcard + id.forceMove(src) src.modules += id /obj/item/weapon/robot_module/robot/syndicate/Destroy() @@ -82,7 +83,7 @@ // Hacking other things. src.modules += new /obj/item/weapon/card/robot/syndi(src) - src.modules += new /obj/item/weapon/card/emag(src) + src.modules += new /obj/item/weapon/card/emag/borg(src) // Materials. var/datum/matter_synth/nanite = new /datum/matter_synth/nanite(10000) @@ -135,7 +136,6 @@ /obj/item/weapon/robot_module/robot/syndicate/combat_medic/create_equipment(var/mob/living/silicon/robot/robot) ..() - src.modules += new /obj/item/borg/sight/hud/med(src) src.modules += new /obj/item/device/healthanalyzer/phasic(src) src.modules += new /obj/item/weapon/reagent_containers/borghypo/merc(src) diff --git a/code/modules/mob/living/silicon/robot/sprites/civilian.dm b/code/modules/mob/living/silicon/robot/sprites/civilian.dm index b6b1fcca53..cddce131db 100644 --- a/code/modules/mob/living/silicon/robot/sprites/civilian.dm +++ b/code/modules/mob/living/silicon/robot/sprites/civilian.dm @@ -1,4 +1,4 @@ -// Clerical and Service modules have a lot of shared sprites so they're in same file + // Clerical and Service modules have a lot of shared sprites so they're in same file // (some of those sprites are also shared with Standard, but ive already done it as its own thing, so some duplicates are fine) // Both Service and Clerical @@ -186,13 +186,13 @@ name = "Hound V2" sprite_icon_state = "vale" has_eye_light_sprites = TRUE - has_vore_belly_sprites = FALSE + has_vore_belly_sprites = TRUE /datum/robot_sprite/dogborg/service/valedark name = "Hound V2 Darkmode" sprite_icon_state = "valedark" has_eye_light_sprites = TRUE - has_vore_belly_sprites = FALSE + has_vore_belly_sprites = TRUE /datum/robot_sprite/dogborg/service/drake name = "Drake" @@ -220,11 +220,11 @@ else ourborg.icon_state = booze_options[ourborg.sprite_extra_customization["boozehound"]] -/datum/robot_sprite/dogborg/service/booze/get_belly_overlay(var/mob/living/silicon/robot/ourborg) +/datum/robot_sprite/dogborg/service/booze/get_belly_overlay(var/mob/living/silicon/robot/ourborg, var/size = 1) if(!("boozehound" in ourborg.sprite_extra_customization) || !ourborg.sprite_extra_customization["boozehound"]) return ..() else - return "[booze_options[ourborg.sprite_extra_customization["boozehound"]]]-sleeper" + return "[booze_options[ourborg.sprite_extra_customization["boozehound"]]]-sleeper-[size]" /datum/robot_sprite/dogborg/service/booze/get_rest_sprite(var/mob/living/silicon/robot/ourborg) if(!(ourborg.rest_style in rest_sprite_options)) @@ -364,13 +364,21 @@ has_dead_sprite = TRUE // Wide/dogborg sprites -/* + /datum/robot_sprite/dogborg/clerical module_type = "Clerical" sprite_icon = 'icons/mob/robot/clerical_wide.dmi' - // None yet -*/ +/datum/robot_sprite/dogborg/clerical/vale + name = "Hound V2" + sprite_icon_state = "vale" + has_eye_light_sprites = TRUE + +/datum/robot_sprite/dogborg/clerical/otie + name = "Otieborg" + sprite_icon_state = "otie" + has_eye_light_sprites = TRUE + // Tall sprites /* /datum/robot_sprite/dogborg/tall/clerical @@ -378,4 +386,4 @@ sprite_icon = 'icons/mob/robot/clerical_large.dmi' // None yet -*/ \ No newline at end of file +*/ diff --git a/code/modules/mob/living/silicon/robot/sprites/syndicate.dm b/code/modules/mob/living/silicon/robot/sprites/syndicate.dm index fb480ce7c3..685ebce2b2 100644 --- a/code/modules/mob/living/silicon/robot/sprites/syndicate.dm +++ b/code/modules/mob/living/silicon/robot/sprites/syndicate.dm @@ -1,5 +1,80 @@ // Syndie borg sprites +/* none yet +/datum/robot_sprite/syndie + module_type = list("Protector", "Mechanist", "Combat Medic") + sprite_icon = 'icons/mob/robot/syndie.dmi' + sprite_hud_icon_state = "malf" +*/ + +// Wide/dogborg sprites + +/datum/robot_sprite/dogborg/syndie + module_type = list("Protector", "Mechanist", "Combat Medic") + sprite_icon = 'icons/mob/robot/syndie_wide.dmi' + sprite_hud_icon_state = "malf" + +/datum/robot_sprite/dogborg/syndie/borgi + name = "Borgi" + sprite_icon_state = "borgi" + has_eye_sprites = FALSE + has_eye_light_sprites = TRUE + has_dead_sprite_overlay = FALSE + +/datum/robot_sprite/dogborg/syndie/drake + name = "Drake" + sprite_icon_state = "drake" + +// Tall sprites + +/datum/robot_sprite/dogborg/tall/syndie + module_type = list("Protector", "Mechanist", "Combat Medic") + sprite_icon = 'icons/mob/robot/syndie_large.dmi' + sprite_hud_icon_state = "malf" + +/datum/robot_sprite/dogborg/tall/syndie/raptor + name = "Raptor V-4" + sprite_icon_state = "raptor" + rest_sprite_options = list("Default", "Bellyup") + +/datum/robot_sprite/dogborg/tall/syndie/meka + name = "MEKA" + sprite_icon_state = "meka" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + has_vore_belly_sprites = FALSE + rest_sprite_options = list("Default", "Sit") + +/datum/robot_sprite/dogborg/tall/syndie/newmeka + name = "MEKA v2" + sprite_icon_state = "newmeka" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + rest_sprite_options = list("Default", "Sit") + +/datum/robot_sprite/dogborg/tall/syndie/mmeka + name = "NIKO" + sprite_icon_state = "mmeka" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + rest_sprite_options = list("Default", "Sit") + +/datum/robot_sprite/dogborg/tall/syndie/fmeka + name = "NIKA" + sprite_icon_state = "fmeka" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + rest_sprite_options = list("Default", "Sit") + +/datum/robot_sprite/dogborg/tall/syndie/k4t + name = "K4T" + sprite_icon_state = "k4t" + has_eye_light_sprites = TRUE + has_custom_open_sprites = TRUE + has_vore_belly_sprites = FALSE + rest_sprite_options = list("Default", "Bellyup") + + // Protector // Regular sprites @@ -25,6 +100,18 @@ name = "XI-ALP" sprite_icon_state = "heavy" +// Wide/dogborg sprites + +/datum/robot_sprite/dogborg/protector + module_type = "Protector" + sprite_icon = 'icons/mob/robot/protector_wide.dmi' + sprite_hud_icon_state = "malf" + +/datum/robot_sprite/dogborg/protector/k9 + name = "K9" + sprite_icon_state = "k9" + has_eye_light_sprites = TRUE + // Mechanist @@ -48,6 +135,7 @@ /datum/robot_sprite/dogborg/mechanist module_type = "Mechanist" sprite_icon = 'icons/mob/robot/mechanist_wide.dmi' + sprite_hud_icon_state = "malf" /datum/robot_sprite/dogborg/mechanist/pupdozer name = "Pupdozer" @@ -74,15 +162,8 @@ /datum/robot_sprite/dogborg/combat_medic module_type = "Combat Medic" sprite_icon = 'icons/mob/robot/combat_medic_wide.dmi' + sprite_hud_icon_state = "malf" -/* //Handled by the normal belly code now. -/datum/robot_sprite/dogborg/crisis/get_belly_overlay(var/mob/living/silicon/robot/ourborg) - if(has_sleeper_light_indicator) - if(ourborg.sleeper_state == 2 && !(ourborg.vore_selected?.silicon_belly_overlay_preference == "Vorebelly")) return "[sprite_icon_state]-sleeper_g" - else return "[sprite_icon_state]-sleeper_r" - else - return ..() -*/ /datum/robot_sprite/dogborg/combat_medic/do_equipment_glamour(var/obj/item/weapon/robot_module/module) if(!has_custom_equipment_sprites) return diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index d16fc7418a..95cd2805af 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -266,7 +266,7 @@ set desc = "Sets an extended description of your character's features." set category = "IC" - var/new_flavortext = strip_html_simple(tgui_input_text(usr, "Please enter your new flavour text.", "Flavour text", null)) + var/new_flavortext = strip_html_simple(tgui_input_text(usr, "Please enter your new flavour text.", "Flavour text", flavor_text, multiline = TRUE)) if(new_flavortext) flavor_text = new_flavortext @@ -409,4 +409,4 @@ return 0 //NOT REAL EYES /mob/living/silicon/can_feed() - return FALSE \ No newline at end of file + return FALSE diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm index 54b63aef97..633df96ec8 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm @@ -489,7 +489,7 @@ var/mob/living/simple_mob/vore/overmap/stardog/m = s.parent log_subtle(message,L) - message = "[L] [message]" + message = "[L] [message]" message = "(From the back of \the [m]) " + message message = encode_html_emphasis(message) @@ -1161,7 +1161,7 @@ return log_subtle(message,L) - message = "[L] [message]" + message = "[L] [message]" message = "(From within \the [s]) " + message message = encode_html_emphasis(message) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index f8de09d78b..b763e2298f 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -70,7 +70,7 @@ to_chat(src, "... You can almost hear someone talking ...") else if(client && client.prefs.chat_timestamp) - msg = replacetext(msg, new/regex("^(]*)?>)(.*)", ""), "$1[time] $2") + msg = replacetext(msg, new/regex("^(]*)?>)((?:.|\\n)*)", ""), "$1[time] $2") to_chat(src,msg) else if(teleop) to_chat(teleop, create_text_tag("body", "BODY:", teleop.client) + "[msg]") diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index f539abbe98..c7cabffc73 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -51,6 +51,8 @@ output += "

Observe

" + /* + //nobody uses this feature if(!IsGuestKey(src.key)) establish_db_connection() @@ -69,6 +71,7 @@ output += "

Show Player Polls (NEW!)

" else output += "

Show Player Polls

" + */ output += "

View Changelog

" diff --git a/code/modules/mob/new_player/sprite_accessories_extra_vr.dm b/code/modules/mob/new_player/sprite_accessories_extra_vr.dm index 201e0a6f81..cf1adc86a0 100644 --- a/code/modules/mob/new_player/sprite_accessories_extra_vr.dm +++ b/code/modules/mob/new_player/sprite_accessories_extra_vr.dm @@ -4,6 +4,8 @@ /datum/sprite_accessory/marking //Override for base markings color_blend_mode = ICON_ADD species_allowed = list() //This lets all races use + var/digitigrade_acceptance = MARKING_NONDIGI_ONLY + var/digitigrade_icon = 'icons/mob/human_races/markings_digi.dmi' /datum/sprite_accessory/marking/vr_vulp_belly name = "belly fur (Vulp)" @@ -1128,4 +1130,105 @@ icon = 'icons/mob/human_races/markings_vr.dmi' icon_state = "backsail" color_blend_mode = ICON_MULTIPLY - body_parts = list(BP_TORSO) \ No newline at end of file + body_parts = list(BP_TORSO) + +//Digitigrade markings +/datum/sprite_accessory/marking/digi + icon = 'icons/mob/human_races/markings_digi.dmi' + digitigrade_acceptance = MARKING_DIGITIGRADE_ONLY + +/datum/sprite_accessory/marking/digi/fullleft + name = "Digitigrade Full Left Leg(Only works with digitigrade legs)" + icon_state = "full" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_L_LEG,BP_L_FOOT) + +/datum/sprite_accessory/marking/digi/fullright + name = "Digitigrade Full Right Leg(Only works with digitigrade legs)" + icon_state = "full" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_R_LEG,BP_R_FOOT) + +/datum/sprite_accessory/marking/digi/longsockleft + name = "Digitigrade Long Socks Left(Only works with digitigrade legs)" + icon_state = "longsock" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_L_LEG,BP_L_FOOT) + +/datum/sprite_accessory/marking/digi/longsockright + name = "Digitigrade Long Socks Right(Only works with digitigrade legs)" + icon_state = "longsock" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_R_LEG,BP_R_FOOT) + +/datum/sprite_accessory/marking/digi/medsockleft + name = "Digitigrade Medium Socks Left(Only works with digitigrade legs)" + icon_state = "medsock" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_L_LEG,BP_L_FOOT) + +/datum/sprite_accessory/marking/digi/medsockright + name = "Digitigrade Medium Socks Right(Only works with digitigrade legs)" + icon_state = "medsock" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_R_LEG,BP_R_FOOT) + +/datum/sprite_accessory/marking/digi/shortsockleft + name = "Digitigrade Short Socks Left(Only works with digitigrade legs)" + icon_state = "shortsock" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_L_FOOT) + +/datum/sprite_accessory/marking/digi/shortsockright + name = "Digitigrade Short Socks Right(Only works with digitigrade legs)" + icon_state = "shortsock" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_R_FOOT) + +/datum/sprite_accessory/marking/digi/toesleft + name = "Digitigrade Toes Left(Only works with digitigrade legs)" + icon_state = "toes" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_L_FOOT) + +/datum/sprite_accessory/marking/digi/toesright + name = "Digitigrade Toes Right(Only works with digitigrade legs)" + icon_state = "toes" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_R_FOOT) + +/datum/sprite_accessory/marking/digi/stripesleft + name = "Digitigrade Stripes Left(Only works with digitigrade legs)" + icon_state = "stripes" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_L_LEG,BP_L_FOOT) + +/datum/sprite_accessory/marking/digi/stripesright + name = "Digitigrade Stripes Right(Only works with digitigrade legs)" + icon_state = "stripes" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_R_LEG,BP_R_FOOT) + +/datum/sprite_accessory/marking/digi/smallspotsleft + name = "Digitigrade Small Spots Left(Only works with digitigrade legs)" + icon_state = "smallspots" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_L_LEG,BP_L_FOOT) + +/datum/sprite_accessory/marking/digi/smallspotsright + name = "Digitigrade Small Spots Right(Only works with digitigrade legs)" + icon_state = "smallspots" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_R_LEG,BP_R_FOOT) + +/datum/sprite_accessory/marking/digi/bigspotsleft + name = "Digitigrade Big Spots Left(Only works with digitigrade legs)" + icon_state = "bigspots" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_L_LEG,BP_L_FOOT) + +/datum/sprite_accessory/marking/digi/bigspotsright + name = "Digitigrade Big Spots Right(Only works with digitigrade legs)" + icon_state = "bigspots" + color_blend_mode = ICON_MULTIPLY + body_parts = list(BP_R_LEG,BP_R_FOOT) diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index b22ee48e98..76283cdf51 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -45,6 +45,8 @@ var/body_hair // Icon blend for body hair if any. var/mob/living/applied_pressure var/list/markings = list() // Markings (body_markings) to apply to the icon + var/skip_robo_icon = FALSE //to force it to use the normal species icon + var/digi_prosthetic = FALSE //is it a prosthetic that can be digitigrade // Wound and structural data. var/wound_update_accuracy = 1 // how often wounds should be updated, a higher number means less often @@ -201,6 +203,12 @@ O = O.parent return 0 +//new function to check for markings +/obj/item/organ/external/proc/is_hidden_by_markings() + for(var/M in markings) + var/datum/sprite_accessory/marking/mark_style = markings[M]["datum"] + if(istype(mark_style,/datum/sprite_accessory/marking) && (organ_tag in mark_style.hide_body_parts)) + return 1 /obj/item/organ/external/proc/dislocate() if(dislocated == -1) diff --git a/code/modules/organs/organ_icon.dm b/code/modules/organs/organ_icon.dm index 1c6be2a3e3..7304bb126a 100644 --- a/code/modules/organs/organ_icon.dm +++ b/code/modules/organs/organ_icon.dm @@ -81,6 +81,17 @@ var/global/list/limb_icon_cache = list() /obj/item/organ/external/proc/get_icon(var/skeletal, var/can_apply_transparency = TRUE) + var/digitigrade = 0 + + // preferentially take digitigrade value from owner if available, THEN DNA. + // this allows limbs to be set properly when being printed in the bioprinter without an owner + // this also allows the preview mannequin to update properly because customisation topic calls don't call a DNA check + var/check_digi = istype(src,/obj/item/organ/external/leg) || istype(src,/obj/item/organ/external/foot) + if(owner) + digitigrade = check_digi && owner.digitigrade + else if(dna) + digitigrade = check_digi && dna.digitigrade + for(var/M in markings) if (!markings[M]["on"]) continue @@ -139,8 +150,12 @@ var/global/list/limb_icon_cache = list() mob_icon = new /icon('icons/mob/human_races/robotic.dmi', "[icon_name][gender ? "_[gender]" : ""]") should_apply_transparency = TRUE apply_colouration(mob_icon) + else if(is_hidden_by_markings()) + mob_icon = new /icon('icons/mob/human_races/r_blank.dmi', "[icon_name][gender ? "_[gender]" : ""]") + should_apply_transparency = TRUE else - mob_icon = new /icon(species.get_icobase(owner, (status & ORGAN_MUTATED)), "[icon_name][gender ? "_[gender]" : ""]") + //Use digi icon if digitigrade, otherwise use regular icon. Ternary operator is based. + mob_icon = new /icon(digitigrade ? species.icodigi : species.get_icobase(owner, (status & ORGAN_MUTATED)), "[icon_name][gender ? "_[gender]" : ""]") should_apply_transparency = TRUE apply_colouration(mob_icon) diff --git a/code/modules/pda/pda.dm b/code/modules/pda/pda.dm index e0408d024c..50d7cca9e7 100644 --- a/code/modules/pda/pda.dm +++ b/code/modules/pda/pda.dm @@ -147,6 +147,10 @@ var/global/list/obj/item/device/pda/PDAs = list() SPECIES_VR_TESHARI = 'icons/mob/species/teshari/pda_wrist.dmi', ) if(7) icon = 'icons/obj/pda_slider.dmi' //VOREStation edit + if(8) + icon = 'icons/obj/pda_vintage.dmi' + desc = "A vintage communication device. This device has been refitted for compatibility with modern messaging systems, ROM cartridges and ID cards. Despite its heavy modifications it does not feature voice communication." + else icon = 'icons/obj/pda_old.dmi' log_debug("Invalid switch for PDA, defaulting to old PDA icons. [pdachoice] chosen.") diff --git a/code/modules/projectiles/guns/launcher/confetti.dm b/code/modules/projectiles/guns/launcher/confetti.dm new file mode 100644 index 0000000000..3d23b19385 --- /dev/null +++ b/code/modules/projectiles/guns/launcher/confetti.dm @@ -0,0 +1,105 @@ +//The confetti cannon is a simple weapon meant to be a toy. You shoot confetti at people and it makes a funny sound. Don't give this any combat use. +/obj/item/weapon/gun/launcher/confetti_cannon + name = "confetti cannon" + desc = "For those times when you absolutely need colored paper everywhere." + icon = 'icons/obj/weapons_vr.dmi' + icon_state = "confetti_cannon" + item_state = "confetti_cannon" + w_class = ITEMSIZE_NORMAL + origin_tech = list(TECH_COMBAT = 1, TECH_MATERIAL = 2) + throw_distance = 7 + release_force = 5 + var/obj/item/weapon/grenade/confetti/party_ball/chambered = null + + var/confetti_charge = 0 + var/max_confetti = 20 + +/obj/item/weapon/gun/launcher/confetti_cannon/examine(mob/user) + . = ..() + if(get_dist(user, src) <= 2) + . += "It's loaded with [confetti_charge] ball\s of confetti." + +/obj/item/weapon/gun/launcher/confetti_cannon/attackby(obj/item/I as obj, mob/user as mob) + if(istype(I, /obj/item/weapon/paper) || istype(I, /obj/item/weapon/shreddedp)) + if(confetti_charge < max_confetti) + user.drop_item() + ++confetti_charge + to_chat(usr, "You put the paper in the [src].") + qdel(I) + else + to_chat(usr, "[src] cannot hold more paper.") + +/obj/item/weapon/gun/launcher/confetti_cannon/proc/pump(mob/M as mob) + playsound(M, 'sound/weapons/shotgunpump.ogg', 60, 1) + if(!chambered) + if(confetti_charge) + chambered = new /obj/item/weapon/grenade/confetti/party_ball + --confetti_charge + to_chat(usr, "You compress a new confetti ball.") + else + to_chat(usr, "The [src] is out of confetti!") + else + to_chat(usr, "The [src] is already loaded!") + +/obj/item/weapon/gun/launcher/confetti_cannon/attack_self(mob/user) + pump(user) + +/obj/item/weapon/gun/launcher/confetti_cannon/consume_next_projectile() + if(chambered) + chambered.activate(null) + return chambered + +/obj/item/weapon/gun/launcher/confetti_cannon/handle_post_fire(mob/user) + chambered = null + +/obj/item/weapon/gun/launcher/confetti_cannon/overdrive + name = "overdrive confetti cannon" + desc = "For those times when you absolutely need colored paper everywhere, EVERYWHERE." + confetti_charge = 100 + max_confetti = 100 + +/obj/item/weapon/gun/launcher/confetti_cannon/fake_shottie + name = "horror movie shotgun" + desc = "The one necessary for survival of any Final Girl." + icon = 'icons/obj/gun2.dmi' + icon_state = "ithaca" + item_state = "ithaca" + confetti_charge = 20 + +/obj/item/weapon/gun/launcher/confetti_cannon/robot + name = "Party Cannon" + desc = "Confetti, pies, banana peels, chaos!" + +/obj/item/weapon/gun/launcher/confetti_cannon/robot/pump(mob/M as mob) + playsound(M, 'sound/weapons/shotgunpump.ogg', 60, 1) + if(!chambered) + var/choice = tgui_alert(usr, "Load the Party Canon with?", "Change What?", list("Confetti","Banana Peel","Cream Pie")) + if(!choice) + return + playsound(src, 'sound/effects/pop.ogg', 50, 0) + switch(choice) + if("Confetti") + chambered = new /obj/item/weapon/grenade/confetti/party_ball + to_chat(usr, "Confetti loaded.") + if(istype(usr,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = usr + R.cell.charge -= 200 + if("Banana Peel") + chambered = new /obj/item/weapon/bananapeel + to_chat(usr, "Banana peel loaded.") + if(istype(usr,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = usr + R.cell.charge -= 200 + if("Cream Pie") + chambered = new /obj/item/weapon/reagent_containers/food/snacks/pie + to_chat(usr, "Banana cream pie loaded.") + if(istype(usr,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = usr + R.cell.charge -= 200 + else + to_chat(usr, "The [src] is already loaded!") + +/obj/item/weapon/gun/launcher/confetti_cannon/robot/consume_next_projectile() + if(istype(chambered,/obj/item/weapon/grenade/confetti/party_ball)) + chambered.activate(null) + return chambered \ No newline at end of file diff --git a/code/modules/research/prosfab_designs_vr.dm b/code/modules/research/prosfab_designs_vr.dm index 7cc81d794a..d5195b28ad 100644 --- a/code/modules/research/prosfab_designs_vr.dm +++ b/code/modules/research/prosfab_designs_vr.dm @@ -21,6 +21,12 @@ materials = list(MAT_STEEL = 4000, MAT_GLASS = 4000) build_path = /obj/item/borg/upgrade/bellysizeupgrade +/datum/design/item/prosfab/robot_upgrade/bellycapupgrade + name = "Robohound Capability Expansion Module" + id = "borg_hound_capability_module" + req_tech = list(TECH_MATERIAL = 5, TECH_ENGINEERING = 4) + materials = list(MAT_STEEL = 8000, MAT_GLASS = 6000) + build_path = /obj/item/borg/upgrade/bellycapupgrade /* Some job related borg upgrade modules, adding useful items for puppers. diff --git a/code/modules/resleeving/machines.dm b/code/modules/resleeving/machines.dm index df40634606..4e7281af6e 100644 --- a/code/modules/resleeving/machines.dm +++ b/code/modules/resleeving/machines.dm @@ -99,6 +99,11 @@ for(var/modifier_type in R.genetic_modifiers) H.add_modifier(modifier_type) + //Apply legs + H.digitigrade = R.dna.digitigrade // ensure clone mob has digitigrade var set appropriately + if(H.dna.digitigrade <> R.dna.digitigrade) + H.dna.digitigrade = R.dna.digitigrade // ensure cloned DNA is set appropriately from record??? for some reason it doesn't get set right despite the override to datum/dna/Clone() + //Apply damage H.adjustCloneLoss(H.getMaxHealth()*1.5) H.Paralyse(4) diff --git a/code/modules/virus2/admin.dm b/code/modules/virus2/admin.dm index 30e673960c..687473c106 100644 --- a/code/modules/virus2/admin.dm +++ b/code/modules/virus2/admin.dm @@ -178,7 +178,7 @@ if("infectee") var/list/candidates = list() for(var/mob/living/carbon/G in living_mob_list) - if(G.stat != DEAD && G.species) + if(G.stat != DEAD && G.species && !isbelly(G.loc)) if(G.species.get_bodytype() in species) candidates["[G.name][G.client ? "" : " (no client)"]"] = G else diff --git a/code/modules/virus2/disease2.dm b/code/modules/virus2/disease2.dm index 0a89665a30..e8a275e838 100644 --- a/code/modules/virus2/disease2.dm +++ b/code/modules/virus2/disease2.dm @@ -284,7 +284,7 @@ var/global/list/virusDB = list() var/list/candidates = list() //list of candidate keys for(var/mob/living/carbon/human/G in player_list) - if(G.client && G.stat != DEAD) + if(G.client && G.stat != DEAD && !isbelly(G.loc)) candidates += G if(!candidates.len) return @@ -297,7 +297,7 @@ var/global/list/virusDB = list() var/list/candidates = list() //list of candidate keys for(var/mob/living/carbon/human/G in player_list) - if(G.client && G.stat != DEAD) + if(G.client && G.stat != DEAD && !isbelly(G.loc)) candidates += G if(!candidates.len) return diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index e2a16c9463..4914633fa1 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -1008,6 +1008,14 @@ set desc = "Switch sharp/fuzzy scaling for current mob." appearance_flags ^= PIXEL_SCALE fuzzy = !fuzzy + update_transform() + +/mob/living/proc/center_offset() + set name = "Switch center offset mode" + set category = "Preferences" + set desc = "Switch sprite center offset to fix even/odd symmetry." + offset_override = !offset_override + update_transform() /mob/living/examine(mob/user, infix, suffix) . = ..() diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm index 15d05d269d..4229a222d8 100644 --- a/code/modules/vore/eating/vorepanel_vr.dm +++ b/code/modules/vore/eating/vorepanel_vr.dm @@ -856,6 +856,11 @@ var/global/list/belly_colorable_only_fullscreens = list("a_synth_flesh_mono", l.adjust_nutrition(thismuch) ourtarget.death() // To make sure all on-death procs get properly called if(ourtarget) + if(ourtarget.is_preference_enabled(/datum/client_preference/digestion_noises)) + if(!b.fancy_vore) + SEND_SOUND(ourtarget, sound(get_sfx("classic_death_sounds"))) + else + SEND_SOUND(ourtarget, sound(get_sfx("fancy_death_prey"))) b.handle_digestion_death(ourtarget) if("Absorb") if(tgui_alert(ourtarget, "\The [usr] is attempting to instantly absorb you. Is this something you are okay with happening to you?","Instant Absorb", list("No", "Yes")) != "Yes") diff --git a/code/modules/vore/resizing/resize_vr.dm b/code/modules/vore/resizing/resize_vr.dm index d31348300d..7b6c39d9ab 100644 --- a/code/modules/vore/resizing/resize_vr.dm +++ b/code/modules/vore/resizing/resize_vr.dm @@ -3,6 +3,8 @@ /mob var/step_mechanics_pref = TRUE // Allow participation in macro-micro step mechanics var/pickup_pref = TRUE // Allow participation in macro-micro pickup mechanics + var/center_offset = 0.5 // Center offset for uneven scaling symmetry. + var/offset_override = FALSE // Pref toggle for center offset. /mob/living var/holder_default @@ -30,9 +32,12 @@ /mob/living/update_icons() . = ..() ASSERT(!ishuman(src)) + var/cent_offset = center_offset + if(fuzzy || offset_override || dir == EAST || dir == WEST) + cent_offset = 0 var/matrix/M = matrix() M.Scale(size_multiplier * icon_scale_x, size_multiplier * icon_scale_y) - M.Translate(0, (vis_height/2)*(size_multiplier-1)) + M.Translate(cent_offset * size_multiplier * icon_scale_x, (vis_height/2)*(size_multiplier-1)) transform = M /** diff --git a/code/stylesheet.dm b/code/stylesheet.dm index 073d91bd39..b62c4a8146 100644 --- a/code/stylesheet.dm +++ b/code/stylesheet.dm @@ -73,7 +73,7 @@ h1.alert, h2.alert {color: #000000;} /* VOREStation Edit Start */ .emote {} -.emote_subtle {font-style: italic;} +.emotesubtle {font-style: italic;} /* VOREStation Edit End */ /* Game Messages */ diff --git a/icons/inventory/feet/mob_digi.dmi b/icons/inventory/feet/mob_digi.dmi new file mode 100644 index 0000000000..c2a1a9ab82 Binary files /dev/null and b/icons/inventory/feet/mob_digi.dmi differ diff --git a/icons/inventory/suit/mob_digi.dmi b/icons/inventory/suit/mob_digi.dmi new file mode 100644 index 0000000000..43ec6bc337 Binary files /dev/null and b/icons/inventory/suit/mob_digi.dmi differ diff --git a/icons/inventory/uniform/mob_digi.dmi b/icons/inventory/uniform/mob_digi.dmi new file mode 100644 index 0000000000..637e63b889 Binary files /dev/null and b/icons/inventory/uniform/mob_digi.dmi differ diff --git a/icons/mob/human_races/markings_digi.dmi b/icons/mob/human_races/markings_digi.dmi new file mode 100644 index 0000000000..c9f504c584 Binary files /dev/null and b/icons/mob/human_races/markings_digi.dmi differ diff --git a/icons/mob/human_races/masks/blood_digitigrade.dmi b/icons/mob/human_races/masks/blood_digitigrade.dmi new file mode 100644 index 0000000000..5980ce30f7 Binary files /dev/null and b/icons/mob/human_races/masks/blood_digitigrade.dmi differ diff --git a/icons/mob/human_races/r_blank.dmi b/icons/mob/human_races/r_blank.dmi new file mode 100644 index 0000000000..9b2fb0341d Binary files /dev/null and b/icons/mob/human_races/r_blank.dmi differ diff --git a/icons/mob/human_races/r_digi.dmi b/icons/mob/human_races/r_digi.dmi new file mode 100644 index 0000000000..4a38e7155e Binary files /dev/null and b/icons/mob/human_races/r_digi.dmi differ diff --git a/icons/mob/human_races/r_digi_xeno.dmi b/icons/mob/human_races/r_digi_xeno.dmi new file mode 100644 index 0000000000..fee592f02e Binary files /dev/null and b/icons/mob/human_races/r_digi_xeno.dmi differ diff --git a/icons/mob/human_races/r_xenomorph_hybrid.dmi b/icons/mob/human_races/r_xenomorph_hybrid.dmi new file mode 100644 index 0000000000..811456cd1f Binary files /dev/null and b/icons/mob/human_races/r_xenomorph_hybrid.dmi differ diff --git a/icons/mob/robot/clerical_wide.dmi b/icons/mob/robot/clerical_wide.dmi new file mode 100644 index 0000000000..d472990269 Binary files /dev/null and b/icons/mob/robot/clerical_wide.dmi differ diff --git a/icons/mob/robot/crisis_large.dmi b/icons/mob/robot/crisis_large.dmi index c15c4ee5c7..fe3eddf6ac 100644 Binary files a/icons/mob/robot/crisis_large.dmi and b/icons/mob/robot/crisis_large.dmi differ diff --git a/icons/mob/robot/protector_wide.dmi b/icons/mob/robot/protector_wide.dmi new file mode 100644 index 0000000000..7028585c11 Binary files /dev/null and b/icons/mob/robot/protector_wide.dmi differ diff --git a/icons/mob/robot/service_wide.dmi b/icons/mob/robot/service_wide.dmi index 1ec76e9e83..3c3613c94f 100644 Binary files a/icons/mob/robot/service_wide.dmi and b/icons/mob/robot/service_wide.dmi differ diff --git a/icons/mob/robot/syndie_large.dmi b/icons/mob/robot/syndie_large.dmi new file mode 100644 index 0000000000..3a0db17d6e Binary files /dev/null and b/icons/mob/robot/syndie_large.dmi differ diff --git a/icons/mob/robot/syndie_wide.dmi b/icons/mob/robot/syndie_wide.dmi new file mode 100644 index 0000000000..23e2b9d13e Binary files /dev/null and b/icons/mob/robot/syndie_wide.dmi differ diff --git a/icons/obj/food_package.dmi b/icons/obj/food_package.dmi index cf22ac48ed..ab8e1c901f 100644 Binary files a/icons/obj/food_package.dmi and b/icons/obj/food_package.dmi differ diff --git a/icons/obj/food_snacks.dmi b/icons/obj/food_snacks.dmi index 6962741815..3761135206 100644 Binary files a/icons/obj/food_snacks.dmi and b/icons/obj/food_snacks.dmi differ diff --git a/icons/obj/food_vr.dmi b/icons/obj/food_vr.dmi index 1e79233304..0f07fdeb2e 100644 Binary files a/icons/obj/food_vr.dmi and b/icons/obj/food_vr.dmi differ diff --git a/icons/obj/grenade.dmi b/icons/obj/grenade.dmi index 8f2ed0d8bb..f55e4af910 100644 Binary files a/icons/obj/grenade.dmi and b/icons/obj/grenade.dmi differ diff --git a/icons/obj/pda_vintage.dmi b/icons/obj/pda_vintage.dmi new file mode 100644 index 0000000000..a386937edd Binary files /dev/null and b/icons/obj/pda_vintage.dmi differ diff --git a/icons/obj/trash.dmi b/icons/obj/trash.dmi index e8841c78cc..8866b481c1 100644 Binary files a/icons/obj/trash.dmi and b/icons/obj/trash.dmi differ diff --git a/icons/obj/trash_vr.dmi b/icons/obj/trash_vr.dmi index cf0cdbd120..e90dc8b1da 100644 Binary files a/icons/obj/trash_vr.dmi and b/icons/obj/trash_vr.dmi differ diff --git a/icons/obj/vending_vr.dmi b/icons/obj/vending_vr.dmi index a11ef2b241..961483a8d2 100644 Binary files a/icons/obj/vending_vr.dmi and b/icons/obj/vending_vr.dmi differ diff --git a/icons/obj/weapons_vr.dmi b/icons/obj/weapons_vr.dmi index 968c6e8ef2..06274f9cf7 100644 Binary files a/icons/obj/weapons_vr.dmi and b/icons/obj/weapons_vr.dmi differ diff --git a/interface/fonts.dm b/interface/fonts.dm new file mode 100644 index 0000000000..31db4fa961 --- /dev/null +++ b/interface/fonts.dm @@ -0,0 +1,6 @@ +/// A font datum, it exists to define a custom font to use in a span style later. +/datum/font + /// Font name, just so people know what to put in their span style. + var/name + /// The font file we link to. + var/font_family diff --git a/interface/skin.dmf b/interface/skin.dmf index c3683f6846..2afdc438bb 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -1429,32 +1429,6 @@ window "rpane" is-checked = true group = "rpanemode" button-type = pushbox - elem "browseb" - type = BUTTON - pos = 580,0 - size = 60x16 - anchor1 = 100,0 - anchor2 = 100,0 - background-color = none - is-visible = false - saved-params = "is-checked" - text = "Browser" - command = ".winset \"rpanewindow.left=browserwindow\"" - group = "rpanemode" - button-type = pushbox - elem "infob" - type = BUTTON - pos = 60,0 - size = 60x16 - anchor1 = -1,-1 - anchor2 = -1,-1 - background-color = none - is-visible = false - saved-params = "is-checked" - text = "Info" - command = ".winset \"rpanewindow.left=infowindow\"" - group = "rpanemode" - button-type = pushbox elem "mediapanel" type = BROWSER pos = 392,25 @@ -1465,28 +1439,6 @@ window "rpane" is-visible = false saved-params = "" -window "browserwindow" - elem "browserwindow" - type = MAIN - pos = 281,0 - size = 640x480 - anchor1 = -1,-1 - anchor2 = -1,-1 - saved-params = "pos;size;is-minimized;is-maximized" - title = "Browser" - is-pane = true - elem "browser" - type = BROWSER - pos = 0,0 - size = 640x499 - anchor1 = 0,0 - anchor2 = 100,100 - background-color = #ffffff - is-default = true - saved-params = "" - on-show = ".winset\"rpane.infob.is-visible=true?rpane.infob.pos=130,0;rpane.textb.is-visible=true;rpane.browseb.is-visible=true;rpane.browseb.is-checked=true;rpane.rpanewindow.pos=0,30;rpane.rpanewindow.size=0x0;rpane.rpanewindow.left=browserwindow\"" - on-hide = ".winset\"rpane.infob.is-visible=true?rpane.infob.is-checked=true rpane.infob.pos=65,0 rpane.rpanewindow.left=infowindow:rpane.rpanewindow.left=textwindow rpane.textb.is-visible=true rpane.rpanewindow.pos=0,30 rpane.rpanewindow.size=0x0\"" - window "preferences_window" elem "preferences_window" type = MAIN diff --git a/maps/stellar_delight/stellar_delight1.dmm b/maps/stellar_delight/stellar_delight1.dmm index d5a56d023a..10768614d8 100644 --- a/maps/stellar_delight/stellar_delight1.dmm +++ b/maps/stellar_delight/stellar_delight1.dmm @@ -3036,7 +3036,9 @@ /turf/simulated/floor/tiled/eris/steel/cargo, /area/stellardelight/deck1/oreprocessing) "fL" = ( -/obj/machinery/firealarm/angled, +/obj/machinery/light{ + dir = 1 + }, /turf/simulated/floor/tiled/eris/white/bluecorner, /area/stellardelight/deck1/resleeving) "fM" = ( @@ -4303,6 +4305,7 @@ /obj/machinery/atmospherics/unary/vent_scrubber/on{ dir = 1 }, +/obj/machinery/light, /turf/simulated/floor/tiled/eris/white/bluecorner, /area/stellardelight/deck1/resleeving) "iq" = ( @@ -5409,6 +5412,9 @@ name = "Station Intercom (General)"; pixel_y = 21 }, +/obj/machinery/light{ + dir = 4 + }, /turf/simulated/floor/tiled/techfloor, /area/stellardelight/deck1/starboard) "kN" = ( @@ -7407,12 +7413,12 @@ /turf/simulated/floor/tiled/techmaint, /area/stellardelight/deck1/port) "oW" = ( -/obj/machinery/light{ - dir = 8 - }, /obj/structure/cable/white{ icon_state = "1-2" }, +/obj/machinery/firealarm/angled{ + dir = 8 + }, /turf/simulated/floor/tiled/eris/white/bluecorner, /area/stellardelight/deck1/resleeving) "oX" = ( @@ -8053,6 +8059,9 @@ "qo" = ( /obj/machinery/atmospherics/unary/vent_scrubber/on, /obj/structure/closet/emcloset, +/obj/machinery/light{ + dir = 8 + }, /turf/simulated/floor/tiled/techfloor, /area/stellardelight/deck1/port) "qp" = ( @@ -14369,6 +14378,9 @@ /obj/machinery/atmospherics/unary/vent_pump/on{ dir = 4 }, +/obj/machinery/light{ + dir = 1 + }, /turf/simulated/floor/tiled/eris/white/bluecorner, /area/stellardelight/deck1/lowermed) "Ev" = ( @@ -18280,9 +18292,6 @@ /obj/structure/closet/crate/bin{ anchored = 1 }, -/obj/machinery/light{ - dir = 1 - }, /turf/simulated/floor/tiled/eris/white/bluecorner, /area/stellardelight/deck1/resleeving) "MZ" = ( diff --git a/maps/stellar_delight/stellar_delight3.dmm b/maps/stellar_delight/stellar_delight3.dmm index 1654195a57..256c4bdc0d 100644 --- a/maps/stellar_delight/stellar_delight3.dmm +++ b/maps/stellar_delight/stellar_delight3.dmm @@ -273,6 +273,18 @@ }, /turf/simulated/floor/tiled, /area/crew_quarters/heads/hop) +"aI" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 1 + }, +/obj/structure/cable/green{ + icon_state = "4-8" + }, +/obj/effect/landmark/vines, +/turf/simulated/open, +/area/stellardelight/deck2/fore) "aJ" = ( /obj/machinery/door/firedoor/glass, /obj/structure/window/bay/reinforced, @@ -288,6 +300,12 @@ }, /turf/simulated/floor/tiled, /area/crew_quarters/heads/hop) +"aL" = ( +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 4 + }, +/turf/simulated/open, +/area/stellardelight/deck2/fore) "aM" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 10 @@ -296,6 +314,17 @@ /area/stellardelight/deck2/central) "aN" = ( /obj/structure/lattice, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/effect/landmark/vermin, +/turf/simulated/open, +/area/stellardelight/deck2/fore) +"aO" = ( +/obj/structure/lattice, /obj/machinery/atmospherics/pipe/manifold/hidden/supply{ dir = 8 }, @@ -305,8 +334,9 @@ /obj/structure/cable/blue{ icon_state = "1-2" }, +/obj/effect/landmark/vermin, /turf/simulated/open, -/area/stellardelight/deck2/starboard) +/area/stellardelight/deck2/fore) "aP" = ( /obj/structure/bed/chair/shuttle{ dir = 1 @@ -329,9 +359,58 @@ "aQ" = ( /turf/simulated/floor/tiled/eris/dark/gray_platform, /area/stellardelight/deck3/commandhall) +"aR" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/effect/landmark/vines, +/turf/simulated/open, +/area/stellardelight/deck2/fore) "aS" = ( /turf/simulated/floor, /area/maintenance/stellardelight/deck3/forestarrooma) +"aT" = ( +/obj/structure/lattice, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/structure/cable/blue{ + icon_state = "1-2" + }, +/obj/effect/landmark/vermin, +/turf/simulated/open, +/area/stellardelight/deck2/starboard) +"aU" = ( +/obj/structure/lattice, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 8 + }, +/obj/effect/landmark/vines, +/turf/simulated/open, +/area/stellardelight/deck2/port) +"aV" = ( +/obj/structure/lattice, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/effect/landmark/vines, +/turf/simulated/open, +/area/stellardelight/deck2/starboard) "aX" = ( /obj/structure/sign/deck3{ pixel_x = 32 @@ -341,11 +420,6 @@ }, /turf/simulated/floor/tiled, /area/stellardelight/deck3/aft) -"ba" = ( -/obj/machinery/atmospherics/unary/vent_pump/on, -/obj/effect/landmark/vines, -/turf/simulated/open, -/area/stellardelight/deck2/fore) "bb" = ( /obj/effect/floor_decal/techfloor/orange{ dir = 8 @@ -888,17 +962,6 @@ }, /turf/simulated/floor, /area/maintenance/stellardelight/deck3/foreportrooma) -"db" = ( -/obj/structure/lattice, -/obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 4 - }, -/turf/simulated/open, -/area/stellardelight/deck2/starboard) "df" = ( /obj/structure/cable/green{ icon_state = "1-2" @@ -6032,13 +6095,6 @@ /obj/structure/low_wall/bay/reinforced/steel, /turf/simulated/floor, /area/stellardelight/deck2/port) -"wc" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 8 - }, -/obj/effect/landmark/vermin, -/turf/simulated/open, -/area/stellardelight/deck2/starboard) "wd" = ( /obj/structure/table/standard, /obj/item/weapon/aiModule/oxygen, @@ -7841,13 +7897,6 @@ /obj/machinery/door/firedoor/glass, /turf/simulated/floor, /area/maintenance/stellardelight/deck3/portaft) -"Cb" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 4 - }, -/obj/effect/landmark/vermin, -/turf/simulated/open, -/area/stellardelight/deck2/fore) "Cc" = ( /obj/machinery/door/firedoor/glass, /obj/machinery/door/airlock/angled_bay/hatch{ @@ -9525,13 +9574,6 @@ }, /turf/simulated/floor/tiled, /area/crew_quarters/heads/chief) -"ID" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 8 - }, -/obj/effect/landmark/vines, -/turf/simulated/open, -/area/stellardelight/deck2/fore) "IG" = ( /obj/structure/cable/blue{ icon_state = "4-8" @@ -10679,13 +10721,6 @@ /obj/random/maintenance, /turf/simulated/floor, /area/maintenance/stellardelight/deck3/starboardfore) -"Mv" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 4 - }, -/obj/effect/landmark/vines, -/turf/simulated/open, -/area/stellardelight/deck2/fore) "Mw" = ( /obj/machinery/atmospherics/pipe/manifold/hidden{ dir = 1 @@ -10905,13 +10940,6 @@ }, /turf/simulated/floor/tiled/techfloor, /area/stellardelight/deck3/cryo) -"Nd" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 4 - }, -/obj/effect/landmark/vines, -/turf/simulated/open, -/area/stellardelight/deck2/port) "Ne" = ( /obj/structure/cable{ icon_state = "1-8" @@ -11569,13 +11597,6 @@ "OX" = ( /turf/simulated/floor, /area/maintenance/stellardelight/deck3/portcent) -"OY" = ( -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 8 - }, -/obj/effect/landmark/vines, -/turf/simulated/open, -/area/stellardelight/deck2/starboard) "Pa" = ( /obj/structure/lattice, /turf/simulated/open, @@ -13769,16 +13790,6 @@ /obj/machinery/atmospherics/pipe/manifold4w/hidden, /turf/simulated/floor/airless, /area/maintenance/stellardelight/deck3/starboardcent) -"Xe" = ( -/obj/structure/lattice, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 8 - }, -/turf/simulated/open, -/area/stellardelight/deck2/fore) "Xf" = ( /obj/machinery/atmospherics/unary/vent_pump/on, /turf/simulated/open, @@ -22020,7 +22031,7 @@ CS oW oW oW -Nd +QF oW oW oW @@ -22162,7 +22173,7 @@ Yw uf uf uf -Mk +aU uf uf uf @@ -22842,7 +22853,7 @@ qF qF qF qF -Cb +aL qF qF qF @@ -22851,7 +22862,7 @@ Cp qF qF qF -Mv +aL qF qF qF @@ -22984,7 +22995,7 @@ qi qi qi qi -Xe +aN qi qi qi @@ -22993,7 +23004,7 @@ kO qi qi qi -Xe +aR qi qi qi @@ -23829,8 +23840,8 @@ qp NF qp Qp -ba -Ie +Hf +aI tV cb gy @@ -25824,7 +25835,7 @@ sd sd sd sd -wy +aO sd sd sd @@ -25840,7 +25851,7 @@ sd sd Rj FL -aN +aT FL FL OI @@ -25966,7 +25977,7 @@ qF qF qF qF -ID +KF qF qF qF @@ -25982,7 +25993,7 @@ qF hC aJ ow -wc +ZC ow yP Ks @@ -26715,7 +26726,7 @@ mS mS mS mS -db +aV mS mS Rz @@ -26857,7 +26868,7 @@ ow ow ow ow -OY +ZC yP ow ZM diff --git a/maps/tether/tether-05-station1.dmm b/maps/tether/tether-05-station1.dmm index 424654bb77..b05742514c 100644 --- a/maps/tether/tether-05-station1.dmm +++ b/maps/tether/tether-05-station1.dmm @@ -133,6 +133,22 @@ /obj/machinery/door/airlock/maintenance/common, /turf/simulated/floor, /area/tether/exploration/hallway) +"aap" = ( +/obj/structure/cable{ + icon_state = "1-2" + }, +/obj/machinery/door/airlock/highsecurity{ + name = "Telecomms Access"; + req_access = list(61); + req_one_access = list() + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/door/firedoor/glass, +/turf/simulated/floor/tiled/techfloor, +/area/tcommsat/entrance{ + name = "\improper Telecomms Entrance" + }) "aaq" = ( /turf/simulated/wall/r_wall, /area/maintenance/station/exploration) @@ -12607,7 +12623,7 @@ frequency = 1443; level = 3; name = "Distribution and Waste Monitor"; - sensors = list("dist_main_meter"="Surface - Distribution Loop","scrub_main_meter"="Surface - Scrubbers Loop","mair_main_meter"="Surface - Mixed Air Tank","dist_aux_meter"="Station - Distribution Loop","scrub_aux_meter"="Station - Scrubbers Loop","mair_aux_meter"="Station - Mixed Air Tank","mair_mining_meter"="Mining Outpost - Mixed Air Tank") + sensors = list("dist_main_meter" = "Surface - Distribution Loop", "scrub_main_meter" = "Surface - Scrubbers Loop", "mair_main_meter" = "Surface - Mixed Air Tank", "dist_aux_meter" = "Station - Distribution Loop", "scrub_aux_meter" = "Station - Scrubbers Loop", "mair_aux_meter" = "Station - Mixed Air Tank", "mair_mining_meter" = "Mining Outpost - Mixed Air Tank") }, /turf/simulated/floor/tiled, /area/engineering/engineering_monitoring) @@ -21737,21 +21753,6 @@ /obj/structure/sign/department/eng, /turf/simulated/wall/r_wall, /area/hallway/station/docks) -"jmn" = ( -/obj/structure/cable{ - icon_state = "1-2" - }, -/obj/machinery/door/airlock/highsecurity{ - name = "Telecomms Access"; - req_one_access = list(10,12,16,17,61) - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/obj/machinery/door/firedoor/glass, -/turf/simulated/floor/tiled/techfloor, -/area/tcommsat/entrance{ - name = "\improper Telecomms Entrance" - }) "jms" = ( /obj/structure/table/rack, /obj/item/clothing/suit/space/void/mining, @@ -23210,7 +23211,6 @@ /area/gateway/prep_room) "kHf" = ( /obj/machinery/conveyor_switch/oneway{ - //convdir = -1; //Incompatable with new behavior -Reo; id = "QMLoad2" }, /obj/machinery/light{ @@ -28372,24 +28372,6 @@ /obj/machinery/atmospherics/pipe/manifold/hidden/supply, /turf/simulated/floor/tiled, /area/quartermaster/office) -"qSM" = ( -/obj/structure/cable{ - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden{ - dir = 4 - }, -/turf/simulated/floor/tiled, -/area/tether/station/dock_two) "qTD" = ( /obj/item/weapon/bedsheet/brown, /obj/structure/bed/padded, @@ -47053,7 +47035,7 @@ aaa aaa fLT cOV -qSM +rQq vcG fLT aaa @@ -47195,7 +47177,7 @@ xIm jRT fLT kbq -qSM +rQq jGw fLT aaa @@ -49041,7 +49023,7 @@ aaa aaa fLT lNz -qSM +rQq qZs fLT aaa @@ -49574,7 +49556,7 @@ hkR lGY nJx acR -jmn +aap acZ adg adr diff --git a/sound/effects/confetti_ball.ogg b/sound/effects/confetti_ball.ogg new file mode 100644 index 0000000000..8db31be074 Binary files /dev/null and b/sound/effects/confetti_ball.ogg differ diff --git a/tgui/packages/tgui-dev-server/package.json b/tgui/packages/tgui-dev-server/package.json index a7cf248a48..ab45774318 100644 --- a/tgui/packages/tgui-dev-server/package.json +++ b/tgui/packages/tgui-dev-server/package.json @@ -4,7 +4,7 @@ "version": "4.4.1", "type": "module", "dependencies": { - "axios": "^0.27.2", + "axios": "^1.6.0", "glob": "^8.0.3", "source-map": "^0.7.3", "stacktrace-parser": "^0.1.10", diff --git a/tgui/packages/tgui-panel/Notifications.js b/tgui/packages/tgui-panel/Notifications.js new file mode 100644 index 0000000000..2b92995287 --- /dev/null +++ b/tgui/packages/tgui-panel/Notifications.js @@ -0,0 +1,28 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { Flex } from 'tgui/components'; + +export const Notifications = (props) => { + const { children } = props; + return
{children}
; +}; + +const NotificationsItem = (props) => { + const { rightSlot, children } = props; + return ( + + + {children} + + {rightSlot && ( + {rightSlot} + )} + + ); +}; + +Notifications.Item = NotificationsItem; diff --git a/tgui/packages/tgui-panel/Panel.js b/tgui/packages/tgui-panel/Panel.js new file mode 100644 index 0000000000..83150ab6ef --- /dev/null +++ b/tgui/packages/tgui-panel/Panel.js @@ -0,0 +1,128 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { Button, Section, Stack } from 'tgui/components'; +import { Pane } from 'tgui/layouts'; +import { NowPlayingWidget, useAudio } from './audio'; +import { ChatPanel, ChatTabs } from './chat'; +import { useGame } from './game'; +import { Notifications } from './Notifications'; +import { PingIndicator } from './ping'; +import { ReconnectButton } from './reconnect'; +import { SettingsPanel, useSettings } from './settings'; + +export const Panel = (props, context) => { + // IE8-10: Needs special treatment due to missing Flex support + if (Byond.IS_LTE_IE10) { + return ; + } + const audio = useAudio(context); + const settings = useSettings(context); + const game = useGame(context); + if (process.env.NODE_ENV !== 'production') { + const { useDebug, KitchenSink } = require('tgui/debug'); + const debug = useDebug(context); + if (debug.kitchenSink) { + return ; + } + } + return ( + + + +
+ + + + + + + + +
+
+ {audio.visible && ( + +
+ +
+
+ )} + {settings.visible && ( + + + + )} + +
+ + + + + {game.connectionLostAt && ( + }> + You are either AFK, experiencing lag or the connection has + closed. + + )} + {game.roundRestartedAt && ( + + The connection has been closed because the server is + restarting. Please wait while you automatically reconnect. + + )} + +
+
+
+
+ ); +}; + +const HoboPanel = (props, context) => { + const settings = useSettings(context); + return ( + + + + {(settings.visible && ) || ( + + )} + + + ); +}; diff --git a/tgui/packages/tgui-panel/audio/NowPlayingWidget.js b/tgui/packages/tgui-panel/audio/NowPlayingWidget.js new file mode 100644 index 0000000000..30052c3f3a --- /dev/null +++ b/tgui/packages/tgui-panel/audio/NowPlayingWidget.js @@ -0,0 +1,109 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { toFixed } from 'common/math'; +import { useDispatch, useSelector } from 'common/redux'; +import { Button, Collapsible, Flex, Knob, Section } from 'tgui/components'; +import { useSettings } from '../settings'; +import { selectAudio } from './selectors'; + +export const NowPlayingWidget = (props, context) => { + const audio = useSelector(context, selectAudio), + dispatch = useDispatch(context), + settings = useSettings(context), + title = audio.meta?.title, + URL = audio.meta?.link, + Artist = audio.meta?.artist || 'Unknown Artist', + upload_date = audio.meta?.upload_date || 'Unknown Date', + album = audio.meta?.album || 'Unknown Album', + duration = audio.meta?.duration, + date = !isNaN(upload_date) + ? upload_date?.substring(0, 4) + + '-' + + upload_date?.substring(4, 6) + + '-' + + upload_date?.substring(6, 8) + : upload_date; + + return ( + + {(audio.playing && ( + + { + +
+ {URL !== 'Song Link Hidden' && ( + + URL: {URL} + + )} + + Duration: {duration} + + {Artist !== 'Song Artist Hidden' && + Artist !== 'Unknown Artist' && ( + + Artist: {Artist} + + )} + {album !== 'Song Album Hidden' && album !== 'Unknown Album' && ( + + Album: {album} + + )} + {upload_date !== 'Song Upload Date Hidden' && + upload_date !== 'Unknown Date' && ( + + Uploaded: {date} + + )} +
+
+ } +
+ )) || ( + + Nothing to play. + + )} + {audio.playing && ( + + + + + +
+ {MESSAGE_TYPES.filter( + (typeDef) => !typeDef.important && !typeDef.admin + ).map((typeDef) => ( + + dispatch( + toggleAcceptedType({ + pageId: page.id, + type: typeDef.type, + }) + ) + }> + {typeDef.name} + + ))} + + {MESSAGE_TYPES.filter( + (typeDef) => !typeDef.important && typeDef.admin + ).map((typeDef) => ( + + dispatch( + toggleAcceptedType({ + pageId: page.id, + type: typeDef.type, + }) + ) + }> + {typeDef.name} + + ))} + +
+ + ); +}; diff --git a/tgui/packages/tgui-panel/chat/ChatPanel.js b/tgui/packages/tgui-panel/chat/ChatPanel.js new file mode 100644 index 0000000000..3132a66ce7 --- /dev/null +++ b/tgui/packages/tgui-panel/chat/ChatPanel.js @@ -0,0 +1,73 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { shallowDiffers } from 'common/react'; +import { Component, createRef } from 'inferno'; +import { Button } from 'tgui/components'; +import { chatRenderer } from './renderer'; + +export class ChatPanel extends Component { + constructor() { + super(); + this.ref = createRef(); + this.state = { + scrollTracking: true, + }; + this.handleScrollTrackingChange = (value) => + this.setState({ + scrollTracking: value, + }); + } + + componentDidMount() { + chatRenderer.mount(this.ref.current); + chatRenderer.events.on( + 'scrollTrackingChanged', + this.handleScrollTrackingChange + ); + this.componentDidUpdate(); + } + + componentWillUnmount() { + chatRenderer.events.off( + 'scrollTrackingChanged', + this.handleScrollTrackingChange + ); + } + + componentDidUpdate(prevProps) { + requestAnimationFrame(() => { + chatRenderer.ensureScrollTracking(); + }); + const shouldUpdateStyle = + !prevProps || shallowDiffers(this.props, prevProps); + if (shouldUpdateStyle) { + chatRenderer.assignStyle({ + 'width': '100%', + 'white-space': 'pre-wrap', + 'font-size': this.props.fontSize, + 'line-height': this.props.lineHeight, + }); + } + } + + render() { + const { scrollTracking } = this.state; + return ( + <> +
+ {!scrollTracking && ( + + )} + + ); + } +} diff --git a/tgui/packages/tgui-panel/chat/ChatTabs.js b/tgui/packages/tgui-panel/chat/ChatTabs.js new file mode 100644 index 0000000000..1d4f6f65ed --- /dev/null +++ b/tgui/packages/tgui-panel/chat/ChatTabs.js @@ -0,0 +1,68 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { useDispatch, useSelector } from 'common/redux'; +import { Box, Tabs, Flex, Button } from 'tgui/components'; +import { changeChatPage, addChatPage } from './actions'; +import { selectChatPages, selectCurrentChatPage } from './selectors'; +import { openChatSettings } from '../settings/actions'; + +const UnreadCountWidget = ({ value }) => ( + + {Math.min(value, 99)} + +); + +export const ChatTabs = (props, context) => { + const pages = useSelector(context, selectChatPages); + const currentPage = useSelector(context, selectCurrentChatPage); + const dispatch = useDispatch(context); + return ( + + + + {pages.map((page) => ( + 0 && ( + + ) + } + onClick={() => + dispatch( + changeChatPage({ + pageId: page.id, + }) + ) + }> + {page.name} + + ))} + + + + + + + ); +}; diff --git a/tgui/packages/tgui-panel/settings/SettingsPanel.js b/tgui/packages/tgui-panel/settings/SettingsPanel.js new file mode 100644 index 0000000000..90abe4e36b --- /dev/null +++ b/tgui/packages/tgui-panel/settings/SettingsPanel.js @@ -0,0 +1,311 @@ +/** + * @file + * @copyright 2020 Aleksej Komarov + * @license MIT + */ + +import { toFixed } from 'common/math'; +import { useLocalState } from 'tgui/backend'; +import { useDispatch, useSelector } from 'common/redux'; +import { Box, Button, ColorBox, Divider, Dropdown, Flex, Input, LabeledList, NumberInput, Section, Stack, Tabs, TextArea } from 'tgui/components'; +import { ChatPageSettings } from '../chat'; +import { rebuildChat, saveChatToDisk } from '../chat/actions'; +import { THEMES } from '../themes'; +import { changeSettingsTab, updateSettings, addHighlightSetting, removeHighlightSetting, updateHighlightSetting } from './actions'; +import { SETTINGS_TABS, FONTS, MAX_HIGHLIGHT_SETTINGS } from './constants'; +import { selectActiveTab, selectSettings, selectHighlightSettings, selectHighlightSettingById } from './selectors'; + +export const SettingsPanel = (props, context) => { + const activeTab = useSelector(context, selectActiveTab); + const dispatch = useDispatch(context); + return ( + + +
+ + {SETTINGS_TABS.map((tab) => ( + + dispatch( + changeSettingsTab({ + tabId: tab.id, + }) + ) + }> + {tab.name} + + ))} + +
+
+ + {activeTab === 'general' && } + {activeTab === 'chatPage' && } + {activeTab === 'textHighlight' && } + +
+ ); +}; + +export const SettingsGeneral = (props, context) => { + const { theme, fontFamily, fontSize, lineHeight } = useSelector( + context, + selectSettings + ); + const dispatch = useDispatch(context); + const [freeFont, setFreeFont] = useLocalState(context, 'freeFont', false); + return ( +
+ + + + dispatch( + updateSettings({ + theme: value, + }) + ) + } + /> + + + + + {(!freeFont && ( + + dispatch( + updateSettings({ + fontFamily: value, + }) + ) + } + /> + )) || ( + + dispatch( + updateSettings({ + fontFamily: value, + }) + ) + } + /> + )} + + + +
+ ); +}; + +const TextHighlightSettings = (props, context) => { + const highlightSettings = useSelector(context, selectHighlightSettings); + const dispatch = useDispatch(context); + return ( +
+
+ + {highlightSettings.map((id, i) => ( + + ))} + {highlightSettings.length < MAX_HIGHLIGHT_SETTINGS && ( + +
+ + + + + Can freeze the chat for a while. + + +
+ ); +}; + +const TextHighlightSetting = (props, context) => { + const { id, ...rest } = props; + const highlightSettingById = useSelector(context, selectHighlightSettingById); + const dispatch = useDispatch(context); + const { + highlightColor, + highlightText, + highlightWholeMessage, + matchWord, + matchCase, + } = highlightSettingById[id]; + return ( + + + +