From fa754d7a7f71e0a10b8b424037cf344d82d653b0 Mon Sep 17 00:00:00 2001 From: InsaneRed <47158596+InsaneRed@users.noreply.github.com> Date: Wed, 27 Dec 2023 21:04:45 +0300 Subject: [PATCH 01/28] Fixes synths being unlungeable while in "critical state" (#5303) # About the pull request Synths were given immunity to dragging from old code back when they could go into 'crit' so they dont get dragged to hell, however they no longer have a crit state but still keep the immunity lunges also do not work because of this. this is not intended. # Explain why it's good for the game bugfix # Testing Photographs and Procedure
Screenshots & Videos yeah i tested it also no you cant get dragged while dead
# Changelog :cl: fix: Synths are no longer immune to lunges / dragging while in 'critical state' since they dont go into crit. /:cl: Co-authored-by: InsaneRed --- code/modules/mob/living/carbon/xenomorph/Xenomorph.dm | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index 3f6e5e85f565..d8f92554c8b3 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -731,8 +731,6 @@ if(!isliving(AM)) return FALSE var/mob/living/L = AM - if(issynth(L) && L.health < 0) // no pulling critted or dead synths - return FALSE if(L.buckled) return FALSE //to stop xeno from pulling marines on roller beds. if(!L.is_xeno_grabbable()) From 5bc9eabe47d0ac9b3f6899c011eb512547acd880 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Wed, 27 Dec 2023 18:12:52 +0000 Subject: [PATCH 02/28] Automatic changelog for PR #5303 [ci skip] --- html/changelogs/AutoChangeLog-pr-5303.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-5303.yml diff --git a/html/changelogs/AutoChangeLog-pr-5303.yml b/html/changelogs/AutoChangeLog-pr-5303.yml new file mode 100644 index 000000000000..68f9dbb14544 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-5303.yml @@ -0,0 +1,4 @@ +author: "InsaneRed" +delete-after: True +changes: + - bugfix: "Synths are no longer immune to lunges / dragging while in 'critical state' since they dont go into crit." \ No newline at end of file From eecedaaedb8b7554f1c37de98cb97342e29ef08c Mon Sep 17 00:00:00 2001 From: fira Date: Wed, 27 Dec 2023 23:44:07 +0100 Subject: [PATCH 03/28] Fixes a simple race condition in XRF Setup (#5312) # About the pull request As seen on ~~TV~~ Live game Someone can remove the vial during the do_after, bricking the machine as it runtimes and is stuck with processing = TRUE # Changelog :cl: fix: Fixed XRF Scanner bricking if people were adding and removing vials at same time. /:cl: --- code/modules/reagents/chemistry_machinery/reagent_analyzer.dm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/modules/reagents/chemistry_machinery/reagent_analyzer.dm b/code/modules/reagents/chemistry_machinery/reagent_analyzer.dm index e0d0a80cadc2..51db188826b8 100644 --- a/code/modules/reagents/chemistry_machinery/reagent_analyzer.dm +++ b/code/modules/reagents/chemistry_machinery/reagent_analyzer.dm @@ -29,6 +29,9 @@ updateUsrDialog() if(!do_after(user, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_GENERIC)) return + if(!sample) + to_chat(user, SPAN_WARNING("Someone else removed the sample. Make up your mind!")) + return processing = TRUE if(sample.reagents.total_volume < 30 || sample.reagents.reagent_list.len > 1) icon_state = "reagent_analyzer_error" From 8963d0a479ff689dc2825b9bb9dcf6869fe9a3c4 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Wed, 27 Dec 2023 22:52:27 +0000 Subject: [PATCH 04/28] Automatic changelog for PR #5312 [ci skip] --- html/changelogs/AutoChangeLog-pr-5312.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-5312.yml diff --git a/html/changelogs/AutoChangeLog-pr-5312.yml b/html/changelogs/AutoChangeLog-pr-5312.yml new file mode 100644 index 000000000000..e7be9dce1385 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-5312.yml @@ -0,0 +1,4 @@ +author: "fira" +delete-after: True +changes: + - bugfix: "Fixed XRF Scanner bricking if people were adding and removing vials at same time." \ No newline at end of file From 92a96a8a4b1d236113ea9ce28efa6bc1971cfea7 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Wed, 27 Dec 2023 23:30:21 +0000 Subject: [PATCH 05/28] Shoe item storage refactor (#5263) # About the pull request Refactors shoe item storage to fix #5245, adds a bit of documentation, and generally just makes it a bit neater. (The overall 'Files changed' view looks a bit messy, so I've tried to keep each commit atomic to help with reviews.) # Explain why it's good for the game Code works gooder. # Testing Photographs and Procedure
Screenshots & Videos **Inserting a knife manually:** https://github.com/cmss13-devs/cmss13/assets/57483089/adf6267c-7a30-4c00-ae32-37524048ddc6 **Inserting a knife with the (un)holster hotkey:** https://github.com/cmss13-devs/cmss13/assets/57483089/b66824cb-5ad8-433e-a732-4854c0f68ff4 **Inserting a knife while holding the shoes:** https://github.com/cmss13-devs/cmss13/assets/57483089/0db1ac5c-7375-478a-9464-449657c7b659 **Picking up/dropping the shoes, and inserting a knife while they're on the ground:** https://github.com/cmss13-devs/cmss13/assets/57483089/404a8199-dee0-4cd0-92a9-d2a46cadfac6 **Trying a few different things with two pairs of shoes:** https://github.com/cmss13-devs/cmss13/assets/57483089/c5aab994-1002-4ffe-80e9-ddbaff4f95af
# Changelog :cl: fix: Fixed inserting/removing an item from shoes sometimes acting weirdly. refactor: Refactored shoe item storage. /:cl: --- code/datums/supply_packs/black_market.dm | 2 +- code/game/objects/items.dm | 2 +- code/modules/clothing/clothing.dm | 90 ++++++++++------- code/modules/clothing/shoes/colour.dm | 11 ++- code/modules/clothing/shoes/marine_shoes.dm | 92 ++++++++---------- code/modules/cm_preds/thrall_items.dm | 2 +- code/modules/cm_preds/yaut_items.dm | 9 +- code/modules/gear_presets/clf.dm | 2 +- code/modules/gear_presets/corpses.dm | 6 +- code/modules/gear_presets/fun.dm | 2 +- code/modules/gear_presets/other.dm | 8 +- code/modules/gear_presets/survivors/misc.dm | 2 +- .../sorokyne_strata/preset_sorokyne_strata.dm | 5 +- .../crashlanding_upp_bar_insert_trijent.dm | 4 +- code/modules/gear_presets/synths.dm | 2 +- code/modules/gear_presets/upp.dm | 96 +++++++++---------- code/modules/mob/inventory.dm | 9 +- .../mob/living/carbon/human/inventory.dm | 5 +- code/modules/projectiles/gun_attachables.dm | 4 + .../FOP_v3_Sciannex/Fiorina_SciAnnex.dmm | 2 +- 20 files changed, 184 insertions(+), 171 deletions(-) diff --git a/code/datums/supply_packs/black_market.dm b/code/datums/supply_packs/black_market.dm index 36d890e2b3d5..43e0358a96f9 100644 --- a/code/datums/supply_packs/black_market.dm +++ b/code/datums/supply_packs/black_market.dm @@ -101,7 +101,7 @@ Non-USCM items, from CLF, UPP, colonies, etc. Mostly combat-related. new /obj/item/clothing/head/helmet/marine/veteran/UPP(src) new /obj/item/clothing/under/marine/veteran/UPP(src) new /obj/item/clothing/suit/storage/marine/faction/UPP(src) - new /obj/item/clothing/shoes/marine/upp(src) + new /obj/item/clothing/shoes/marine/upp/knife(src) new /obj/item/clothing/gloves/marine/veteran(src) new /obj/item/storage/backpack/lightpack/five_slot(src) if(5) //freelancer diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 11da4cce6d98..ef9fcacf5647 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -708,7 +708,7 @@ cases. Override_icon_state should be a list.*/ if(WEAR_IN_SHOES) if(human.shoes && istype(human.shoes, /obj/item/clothing/shoes)) var/obj/item/clothing/shoes/shoes = human.shoes - if(shoes.attempt_insert_item(human, src)) + if(shoes.can_be_inserted(src)) return TRUE return FALSE if(WEAR_IN_SCABBARD) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index d6596474885c..91f42fbafe79 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -336,41 +336,64 @@ permeability_coefficient = 0.50 slowdown = SHOES_SLOWDOWN blood_overlay_type = "feet" + /// The currently inserted item. var/obj/item/stored_item - var/list/items_allowed + /// List of item types that can be inserted. + var/list/allowed_items_typecache + /// An item which should be inserted when the shoes are spawned. + var/obj/item/spawn_item_type var/shoes_blood_amt = 0 -///Checks if you can put the item inside of the shoes -/obj/item/clothing/shoes/proc/attempt_insert_item(mob/user, obj/item/attacking_item, insert_after = FALSE) - if(!items_allowed) - return +/obj/item/clothing/shoes/Initialize(mapload, ...) + . = ..() + if(allowed_items_typecache) + allowed_items_typecache = typecacheof(allowed_items_typecache) + if(spawn_item_type) + _insert_item(new spawn_item_type(src)) + +/// Returns a boolean indicating if `item_to_insert` can be inserted into the shoes. +/obj/item/clothing/shoes/proc/can_be_inserted(obj/item/item_to_insert) + // If the shoes can't actually hold an item. + if(allowed_items_typecache == null) + return FALSE + // If there's already an item inside. if(stored_item) - return - var/allowed = FALSE - for(var/allowed_item in items_allowed) - if(istype(attacking_item, allowed_item)) - allowed = TRUE - break - if(!allowed) - return - if(!insert_after) - return TRUE - insert_item(user, attacking_item) - -///Puts the item inside of the shoe -/obj/item/clothing/shoes/proc/insert_item(mob/user, obj/item/attacking_item) - stored_item = attacking_item - user.drop_inv_item_to_loc(attacking_item, src) - to_chat(user, SPAN_NOTICE("You slide [attacking_item] into [src].")) - playsound(user, 'sound/weapons/gun_shotgun_shell_insert.ogg', 15, 1) + return FALSE + // If `item_to_insert` isn't in the whitelist. + if(!is_type_in_typecache(item_to_insert, allowed_items_typecache)) + return FALSE + // If all of those passed, `item_to_insert` can be inserted. + return TRUE + +/** + * Try to insert `item_to_insert` into the shoes. + * + * Returns `TRUE` if it succeeded, or `FALSE` if [/obj/item/clothing/shoes/proc/can_be_inserted] failed, or `user` couldn't drop the item. + */ +/obj/item/clothing/shoes/proc/attempt_insert_item(mob/user, obj/item/item_to_insert) + if(!can_be_inserted(item_to_insert)) + return FALSE + // Try to drop the item and place it inside `src`. + if(!user.drop_inv_item_to_loc(item_to_insert, src)) + return FALSE + _insert_item(item_to_insert) + to_chat(user, SPAN_NOTICE("You slide [item_to_insert] into [src].")) + playsound(user, 'sound/weapons/gun_shotgun_shell_insert.ogg', 15, TRUE) + return TRUE + +/// Insert `item_to_insert` directly into the shoes without bothering with any checks. +/// (In the majority of cases [/obj/item/clothing/shoes/proc/attempt_insert_item()] should be used instead of this.) +/obj/item/clothing/shoes/proc/_insert_item(obj/item/item_to_insert) + PROTECTED_PROC(TRUE) + stored_item = item_to_insert update_icon() -///Removes the item from the shoes +/// Remove `stored_item` from the shoes, and place it into the `user`'s active hand. /obj/item/clothing/shoes/proc/remove_item(mob/user) - if(!user.put_in_active_hand(stored_item)) + if(!stored_item || !user.put_in_active_hand(stored_item)) return to_chat(user, SPAN_NOTICE("You slide [stored_item] out of [src].")) - playsound(user, 'sound/weapons/gun_shotgun_shell_insert.ogg', 15, 1) + playsound(user, 'sound/weapons/gun_shotgun_shell_insert.ogg', 15, TRUE) stored_item = null update_icon() @@ -380,10 +403,8 @@ user.update_inv_shoes() /obj/item/clothing/shoes/Destroy() - if(stored_item) - qdel(stored_item) - stored_item = null - . = ..() + QDEL_NULL(stored_item) + return ..() /obj/item/clothing/shoes/get_examine_text(mob/user) . = ..() @@ -391,17 +412,14 @@ . += "\nIt is storing \a [stored_item]." /obj/item/clothing/shoes/attack_hand(mob/living/user) - if(!stored_item) //Only allow someone to take out the stored_item if it's being worn or held. So you can pick them up off the floor - return ..() - if(user.is_mob_incapacitated()) - return ..() - if(loc != user) + // Only allow someone to take out the `stored_item` if it's being worn or held, so that you can pick them up off the floor. + if(!stored_item || loc != user || user.is_mob_incapacitated()) return ..() remove_item(user) /obj/item/clothing/shoes/attackby(obj/item/attacking_item, mob/living/user) . = ..() - user.equip_to_slot_if_possible(attacking_item, WEAR_IN_SHOES) + attempt_insert_item(user, attacking_item) /obj/item/clothing/equipped(mob/user, slot, silent) if(is_valid_slot(slot, TRUE)) //is it going to a matching clothing slot? diff --git a/code/modules/clothing/shoes/colour.dm b/code/modules/clothing/shoes/colour.dm index b5ec4f3ab924..4318e1a3b184 100644 --- a/code/modules/clothing/shoes/colour.dm +++ b/code/modules/clothing/shoes/colour.dm @@ -41,7 +41,14 @@ /obj/item/clothing/shoes/red/knife name = "dirty red shoes" desc = "Stylish red shoes with a small space to hold a knife." - items_allowed = list(/obj/item/attachable/bayonet, /obj/item/weapon/throwing_knife, /obj/item/weapon/gun/pistol/holdout, /obj/item/weapon/gun/pistol/clfpistol, /obj/item/tool/screwdriver, /obj/item/weapon/straight_razor) + allowed_items_typecache = list( + /obj/item/attachable/bayonet, + /obj/item/weapon/throwing_knife, + /obj/item/weapon/gun/pistol/holdout, + /obj/item/weapon/gun/pistol/clfpistol, + /obj/item/tool/screwdriver, + /obj/item/weapon/straight_razor, + ) /obj/item/clothing/shoes/white name = "white shoes" @@ -90,5 +97,3 @@ ..() if (istype(H, /obj/item/handcuffs)) attach_cuffs(H, user) - - diff --git a/code/modules/clothing/shoes/marine_shoes.dm b/code/modules/clothing/shoes/marine_shoes.dm index c7eb4ba53982..7855075c2fb4 100644 --- a/code/modules/clothing/shoes/marine_shoes.dm +++ b/code/modules/clothing/shoes/marine_shoes.dm @@ -18,47 +18,46 @@ min_cold_protection_temperature = SHOE_MIN_COLD_PROT max_heat_protection_temperature = SHOE_MAX_HEAT_PROT siemens_coefficient = 0.7 - var/armor_stage = 0 - items_allowed = list(/obj/item/attachable/bayonet, /obj/item/weapon/throwing_knife, /obj/item/weapon/gun/pistol/holdout, /obj/item/weapon/gun/pistol/clfpistol, /obj/item/tool/screwdriver, /obj/item/tool/surgery/scalpel, /obj/item/weapon/straight_razor) - var/knife_type + allowed_items_typecache = list( + /obj/item/attachable/bayonet, + /obj/item/weapon/throwing_knife, + /obj/item/weapon/gun/pistol/holdout, + /obj/item/weapon/gun/pistol/clfpistol, + /obj/item/tool/screwdriver, + /obj/item/tool/surgery/scalpel, + /obj/item/weapon/straight_razor, + ) drop_sound = "armorequip" -/obj/item/clothing/shoes/marine/Initialize(mapload, ...) - . = ..() - if(knife_type) - stored_item = new knife_type(src) - update_icon() - /obj/item/clothing/shoes/marine/update_icon() - if(stored_item && !armor_stage) + if(stored_item) icon_state = "[initial(icon_state)]-1" else - if(!armor_stage) - icon_state = initial(icon_state) + icon_state = initial(icon_state) /obj/item/clothing/shoes/marine/knife - knife_type = /obj/item/attachable/bayonet + spawn_item_type = /obj/item/attachable/bayonet /obj/item/clothing/shoes/marine/jungle icon_state = "marine_jungle" desc = "Don't go walkin' slow, the devil's on the loose." /obj/item/clothing/shoes/marine/jungle/knife - knife_type = /obj/item/attachable/bayonet + spawn_item_type = /obj/item/attachable/bayonet /obj/item/clothing/shoes/marine/brown icon_state = "marine_brown" desc = "Standard issue combat boots for combat scenarios or combat situations. All combat, all the time. These are brown." /obj/item/clothing/shoes/marine/brown/knife - knife_type = /obj/item/attachable/bayonet + spawn_item_type = /obj/item/attachable/bayonet /obj/item/clothing/shoes/marine/monkey name = "monkey combat boots" desc = "A sturdy pair of combat boots, the reflection of the polished leather reflects your true self." icon_state = "monkey_shoes" item_state = "monkey_shoes" - knife_type = /obj/item/attachable/bayonet + spawn_item_type = /obj/item/attachable/bayonet /obj/item/clothing/shoes/marine/upp name = "military combat boots" @@ -67,10 +66,9 @@ armor_bullet = CLOTHING_ARMOR_HIGHPLUS armor_bomb = CLOTHING_ARMOR_MEDIUM armor_internaldamage = CLOTHING_ARMOR_MEDIUMHIGH - knife_type = /obj/item/attachable/bayonet/upp -/obj/item/clothing/shoes/marine/upp_knife - knife_type = /obj/item/attachable/bayonet/upp +/obj/item/clothing/shoes/marine/upp/knife + spawn_item_type = /obj/item/attachable/bayonet/upp /obj/item/clothing/shoes/marine/joe name = "biohazard boots" @@ -80,7 +78,7 @@ armor_bio = CLOTHING_ARMOR_MEDIUMHIGH armor_rad = CLOTHING_ARMOR_MEDIUMHIGH armor_internaldamage = CLOTHING_ARMOR_MEDIUMLOW - knife_type = /obj/item/attachable/bayonet + spawn_item_type = /obj/item/attachable/bayonet /obj/item/clothing/shoes/dress name = "dress shoes" @@ -120,7 +118,13 @@ flags_heat_protection = BODY_FLAG_FEET flags_inventory = FPRINT|NOSLIPPING siemens_coefficient = 0.6 - items_allowed = list(/obj/item/attachable/bayonet, /obj/item/weapon/throwing_knife, /obj/item/weapon/gun/pistol/holdout, /obj/item/weapon/gun/pistol/clfpistol, /obj/item/weapon/straight_razor) + allowed_items_typecache = list( + /obj/item/attachable/bayonet, + /obj/item/weapon/throwing_knife, + /obj/item/weapon/gun/pistol/holdout, + /obj/item/weapon/gun/pistol/clfpistol, + /obj/item/weapon/straight_razor, + ) /obj/item/clothing/shoes/veteran/pmc/update_icon() if(stored_item) @@ -128,10 +132,8 @@ else icon_state = initial(icon_state) -/obj/item/clothing/shoes/veteran/pmc/knife/Initialize(mapload, ...) - . = ..() - stored_item = new /obj/item/attachable/bayonet(src) - update_icon() +/obj/item/clothing/shoes/veteran/pmc/knife + spawn_item_type = /obj/item/attachable/bayonet /obj/item/clothing/shoes/veteran/pmc/commando name = "\improper PMC commando boots" @@ -141,22 +143,13 @@ siemens_coefficient = 0.2 unacidable = TRUE -/obj/item/clothing/shoes/veteran/pmc/commando/knife/Initialize(mapload, ...) - . = ..() - stored_item = new /obj/item/attachable/bayonet(src) - update_icon() +/obj/item/clothing/shoes/veteran/pmc/commando/knife + spawn_item_type = /obj/item/attachable/bayonet /obj/item/clothing/shoes/veteran/pmc/van_bandolier name = "hiking boots" desc = "Over stone, over ice, through sun and sand, mud and snow, into raging water and hungry bog, these will never let you down." - -/obj/item/clothing/shoes/veteran/pmc/van_bandolier/New() - ..() - var/obj/item/attachable/bayonet/upp/knife = new(src) - knife.name = "\improper Fairbairn-Sykes fighting knife" - knife.desc = "This isn't for dressing game or performing camp chores. It's almost certainly not an original. Almost." - stored_item = knife - update_icon() + spawn_item_type = /obj/item/attachable/bayonet/van_bandolier /obj/item/clothing/shoes/veteran/pmc/commando/cbrn name = "\improper M3 MOPP boots" @@ -165,22 +158,18 @@ item_state = "cbrn" armor_rad = CLOTHING_ARMOR_GIGAHIGHPLUS armor_bio = CLOTHING_ARMOR_GIGAHIGHPLUS - -/obj/item/clothing/shoes/veteran/pmc/commando/cbrn/Initialize(mapload, ...) - . = ..() - stored_item = new /obj/item/attachable/bayonet(src) - update_icon() + spawn_item_type = /obj/item/attachable/bayonet /obj/item/clothing/shoes/marine/corporate name = "rugged boots" desc = "These synth-leather boots seem high quality when first worn, but quickly detoriate, especially in the environments the corporate security members these are issued to operate in. Still, better than nothing." - knife_type = /obj/item/attachable/bayonet + spawn_item_type = /obj/item/attachable/bayonet /obj/item/clothing/shoes/marine/ress name = "armored sandals" icon_state = "sandals" item_state = "sandals" - items_allowed = null + allowed_items_typecache = null /obj/item/clothing/shoes/hiking name = "hiking shoes" @@ -201,7 +190,13 @@ flags_heat_protection = BODY_FLAG_FEET flags_inventory = FPRINT|NOSLIPPING siemens_coefficient = 0.6 - items_allowed = list(/obj/item/attachable/bayonet, /obj/item/weapon/throwing_knife, /obj/item/weapon/gun/pistol/holdout, /obj/item/weapon/gun/pistol/clfpistol, /obj/item/weapon/straight_razor) + allowed_items_typecache = list( + /obj/item/attachable/bayonet, + /obj/item/weapon/throwing_knife, + /obj/item/weapon/gun/pistol/holdout, + /obj/item/weapon/gun/pistol/clfpistol, + /obj/item/weapon/straight_razor, + ) var/weed_slowdown_mult = 0.5 /obj/item/clothing/shoes/hiking/equipped(mob/user, slot, silent) @@ -239,7 +234,7 @@ flags_heat_protection = BODY_FLAG_FEET flags_inventory = FPRINT|NOSLIPPING siemens_coefficient = 0.6 - items_allowed = list( + allowed_items_typecache = list( /obj/item/attachable/bayonet, /obj/item/weapon/throwing_knife, /obj/item/weapon/gun/pistol/holdout, @@ -248,7 +243,4 @@ flags_atom = NO_NAME_OVERRIDE /obj/item/clothing/shoes/royal_marine/knife -/obj/item/clothing/shoes/royal_marine/knife/Initialize(mapload, ...) - . = ..() - stored_item = new /obj/item/attachable/bayonet/rmc(src) - update_icon() + spawn_item_type = /obj/item/attachable/bayonet/rmc diff --git a/code/modules/cm_preds/thrall_items.dm b/code/modules/cm_preds/thrall_items.dm index 80b4d42c16e2..708b230d5c11 100644 --- a/code/modules/cm_preds/thrall_items.dm +++ b/code/modules/cm_preds/thrall_items.dm @@ -35,7 +35,7 @@ ) thrall = TRUE - items_allowed = list( + allowed_items_typecache = list( /obj/item/attachable/bayonet, /obj/item/weapon/throwing_knife, /obj/item/weapon/gun/pistol/holdout, diff --git a/code/modules/cm_preds/yaut_items.dm b/code/modules/cm_preds/yaut_items.dm index a648f2392d47..c646d929d9f7 100644 --- a/code/modules/cm_preds/yaut_items.dm +++ b/code/modules/cm_preds/yaut_items.dm @@ -217,7 +217,7 @@ siemens_coefficient = 0.2 min_cold_protection_temperature = SHOE_MIN_COLD_PROT max_heat_protection_temperature = SHOE_MAX_HEAT_PROT - items_allowed = list( + allowed_items_typecache = list( /obj/item/weapon/yautja/knife, /obj/item/weapon/gun/energy/yautja/plasmapistol, ) @@ -259,10 +259,9 @@ armor_rad = CLOTHING_ARMOR_MEDIUMHIGH armor_internaldamage = CLOTHING_ARMOR_MEDIUMHIGH -/obj/item/clothing/shoes/yautja/hunter/knife/New() - ..() - stored_item = new /obj/item/weapon/yautja/knife(src) - update_icon() +/obj/item/clothing/shoes/yautja/hunter/knife + spawn_item_type = /obj/item/weapon/yautja/knife + /obj/item/clothing/under/chainshirt name = "ancient alien mesh suit" desc = "A strange alloy weave in the form of a vest. It feels cold with an alien weight." diff --git a/code/modules/gear_presets/clf.dm b/code/modules/gear_presets/clf.dm index d89e349a62c1..7748f4e0c558 100644 --- a/code/modules/gear_presets/clf.dm +++ b/code/modules/gear_presets/clf.dm @@ -918,7 +918,7 @@ new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/smartgun/clf(new_human), WEAR_J_STORE) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/black(new_human), WEAR_HANDS) new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/smartgunner/clf/full(new_human), WEAR_WAIST) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife(new_human), WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/survival/full(new_human), WEAR_L_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full(new_human), WEAR_R_STORE) diff --git a/code/modules/gear_presets/corpses.dm b/code/modules/gear_presets/corpses.dm index ca2b2e2ab52d..72513a95f880 100644 --- a/code/modules/gear_presets/corpses.dm +++ b/code/modules/gear_presets/corpses.dm @@ -111,7 +111,7 @@ new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/satchel/sec(new_human), WEAR_BACK) new_human.equip_to_slot_or_del(new /obj/item/storage/belt/marine(new_human), WEAR_WAIST) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/satchel(new_human), WEAR_BACK) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife(new_human), WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/mask/rebreather/scarf(new_human), WEAR_FACE) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine(new_human), WEAR_HANDS) if(prob(25)) @@ -738,7 +738,7 @@ new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/marine/faction/UPP, WEAR_JACKET) new_human.equip_to_slot_or_del(new /obj/item/device/binoculars, WEAR_IN_JACKET) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran, WEAR_HANDS) add_random_survivor_equipment(new_human) @@ -854,7 +854,7 @@ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/veteran/freelancer, WEAR_BODY) new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/marine/faction/freelancer, WEAR_JACKET) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/pmc, WEAR_HANDS) new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/distress/dutch, WEAR_L_EAR) new_human.equip_to_slot_or_del(new /obj/item/storage/belt/marine, WEAR_WAIST) diff --git a/code/modules/gear_presets/fun.dm b/code/modules/gear_presets/fun.dm index 68253afbf90a..44b2a1a1157a 100644 --- a/code/modules/gear_presets/fun.dm +++ b/code/modules/gear_presets/fun.dm @@ -327,7 +327,7 @@ //head new_human.equip_to_slot_or_del(new /obj/item/clothing/head/ivanberet, WEAR_HEAD) //limb - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/pmc, WEAR_HANDS) //waist new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/type47/ivan, WEAR_WAIST) diff --git a/code/modules/gear_presets/other.dm b/code/modules/gear_presets/other.dm index 6a9fa4d6f55a..3f773f90520e 100644 --- a/code/modules/gear_presets/other.dm +++ b/code/modules/gear_presets/other.dm @@ -69,7 +69,7 @@ //generic clothing new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/veteran/freelancer, WEAR_BODY) new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/marine/faction/freelancer, WEAR_JACKET) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/pmc, WEAR_HANDS) spawn_merc_helmet(new_human) //storage and specific stuff, they all get an ERT medpouch. @@ -149,7 +149,7 @@ new_human.equip_to_slot_or_del(FREELANCER, WEAR_BODY) new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/marine/faction/freelancer, WEAR_JACKET) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/pmc, WEAR_HANDS) spawn_merc_helmet(new_human) @@ -216,7 +216,7 @@ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/veteran/freelancer, WEAR_BODY) new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/marine/faction/freelancer, WEAR_JACKET) new_human.equip_to_slot_or_del(new /obj/item/clothing/head/freelancer/beret, WEAR_HEAD) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran, WEAR_HANDS) if(new_human.disabilities & NEARSIGHTED) new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/hud/health/prescription(new_human), WEAR_EYES) @@ -774,7 +774,7 @@ /datum/equipment_preset/other/xeno_cultist/load_gear(mob/living/carbon/human/new_human) new_human.equip_to_slot_or_del(new /obj/item/clothing/under/rank/chaplain/cultist(new_human), WEAR_BODY) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife(new_human), WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/lightpack(new_human), WEAR_BACK) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/tools/full(new_human), WEAR_R_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/survival/full(new_human), WEAR_L_STORE) diff --git a/code/modules/gear_presets/survivors/misc.dm b/code/modules/gear_presets/survivors/misc.dm index 396c38054965..692833bfa82b 100644 --- a/code/modules/gear_presets/survivors/misc.dm +++ b/code/modules/gear_presets/survivors/misc.dm @@ -242,7 +242,7 @@ Everything below isn't used or out of place. new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/veteran/freelancer, WEAR_BODY) new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/marine/faction/freelancer, WEAR_JACKET) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/pmc, WEAR_HANDS) spawn_merc_helmet(new_human) new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/distress/dutch, WEAR_L_EAR) diff --git a/code/modules/gear_presets/survivors/sorokyne_strata/preset_sorokyne_strata.dm b/code/modules/gear_presets/survivors/sorokyne_strata/preset_sorokyne_strata.dm index f53f25326b69..220034399293 100644 --- a/code/modules/gear_presets/survivors/sorokyne_strata/preset_sorokyne_strata.dm +++ b/code/modules/gear_presets/survivors/sorokyne_strata/preset_sorokyne_strata.dm @@ -5,7 +5,7 @@ /datum/equipment_preset/survivor/engineer/soro/load_gear(mob/living/carbon/human/new_human) new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/veteran/UPP(new_human), WEAR_BODY) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/satchel(new_human), WEAR_BACK) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife(new_human), WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/snow_suit/soviet(new_human), WEAR_JACKET) new_human.equip_to_slot_or_del(new /obj/item/clothing/head/ushanka(new_human), WEAR_HEAD) new_human.equip_to_slot_or_del(new /obj/item/clothing/mask/rebreather/scarf(new_human), WEAR_FACE) @@ -19,7 +19,7 @@ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/rank/veteran/soviet_uniform_01(new_human), WEAR_BODY) new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/snow_suit/soviet(new_human), WEAR_JACKET) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/satchel/sec(new_human), WEAR_BACK) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife(new_human), WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/mask/rebreather/scarf(new_human), WEAR_FACE) new_human.equip_to_slot_or_del(new /obj/item/clothing/head/ushanka(new_human), WEAR_HEAD) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine(new_human), WEAR_HANDS) @@ -71,4 +71,3 @@ new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/satchel/lockable/liaison, WEAR_BACK) new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) ..() - diff --git a/code/modules/gear_presets/survivors/trijent/crashlanding_upp_bar_insert_trijent.dm b/code/modules/gear_presets/survivors/trijent/crashlanding_upp_bar_insert_trijent.dm index 324cfbe3bf7a..99589582cbf6 100644 --- a/code/modules/gear_presets/survivors/trijent/crashlanding_upp_bar_insert_trijent.dm +++ b/code/modules/gear_presets/survivors/trijent/crashlanding_upp_bar_insert_trijent.dm @@ -26,7 +26,7 @@ uniform.roll_suit_sleeves(new_human) new_human.equip_to_slot_or_del(uniform, WEAR_BODY) new_human.equip_to_slot_or_del(new /obj/item/clothing/accessory/patch/upp (new_human), WEAR_ACCESSORY) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp_knife(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife(new_human), WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/flare(new_human), WEAR_R_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full/alternate(new_human), WEAR_L_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/lightpack/five_slot(new_human), WEAR_BACK) @@ -207,4 +207,4 @@ new_human.equip_to_slot_or_del(new /obj/item/clothing/accessory/patch/upp, WEAR_ACCESSORY) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran, WEAR_HANDS) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/tools/uppsynth, WEAR_R_STORE) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) diff --git a/code/modules/gear_presets/synths.dm b/code/modules/gear_presets/synths.dm index 3b2efd8c22be..9a181c817020 100644 --- a/code/modules/gear_presets/synths.dm +++ b/code/modules/gear_presets/synths.dm @@ -317,7 +317,7 @@ WEAR_WAIST = /obj/item/storage/belt/marine, WEAR_HANDS = /obj/item/clothing/gloves/marine/veteran, WEAR_R_HAND = /obj/item/storage/pouch/flare/full, - WEAR_FEET = /obj/item/clothing/shoes/marine/upp, + WEAR_FEET = /obj/item/clothing/shoes/marine/upp/knife, WEAR_L_HAND = /obj/item/storage/large_holster/katana/full ) diff --git a/code/modules/gear_presets/upp.dm b/code/modules/gear_presets/upp.dm index dc79f87c5135..0b3b4d4ecfb5 100644 --- a/code/modules/gear_presets/upp.dm +++ b/code/modules/gear_presets/upp.dm @@ -78,7 +78,7 @@ new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/marine/faction/UPP, WEAR_JACKET) new_human.equip_to_slot_or_del(new /obj/item/device/binoculars, WEAR_IN_JACKET) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/upp, WEAR_HANDS) if(SSmapping.configs[GROUND_MAP].environment_traits[MAP_COLD]) @@ -151,7 +151,7 @@ /datum/equipment_preset/upp/soldier/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("UM5 Personal Armor", 0, /obj/item/clothing/suit/storage/marine/faction/UPP, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran/upp, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), @@ -261,7 +261,7 @@ //waist new_human.equip_to_slot_or_del(new /obj/item/storage/belt/medical/lifesaver/upp/full, WEAR_WAIST) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/upp, WEAR_HANDS) //póckets var/obj/item/storage/pouch/magazine/large/ppouch = new() @@ -280,7 +280,7 @@ /datum/equipment_preset/upp/medic/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Medic Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP/medic, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("UL6 Personal Armor", 0, /obj/item/clothing/suit/storage/marine/faction/UPP/support, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran/upp, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), @@ -435,7 +435,7 @@ new_human.equip_to_slot_or_del(new /obj/item/storage/belt/marine/upp/sapper(new_human), WEAR_WAIST) //limb new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/insulated(new_human), WEAR_HANDS) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) //pockets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/ert(new_human), WEAR_L_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/construction/full(new_human), WEAR_R_STORE) @@ -443,7 +443,7 @@ /datum/equipment_preset/upp/sapper/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("UM5 Personal Armor", 0, /obj/item/clothing/suit/storage/marine/faction/UPP, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran/upp, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), @@ -556,7 +556,7 @@ new_human.equip_to_slot_or_del(UPP, WEAR_BODY) new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/marine/faction/UPP/heavy, WEAR_JACKET) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/upp, WEAR_HANDS) //pockets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/explosive/C4, WEAR_R_STORE) @@ -582,7 +582,7 @@ /datum/equipment_preset/upp/specialist/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("UH7 Heavy Plated Armor", 0, /obj/item/clothing/suit/storage/marine/faction/UPP/heavy, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran/upp, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), @@ -683,7 +683,7 @@ new_human.equip_to_slot_or_del(UPP, WEAR_BODY) new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/marine/faction/UPP/heavy, WEAR_JACKET) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/upp, WEAR_HANDS) //pockets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/explosive/C4, WEAR_R_STORE) @@ -707,7 +707,7 @@ /datum/equipment_preset/upp/machinegunner/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("UH7 Heavy Plated Armor", 0, /obj/item/clothing/suit/storage/marine/faction/UPP/heavy, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran/upp, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), @@ -829,7 +829,7 @@ if(4) //25% new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/type47/revolver, WEAR_WAIST) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/upp, WEAR_HANDS) //pockets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/flamertank, WEAR_R_STORE) @@ -843,7 +843,7 @@ /datum/equipment_preset/upp/leader/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("UH7 Heavy Plated Armor", 0, /obj/item/clothing/suit/storage/marine/faction/UPP/heavy, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran/upp, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), @@ -979,7 +979,7 @@ //waist new_human.equip_to_slot_or_del(new /obj/item/storage/belt/security/MP/UPP/full, WEAR_WAIST) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/upp, WEAR_HANDS) //pockets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/autoinjector/full, WEAR_L_STORE) @@ -990,7 +990,7 @@ /datum/equipment_preset/upp/military_police/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP/mp, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("UL4 camouflaged jacket", 0, /obj/item/clothing/suit/storage/marine/faction/UPP/mp, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran/upp, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), @@ -1140,7 +1140,7 @@ //waist new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/type47/np92, WEAR_WAIST) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/upp, WEAR_HANDS) //pockets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/general/large, WEAR_L_STORE) @@ -1155,7 +1155,7 @@ /datum/equipment_preset/upp/officer/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP/officer, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran/upp, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/distress/UPP/command, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), @@ -1300,7 +1300,7 @@ //waist new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/type47/t73, WEAR_WAIST) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/upp, WEAR_HANDS) //pockets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/general/large, WEAR_L_STORE) @@ -1315,7 +1315,7 @@ /datum/equipment_preset/upp/officer/senior/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP/officer, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran/upp, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/distress/UPP/command, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), @@ -1461,7 +1461,7 @@ //waist new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/type47/t73, WEAR_WAIST) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran, WEAR_HANDS) //pockets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/general/large, WEAR_L_STORE) @@ -1476,7 +1476,7 @@ /datum/equipment_preset/upp/officer/kapitan/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP/officer, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/distress/UPP/command, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), @@ -1622,7 +1622,7 @@ //waist new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/type47/t73/leader, WEAR_WAIST) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/upp, WEAR_HANDS) //pockets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/general/large, WEAR_L_STORE) @@ -1637,7 +1637,7 @@ /datum/equipment_preset/upp/officer/major/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP/officer, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran/upp, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/distress/UPP/command, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), @@ -1783,7 +1783,7 @@ //waist new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/type47/t73/leader, WEAR_WAIST) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran, WEAR_HANDS) //pockets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/general/large, WEAR_L_STORE) @@ -1798,7 +1798,7 @@ /datum/equipment_preset/upp/officer/lt_kolonel/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP/officer, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/distress/UPP/command, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), @@ -1944,7 +1944,7 @@ //waist new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/type47/t73/leader, WEAR_WAIST) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/upp, WEAR_HANDS) //pockets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/general/large, WEAR_L_STORE) @@ -1959,7 +1959,7 @@ /datum/equipment_preset/upp/officer/kolonel/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP/officer, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran/upp, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/distress/UPP/command, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), @@ -2105,7 +2105,7 @@ //waist new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/type47/t73/leader, WEAR_WAIST) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran, WEAR_HANDS) //pockets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/general/large, WEAR_L_STORE) @@ -2120,7 +2120,7 @@ /datum/equipment_preset/upp/officer/may_gen/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP/officer, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/distress/UPP/command, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), @@ -2266,7 +2266,7 @@ //waist new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/type47/t73/leader, WEAR_WAIST) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran, WEAR_HANDS) //pockets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/general/large, WEAR_L_STORE) @@ -2281,7 +2281,7 @@ /datum/equipment_preset/upp/officer/ley_gen/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP/officer, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/distress/UPP/command, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), @@ -2427,7 +2427,7 @@ //waist new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/type47/t73/leader, WEAR_WAIST) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran, WEAR_HANDS) //pockets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/general/large, WEAR_L_STORE) @@ -2442,7 +2442,7 @@ /datum/equipment_preset/upp/officer/gen/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP/officer, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/distress/UPP/command, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), @@ -2583,7 +2583,7 @@ new_human.equip_to_slot_or_del(new /obj/item/storage/belt/shotgun/upp/heavybuck(new_human), WEAR_WAIST) //limb new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/insulated(new_human), WEAR_HANDS) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) //pockets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/ert(new_human), WEAR_L_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/explosive/C4, WEAR_R_STORE) @@ -2667,7 +2667,7 @@ //waist new_human.equip_to_slot_or_del(new /obj/item/storage/belt/medical/lifesaver/upp/full, WEAR_WAIST) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/upp, WEAR_HANDS) //póckets var/obj/item/storage/pouch/magazine/large/ppouch = new() @@ -2836,7 +2836,7 @@ new_human.equip_to_slot_or_del(new /obj/item/explosive/grenade/high_explosive/upp, WEAR_IN_JACKET) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) var/maybegloves = prob(80) ? pick(/obj/item/clothing/gloves/black, /obj/item/clothing/gloves/marine/veteran/upp, /obj/item/clothing/gloves/combat) : null if(maybegloves) new_human.equip_to_slot_or_del(new maybegloves, WEAR_HANDS) @@ -2865,7 +2865,7 @@ /datum/equipment_preset/upp/conscript/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/distress/UPP, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), list("Ration", 0, /obj/item/reagent_container/food/snacks/upp, MARINE_CAN_BUY_MRE, VENDOR_ITEM_MANDATORY), @@ -2933,7 +2933,7 @@ new_human.equip_to_slot_or_del(new /obj/item/clothing/head/uppcap, WEAR_HEAD) new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/type47/np92/suppressed, WEAR_WAIST) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/marine/satchel/scout_cloak/upp, WEAR_BACK) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/upp, WEAR_HANDS) new_human.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/pmc/upp, WEAR_FACE) new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/m42_night_goggles/upp, WEAR_EYES) @@ -2954,7 +2954,7 @@ /datum/equipment_preset/upp/commando/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/suit/storage/marine/faction/UPP/commando, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran/upp, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/distress/UPP/kdo, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), @@ -3055,7 +3055,7 @@ new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/type71/ap, WEAR_IN_JACKET) new_human.equip_to_slot_or_del(new /obj/item/clothing/head/uppcap, WEAR_HEAD) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/marine/satchel/scout_cloak/upp, WEAR_BACK) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/upp, WEAR_HANDS) new_human.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/pmc/upp, WEAR_FACE) new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/m42_night_goggles/upp, WEAR_EYES) @@ -3085,7 +3085,7 @@ /datum/equipment_preset/upp/commando/medic/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues Medic", 0, /obj/item/clothing/under/marine/veteran/UPP/medic, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran/upp, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/distress/UPP/kdo/medic, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), @@ -3225,7 +3225,7 @@ new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/type71/ap, WEAR_IN_JACKET) new_human.equip_to_slot_or_del(new /obj/item/clothing/head/uppcap/beret, WEAR_HEAD) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/marine/satchel/scout_cloak/upp, WEAR_BACK) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/upp, WEAR_HANDS) new_human.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/pmc/upp, WEAR_FACE) new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/m42_night_goggles/upp, WEAR_EYES) @@ -3249,7 +3249,7 @@ /datum/equipment_preset/upp/commando/leader/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Fatigues", 0, /obj/item/clothing/suit/storage/marine/faction/UPP/commando, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran/upp, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), list("Headset", 0, /obj/item/device/radio/headset/distress/UPP/kdo/command, MARINE_CAN_BUY_EAR, VENDOR_ITEM_MANDATORY), @@ -3369,7 +3369,7 @@ new_human.equip_to_slot_or_del(new /obj/item/clothing/head/uppcap, WEAR_HEAD) new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/type47/np92/suppressed, WEAR_WAIST) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/marine/satchel/scout_cloak/upp/weak, WEAR_BACK) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran, WEAR_HANDS) new_human.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/pmc/upp, WEAR_FACE) new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/m42_night_goggles/upp, WEAR_EYES) @@ -3399,7 +3399,7 @@ new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/type71/ap, WEAR_IN_JACKET) new_human.equip_to_slot_or_del(new /obj/item/clothing/head/uppcap, WEAR_HEAD) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/marine/satchel/scout_cloak/upp/weak, WEAR_BACK) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran, WEAR_HANDS) new_human.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/pmc/upp, WEAR_FACE) new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/m42_night_goggles/upp, WEAR_EYES) @@ -3438,7 +3438,7 @@ new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/type71/ap, WEAR_IN_JACKET) new_human.equip_to_slot_or_del(new /obj/item/clothing/head/uppcap/beret, WEAR_HEAD) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/marine/satchel/scout_cloak/upp/weak, WEAR_BACK) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran, WEAR_HANDS) new_human.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/pmc/upp, WEAR_FACE) new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/m42_night_goggles/upp, WEAR_EYES) @@ -3472,7 +3472,7 @@ /datum/equipment_preset/upp/tank/load_gear(mob/living/carbon/human/new_human) new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/veteran/UPP(new_human), WEAR_BODY) - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife(new_human), WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/distress/UPP/cct(new_human), WEAR_L_EAR) new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/welding(new_human), WEAR_EYES) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/yellow(new_human), WEAR_HANDS) @@ -3611,7 +3611,7 @@ new_human.equip_to_slot_or_del(new /obj/item/storage/belt/medical/lifesaver/upp/full, WEAR_WAIST) new_human.equip_to_slot_or_del(new /obj/item/reagent_container/hypospray/autoinjector/oxycodone, WEAR_IN_BELT) //limbs - new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp, WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/upp/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/veteran/upp, WEAR_HANDS) //póckets new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/general/large, WEAR_R_STORE) @@ -3630,7 +3630,7 @@ /datum/equipment_preset/upp/doctor/get_antag_clothing_equipment() return list( list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), - list("Boots", 0, /obj/item/clothing/shoes/marine/upp, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), + list("Boots", 0, /obj/item/clothing/shoes/marine/upp/knife, MARINE_CAN_BUY_SHOES, VENDOR_ITEM_MANDATORY), list("Medic Fatigues", 0, /obj/item/clothing/under/marine/veteran/UPP/medic, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), list("UL6 Personal Armor", 0, /obj/item/clothing/suit/storage/marine/faction/UPP/support, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_MANDATORY), list("Gloves", 0, /obj/item/clothing/gloves/marine/veteran/upp, MARINE_CAN_BUY_GLOVES, VENDOR_ITEM_MANDATORY), diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index d71a908d627a..8a0f0f8aa1e9 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -347,13 +347,12 @@ W.forceMove(B) equipped = 1 if(WEAR_IN_SHOES) - if(!shoes) - return + // If the player isn't wearing shoes, or the shoes somehow aren't shoes. if(!istype(shoes, /obj/item/clothing/shoes)) return - if(shoes.stored_item) - return - shoes.attempt_insert_item(src, shoes, TRUE) + // If the item was successfully inserted. + if(shoes.attempt_insert_item(src, W)) + equipped = 1 // what is this proc if(WEAR_IN_SCABBARD) if(src.back && istype(src.back, /obj/item/storage/large_holster)) var/obj/item/storage/large_holster/B = src.back diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index b54f03e2ce7d..34b80d1ce6f9 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -354,8 +354,7 @@ current_storage.attempt_item_insertion(equipping_item, disable_warning, src) back.update_icon() if(WEAR_IN_SHOES) - shoes.attempt_insert_item(src, equipping_item, TRUE) - shoes.update_icon() + shoes.attempt_insert_item(src, equipping_item) if(WEAR_IN_SCABBARD) var/obj/item/storage/current_storage = back current_storage.attempt_item_insertion(equipping_item, disable_warning, src) @@ -571,5 +570,3 @@ /mob/living/carbon/human/drop_inv_item_on_ground(obj/item/I, nomoveupdate, force) remember_dropped_object(I) return ..() - - diff --git a/code/modules/projectiles/gun_attachables.dm b/code/modules/projectiles/gun_attachables.dm index 33d28527c8a1..e0dda3203d96 100644 --- a/code/modules/projectiles/gun_attachables.dm +++ b/code/modules/projectiles/gun_attachables.dm @@ -342,6 +342,10 @@ Defined in conflicts.dm of the #defines folder. throw_range = 7 pry_delay = 1 SECONDS +/obj/item/attachable/bayonet/van_bandolier + name = "\improper Fairbairn-Sykes fighting knife" + desc = "This isn't for dressing game or performing camp chores. It's almost certainly not an original. Almost." + /obj/item/attachable/bayonet/co2/update_icon() icon_state = "co2_knife[filled ? "-f" : ""]" attach_icon = "co2_bayonet[filled ? "-f" : ""]_a" diff --git a/maps/map_files/FOP_v3_Sciannex/Fiorina_SciAnnex.dmm b/maps/map_files/FOP_v3_Sciannex/Fiorina_SciAnnex.dmm index b37d42f1a55f..ab98e02cb6e4 100644 --- a/maps/map_files/FOP_v3_Sciannex/Fiorina_SciAnnex.dmm +++ b/maps/map_files/FOP_v3_Sciannex/Fiorina_SciAnnex.dmm @@ -31053,7 +31053,7 @@ }, /area/fiorina/station/park) "sRv" = ( -/obj/item/clothing/shoes/marine/upp_knife, +/obj/item/clothing/shoes/marine/upp/knife, /turf/open/floor/prison, /area/fiorina/station/lowsec) "sRE" = ( From f24799c6b25055b857da1c413b57e920809e216a Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Wed, 27 Dec 2023 23:41:44 +0000 Subject: [PATCH 06/28] Automatic changelog for PR #5263 [ci skip] --- html/changelogs/AutoChangeLog-pr-5263.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-5263.yml diff --git a/html/changelogs/AutoChangeLog-pr-5263.yml b/html/changelogs/AutoChangeLog-pr-5263.yml new file mode 100644 index 000000000000..3b2b0690a4ed --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-5263.yml @@ -0,0 +1,5 @@ +author: "SabreML" +delete-after: True +changes: + - bugfix: "Fixed inserting/removing an item from shoes sometimes acting weirdly." + - refactor: "Refactored shoe item storage." \ No newline at end of file From c3ae2dbf71e010d70579657506f5ad77403b381c Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 28 Dec 2023 01:09:10 +0000 Subject: [PATCH 07/28] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-5263.yml | 5 ----- html/changelogs/AutoChangeLog-pr-5303.yml | 4 ---- html/changelogs/AutoChangeLog-pr-5312.yml | 4 ---- html/changelogs/archive/2023-12.yml | 10 ++++++++++ 4 files changed, 10 insertions(+), 13 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-5263.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-5303.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-5312.yml diff --git a/html/changelogs/AutoChangeLog-pr-5263.yml b/html/changelogs/AutoChangeLog-pr-5263.yml deleted file mode 100644 index 3b2b0690a4ed..000000000000 --- a/html/changelogs/AutoChangeLog-pr-5263.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "SabreML" -delete-after: True -changes: - - bugfix: "Fixed inserting/removing an item from shoes sometimes acting weirdly." - - refactor: "Refactored shoe item storage." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-5303.yml b/html/changelogs/AutoChangeLog-pr-5303.yml deleted file mode 100644 index 68f9dbb14544..000000000000 --- a/html/changelogs/AutoChangeLog-pr-5303.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "InsaneRed" -delete-after: True -changes: - - bugfix: "Synths are no longer immune to lunges / dragging while in 'critical state' since they dont go into crit." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-5312.yml b/html/changelogs/AutoChangeLog-pr-5312.yml deleted file mode 100644 index e7be9dce1385..000000000000 --- a/html/changelogs/AutoChangeLog-pr-5312.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "fira" -delete-after: True -changes: - - bugfix: "Fixed XRF Scanner bricking if people were adding and removing vials at same time." \ No newline at end of file diff --git a/html/changelogs/archive/2023-12.yml b/html/changelogs/archive/2023-12.yml index 43d61e9d7aec..0333e4beea0c 100644 --- a/html/changelogs/archive/2023-12.yml +++ b/html/changelogs/archive/2023-12.yml @@ -521,3 +521,13 @@ - code_imp: Tweaked the way prayer sends notifications to be more efficient. - admin: Moved the prayer notification sound to a toggle preference, combined with ARES Interface notifications. +2023-12-28: + InsaneRed: + - bugfix: Synths are no longer immune to lunges / dragging while in 'critical state' + since they dont go into crit. + SabreML: + - bugfix: Fixed inserting/removing an item from shoes sometimes acting weirdly. + - refactor: Refactored shoe item storage. + fira: + - bugfix: Fixed XRF Scanner bricking if people were adding and removing vials at + same time. From 0747cc806cff131925f4f1c0eff4f624f4262bc5 Mon Sep 17 00:00:00 2001 From: sleepynecrons <106241650+sleepynecrons@users.noreply.github.com> Date: Thu, 28 Dec 2023 03:46:15 -0600 Subject: [PATCH 08/28] new sprites for predalien (abomination) and co. (#5269) # About the pull request this PR replaces the predalien sprites with some that i think match the look of the rest of our xenos a bit better also replaces the sprites for the predalien larva, adds wounded overlays, and updates the corpse weed sprites ![paulblart](https://github.com/cmss13-devs/cmss13/assets/106241650/68ed6d5c-5536-41e2-9239-04917b6caea4) # Explain why it's good for the game visual consistency good # Testing Photographs and Procedure
Screenshots & Videos ![46QUJQC](https://github.com/cmss13-devs/cmss13/assets/106241650/6813bc51-f009-4525-8fe8-f513642f5edf)
# Changelog :cl: imageadd: new sprites for predalien, predlarva and weeded corpse imageadd: added predalien wound overlays /:cl: --- icons/mob/xenos/predalien.dmi | Bin 3963 -> 12846 bytes icons/mob/xenos/predalien_larva.dmi | Bin 1207 -> 3616 bytes icons/mob/xenos/weeds_64x64.dmi | Bin 32998 -> 32984 bytes icons/mob/xenos/wounds.dmi | Bin 64220 -> 68814 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/mob/xenos/predalien.dmi b/icons/mob/xenos/predalien.dmi index 1e3ec5caf8065951ece16bcacdfc3106e00aa40d..c6162729b5169dac5913c9d53919411299d69ce3 100644 GIT binary patch literal 12846 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 diff --git a/icons/mob/xenos/predalien_larva.dmi b/icons/mob/xenos/predalien_larva.dmi index 82786f273980688eaddf5bc0d25d0e48ab36a1a8..41eb31a2c809ebb57895a6423e5e1be204071cc1 100644 GIT binary patch delta 3497 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 delta 1068 zcmV+{1k?MV9JdLO7fWCS0{{R3Csb#80000aP)t-sz`(#26Az=4Xu+;~$iSmTKrv%n zNA2XoI5a4;!YbMI0Bmn0+p1V300001bW%=J06^y0W&i*HpOGboe~nm;C8c?JsVOAu zb4g9asYzME)z1YSuXu8KY^Ee_$ zoSDrg`}d5{hS4W}Vfs%FPf57EY zw7^hca3Mw&Mc{By6iS3UlFf3xh*C&Z5gY>J%c2-^Bo0L>5VKs1k$?&W(tQGXB%tDy z+(!pnFhITGPzgr}K?Z~_xZFennNgw~cmskDI}jsrA-IREe_WN>VRUOufT;&w+f{9j zJ$@?KVWqQSgQmQgUp^lyfiN9rKpM^T#XLRt{ImS>wXSvJw`5SCT)aMIeF~|tE`z-1 zZD!G9_yqK>%BnwwROXx2;Ue_`gv*j)1_Lixg&uah zKC{h9e*}04f2U1Vg1;BsP`xwabLxvRl`=N~s_qj~LIVW%o&sp2crU;eUhGSnb^=(} z661#qk;g&^?ww&7NF{yBDF!IDNJ#DloFeZ_4SB>e__s2IfdfMa0MQGiI|12OqT?~8 zFarR$gI~cy-W6_|czP$$R~{Cgic8&-i;QWgX`VcO>v)m zwvTV|+0EuG60omUYJJq6vI}+-LOt8ZcLJv$__94kycQfc_=`<9++yoh554 mzt^5@udlCv{CfQV%671dP0i~1}8YE{3 znStTV$MfU;|E=}DKh9d`+gNBHR==#G4+RuoHh!Iy; zBo)QgigNf5-m3@hP-C+IZAX85KUbdsS8p#OqTu|LELry+nVY)KyQc9D(hoUX10Qnz zxpv(%CsniP@$2PBKG_9u+or^1(aejxL#n}azVCBhwE^l}o|mCAqz?yV=Y-o@EOU2; z)fLt@eeJ)!!T$Wz{`dXkJ5sFkgOWq89Wq(YfBT{CMg@K0hBgH9LqoJCWmtM}-#R(@ z3HdbXEB)A8z^%aWTY+IuooRS}Ldy?e25QT3ly0TLe0Ex=k<`|%sZe~~++|&4F7oL>`nKKSeZ)FD*#i62Gz@YkI4s&Y$TjY&_EMj; zChEjGrh`I}A^5u2CokZTngcQVcXM=QD-EU=aX|Q!^9ra008J zPwA-5>B*$cWPg)CC6~1J+%0T;W$AgQ&V%8SEmiz5de2_BH<^XL^lTD_`88W(3umH< z(<(;a#fJs)Y7`rYFwq1RG1>ihW0UYK^2%foEcl3+<;rO#ON89)${uH0^1pUi^*&IK zG{l<{#()bt!Wuw8T?U-_E|8-M0O63ZHNOQM9YZdU8vQY^z^ll?s{JIfh?twbTL1=0 z*nljAtC~i)-@;rrujgJ8h971_@g=gbVxeu6Z0QjW_v#x=$<~!jWSZ8DPEQfQJG&-iT;)w_L-H zZj|SDIx5X&>THdE*of2F+mCPYu*jxkX{IHb!QB}wEFCq+BP}*5;FCZy#jZ+)$3TJe zXvU~R<7k0s183TAWTtw(ypiH*BTl#q2D5MmA0_~`WrV$os(Tl_g+#NjH7UNyB_-+m zx&-UM{@tCe(c3Gd4Rrj{boq4hEz3| zRuhKtv~h|8?*U^QWl#WmbLR8QPg{o~hse+7MLTpt|N8xlh*D3eVF^|EzhWohm^v@` z4+f?8@Kw?O_93!9SonM!B@(;yJi1D@UC_BGZe)Z{V~&~SsXf(zIdOk(pHU`XDywQk zwQnpW!hZE;r@Jc=Ix|=VC+>t*DeQ+EU;~0}^rS0w1mhE=`jytAe|L%=r+p{!{z{ts z@`c$ObE3iH^%OEa;=*^6r-yGYS}pMkx^Iw$Ca-%|4t1G+ac&U4PF!meUg*&)#R3!r z5#v&n{C%Aaj$$(No$P`n6C1=eFT==*6D4|!xm3p!>R%gu9>w&kqT+YfkZVDp71qznf{BO$e*-Ut+Qn&S_5md$_qr& zqttF1l)PW?z+I;IO!)$}oo&BX%=veaVVIEP5RP+Pt>gXzbxOoymxO;%4 z>b#7qt7BsK+jZ%sL0B*iAU!=i%sv<=msA^mdbE7(@@&*bFxX7|&Wy|U6E2cu)-1~5 z+aG?D4xD$qnOjiQpPPR4eSmkufzDRh z7x8IihyFCwG+k}NubgAnSZALJ2SVM$o0*4s5pDfF-#v6di}%y-cg5P^X>0IQ*VK6z zywTm41p<}oeJd;EuwaK_C146sPlAsc_;P;L?SC>4dPHYnGP&id!qal zgWeu($sYOFd%Zdqw`!@?{8wfccawidYgJ*od6`inT5UopC=+u=0mcqAnXc937IyS9 z1%{k^SL0u+u7N?gSK5~K_w6I|TQJKF8|HKYIr}NDi_dRNt|B**eOJ!5o!EUHU-HQq zF`&9~2tlktOLJZ;vejkse^?0g?;z<}daBGeLcL%DwvzGFG}(%wL5QaKToxbtFW&Oe zO|t~T1E{mjfJf!IwyAJK?ux%Q3*L)WguJu$u4txS7Vp26nY2RVJVZqvfgM0tA{?ta zGC!i8aL^um{tbg0Vb&JC_gskN5o#6qP<$!Dmiu=|lCl$8er>ro0~SBIcDSa!7}YC$ zg#0c>n55*8@z!MKbSKm+iY%#3P1A<&cS+H{>xQx1SPM|z^lBJDWfDVji1P$SdC;BD9@8v(q)36}Bvf^iiP!{e=VBoCUeM>r4BW~Vui`C9_DnR4sSSExZH@�LV< zEl8qATN_S~(FYkbq5WXE?g>OYw-6*+EUg_PNsdor5qiefO1>;lyqM#}`0X81fBiRz z9z7by{_=ays_Q`PcyXu@^J<|FLMqv42u9S^^aB*RmayoOt%FGkTgrj_yYJ1o=>by@ zY-M(|uy!(wMNM*{1`;c7ava_KHu_8`$1xCfuF~`14iWw#eLcljwlj-2Z4w$bY|QwM zq!MIJ5(9rd#Uu9~Hu*$~bM6_sB1IwfTjEaL=Biqc zd9Z##JT1=n(#s3L*XP}?7+&oGuOK2B?X8K^8}?>?JQx@C<@oqwyN)aO`IACu@X^C0 z$N)v~wp!(I`Xl`jl6-g}@_Dt&3cj>gV{9k6or{O?5A$O<9O)n!8tPQ{bGl>}Thy;8 zFTHHDH%!7U8o?FUIGA7+seHer#!RIQwL$R=G!71xPcG!`C|3jPV*@DKNdN@n^VDXD z9Eg8XDMS`EYCTX}dXVp7=g!TC8~-=ZL1XxXvdBwc(slCZ4GCdh=At~bCRkx}mJIKH z9GVHSO?-}PJ9{i2px42a$4Nh=k>wqHHZinxyJ$?xfP1bk=H2}HE1uiWH~Nv2jX?`U zToZpL=8fh`CE%4eCeBiV0-2A2DZvMo2uR|VDAdzWlT9(#?f znFdK)7yO}4wjV*xnk==A@DUOG4;|9?W9D%Z30?Z0F`Fzm;7vS*!9pVVkZanv7ZgDH z{fa(bbaO7t`=v47Z49Larqd(4U5-Fyvo@WSpdIrnK&B1-F(hElJYIq~B`maBBVcqC z-`^39%wtNwJRHVf)=6=$p#D($QUYS4-e*c}u)*ioT+-ohI;KMZ4G4L5ZAwgdn2ba( ziY#+$(w1}xAgI0{Ol!SkjV0`w_+-vyP!s4u!-eD+?X)$vSK%T+_eF&ARXt#`cIeZ@ z8h1IkX2)MFoA*Rxd?^6$ru`zR+=KMBZ-=F?BzbV{jd!25^K{ykfk66il=g4n2gthe zT>20Nz~VSeLi*q>42PADQ)fxZ<`YKLzX_3Q>hCMFE|UDbDNoPU>=dXwAC>9s@9MMQ zepy1;7z@;Cy93*pJbkEGb$mEBdO}S}CN1Qg@JCJaY`-}MLa#RVLL4{<(gD@#GYffO z5wBQz2T~4^12+e5s2?)x>UDLHh!wH5ZJhQyr*isX{+UG%-|W~r!MKPY%|7H^3mUi0 z@$Z;v_64n8F#}6EJAam1Ydk7_7WCl11iqg_xFO+}=YgT61PTPd85~u}81J zB4!EQ&MfguW3Yi$F9W+wf}$XHqv>sj6Fv|njuAFCI163gxs?4mrnUHD;jSBdpl~LH zb_#bV=qb(7#eK#+In{IsBJAT;fqOTynISXKB2VW1R+sFz41&u?6P+k=^&mo1Wk1W^ z77c1aGKck&ap_#~x3JRDXJXN9P8Z7eC!_Z9@{b?jc3&B~!EdlE?Ny*nt%i7)!9$Z! z8fgEZGV#4THlMcc(eIoY|1_n&;8zp>hJ|6aUf{DhUS1&r#oxgDmbpX)bEJ-rOU% z>ChMFpV@p;6=^1|)E4~xcR$~vEjR?8RRD4iX7#1^swCZMJdIE@JkVQ!JE+#1M_iD|B zO$vOb+{x>n_iANdM{w=t*zDQB6&fu^uSGPFBD1z0v;_pWsw19JydD=)UN1e(fOXp* zZqb7@`y?5dGua>tpkPqe=3XnIe7xlpGMcsA{8Q-9-j6`0FA|7tgeysy5QDeX^iNY(g8CxyB}bd?3a2ydMoAD_i>R_AB!z#kt^9hk6(hCDI!dczDT^fUH;e<}y`O|q ztKK#fWRES13>dNb*c@gl4-rC}vU?DV3Z)U5on$yF|0RyU!K zkaQ$(M!^)^G#i+mIWU0mqF@PU76+d_mKCoXfK?-& zP%n+4UyR~{Ku={$E+UkcP3)Ry%Y4aru$I@eT(@Sh%I_{M4tT<(0O$<}8+pz7H7 zwH)xpm$%P$1#hZGnVNm%pOZd2E;qhbD`z(%V58gij*HqfB6ybV?jf^&CY~(}ACjt@ zy5R-VhvLI7%o2e0T=aWI5>%kyUcn2q`RxnC8y5Cq6nB}sFUGz-zu2ksoc0hE-Gi=a z=U=Z9Bf4~QG~DLI8kvcXuM(KbWzfc8;p0qs*S#L{+s@Nf-7gmDW*|Qv1T&@k%zUDj zS_|*$rHVca>4go^cN~A`AZ#nif%S9$j*#Hl1GG(Ft-%dDcFDlko4&e7Ne?rm?%$!_ z9JWANcW5M(kI_&5T7o~0y;-?OF|x{uC_A1#iW_W@AAwwWJ_p(B5#dR+85agkKlI5$ zt3I*0x9qk%;-_`q9CmnJ;l2`9_tuX98MlBlX5ixY(91s)U61F3+e_C_oNVZG>)ew@ zOJb+tL)UJ1+7ji)RRRxqgZZUpp&^T4xKfE(Qgzr?9mWE$Cqz~%Wt%2lJr0}D&KY&% z!NF8;?)=x(6!M7G<#8!Y+k>z4R&UbYY_7N&NNz=6Y0d1_)sX^FusRu&KnQwOlO@OIWTHVl|&Mgnx7iD=`JmWMTx);n@*Su^$0 zN{a=*zu)+!g&`QSyUFh*!-0RE%`joKE&YG4oD)fBC##V=(V-=1aqw7BioS3dV9xw6 zVqCX)?QT@_e}tomD)WENSFGft|1lZTeE*M{tkD)l{O8cl@PFrkA6uj}2&Tl|Gz#ay zel)wwR2tSBubD|ZG_UEha`B@sZAHJm021{vC;u|PzOe_F*cir2J8mZ#ydLbrt7AH$b!K-XX`ks;xFXQhwO)HLtrhHYyghdBZ`+f|b3k36wH zYb1QBNCPUhx@=(@VPfIshhCA%kmjq@cNe+_kX?N!m-?jG2jUQT7Vt(GQ#MOkq{6yp zy4Wh9`nsTOFj5U4f~ug5Qi>)B(!5K2Of1J2x$*rCdRSj;oj_UWN9uqt9{i8l>xPq$ zZ>IJejXzBzm=F_0@x;6;0%i%2c7<_b8ZMK{{>IQ*4nHzK(jTi2=Xzix-_zu=w%KHB zQYsceZ?nS2PUVDO9gI1Hoy{Lo)O0$;Su&{$v32 zjjI|#b{IGTOjc`%g3x5a+_K=ke_a{yrby3P=~jZt>RdMu$f0tZP`Zv1rJ3;FG~vtS zu+Gv*%KX?RUeX8oK?X^I5Lf@MlzK)|>Z613thFtKF*^g%3)M-%m*)9iJrjxr<*G+y(%_RN`HmSso81|k$zH|l+-Cu-fxvpFS6+SZyz8s!XqpO@7{?iO z5460UDrVo=5J4!LgFfKiqC_-O^T}ax0$Bgu1Nqz7!`o(bafhyxZ5xhlUqvbvGoxGowUfkiBCLW;g z5uW?o#B;m0=`xm%W4o)eOMX1FKkCk1fi;-9X1YunIn(8v@FN>`QNb1t0lYP}vIU-a z15Ok0zWVG=j(@jqTvSjyf;>?JdHwKWyHH(@<<;%f^_q(l!o6t1i#Rlsu`vnHhnc_* zKC8tNCHmVN!o6qo`xjCo0724k{$1&Sk}l4FUXtC0bh{QG` z$=7Wmb)d@eg@yRTh~EuXjwO`IM_aASs>3i?N8vdY_|`m9nRFv+@<-R$lMM~V*(yG6 zHtZgXyXsH6%FQv2q3dvr&gaG)f)T>pVkD82t*vx1pYtxTRjabqh9FZ>8zoT3#x!L~NgOwU7d15 z6fUo^UJiKTqghtj9@N@fJ+8A`GzO%wgYk90cKKaB+CK`#F~eQZOqdMaH=eE+bSK@S zCArBgUEUjn+Y=<85FDcZhO-or`=!Z>lAmv}LB|{KaZdI=!TBHc5T~FNYTwQ)0TDrQ zMR-TC#^@*r`6?@^)p6?lmqpGsdAzAXw7k5` z#)g7z)h?xYWViG&Cd>{mc4pge>s+pSV~bA14&-O!CKpe->!JREL1%DNmyxlxuhibj$Opw*qZ0c8?0nhJS%k0atd<0oOSxC*41BjQgL0hh z#DPFhU3A!0GHFhPR41j*3;5IX$4w@|Z1;D@vGSW=cfWNHTNL6txP*Srh5H$cPKX9Z z282Ijzxj>n2U}!oO#L~G{Ux-^1f+o})bv6)%9p?OwNzU6oMoRLUQBmYA20_ByUSb0 z2~Xz7B}3xw8nqFRXUc=EuQTD^hg++u54-8{0?Fv0{4q#gv(E0mVX8dMrJEqz5I;-B z#hihnw>vDNIv-NwI>qEDej|yPA=Jlkv5*$DS)lEXBpp(DTggUy%vNNd4Tpw{X80iwdK*JKhScMZQ(1w;?Bv<)Y=m zaW1Lp-2K52_+|OGcLx!+V4_GS?W3v!yKau2AVaGa?wFom96kHek-SDaOD)kZyu+qs zxXBX$e+32c#g)()ALyZ4_L=#BvDls?9ssY;vt08Cnvrj^RdW`~f)W6pNB=o`#Qaf8 z09Z8bg$=9_!kEo6krxQqvugX(u$jXed#LDoG(9BBDiiA!XNI(Jb-{MS@W?8at;38VHLF*BM1eD9 z=YII_`odmkLE-=*>X?C)$Ii3}~3q8NusFWy~+R*u5A-mjcGzKj{@ z=32<1b1;>|TO)h2v@~$vW#-lxB(AfqAX%WL_>d0MWuynx^H8r`hN}fc46YyOgZT^F z4g5hV-ozcBcn{OqFHP5_gbtovL9*3T0qh0Xa`_vtD6S!G^Qqg&^8kMA@V9T~H(3#} zA#ecGA_v3^16cUM!uI!=AP2l<-FzF4@z2NiBdV9?yTJip=AJDW(|C!#7v`-V`tTln zC8R1FS1s{$Dbek|JgA)Hs7ep}s#K~?x5O%r-g17rVTrD>Hu!2LDE7DCv*n4K%Szt&+R zGwy%gN|3BwKMn7zHWj{BozHua6A6)|^(w_^ZV*(0mizGB#k=5$G^AMp7uJiiE;AfW z;|f8c`cS(IOvAI*{+2M4;*OV?YRrr9*5L=w#^~dNT?!h9rFd)`t?AlL%f(MFAAlbv zG?<;v2fX^-XL5wwnL-Nh z_qPIG>4|^c;=gr*dr_#sxv1#eC3&a4;v-V>UR6TD26CNUEp5H#piEp?BX4||@v9mB{iD8SynsD{UQO+eg=y!5?D`!}xV@*edGO;0D{43@ju;6a{yYA*R+Ofb= z$Y7I)VMyXBKmY6Ss22)c%oif;x6!`P&I7ZE%;U8OL4%f z;sE&^N1A-RTIW>druEh`;9$fwsVwKue&0zj(qglKnt6d95F>tyK1yzmCp2+{{#cA3CPMZm3M2kFI!7Kd7OHZyRO{@!#+3@}r7H(hP(>dL7 z>h*3#iCd#4PfZ24htmdz%sQ8l9v`|Mj$7k_^Yhc)DT?YSg@`p)b-AYK_p`?zGCGT9MG4vpi< zxbZI;0`P7i!yeMEGOl%aX}bw&5iuw_?g;gk-O`9i;>D;>7`W`(XUX4bfLf6c;W)4wXmuEjT@km ztVSVG3e;7o#8N9ybi31r8=uGAzYLrZevdAH>yjBkr75&V@q@Xvm@8IjN)B_!QG>P( zr;;{5A1PbI&rXJ8M7oYsA76Dj}U=>218IGfGYXw?UcnwP}3)uIUl4No0Oh=vFA7d?53v&055d zWWEFBVp;BE^f1XpHiN(w4r%qbz+?{oY5NFJ1R09eJEiSvXOPiASfiJomIp0WYZxyr zdvSGJM@Vo8mKz_2%yT@=o~M=zs;~~ zpZ!?YEcc>R5KnDNGWm-P4N;Lif z*3EMfWA0FnR_tx7jzQ+~!F5~Yurh6W@#<%q$yNb;U`r6y z2$q+dhV82QZ4G>kc4i&grOdsdPd;=_se^u-z+-a-K*Dw=QrJ*)ng#q6Tz``g`wW7%>;Wp;LN@H3khClK)*xIbgI? z0F@8)9_j05GOmI2(omAgaNVle>e!<+w{u;`TR8V_`;!2w_O>(H$Whgu2)0*I|17Li z4k&xk&sb?F6KJkSCL%KQ57@3%y+w~Nz1yK#4jRu^%XMM~>F->cX9Sh_y)ks~MNJnH zt#YenLTWzFNbh7o=g5VW6=B_w#M7?|4}!|=pM!1>z%0BRK6`sO}hkQ+(Fb+zV8YR;DAf=RQgaGna+7uDe5TbBJUqGFsr#>amK6SuI?5dU;x z+XpLhU-kmkT>8HZ#KrIBrdNd@9X~NGu2}iZcXf!1PpBg}fWCMJt0=ht#b&3xyCYM2 zL(|a*3JW}U;oo_q$Vp{9)cc*^Oan|TcGf&ssLCKCES#!ojR^T~mzvj2Z2>b{ac$f- zZTA5fe0Imz*4t4VV+qZiK%L@sE>`c^hAkV;pCVocah?!s+~kn3i2qfl9wyeQxg#f ziH$I}Z|3mvP||g}P26lIk8fc6VCT8KgLm%IrNCDr(e|4)km=PS#Od?mK?-V641}jd z38S|HNdgv(M0QJSoc<*Q6*4A=-=&P_Aq{XAZ)O41_g}n$i`A;&ppffYv|$1{OHVrT zgtL8K)%yJ$I0HXFWZW|Zd6p@g;aNCdYPB5LON?@;BVQjO1Yg?fU^h~mwoVbOyS@lT zU~hxJXeMHQ-bpHDQRrZN-`8uxLq-qu(c|?R!;?Gihe5|MlSu883B9o$mGx~F-QD6G?`7b2``F_AxGe?{x~d$!z00y6 ziwk9|Juy+!%5(YgCu9ig?jf_*gS^_DO3dK)W+$rZRr$7 zZAJ3qo<-7;G7&A>!KBDe6DHi~JJaD}T}^0drtyAzCO$Gg7|-jo+J%IsW+G8MJK?9& z94Goph}+E^97{6gK()Ltk5UxT^qE>`-M|Zh^kR(l21*oVtlbs6iMiqDDn^TXjg(5* zVlu*k?dASav_TpH1zw_nFv1!PJlXFU2q&w6y=4K4f^OJhDlU*&s4IcV(qcCxI{W?= z(lIdOF0+hOMwrikmbYYOU>6~S1od0-#qB^V=jSe_QHcMi_uEH-OjCDFa#=V zo(1F~UB6(&I%CtoHNpumw)Mj7Km%j@mLMo)U>eNUD@7I>t-(kVFWjspN`|Y}GPviA zzqNOXZw~X=IG$LA)>lJt$MQ?CUX<(z#6Lzo0ZyZQiHBd-5RSzqW}A-Em=@je(uR?S zs-)3GS{n9Yl7i*(%Vp+Kl7d7l3j7Fu)89tp_md#D8oTHA+^v_*ON>~(Sx;#~S;&2n zZT^*}Xl9?gOT)IzRt}gdJ93+BGE%|qY6um{4L6Z4!&yFby|E8$Lr<#m0nty3f2jJq zH_R?olhJ7!pc${Ues*Cm{4-gY3&yl^6c(w`8*JJYkGvU8=z;h1y@N%A96XVf0_P1WI$tV z&ky0FGefPbgN-gsVq(LE`3Eh`=1={-r))&c^My#Z zSs|PF*5?=#auWxPFGVD(etYpFF@#&$aQU9$Myfwzh_o|Ikx5^y8T=(g;=RTDA`>1) z5(!;K9T83H1h1@Er6xl{u9*I6_DXZx165b%bHC@Yz2=Y5cUVR0)U2sjb(&an{Qo5} zPA2+mC!$?zH7tmY_wvY!vt>e7R3e<)X}3~mGFq8o(E_+#u<%N7%M817>o!7mgywY& z1DVSuC`|Yb@CYR@1X@`V3qEM7UP2<`XZert+$lXYE5(r|F_&M+{!<|EZMIt3HvM9+ zxpCq$;jX%_A6(l=v#~8o@okxaJ@%&I-5T^}BHDVp^#qpDM5BwVw0zQ*9f{I;BuZPAHFiM_0`i(ttk@4hTQp;@}SMH6rOXy7qL~*1b>dWrW2lc zFXy5)IsHh*i|qAVgEGfTD_ORwKd1gx(D-KB<*&o)9B6YoXg_ggSQ2FBY-nZ?A5OuE zNposOuz-{5CgibpnFvPnK=bVNjC72!)spO+&EdnZTaMX~mBKE0nJOZ+-*E@9Lfj(< zEuulIawu6=2w93P?!K2oCv!_YyYSJdh1i7AU;x6t>*+W1g5Tlv3N5K#|5yNW!kRvK zka~y-;_3n%U8FSVjH98;XDJnlztoQ(gwdq3=hqv5FU*$5)*YUN^};UJL+m!!ryos78uBRO zcEhV=)uXMN(6a<9?k5L)Il^tHjdt0POoDK}faJabsMf-}xVxlvOyx0568A1aB7df< zfx#p+$_6PESh)$l=s8qN+b{l@aUjE7SkWBakt3Rw*VGjAvKzD3X*iNbe(6OnZh^n| zuz8m~y$USwx_*RJ6H<~(usS_QMw4_1&)pKi;W8w;B=Hb(gV=R7`4?+gr4fxkRuuH2 z1xtv0LD`>F!8#+8_OC4)&scmdr0b$ja~w;5a+k{*e9<&|v8>ocM14@#2ix_v+}qmm zXnBGQQH`ON_=YbrD=r;?SOS433&Bj8txNH{X^;F){i0Y{vmpkZD`6+A=Y|8BS8ZfN zIBFn0*?TBxhi$7fi%=XGnI5-Uw;};f<}qU8*lD4Us!BAZPj2*-4njfJ!^~2p!@l42D5`&-@J#WQMTAHMoxH8%C74EK>o+QXo7~m7)wVx09%?<% z5bfndi-~c$L>8d+S+3+r;Nddr{zz8onfg+x#6&WIk)FA8cl|?rEQe&Fuy_{>&~U;W z05hsSx=c7jeEW~_quVCs>dkBXmYBj}{V)ZeHqK^}i_s-NU|-O(H_h+}6H~H=!Eq@i zk2Z&+G>H#p-waeIDnD~Mj}0n#U_jqJoWzu8p%FAg;)IvS^38_Xl6M6){jGt|_bEE$ z79obC=@ZASO+)o9hW8oWNaexyf9a|l%0$A{@o8>~xzkmMnO;Y7@Z-x!re~@$!1pQ! zU%|5u`BB@PGpm>#7EJKq;sl$CyBbxfUw>-=;a_8^O2#3mVb*DXFSD<(_oF1AaC?S8 z+T$$FxK@@Bae{=?&WKgi&QTlgIBa(V{~XgotMJU}cQ|sx^w|5>BV8Z;Kl`8FmYD+r z_=bhgS%PW%!6;Qn{+nv#5jx;6mZE{z_|4}d)nyBzCd*AnZ>8a}kKQexRqVop_XLL6 zek+%llj=6RyPRUBzDpz=bri1qNF47f=_s$*$YvjYe zI-oksLTl1Y0t2yeZPhrWC!S$sp-|FvEB>Wbm!Q(O-b;|^$3u|L@lJv}msvWnnQa?K z$fT|RjL4*-DnFbF<4o0vBVrcGx<$Ko7|QfsQHAGk63yOMR1Cw^o56NNAN6W|q9JUC z3a*anCE0S3`6nw-a`%`(@N@*(`E}-^onjfz@2$~Qz9-UNd3z?=tz^VgbuOi@yY00C zEi&;IdThA3UM&-fih7Pa=HYe?@M9&sApbDkq+=kcK++o3PW=4BU!&Fly37jyS0Mh4Ssd!OSNB|*bv zfoEPfI?hVp{2t9DH8G5)zY~GVpe_76fUGRoy_{X_Th7P2Oty*>Z$8yF0KG2L?3lrJ zy;7kY6==eLV^{aZpAC-oDn?ee6UV!eo;G=?Aj^Mc1ZJz;soPQIyb}uAl8upVtd}&T zI6eAlUG60pe)}i;R#6{sd~BO7L=6h!9|RIyp@yi!gGu2d(x7O1AzTYXy;q=PC77BGyN&;FGFjf{U>!+TEM z;oAqXN67cGOZ~j@LT}W-B{Qw2dr5?1nhARzd75{FWE!uIrX)kZ92wDm=x!@p=994` z8OkDIh7Zsvh>~6Si9d+j`_1zGIA~-lD@RD9<>&FbNC9>m2!3|WM;I`TR5x49C>~j$ znL_bbyi-ad(9_5y1?gndk>?7xH8V`0OqoFq3?T)ges+MmwsSP|P|!z+a6c@{sq12L zpPzQzsN+(H-2atO`D{yy2kEU;PLjl1e#JVqH~Z`BCE4P*Y`$H?w-nFS0W6X$blS4&hzqM~3A|-6C%_}m zYt)A0yLe4k}GyT8XRYx3t%rAE{H5<9RUX1)qFc|;j4rFqa}|Ki+IdLnEf zWDu*O%JU5=9{?tYg|_eh#S3U3j7uy9DG=0HifG+#hX)67F-L$7L``49f3~-xr9n6* zNRS0{hB947Rgr!w;z%Lre0XYfc-@a?rh)tUSXm?Lvhy&6FeAv zoJ#br=wm|lqU(vFPV6zEbG!z*3M*Dr&xH54!4PnA)@K26Q5mzRf46wYyK+!WgdHtZ z*P3Jh);yLpSI!^&wtSV98i<<2G{$3<44kVFduC2E5QcM?g!a7{sv%7-4l>(N%i`Wl_UvXML8~4BM&e zPyWMiZL$dVjjbW#Nus`lc&i7=S(puYh04C0gDBdPr)N#wE1$OD_ErC=!Kf6;v2Z?D zT0LV`!%bs_f@`c%}O-F$dj*2Vn1BFWL=Mo~aJ@FwVSIBKw`UHS{%34}>y- zH%ucEp&K=_YW(l_#g7jyA`8E%%P*_Ve1_xJGD?&+s<%cyyo9{wQ$gHL-Y)Ktm(_@v z;S>@NLH~a5)XHF-X9e_f%pJ8OSb!9qV>J{Z$=3}FO;@9EjfD$+46aqEnv%4M;UUmF z;MHzCuo@z`&>F1drWT6PRa(s7O=N*Vx1dsno50kJmk!utUR3ogmg;w;;D=ker_?Eb z%4+W;vaAm=wpi$M5c~k+$y6D?Wy4M>F{@97_f}&)F!7>3UApfS7LR58cGJS^?jgE| z6-GJeC7ql$c69b-3ST|zTAws&0!ljI8|>dS#waI3(t_v+JSPd8SK3ghIPlWLoka=d zd~_x}h+4$N+0FR5Yc-1zik;@dvTVs}*xgS}PNZ)2Q2Ozm3~k`mTRqo*x|!S8e>zDR zG|Z3h3~cIbU(B;ikRMWM#bzRkpdqi3ELMH6hF6nhdk4arss)61v`mKDZnVY4q9_&n{UP zFNq5MA-I%rm0)=X2qNSU;zmx+axYJK>`PArV~?6gIzojA9;n!(S@(#Imbo5y8ClIL zq>>0zt;XFEJR5^nE3Up8s*+0*^?bNKN9*0!V9JiP(ALN%-&Ld}w>A!I(ZQ0Mi_3X> zzj0iuFrLr*3x?uPIoiU46hL#^sVY46M$JeVzBJRHe-+RcuNNUMQ{+rrRjlifIebMR zHpNi>cw+aQ#1u+VI1Y$VJm`Dd^`NUHuA>?e+T9nIp~y&4LYCIXbJiX0sA2DAd6q-{ zcP7NW@BIn38N!SR;6*wlJ6#aGLhz?5YbAvqr5GWUZ9i;C=JkMF;Z_Gep%hmktliRR zQRJ9%D}d{i$#xfOG4MSOpv~jEO;V|%Uwh!fa9?PuIZcI^EQ}lg(_)6dJm>entEyS4 zKx|am4K%agE&98Y>r}{Ym!70or={R&DH*BKYNt)j?RMSkp@ffn>t|yeAtFX+OCLC% z`)fk0yhax+r+1?E$GPSnNpWqJmG)v25 za?F_Ap1k8Msu79dd-_1>kJ`N>d{>(fIUx(94Sr z7~A*u{rP_X`Th6fPaf>B$GOja&ULQq^?F_d#0Qk+wc^R>ubO^)#q|q4W~_xNYrMlJ zW`AIhNy%y)GWHqRBc=jFXix^N&a@Vp#U*TX&u*z5K`p9elLcO!HYG6-ZUo$v0ROeA zSYGRHTfr=>gUwbiUJ#7Mj0a#>!Ap#?jPF$&SvXVG7?x|4ENQEn$A2fbqA?=h^t@f{ zC<&b`cC@Jx+n-$|Ql_4(&{~Q-3|taRjP_ud`kmjq3~r=3rJ6upZFm@2NPDTqv=7ul zQ%0t5Zql{6wPacQ$B+r0?2u>((pqjwFr`#=F2pIKJ^dpr;)xYBC@G`F`Q^R@fef4r zZh(b-6YkGt(Xao7A|%YIZs-L;0EjD0X;1+k->!8ZH{?b@bX-5CQMaB2&2BiM`>>IA-tv1R3w8)ZlXE^R4?O&q*qa?fx>fOC> zXnk^>JIG+0>i1$6?DJ#l7Y0Du;t*;_ZE zrH^tqqxT658`)xd$M?gRB?P-i&Yws;2Xe&yXs`CDL;ZL6$jU@DcmyK?X!;9fewIb9 zUp{<9|K;92oS z#b|&8*lYMP%Lo&W9Cm$ zQGDvu2q;Qx2Vh2`)^rA$n31Ua)ppcpp+xzFA!bBH`bK4+SaVpije0C6DMjFf4wd(!T(wJUWFNAjvD>i zkzPq@=v;ShP$lED_@oQR*A5i9NbB1O7p>{Fy0nPY(E;%hte(pgKTB8`ztSzsOM*J> zzaq!I*MCB8?>8!P9Gp4*YKm$=aM1bbbi9&Fil#*4^PgM^#=oRQ4+?S;2+V{KB%Vd$ z7(v#pr=Gk>wKBo$qoKwF7!qjQg~5Hpfo@ip9^<$UYhbBXU<3P1M|Pg{1|nyNgD9Fx z6Xys!e7viWfaZ5zGmzbw0O52{ajkLq7LZ=^dW@pRx2{!SE?ywRgT}hUSbHy@VMElu z#t!IKQU>>`_Xx4A*j$mNNp>@)mYMoS3pcn$LizI3g85|JgtQmy{LNK3ywIkdKUh&o zsT@Z5f#r=62~?WueYUn_zAA=a{{G_=^9b3Kh#wPgW3oV}L-#hn6;4k((ilncNr8J4 z(IukDibqEAh0C|>XiI1{Qy9SE@9pLZSv0M&Dd9YGsqF0x1#n5C;;KhxQA(O&eUuYJ zGtr7W_2@@H@?QJZiPhqgOh$+6xI&rn&#ZhgHg~FKu8r(dIC}T86xEF58^u9ehl;_6 zf1WEa2(KL)Nu&gR*MQL)){~v}OGURTssY>wQL#XO>{09)3HWBlLM?>=1ZtIO<&{JB z^Eur#)5b3U;A6x5H=PNLevj#<;Zwkr&A}5pC~P#U`?=$=5^{v@Jae3ix=m2+?jI0s z{%GCyay!|JyG_d2IC(C``|Q=2&&_&+SCOq!V_g{x9j!cAMoOyh^snT}644E!H`*F* z(ih1gy}uvDV_SvEUR>SkGH3drHtuQmve}gaM7?m#SWKmEGfF>qy--#P=f_1nE=P?!od9Q!m4E8BJo?6bNQUU#kzUM;_ZHiJLb(V|29@8`OV`j8l-|(V!-ZY^n0S{T=dvD<|H%-GyH)1>yqU z$oGRyUFZx~^3@0$d!uxQYalWYwh@s~Z7GC0!KD8vWto_daY#hg*k-HrXt z)6iT4RlMw(f9&^~@mh%X5jCk)xuA%qn20xMqI!7T#g&0yp6xSga8fv29VW1dTKaNRX(ztpEY=$m(V@BxN7pP00 zd$xujfotS4c!rJ9mNqwQ+3R? z)mt@^DCx(l8kKQyYTV>>z(Ex4`&(fK9*-($CrAMCm?m|agRbP|1L?}F*Ah2cNu1N| z%otaTihd?(6eh7a4I2-qji~kVdu<->>3R3Wfne|}8E~K|uayYv$22PwEs!h8uDn)J z$cK0mFy9>}q3k;hXy-qCy+*yyJGKCKaZZLrzwgbK-kTO71pyQ=UOan?=*BnZ zA`p71SZdm9rhdiUQ=c(~Sp=#T-du#TPY&GCk5LS7dI2x1y_i1qQ>g7n97ZM)_xUVS ziL774<2_cDWP5`~(}8@DhQ>D@{RDfo&j4?)k3U5HdM$ng`eu@W&^v|?!PvtqkCk|) z4Ab{Z5X;+W>XXcDG$5C!1?=Y6xPSdTx4QcF6U8ZMywzDd+npUW5xZ~bZxjhXMOoa& zyJVJGYHf7WfV-^Qb?_KF9YQH;gU=eAoT!_L-p!{{zmkj)qr=u>G$EiBXeQNC-}Ovb=9AA3x%VmZ7vkeXzM1pT zYC771?#{%h94*1PERf}}{53Hu|Am~W`zm>EyP#$E-(@NJrw^%WhNf}}L=!@=FWK(V z>S3=a_#nD157u8($ncftQS^mzDf#Bt%A4tcI!!M?5gD%!7}oY``oWHboV7hPl^ffA2z%IMWrFfZNVP;1UI&Fbp^?x7$V^uGSui2{an=vi;HxDc8NQR$$Ai!$DYAQ4ay|A_2R@ z7rfa9olKgq;LVgqC$G;wE|Z_QC0e2cz?Ze$)+3NnZqBW>=9FAP?R6wIKI~~r1}v7! z1h;&Bb1~QJ%|fd|5v(BVHVlut+2{KQ&h@j_s`1=8jkd|OtAkC-_BMUHamx820}{)> zS{0QCs|p$CJ$`p;!8H2)!?vn=4w&|U;66(!e(;Cx>z3Og?4FU@OuTx>s|DpA~_;S2>vk0&ACamN+GTGi7cCWE8eq4qq)V3djmPIY2pgdxv(#!-jhm2(4s9 zvtLoD`fPvFgrRCkvRO6gD0ly!;ty87H0G`hID?b&4;%EW>F0_0{@u&q76w2|p2pIAi5hR4jo2=Dx+jq1K<;$!%+=AiNBcPDo_lTRR(_5!b{Osyg zLJ#(KuLH&sM!|HV&8AG{2d8AN$s1F`)z$0cwe?w#Q7d*o;?$U;UsG;V))by~oN7c= zv;0bk0~QGzGhc`I&w}!~)ql{Rk9IdnA&RbE`^!=h@Zwx8H2$m<}0&T33Wdo~9>!`y)Vp!u|xh;1BshO_OfkKrNa z82nYfIfaFsaCVa!Un8^If6NrL&1$B|4&F35b3xPS^ZMbW2Z|@#5=9t-qSXa2X|0oG%uA{WZ10>a`XOJfctj5SANh&)}=zfvJOWuTi)Dg?5!r1#JO=jxw%6YAQXwb z6eSoxQUdlbGn`g>{>IL}JXh17k6XJ_vPit?whMK{+*bw$a1j6tV6O#bedbU9-$E@7PDW)pcsDtli6g@$mV{M7KA z6Q|GKU$;zJuLtt(G%}1+>FF(fyOR-0*{ab#!YzI*4G$xR6e8ka=a&Wc4mPKjWXqAM zZC9q(51S)7h@Hj53c*rMH5P_(OK1DBVP~0O+M=wrz zE^lb#XHVyYl_v`DVLtK=lbMzVFk9U&L96>hd6vbbGsoDH(#RG&VfH zoU%2mCt{t+DW?UQmWOG~_yCQgWw+rULv!SVC&Kf^QPaV4f1SK%(T6&TAlRNtW(Zky z2ifxAX3bAC6~&q>zofR60{Owolr2kGKPz1hxO~lb-TG$AtuJOS_|nuKuY*MqFJryX z7Aw!DMut-rlg(kc1?hf(IkFDM65#r>>uyvS4Y;?a&zLaq0}Fp1v6OPi)l>!Wv6`@Z z+2$OP@D;W+jSC3_GNssZ8FLrPKhqcBEAn_)a*QpcqF$YoGs`b9n(n<}!bxL`!nX#7 zm=+PqmPInI*|wZP4Tp!a%5E!uMIwFC#QeS;{X*(%#v=55KHRP%RL!9#cC}v8fLCmP zpzKH_&@)B<3X8gndCn@lA16^VS|{wU6nMk03v!nWM%$Q{WlX3QHD9YU^kQV@5xZh8=y~6!j~8_@3_4gbe52c=z_)>WJX6)%RYQ1bTCa^Y?dV_Q z{0-mZ%{p+)E|cFaAux2)>u~s*O%)9>4$S-m2xd7>dS)-ISNm@@@C1dM=UrmFD2Q|G zb7t?)B81cnV2T>Nrr{EHS!7GE3U!}E*`(HHpR9RN(%(8>*29wq2r(1=aS*KM5lLt5F;HTYt-^C*^&zq2d@DV z=n};%4cKkh+PWG*=r>6eJ5uhKrlc~W)_nuIjty2MAAaU^Eu|FOd4Uw$5_lTrxduv1 zrC$9Zg<$6QasANL;|*!oH;BemSX*Rs}5G>uD%051I6$o~ez0gL9QrG&(;F zmuuqPUBr&bWWg?YP(;u+(r_KYIYcY0zdOBL?e|=xtDXWqLPG*y$wl+D zsfPRHu10%D{6$UGK5R;OoBE4->!un#04-}X?lbNaKWxN;9+9p&R6?-_>+PHpN5gzY zGDtVS#Z-~kdrx3A&VxDl*VH{3pc+748~6#kL!)^5M}R%52&F2xpN~8+ zX-qsHL`_*QILrzTPx5lif8LJnP$If70xs_Nc#bPx(~Dj|2exHtyiE7D^hLK!aX-ut z`;EYmca&dsik21DH*wCPT1=$*u%n-QEio|oN5COJzoo8=!*o#v7~u22l@CXcrEWc_ z;RqWBROBTt`}-5eCHBwZk(pIZ!txy8_u`rb*SzG)mmO1#qQ)gOK3JM!q1UZZA}CMC zFLG~oeyxjlTT-7)!H&&oZyYiZXL5Sz-cqHCpdi-f3C09zpnwrm+5c1r)L7FmRW7xz zm4W0~C|*#1T|B8zraSk{5MmjX@4nuc`DA|;)reH)+0q(1Y=G)?rzETE6yJ}Ho2(`J3 zy=U*sME|_c9O8$v+*S_3U6406)_;EFnMwRk^Wisdbc_hZ3B|z{EHph!Qfm|y$Y8j7 zSli(K_HG&#iS_ae@!U-a)rGs2USidkcZf~uU*EtKh7$Y2CAouCHNLZ*S$e~Vq4qlEYe4q}?5k8<+J6$AGAvN_?eZhf84I`ztAkzqU@3%Ad|kK4P4I-XgF3Nd*v%If+8 zV6E2P+)cV_R$BLDW1`2;>klN}7d4cYAn%Q(BU7nmYXki)V$J%miD+$j}9%6M2gzy_C&zC+^=;HP;RHgXF(PBm%^|kTnYH4<>VD8UqR`n< zLaxfFE|u`bqRVou2&tx>l8e=I+{UBVoKJ65GIFiLn#csZWPp7~EQx$RDf$;Jbf>}Y zBSiQdH8gy;Ccc-2n)#srJHqmfmN@n1;lI>5#nrRVnX_+v$m52rO}4T$+m)Pf$7&7y zwNZ#~Cnh?3Z&J}ov(*Hp*P~tCC8d}vckVF;E zyFX-D7=fW5E4iBqmzzsj`Gzft%tn&sTS0TLEu->`=tT zhTE{voAk=;E>cdaViZm)ulHj*$U^#^>A+!J6M#Ey=?rE568D7qE%xFqbB7;oVIORk zG#0aAyg~)tUgavc`T#w}+udx=q_Q*(5qY3SIL}+5<;46ji*GXU-xs}V`qm2T2AgIj zT1oY~+%0IP`QD)vCQgQa*P-;j487)CXKLg`SqNa?+H`Q-1JShP+bGQ86JW zs?zDf-<3)_aBr(Bs$>0m0j|eM1u1in^YNkPVe&pqo-pSB4#Z#)X^u9(9m|^FY1|WB zy-T1_y(MThw7KwuIVD!apJA8mbN>(TB3TcfPTnmB{H)FI{?{}{@`#hquuhUb6>9BC zGw8b{nDD8W+VT_*#Qj_6UH`)v3MVJY^39Im(!J{|zV9m^Z&yFBroU6qD)jb_K+1|VZ(4Pfh7hRw$9nQPn*-i)xy5eCc% z&LZEMl#AU>@2FdpeE)MVN-nP2QDeR2#{T;~ZiVy0q4X$PNvo83nF!Ot(8oLZm6c*;;E&Y7aoiTO zpPI=7TUpYVQtTi-ReF? zFa2B6;%+tLp>e0y%Hx#TghEfBMo)P~o7$+B3W5ar==X{e zf$~@N9v^;`QsXB&Qa*_7Qz75FylO{|C|*y0Q@;K^>`-J8>?dzMiGW0BPMT3B?bUAe zd73rfP#uRX+TS#cR3GP0!IDe4g?~~dG1?p^?x01?{(w5cmr!Fup``B>Fidgza@ohf zGSsLTzAk7^2D^|O3Whi~bBj0bu#6pGO0gl1y(8#?N)ma+C&DMCXLoiL=Pk7V$gSN~ z<@kl*1@{b5ZYxE>_-VIWnJ04a{`?>P5x+lHQ}k z-x%;}XDhksNw2a1G8}!oKz8v6+hwcqU(0l=`;Nb!(U=dy__+pQF`d{>1)l3IYM;fI z5F^Mp1!bO05wN+Gb}O&5Y-V{NMKq(F3S=fqF!#+kk0}Tme$Xit{A&!6h5a?d&>sDu zvb=VIrzJ7$irk>Vq1El0YDA#Z9Kzjm3OKcCdKUSZMeOe;#;Rz4nD2T6-MDH<4 zm(KSI?<6jSWP{tEWf`h~!*bfD04^y)h}RXOdqFw<3V3{a9Xvc@mX7C!3N{S$rKM4z1mkAo25l@Xe(Ng4B&1^m?RKYHgzlo{@vUTTBs&D)t0%LT2J;QdDBPDsAm1y%LCaA9x-@N7b62v z6gL<|8r;Y)~p}CybbneYTuk+J51xt z)H}iM$=3aI7V#R5^D!lvlQayAh!!F>PnPmaGlK<>%ijeRmd0;dux~=(;#pqq9e6mN>HYdTX8y32(50nzm=4uzS4RmVj2Hf?-;TsyJ*BT zixSZ{v>QL!bnd#)A#Dh5C}o)KDHuf*$CK+F&F9@=;x~TFMpU6OIPRqRa7`eZukyai zBjn%B!{MFiGfBe0%CXlK@ZbVIQa&B3{z)N0L02JB^|n#O3bWd8#c58MIJPv`K4W0R8^o|gpNE)36-r(9>%047Xl1lk;*T3_#vLVty0|!7){Qys*EB?~y zI7z!Ujr*!bz_N>3nWe1y2j(0vcj`S0u0GJ1tC`~mwSA^v0P<2wr zij;=cs3f=BYjgT0+~e9#)Vl*R$1CO5$y0QYosny(Qk>oj&0oq#1R8jyS~T&%%;n^n zZ;^AqZQi91&gF^qpJPW<9{GL>^Goy4(lNT{$)FbJC06!$p`f|UxAu^Ti-<*Jqq=l_ z&MT!GKK4;p!;e2v^Bn4Sz<>=YD5(wZEp54w%*C{!K?vntty?@COvRISK}Vs#@=ntF z(!xxz^2f}uwD%C-AxX^LJ&dK+GA4(8lUEF+ri&W(ROXROoMz(nFObI?N@&#W{g^0! z@Zk7U(p%Z-Cc<{?7P!1+OY%5DL`w+_hGQYG(qU8ikUvn$mB!N``Q7@n2F=pTN zSa>e=f&^qCS^!IK@~2BZbSd#*9+N@sdxZI3EH4)c*??bU3dtX0hwbOd9-IUV=?(#$r$RbB(rS{W5M}lR^a$ zLBcFNY6Jm7uS>%Vlft!mi~*qZw@a_l`CKIU{G=u-?~U}E!|2CpT3pIso4VE}-moz= zxGQXNqUZmfp%72y>M8XvrwEUiO}eXlM=Y%@aI%}hfYadqGXSyHElB}_%3gq?!0A-$ zix;@~sd;Yv>}8p3ooK4a({NSkQI-ic>5duvLV%pPrG78-83elH)?cJ8qC zhVX6jYw3huM3lOUQNLmKjT;4{VR;K-@tvezb7jr9Ye?S;>f&09@-ZmLSpaKSw{d30 zqj?Y35sb&7`_3JjX4N+Lcd+4@WU{R%cn6@B3GvhXq&ED>^_6rlT`B>V#g>ypu9AuNTS$+z{LyF-{%>C=9_%L2zLZu3+}<%Inaa^ zN(jfX#S=g*cIhCc<8Po0C=Y>^Vbio$H}^pGLe0Dcxv%>uCH^cySGN1x{n1 zgD<`vB@%t%d^DWX4;uvU_4vK*ih&&*x^F@+zZ_h@9;>%^gpsgr)hjaX)D|`00zjo4 zV72#^?);dZvzI?T;3%>t*Li+ze96V#^*Z8Bsd-0pV3F0{lk*<0hVm>$`4}NDWVJEB zjJMH{srQz!z~sV29xxHqp@BI9zEQZwi&J=Xe3SP^rzwEBADU@0!{2^ZqIMl8d4h$n zy~dle?_B2=y9!&Gskce3>0~R69D_3u9~iHy+Wh2|vNHe&$?ujOa{F6rXfPEPlEoX0cV$_fO;bn>*cNrb*Q-`yHZS{zkWB!# zLnV0cU=_qnZUVc#Zh(SU^5()YXPe8KsM_e_&lIX(yi6H&hQM^HJP)deKn+USC)$e8 z5K{I$Q$;>x#gBpNW^V;K!i(Emc+w>i4zM8&5^O{rY!OGO9j}deA+W`3VHbkaLqObd zbI~31!IRwBn^Uwr22VcEAL+{;)ZwlXhyuewPGUxhuuk3#*c^@1QS~4~UcGcZcjlhd zHRs4(-uAq*jBfIesXLVy9Fa8Ox^w6J*MZJA>CwEA$L6Xru+Ej|h*)?IZNB_~XBuVw z8?kGrL$($;hAAkYC+Z|*P|Hn+&tW5ff!04Dn=6`_JRUD$3jc0N z-I4Ec+n=Z3h!n;TEDW&JDs0g;HSmP&eV7*o`v)~Fj+o+S|NcC$OOl8wmgrL(o}`Gb zS#14aA+k#b;k@r~;Y)ZY^1R}-EJ617)+`=f7()__MjI3Gkhyw#=OgDf(se1{x{BU8 z!J-$4XR$JY(yeV?%|`03@HRFzLhu9!G1J|IUxM38WzwE#Nbb3E+jWSh)J#<_NV}LuZ(|CQu%^cH0u1T(D0%k@@RR!PJ-nVzFqb$5 zN#r5bPeZEw%C81nOmSZ50SJWRapfb3b>%_0Y1nGaxz)cTMay2bl&$VFNlE%#x!XIQ z$LT)dEo6cw3_N|Heo^qGu-Y^Ba*`6%&h?d?3;QeP;vhbz9*a_PbJi}H73)*Dkilk9 z^U>9_BMbuQKw^7ug_`E2hhFTa`mOKOs#3*OOD)b$eTS=b+Y~A6H7o%R-rv>mii+R< z401PWW;|C3)jrNnk@lftI&O_*(#min<7_i7tOV?yhEJ8UQgE2YaQB#(}*%S+Mr_3bxpt z%Z0$7r_FA&&+4;a(!99aw)3al_CL|8`H z&uPh%GV)^(?+B<8a@+&$0r?zrD&1DFj0DHBf(?0m0a;32s!b$lSdw>dU7?P%BTh@D z@%i5l&sD^lO#fu#W5`GUyh19(7=hFp3mG7AnP0&=15Lk-rE;B0NplxA2df&VbBI8c zPm=TDErB8iCQcz$fmD9OLY8X{FtkaAzXL#WICif8Fm>Z=4sk>-=`d;>1Z)A0fRMPs zF)*NRG&L>q2~gDm{E(fsem{7UTLI1yJXX*$=Ub|qgF>HSpo*OIyn$FC1Pf`aRkH~- zB>)8?rm7|wN!3b|-uhp> zfQxsy8@wH@b8U$hCJk>>mQeShOdR{{9S zleKt?mv>)2FTR{*5G5RL@S>f{wV`i#216UmHma-fT!w4lxPNry;nf`)yW8sV;Gd_I zaf}-!2(yRyg@jq0p>rfqPdY|Z_k-!wV~DKdj?L9@wdVz3i~rlY?QW}<#D9wA(f`-H zZS4-_NTG+}VT?IYo{E7FRInl+U5fw1EgKo-eACl3CYKdx6LLtM4o~CiX zh0C#Q#5}q(qd--lgF?z|T(Z`|1H<_Wh&dz(dftQpl#p2qgQJx8G{jOg&uLT?dKzz@U)}#6AT}3p&t>_n~ z%+656{+JO6aQ-BiLqh)f?o;LBIpiWmq&nZ}^`+UP)v!}DLW<%)$i;v(Eq#Li)nbXd z2RX(MwIYqtIAyHbq8S2FNdY}^NmoNsB&3PHz$l{U55p0Fh&n9$X~g-Ginu6uQcbVw zyxZ*6-EYk8wGvw5)2-r~2At{ziZNhj&u}KIUw!#z!+vK_j_$Un^SA`k;=S_)aB%qibKkWDaKoouXJd+?5fyUW#7*Q`j| zR|uQAKP~!tJ53`-PqExm+a$^p$y;n)9Mdn${xpJFX<^^0QPrQD_1nd{MG~Ar?N(cv zHX@s!u#@Qt=LS^1A%QAHt(Ovats?vejZ-zL4{G4Y4Oa_x8gz~3PvHsz1j$~SwaZP` znVZ&;V+iyWfbg-vo4#W`&hT)FgIlGh@r(TOQ8=;_2w zZ0mnS5S}|Mc8?=>Je42EFmlCM1>e|zoWa-2sUbOkAbYNYq7cf?h)gPC5wK)1u@1J; z#W@$eFMOx=Pe^^wMZ8yvBOqs7H>)+Br|8j>489jlglwrwd8CN&!2XU)DMxXYL}*NBJ(Qw1oVmv6kE=hXO=IZy~A; zq?%w7w}z|&98tB>Ry1AaCPy0(w=W*!s2qh*>92qTr&bF~VEwPRpuS_|SthBm56uUQ zSbD~!!wLmG^U4mB=5#HoUbCnPZuxbyqp15aE1C8-^;}VS8|=D#&D?gj0O29D56$b5VY$Grm-9_gEH4>e3^#=tBOtuFaQ@ z2`QNAl1`|SOe5ZU6nFl7XftpaU4?`Y$j6XxgrETBgGA5Zh3Gy9+)-btAy5hZ%50kn zd;FOMBZcR#0!03W5dd;StYVEkTSkjA9?=N&6bW&ntet@NI>U%I3(cH^tzT(~TB~BeOs=d_ z^Kg9?pb^=_0#NxU^muU&D69purS;vdy2O7fO1*v2jae@xa*lECGi5PM$4+j9roV2G zcmCNSU3KDK%KD$iTcgl<_4T^z4Hc^Y_+CNJ9(FL|zh&`4lNiN%JJq;j`qN}L$!7ca z%oz3SrfoE{Ap8yVJ96JIb%!-19@h*?Of!a;ZfQwrQ(+4i)8iPQ)apV&EE#hn3}esg z!qO$R*%UK)SvCQH4Yh40HnQU+Ns!xefW>E#?;jE`LVLb<$>9?3|>l#7%~LF z;e5d=o-xYu`bZp~jfxCF4XR)#oFsyit;YM?JDCAvGV*lb-ZZDCvK zKZRlurnKGi5ulWuL)UmF0%~LAe8!n{ZQ0(%du_4!!oYh z2;eBaRLPaqpyC|5xO1TRbXP;Wz>0lq{KM(RMtBfccW_7JsyuPxNk#t(CA+plVb#3x8acN0Ma3{>*j=7BDXDF9| zKp8K;RyR_}6ezSkmF$Xhxtv5n0?m#d7klwMrTr>m1XCy`xH&C8_&%)fyZfS36x6am zdTcJ>>QX&td#4jVCEv0h^fS1(Fe8ZVXL8j-vKoQLpyf_q%;J&F;d_>ZwZ>{EyG+=t zci>{9U+*i}i-skX9#kxKiP|tsMz9!r*gnQp%w|y&tE%}eZ>9Qtw@1Clt@-Z#64?9m zMyG80Y4S)%@#cMPJWHX`YzGue46uyY4Nt~~F#ekPw{fcLpOPgrXIn+Aj5>azT4Av< z+c0?SsZCwYC{Ze5qyiSTd_>P)!P{je_LMr6HwIMG$ODe(2PGcrF0Q`lTqHA50>6qS zmb*17t^$!om_AE?NS8p!Ss`nq-lDEy=yqhSY{0!5F4|GXJ6-o5j4SMOl$d0z@)~n* zvH;g5)f>GrL{Ttvm_)Y5`j)PURTt#o4`j=jXA*j0nE@_FQUBM)bUA|^^8M-@N8PvrOIkNz&+isg#cb6c0VmUCW?P?fuVe|pUoe?1zb zvwJJp{#5DI8X5t*@jfnLq8(mEpP|-TXm2YrJPPIR)e*S_f zpAI5rBYS}{5H|L{dq`cAL0+=;D0m4jqH6eu*CXvOd_8i&6?jsHnm@=K4t4r7_!@to z+zTrltQeJDC{5unmq_-KIDTDEcX&;n^WvEV*`hY9LU^Yo_I1_0?=)P^)U>~xMhNb>2Nf?$Hw%x~pRNfKgT+3gRv>r$P<8JP)|Jz7<_eaPLM(@b%D z^}2_@Hy?;ls^3cz)~Es;XzJ9Hg6tk)f2d^yGM8M?b(SgOqBgkZS5B%!z}8~vUP>)3 z)wcIxq+0i|G>FwCvY9d0~&_ts=M6xnD!AnPS zniuzNb44^CxnBr_w>i&x{Br%I)`?Iv`uu6m_7C;+`k=FANDp`B>-%1}oh?#fuhKyg z7Zx}-HlbvXR@bX6=D>lZ&hUh?Tp>K-M(>RDiNzHc!`G*lB{tMyaaFW8{WnPqI}BDq z$Ka*1PE&4kH7YY8*nc|z8XX{`sk z+q*JGY_AQ=>w0ZfU?c+b&~X>a%78&!?Fi6LSKE(v_4Ot$V!Rsm0QXYk;!NJVbFRaZ zIaEhd#wW&6{wIBW5ZJXwwSW|bu2>o0SLG|X4)E|folfGj%qD9CN>g=iNy z@C?Nkx))04b-lkjMf2`8%1_MYRLqHyIS-Lo(PT$?p4IDG^OA}C)VRh9F1~QQIJ!Kt z2=i;78oJeZsTW1 zwop&CgAtVodgFfDxmEBFZe>Q^d!1}9Zp54@caQsQGH|^Or$42!fd(Ol?;wTrBwVR? z`p(rR-8aKqkIeUMDAnb)Apl0EgT)WMcNuaAT=2lPf0E|kyK^7o{eam|ndF`u{3B`C z%6LrgoJgCVM`M?|w_}p9w03i*6s?a{69R#NY-vn|6(h&t3gartV zm=*W61o1ix!cw9A5%qehQ5)y-)iob_StH`|E8HnYTJK4`^T!BQCAetYi;sz|v%Al_ zc?%^=$4@)!))yVOHu65;$36F4lb0FDrt2`(8qn24>RVP=&x$_xmvxC@XXjN%oSX3T zf$}@0Mxyw*)vIf31?1u(=l8!fIZ5`uFe~c}EL3XbW*Ad5&nlS@IH3|MH%k|BoH)Qp z60l2*K%RGt!c&N_65#h18q;qjn@%~_amT4#HfV6M;H8%?xk;9e84oDrzQg+t)6(Dl zWqc}c!uFG`G&MHJcpg4oyB`Ema$>DKe61SJ3SLq)_L*Y9Bv`)OsH;aWgz1d89yxzZ zM3Cp2p8u?WDw-c(OM8c`M&0w{->~Z}0@Bl&lx+>0Wi`{f%k|Pm1yB*jW}chcdmH;V zZs|wdG7l~L+LH(CQAzPh)oZS?p3CdHm$CtU5*}Dn$jC3sTs!oE_UGy-bp*{--azAT zE&+?}Q9u1nm8zACa^hqbQxVH)7P5XDX6kZ1ie!_|O=GH(YXO?zv}+d++FVg+KIdL0 zPdaS)*9hp*xhv3k((V&Ico6uO)lq=o74?g6dY4R|2E1|Y>u$tbM-uI^?$0NBGmNO5 zM4YIL(`TA6C$WQ7Xc%TR=6L=v;3$9=?Lug@cb)xjgeTI|`Y6J*6mcAqxi}K-&3&+D zG5UAMu2V^hi4>bd^EBhUkoi)-&Bl}#XY&h;tI<3W1)K7?Ht%>wfHCp&?#s&y_-0Ab zwVbe_b3)!>^j;E=ZL!g|eHvL3GE4$pyL`}`odtQGPJ8K zUd?E&IZ~n169Y_q3eGD8!D;aE)49ddZj&T$2GK3^@|O7Wz1@%zG^;&#;spa)C`v z!_EMj7#6P%vZW{imF%UM)Qwn|%M7Vyj*~|~t07M)MTJk-x6O8zMjNntGH`}cNLG-5 yI9?dlCLs6aVp(Lq5uZ)z4dJAKSIrbnB-Opsds9Utu#W`zd8lKcU8`jm^?v}{X~?Dk literal 32998 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 diff --git a/icons/mob/xenos/wounds.dmi b/icons/mob/xenos/wounds.dmi index bf7d573b73a9b66a09ec94508614e537a4a7539e..730e367f43aecdbf019705b7a6ae312db3aa49d1 100644 GIT binary patch delta 23430 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 From 4a4c961236cee9601550563820c0d42af8e17d33 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Thu, 28 Dec 2023 09:54:02 +0000 Subject: [PATCH 09/28] Automatic changelog for PR #5269 [ci skip] --- html/changelogs/AutoChangeLog-pr-5269.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-5269.yml diff --git a/html/changelogs/AutoChangeLog-pr-5269.yml b/html/changelogs/AutoChangeLog-pr-5269.yml new file mode 100644 index 000000000000..b07fa02631ab --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-5269.yml @@ -0,0 +1,5 @@ +author: "sleepynecrons" +delete-after: True +changes: + - imageadd: "new sprites for predalien, predlarva and weeded corpse" + - imageadd: "added predalien wound overlays" \ No newline at end of file From 33af189ea109dd0f8202715e502fc98a3de2b04b Mon Sep 17 00:00:00 2001 From: Changelogs Date: Fri, 29 Dec 2023 01:00:20 +0000 Subject: [PATCH 10/28] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-5269.yml | 5 ----- html/changelogs/archive/2023-12.yml | 4 ++++ 2 files changed, 4 insertions(+), 5 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-5269.yml diff --git a/html/changelogs/AutoChangeLog-pr-5269.yml b/html/changelogs/AutoChangeLog-pr-5269.yml deleted file mode 100644 index b07fa02631ab..000000000000 --- a/html/changelogs/AutoChangeLog-pr-5269.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "sleepynecrons" -delete-after: True -changes: - - imageadd: "new sprites for predalien, predlarva and weeded corpse" - - imageadd: "added predalien wound overlays" \ No newline at end of file diff --git a/html/changelogs/archive/2023-12.yml b/html/changelogs/archive/2023-12.yml index 0333e4beea0c..73cd5f8771a1 100644 --- a/html/changelogs/archive/2023-12.yml +++ b/html/changelogs/archive/2023-12.yml @@ -531,3 +531,7 @@ fira: - bugfix: Fixed XRF Scanner bricking if people were adding and removing vials at same time. +2023-12-29: + sleepynecrons: + - imageadd: new sprites for predalien, predlarva and weeded corpse + - imageadd: added predalien wound overlays From f18d284cb9c83459585ce00fbb58b8321e83d779 Mon Sep 17 00:00:00 2001 From: cuberound <122645057+cuberound@users.noreply.github.com> Date: Fri, 29 Dec 2023 11:50:03 +0100 Subject: [PATCH 11/28] north facing m56d shooting angle fix (#5308) # About the pull request prevents m56d from shooting anywhere to the right when facing north # Explain why it's good for the game fix good # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: fix: m56d can not longer shoot backwards when facing north /:cl: Co-authored-by: vincibrv --- code/modules/cm_marines/smartgun_mount.dm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/modules/cm_marines/smartgun_mount.dm b/code/modules/cm_marines/smartgun_mount.dm index 765f7a673812..21c8a58e279b 100644 --- a/code/modules/cm_marines/smartgun_mount.dm +++ b/code/modules/cm_marines/smartgun_mount.dm @@ -703,6 +703,9 @@ if((dir == NORTH) && (angle > 180) && (abs(360 - angle) > shoot_degree)) // If north and shooting to the left, we do some extra math return + if((dir == NORTH) && (angle < 180) && (angle > shoot_degree)) + return + else if((dir != NORTH) && (abs(angle - dir2angle(dir)) > shoot_degree)) return From 7479788b7cd3198b514492fe889375fa0c84df6d Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 29 Dec 2023 10:58:26 +0000 Subject: [PATCH 12/28] Automatic changelog for PR #5308 [ci skip] --- html/changelogs/AutoChangeLog-pr-5308.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-5308.yml diff --git a/html/changelogs/AutoChangeLog-pr-5308.yml b/html/changelogs/AutoChangeLog-pr-5308.yml new file mode 100644 index 000000000000..3adc1465faaf --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-5308.yml @@ -0,0 +1,4 @@ +author: "cuberound" +delete-after: True +changes: + - bugfix: "m56d can not longer shoot backwards when facing north" \ No newline at end of file From 95b52c8f3149a2800e41a55b5c06357dd855a2ce Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Fri, 29 Dec 2023 10:50:46 +0000 Subject: [PATCH 13/28] Makes the designation of a tunnel display in chat when entered (#5315) # About the pull request Makes the designation of a tunnel display in chat when a player enters it. # Explain why it's good for the game I've quite often gone through a tunnel to drop a capture off at the hive, and then had no idea which tunnel to select in order to get back. It is possible to examine a tunnel before you go through it to see its name, but this just streamlines the whole process. # Testing Photographs and Procedure
Screenshots & Videos **Before:** ![before](https://github.com/cmss13-devs/cmss13/assets/57483089/de1a4a73-0d39-456a-a7fd-b0ddf401dc4f) **After:** ![after](https://github.com/cmss13-devs/cmss13/assets/57483089/75d139eb-5ea2-41b1-a003-e42b52d08ecd)
# Changelog :cl: qol: Made the designation of a tunnel display in chat when a player enters it. /:cl: --- code/modules/cm_aliens/structures/tunnel.dm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/code/modules/cm_aliens/structures/tunnel.dm b/code/modules/cm_aliens/structures/tunnel.dm index 1f0f98c14361..8e2993704f31 100644 --- a/code/modules/cm_aliens/structures/tunnel.dm +++ b/code/modules/cm_aliens/structures/tunnel.dm @@ -221,7 +221,7 @@ return XENO_NO_DELAY_ACTION if(!hive.tunnels.len) - to_chat(M, SPAN_WARNING("\The [src] doesn't seem to lead anywhere.")) + to_chat(M, SPAN_WARNING("[src] doesn't seem to lead anywhere.")) return XENO_NO_DELAY_ACTION if(contents.len > 2) @@ -236,11 +236,11 @@ tunnel_time = TUNNEL_ENTER_LARVA_DELAY if(M.mob_size >= MOB_SIZE_BIG) - M.visible_message(SPAN_XENONOTICE("[M] begins heaving their huge bulk down into \the [src]."), \ - SPAN_XENONOTICE("We begin heaving our monstrous bulk into \the [src]
.")) + M.visible_message(SPAN_XENONOTICE("[M] begins heaving their huge bulk down into [src]."), + SPAN_XENONOTICE("We begin heaving our monstrous bulk into [src] ([tunnel_desc]).")) else - M.visible_message(SPAN_XENONOTICE("\The [M] begins crawling down into \the [src]."), \ - SPAN_XENONOTICE("We begin crawling down into \the [src].")) + M.visible_message(SPAN_XENONOTICE("[M] begins crawling down into [src]."), + SPAN_XENONOTICE("We begin crawling down into [src] ([tunnel_desc]).")) xeno_attack_delay(M) if(!do_after(M, tunnel_time, INTERRUPT_NO_NEEDHAND, BUSY_ICON_GENERIC)) @@ -252,7 +252,7 @@ to_chat(M, SPAN_HIGHDANGER("Alt + Click the tunnel to exit, Ctrl + Click to choose a destination.")) pick_tunnel(M) else - to_chat(M, SPAN_WARNING("\The [src] ended unexpectedly, so we return back up.")) + to_chat(M, SPAN_WARNING("[src] ended unexpectedly, so we return back up.")) return XENO_NO_DELAY_ACTION /obj/structure/tunnel/maint_tunnel From 4f378ec6a81ec9f34b1d36b2ed34f47435a061ac Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 29 Dec 2023 11:11:14 +0000 Subject: [PATCH 14/28] Automatic changelog for PR #5315 [ci skip] --- html/changelogs/AutoChangeLog-pr-5315.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-5315.yml diff --git a/html/changelogs/AutoChangeLog-pr-5315.yml b/html/changelogs/AutoChangeLog-pr-5315.yml new file mode 100644 index 000000000000..c5dc61beb308 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-5315.yml @@ -0,0 +1,4 @@ +author: "SabreML" +delete-after: True +changes: + - qol: "Made the designation of a tunnel display in chat when a player enters it." \ No newline at end of file From 86914ec2f1f0f8bdf0b681349cd960469a968c09 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Fri, 29 Dec 2023 17:28:30 +0000 Subject: [PATCH 15/28] Fixes a laser cannon bug which I added (#5319) # About the pull request Fixes CAS lasers only setting fire to a single tile, rather than in a 7x7 range around the target. This was caused by me somehow incorrectly setting the target turf in #5205. # Explain why it's good for the game uh, whoops # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: fix: Fixed the CAS laser cannon only setting fire to a single tile, rather a 7x7 range. /:cl: --- code/modules/cm_marines/dropship_ammo.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/cm_marines/dropship_ammo.dm b/code/modules/cm_marines/dropship_ammo.dm index 9f28518915ea..19086b36c957 100644 --- a/code/modules/cm_marines/dropship_ammo.dm +++ b/code/modules/cm_marines/dropship_ammo.dm @@ -251,7 +251,7 @@ for(var/i=1 to 16) //This is how many tiles within that area of effect will be randomly ignited var/turf/U = pick(turf_list) turf_list -= U - fire_spread_recur(impact, create_cause_data(fired_from.name, source_mob), 1, null, 5, 75, "#EE6515")//Very, very intense, but goes out very quick + fire_spread_recur(U, create_cause_data(fired_from.name, source_mob), 1, null, 5, 75, "#EE6515")//Very, very intense, but goes out very quick if(!ammo_count && !QDELETED(src)) qdel(src) //deleted after last laser beam is fired and impact the ground. From 5053f217d4236dd4acc6142ce94afedae5af8abd Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 29 Dec 2023 17:36:37 +0000 Subject: [PATCH 16/28] Automatic changelog for PR #5319 [ci skip] --- html/changelogs/AutoChangeLog-pr-5319.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-5319.yml diff --git a/html/changelogs/AutoChangeLog-pr-5319.yml b/html/changelogs/AutoChangeLog-pr-5319.yml new file mode 100644 index 000000000000..d9582b58f9bc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-5319.yml @@ -0,0 +1,4 @@ +author: "SabreML" +delete-after: True +changes: + - bugfix: "Fixed the CAS laser cannon only setting fire to a single tile, rather a 7x7 range." \ No newline at end of file From 932138ede8be1d06d2119777c11f7f181f793415 Mon Sep 17 00:00:00 2001 From: InsaneRed <47158596+InsaneRed@users.noreply.github.com> Date: Fri, 29 Dec 2023 20:29:02 +0300 Subject: [PATCH 17/28] Moves around "Remove Splints" and "View playtime" (#5323) # About the pull request This pr moves "View Playtimes" under the "Records" tab of OOC and "remove splints" into "IC" tab . # Explain why it's good for the game viewplaytimes s a record, and "remove splints" should be under IC for new players, not even i remember where to look for it sometimes because under objects doesnt make sense # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: qol: "View Playtime" is now under the "Records" section under OOC qol: "Remove Your Splints" is now under the "IC" section. /:cl: Co-authored-by: InsaneRed --- code/modules/mob/living/carbon/human/human.dm | 2 +- code/modules/mob/mob_verbs.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index b523cef08eec..26be5e97f9dd 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1445,7 +1445,7 @@ /mob/living/carbon/human/verb/remove_your_splints() set name = "Remove Your Splints" - set category = "Object" + set category = "IC" remove_splints() diff --git a/code/modules/mob/mob_verbs.dm b/code/modules/mob/mob_verbs.dm index a941dfc51090..1ba8985d56bd 100644 --- a/code/modules/mob/mob_verbs.dm +++ b/code/modules/mob/mob_verbs.dm @@ -32,7 +32,7 @@ return /mob/verb/view_stats() - set category = "OOC" + set category = "OOC.Records" set name = "View Playtimes" set desc = "View your playtimes." if(!SSentity_manager.ready) From 2bc3c4794cd6b473782a2ab6b8f46f466d3a3dd6 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 29 Dec 2023 17:49:34 +0000 Subject: [PATCH 18/28] Automatic changelog for PR #5323 [ci skip] --- html/changelogs/AutoChangeLog-pr-5323.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-5323.yml diff --git a/html/changelogs/AutoChangeLog-pr-5323.yml b/html/changelogs/AutoChangeLog-pr-5323.yml new file mode 100644 index 000000000000..1a521533c287 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-5323.yml @@ -0,0 +1,5 @@ +author: "InsaneRed" +delete-after: True +changes: + - qol: "\"View Playtime\" is now under the \"Records\" section under OOC" + - qol: "\"Remove Your Splints\" is now under the \"IC\" section." \ No newline at end of file From f377f35b62161666d93e455b612e919631042785 Mon Sep 17 00:00:00 2001 From: Zonespace <41448081+Zonespace27@users.noreply.github.com> Date: Fri, 29 Dec 2023 09:56:13 -0800 Subject: [PATCH 19/28] Tutorial System: Retutorializing (#5030) # About the pull request Reopening of #4442 Adds a tutorial system to the game, accessible from the lobby screen. The tutorial system is entirely isolated from the main game, allowing players to get a curated experience to be taught the mechanics of SS13 or specific roles within CM. The tutorial system is fully capable of supporting a theoretically infinite amount of players at once, each getting their own instance. See below video for an example of the in-dev "Marine - Basic" tutorial. https://www.youtube.com/watch?v=aWEtd6EAZWk # Explain why it's good for the game Teaching new players how to play the game has always been a tough bit for us, so why not add a full-on tutorial system to get people into the know? # To-Do: This list is alive and will change over time. If you are interested in coding a tutorial, know that it's very easy and that most of the heavy lifting's done for you! You can find a [tutorial creation guide here](https://hackmd.io/@mRAdleXgRfmKqh97O8ixSA/BJQsmO8kT), and you can additionally contact me on discord at any time with questions. Also, you can find an example tutorial [here](https://github.com/cmss13-devs/cmss13/pull/4442/files#diff-843b2f84360b9b932dfc960027992f2b5117667962bfa8da14f9a35f0179a926). Backend: - [x] TGUI - [x] Add finished tutorials to save files - [x] Communicate to players with little playtime - [x] Suppress combat logs and similar done in tutorials SS13: - [x] Basics - [x] Intents Marine: - [x] Basics - [x] Medical - [ ] Weaponry - [ ] Comtech - Basics - [ ] Medic - Basics - [ ] FTL - Basics - [ ] Smartgunner - Basics - [ ] Specialist - Demolitionist - [ ] Specialist - Scout - [ ] Specialist - Pyrotechnician - [ ] Specialist - Grenadier - [ ] Specialist - Sniper - [ ] Squad Leader - Basics Xenomorph: - [ ] Basics - [ ] Builder Caste - Basics # Changelog :cl: add: Added a tutorial system for various roles (and just general information), find it in the lobby screen. /:cl: --------- Co-authored-by: fira --- code/__DEFINES/access.dm | 2 + .../signals/atom/mob/living/signals_human.dm | 3 + .../signals/atom/mob/living/signals_living.dm | 12 + .../dcs/signals/atom/mob/signals_mob.dm | 37 +++ .../__DEFINES/dcs/signals/atom/signals_obj.dm | 10 + code/__DEFINES/dcs/signals/signals_client.dm | 3 - code/__DEFINES/mob.dm | 1 + code/__DEFINES/traits.dm | 5 + code/__DEFINES/tutorial.dm | 6 + code/__HELPERS/level_traits.dm | 1 - code/__HELPERS/unsorted.dm | 12 + code/_onclick/item_attack.dm | 2 + code/_onclick/observer.dm | 2 +- code/_onclick/xeno.dm | 2 +- code/controllers/subsystem/ticker.dm | 1 + code/datums/ammo/ammo.dm | 2 +- code/datums/ammo/misc.dm | 2 +- code/datums/components/tutorial_status.dm | 25 ++ code/datums/datacore.dm | 4 +- code/datums/effects/bleeding.dm | 13 +- code/datums/helper_datums/teleport.dm | 2 +- code/datums/mind.dm | 2 - .../status_effects/_status_effect_helpers.dm | 1 + code/datums/tutorial/_tutorial.dm | 259 ++++++++++++++++++ code/datums/tutorial/_tutorial_menu.dm | 83 ++++++ code/datums/tutorial/creating_a_tutorial.md | 96 +++++++ code/datums/tutorial/marine/_marine.dm | 21 ++ code/datums/tutorial/marine/basic_marine.dm | 208 ++++++++++++++ code/datums/tutorial/marine/medical_basic.dm | 174 ++++++++++++ code/datums/tutorial/ss13/_ss13.dm | 41 +++ code/datums/tutorial/ss13/basic_ss13.dm | 84 ++++++ code/datums/tutorial/ss13/intents.dm | 113 ++++++++ code/datums/tutorial/tutorial_example.dm | 74 +++++ code/game/area/admin_level.dm | 19 ++ code/game/area/areas.dm | 4 + code/game/gamemodes/cm_initialize.dm | 2 +- .../colonialmarines/colonialmarines.dm | 2 +- .../whiskey_outpost/whiskey_output_waves.dm | 2 +- code/game/jobs/job/job.dm | 24 +- code/game/machinery/camera/tracking.dm | 2 +- .../game/machinery/computer/camera_console.dm | 2 +- code/game/machinery/cryopod.dm | 40 ++- .../telecomms/machine_interactions.dm | 4 +- code/game/machinery/teleporter.dm | 4 +- code/game/machinery/vending/cm_vending.dm | 2 + .../machinery/vending/vendor_types/food.dm | 21 ++ .../vendor_types/squad_prep/squad_prep.dm | 28 ++ .../vendor_types/squad_prep/tutorial.dm | 30 ++ .../objects/effects/landmarks/landmarks.dm | 4 + code/game/objects/items.dm | 1 + .../objects/items/devices/teleportation.dm | 4 +- .../items/reagent_containers/autoinjectors.dm | 18 ++ .../items/reagent_containers/food/snacks.dm | 1 + .../items/reagent_containers/hypospray.dm | 1 + code/game/objects/items/shards.dm | 16 +- code/game/objects/items/stacks/medical.dm | 3 + code/game/objects/items/weapons/blades.dm | 2 + code/game/supplyshuttle.dm | 2 +- .../admin/player_panel/actions/general.dm | 10 +- code/modules/asset_cache/asset_list_items.dm | 16 ++ code/modules/client/preferences.dm | 21 +- code/modules/client/preferences_savefile.dm | 6 + code/modules/cm_marines/marines_consoles.dm | 2 +- code/modules/cm_preds/yaut_items.dm | 4 +- code/modules/gear_presets/other.dm | 18 ++ code/modules/gear_presets/uscm.dm | 2 +- code/modules/maptext_alerts/screen_alerts.dm | 20 ++ code/modules/mob/dead/observer/observer.dm | 5 +- code/modules/mob/living/carbon/human/human.dm | 25 ++ .../living/carbon/human/human_attackhand.dm | 4 +- .../mob/living/carbon/human/human_dummy.dm | 9 + .../mob/living/carbon/xenomorph/Embryo.dm | 2 +- .../mob/living/carbon/xenomorph/Evolution.dm | 2 +- .../living/carbon/xenomorph/XenoOverwatch.dm | 6 +- .../mob/living/carbon/xenomorph/Xenomorph.dm | 4 +- .../living/carbon/xenomorph/castes/Drone.dm | 6 +- .../living/carbon/xenomorph/castes/Queen.dm | 6 +- .../mob/living/carbon/xenomorph/death.dm | 2 +- .../living/carbon/xenomorph/hive_status.dm | 16 +- .../living/carbon/xenomorph/hive_status_ui.dm | 6 +- .../mob/living/carbon/xenomorph/mark_menu.dm | 4 +- .../silicon/ai/freelook/update_triggers.dm | 17 +- code/modules/mob/mob.dm | 13 + code/modules/mob/mob_defines.dm | 2 +- code/modules/mob/mob_grab.dm | 4 + code/modules/mob/mob_helpers.dm | 2 + code/modules/mob/new_player/new_player.dm | 53 ++-- code/modules/organs/limbs.dm | 1 + code/modules/projectiles/gun.dm | 2 + colonialmarines.dme | 13 + icons/misc/tutorial.dmi | Bin 0 -> 938 bytes icons/turf/areas.dmi | Bin 35248 -> 35304 bytes maps/tutorial/tutorial_12x12.dmm | 180 ++++++++++++ maps/tutorial/tutorial_7x7.dmm | 75 +++++ maps/tutorial/tutorial_8x9.dmm | 100 +++++++ maps/tutorial/tutorial_8x9_nb.dmm | 100 +++++++ .../packages/tgui/interfaces/TutorialMenu.tsx | 149 ++++++++++ 97 files changed, 2308 insertions(+), 140 deletions(-) create mode 100644 code/__DEFINES/mob.dm create mode 100644 code/__DEFINES/tutorial.dm create mode 100644 code/datums/components/tutorial_status.dm create mode 100644 code/datums/tutorial/_tutorial.dm create mode 100644 code/datums/tutorial/_tutorial_menu.dm create mode 100644 code/datums/tutorial/creating_a_tutorial.md create mode 100644 code/datums/tutorial/marine/_marine.dm create mode 100644 code/datums/tutorial/marine/basic_marine.dm create mode 100644 code/datums/tutorial/marine/medical_basic.dm create mode 100644 code/datums/tutorial/ss13/_ss13.dm create mode 100644 code/datums/tutorial/ss13/basic_ss13.dm create mode 100644 code/datums/tutorial/ss13/intents.dm create mode 100644 code/datums/tutorial/tutorial_example.dm create mode 100644 code/game/machinery/vending/vendor_types/squad_prep/tutorial.dm create mode 100644 icons/misc/tutorial.dmi create mode 100644 maps/tutorial/tutorial_12x12.dmm create mode 100644 maps/tutorial/tutorial_7x7.dmm create mode 100644 maps/tutorial/tutorial_8x9.dmm create mode 100644 maps/tutorial/tutorial_8x9_nb.dmm create mode 100644 tgui/packages/tgui/interfaces/TutorialMenu.tsx diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm index 97e4b0dbd1e8..be96a2e32b85 100644 --- a/code/__DEFINES/access.dm +++ b/code/__DEFINES/access.dm @@ -152,6 +152,8 @@ most of them are tied into map-placed objects. This should be reworked in the fu /// Ancients only #define ACCESS_YAUTJA_ANCIENT 392 +/// Anything in a tutorial sequence that shouldn't be accessed +#define ACCESS_TUTORIAL_LOCKED 998 ///Temporary, just so I can flag places I need to change #define ACCESS_COME_BACK_TO_ME 999 diff --git a/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm b/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm index 6614272d33e5..2e247cdccc73 100644 --- a/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm +++ b/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm @@ -67,3 +67,6 @@ #define COMSIG_HUMAN_SURGERY_APPLY_MODIFIERS "human_surgery_apply_modifiers" /// From /mob/living/carbon/human/proc/get_flags_cold_protection() #define COMSIG_HUMAN_COLD_PROTECTION_APPLY_MODIFIERS "human_cold_protection_apply_modifiers" + +/// From /obj/item/proc/dig_out_shrapnel() : () +#define COMSIG_HUMAN_SHRAPNEL_REMOVED "human_shrapnel_removed" diff --git a/code/__DEFINES/dcs/signals/atom/mob/living/signals_living.dm b/code/__DEFINES/dcs/signals/atom/mob/living/signals_living.dm index 89f3951e7c99..cea905dd1011 100644 --- a/code/__DEFINES/dcs/signals/atom/mob/living/signals_living.dm +++ b/code/__DEFINES/dcs/signals/atom/mob/living/signals_living.dm @@ -29,7 +29,19 @@ #define COMSIG_LIVING_PRE_COLLIDE "living_pre_collide" #define COMPONENT_LIVING_COLLIDE_HANDLED (1<<0) +/// From /mob/living/proc/do_ghost() : (mob/dead/observer/ghost) +#define COMSIG_LIVING_GHOSTED "living_ghosted" + +/// From /mob/living/carbon/human/attack_hand() : (mob/living/carbon/human/attacked_mob) +#define COMSIG_LIVING_ATTACKHAND_HUMAN "living_attackhand_human" + +/// From /obj/item/reagent_container/hypospray/attack() : (obj/item/reagent_container/hypospray/injector) +#define COMSIG_LIVING_HYPOSPRAY_INJECTED "living_hypospray_injected" + ///from base of mob/living/set_buckled(): (new_buckled) #define COMSIG_LIVING_SET_BUCKLED "living_set_buckled" ///from base of mob/living/set_body_position() #define COMSIG_LIVING_SET_BODY_POSITION "living_set_body_position" + +/// from base of /mob/living/apply_status_effect(): (datum/status_effect/new_effect) +#define COMSIG_LIVING_APPLY_EFFECT "living_apply_effect" diff --git a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm index f288f5d94584..58021ba564a2 100644 --- a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm +++ b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm @@ -131,5 +131,42 @@ /// From /obj/item/proc/pickup() : (obj/item/picked_up) #define COMSIG_MOB_PICKUP_ITEM "mob_pickup_item" +/// From /obj/item/proc/attack_self() : (obj/item/used) +#define COMSIG_MOB_ITEM_ATTACK_SELF "mob_item_attack_self" + +/// From /obj/item/proc/dropped() : (obj/item/dropped) +#define COMSIG_MOB_ITEM_DROPPED "mob_item_dropped" + + +/// From /obj/item/reagent_container/food/snacks/proc/on_Consume() : (obj/item/reagent_container/food/snacks/eaten_food) +#define COMSIG_MOB_EATEN_SNACK "mob_eaten_snack" + +/// From /atom/proc/attackby() : (atom/attacked, obj/item/attacked_with) +#define COMSIG_MOB_PARENT_ATTACKBY "mob_parent_attackby" + +/// From /obj/item/weapon/gun/proc/reload_into_chamber() : (obj/item/weapon/gun/empty_gun) +#define COMSIG_MOB_GUN_EMPTY "mob_gun_empty" + +/// From /obj/item/weapon/gun/proc/reload() : (obj/item/weapon/gun/reloaded) +#define COMSIG_MOB_RELOADED_GUN "mob_reloaded_gun" + +/// From /mob/proc/get_status_tab_items() : (list/status_list) +#define COMSIG_MOB_GET_STATUS_TAB_ITEMS "mob_get_status_tab_items" + +/// From /datum/tutorial/proc/update_objective() : (new_objective) +#define COMSIG_MOB_TUTORIAL_UPDATE_OBJECTIVE "mob_tutorial_update_objective" + +/// From /mob/proc/swap_hand() : () +#define COMSIG_MOB_SWAPPED_HAND "mob_swapped_hand" + +/// From /mob/proc/a_intent_change() : (new_intent) +#define COMSIG_MOB_INTENT_CHANGE "mob_intent_change" + +/// From /obj/item/grab/proc/progress_passive() : (mob/living/carbon/human/grabber) +#define COMSIG_MOB_AGGRESSIVELY_GRABBED "mob_aggressively_grabbed" + #define COMSIG_MOB_AGGRESIVE_GRAB_CANCEL (1<<0) + /// Cancels all running cloaking effects on target #define COMSIG_MOB_EFFECT_CLOAK_CANCEL "mob_effect_cloak_cancel" + +#define COMSIG_MOB_END_TUTORIAL "mob_end_tutorial" diff --git a/code/__DEFINES/dcs/signals/atom/signals_obj.dm b/code/__DEFINES/dcs/signals/atom/signals_obj.dm index b5f2bb3ff6a9..c870a55ed746 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_obj.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_obj.dm @@ -30,6 +30,16 @@ /// from /obj/proc/afterbuckle() #define COSMIG_OBJ_AFTER_BUCKLE "signal_obj_after_buckle" +/// from /obj/structure/machinery/cryopod/go_out() +#define COMSIG_CRYOPOD_GO_OUT "cryopod_go_out" + +/// from /proc/vendor_successful_vend() : (obj/structure/machinery/cm_vending/vendor, list/itemspec, mob/living/carbon/human/user) +#define COMSIG_VENDOR_SUCCESSFUL_VEND "vendor_successful_vend" + +/// from /obj/limb/proc/remove_all_bleeding() : (external, internal) +#define COMSIG_LIMB_STOP_BLEEDING "limb_stop_bleeding" + #define COMSIG_DROPSHIP_ADD_EQUIPMENT "dropship_add_equipment" #define COMSIG_DROPSHIP_REMOVE_EQUIPMENT "dropship_remove_equipment" + #define COMSIG_STRUCTURE_CRATE_SQUAD_LAUNCHED "structure_crate_squad_launched" diff --git a/code/__DEFINES/dcs/signals/signals_client.dm b/code/__DEFINES/dcs/signals/signals_client.dm index 6733e0703514..3968f654c486 100644 --- a/code/__DEFINES/dcs/signals/signals_client.dm +++ b/code/__DEFINES/dcs/signals/signals_client.dm @@ -27,6 +27,3 @@ /// Called when something is removed from a client's screen : /client/proc/remove_from_screen(screen_remove) #define COMSIG_CLIENT_SCREEN_REMOVE "client_screen_remove" - -/// When a mind is transfered to another mob at /datum/mind/proc/transfer_to() -#define COMSIG_CLIENT_MIND_TRANSFER "mind_transfer" diff --git a/code/__DEFINES/mob.dm b/code/__DEFINES/mob.dm new file mode 100644 index 000000000000..7f9f33ea483c --- /dev/null +++ b/code/__DEFINES/mob.dm @@ -0,0 +1 @@ +#define DEFAULT_MOB_STATUS_FLAGS CANKNOCKDOWN|CANPUSH|STATUS_FLAGS_DEBILITATE diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index d37c9185fa6d..8c93957c3ca0 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -221,6 +221,8 @@ #define TRAIT_HARDCORE "t_hardcore" /// If the mob is able to use the vulture rifle or spotting scope #define TRAIT_VULTURE_USER "t_vulture_user" +/// If the mob is currently loading a tutorial +#define TRAIT_IN_TUTORIAL "t_IN_TUTORIAL" /// If the mob is cloaked in any form #define TRAIT_CLOAKED "t_cloaked" @@ -297,6 +299,7 @@ GLOBAL_LIST_INIT(mob_traits, list( TRAIT_REAGENT_SCANNER, TRAIT_ABILITY_BURROWED, TRAIT_VULTURE_USER, + TRAIT_IN_TUTORIAL, )) /* @@ -403,6 +406,8 @@ GLOBAL_LIST(trait_name_map) #define TRAIT_SOURCE_JOB "t_s_job" ///Status trait forced by staff #define TRAIT_SOURCE_ADMIN "t_s_admin" +/// Status trait coming from a tutorial +#define TRAIT_SOURCE_TUTORIAL "t_s_tutorials" ///Status trait coming from equipment #define TRAIT_SOURCE_EQUIPMENT(slot) "t_s_equipment_[slot]" ///Status trait coming from skill diff --git a/code/__DEFINES/tutorial.dm b/code/__DEFINES/tutorial.dm new file mode 100644 index 000000000000..75dc7f6da21f --- /dev/null +++ b/code/__DEFINES/tutorial.dm @@ -0,0 +1,6 @@ +#define TUTORIAL_ATOM_FROM_TRACKING(path, varname) var##path/##varname = tracking_atoms[##path] + +#define TUTORIAL_CATEGORY_BASE "Base" // Shouldn't be used outside of base types +#define TUTORIAL_CATEGORY_SS13 "Space Station 13" +#define TUTORIAL_CATEGORY_MARINE "Marine" +#define TUTORIAL_CATEGORY_XENO "Xenomorph" diff --git a/code/__HELPERS/level_traits.dm b/code/__HELPERS/level_traits.dm index 01a972485fa2..8b3d1b0a3809 100644 --- a/code/__HELPERS/level_traits.dm +++ b/code/__HELPERS/level_traits.dm @@ -1,4 +1,3 @@ - #define is_admin_level(z) SSmapping.level_trait(z, ZTRAIT_ADMIN) #define is_ground_level(z) SSmapping.level_trait(z, ZTRAIT_GROUND) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 7425046da7c7..9faa74354494 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -2088,3 +2088,15 @@ GLOBAL_LIST_INIT(duplicate_forbidden_vars,list( if(NORTHWEST) return list(NORTHWEST, NORTH, WEST) + +/// Returns TRUE if the target is somewhere that the game should not interact with if possible +/// In this case, admin Zs and tutorial areas +/proc/should_block_game_interaction(atom/target) + if(is_admin_level(target.z)) + return TRUE + + var/area/target_area = get_area(target) + if(target_area?.block_game_interaction) + return TRUE + + return FALSE diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index c6052da33199..8d77920a59cc 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -3,6 +3,7 @@ /obj/item/proc/attack_self(mob/user) SHOULD_CALL_PARENT(TRUE) SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_SELF, user) + SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK_SELF, src) if(flags_item & CAN_DIG_SHRAPNEL && ishuman(user)) dig_out_shrapnel(user) @@ -11,6 +12,7 @@ /atom/proc/attackby(obj/item/W, mob/living/user,list/mods) if(SEND_SIGNAL(src, COMSIG_PARENT_ATTACKBY, W, user, mods) & COMPONENT_NO_AFTERATTACK) return TRUE + SEND_SIGNAL(user, COMSIG_MOB_PARENT_ATTACKBY, src, W) return FALSE /atom/movable/attackby(obj/item/W, mob/living/user) diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index f87778355755..21dd804f09c4 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -29,7 +29,7 @@ if(ismob(target) || isVehicle(target)) if(isxeno(target) && SSticker.mode.check_xeno_late_join(src)) //if it's a xeno and all checks are alright, we are gonna try to take their body var/mob/living/carbon/xenomorph/xeno = target - if(xeno.stat == DEAD || is_admin_level(xeno.z) || xeno.aghosted) + if(xeno.stat == DEAD || should_block_game_interaction(xeno) || xeno.aghosted) to_chat(src, SPAN_WARNING("You cannot join as [xeno].")) do_observe(xeno) return FALSE diff --git a/code/_onclick/xeno.dm b/code/_onclick/xeno.dm index cc785f32f426..ad4ba9d72546 100644 --- a/code/_onclick/xeno.dm +++ b/code/_onclick/xeno.dm @@ -111,7 +111,7 @@ so that it doesn't double up on the delays) so that it applies the delay immedia if(alt_pressed && shift_pressed) if(istype(target, /mob/living/carbon/xenomorph)) var/mob/living/carbon/xenomorph/xeno = target - if(!QDELETED(xeno) && xeno.stat != DEAD && !is_admin_level(xeno.z) && xeno.check_state(TRUE) && xeno.hivenumber == hivenumber) + if(!QDELETED(xeno) && xeno.stat != DEAD && !should_block_game_interaction(xeno) && xeno.check_state(TRUE) && xeno.hivenumber == hivenumber) overwatch(xeno) next_move = world.time + 3 // Some minimal delay so this isn't crazy spammy return TRUE diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index c6d6f008acd6..2e11ba8a96cb 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -46,6 +46,7 @@ SUBSYSTEM_DEF(ticker) var/totalPlayers = 0 //used for pregame stats on statpanel var/totalPlayersReady = 0 //used for pregame stats on statpanel + var/tutorial_disabled = FALSE //zonenote /datum/controller/subsystem/ticker/Initialize(timeofday) load_mode() diff --git a/code/datums/ammo/ammo.dm b/code/datums/ammo/ammo.dm index 48a387e54d20..7a4006deee73 100644 --- a/code/datums/ammo/ammo.dm +++ b/code/datums/ammo/ammo.dm @@ -106,7 +106,7 @@ SHOULD_NOT_SLEEP(TRUE) return -/datum/ammo/proc/on_embed(mob/embedded_mob, obj/limb/target_organ) +/datum/ammo/proc/on_embed(mob/embedded_mob, obj/limb/target_organ, silent = FALSE) return /datum/ammo/proc/do_at_max_range(obj/projectile/P) diff --git a/code/datums/ammo/misc.dm b/code/datums/ammo/misc.dm index 607a6e517a7c..3aaba8443efb 100644 --- a/code/datums/ammo/misc.dm +++ b/code/datums/ammo/misc.dm @@ -178,7 +178,7 @@ accurate_range = 12 shell_speed = AMMO_SPEED_TIER_1 -/datum/ammo/souto/on_embed(mob/embedded_mob, obj/limb/target_organ) +/datum/ammo/souto/on_embed(mob/embedded_mob, obj/limb/target_organ, silent = FALSE) if(ishuman(embedded_mob) && !isyautja(embedded_mob)) if(istype(target_organ)) target_organ.embed(new can_type) diff --git a/code/datums/components/tutorial_status.dm b/code/datums/components/tutorial_status.dm new file mode 100644 index 000000000000..97b8d408bcb5 --- /dev/null +++ b/code/datums/components/tutorial_status.dm @@ -0,0 +1,25 @@ +/datum/component/tutorial_status + dupe_mode = COMPONENT_DUPE_UNIQUE + /// What the mob's current tutorial status is, displayed in the status panel + var/tutorial_status = "" + +/datum/component/tutorial_status/Initialize() + . = ..() + if(!ismob(parent)) + return COMPONENT_INCOMPATIBLE + +/datum/component/tutorial_status/RegisterWithParent() + ..() + RegisterSignal(parent, COMSIG_MOB_TUTORIAL_UPDATE_OBJECTIVE, PROC_REF(update_objective)) + RegisterSignal(parent, COMSIG_MOB_GET_STATUS_TAB_ITEMS, PROC_REF(get_status_tab_item)) + +/datum/component/tutorial_status/proc/update_objective(datum/source, objective_text) + SIGNAL_HANDLER + + tutorial_status = objective_text + +/datum/component/tutorial_status/proc/get_status_tab_item(datum/source, list/status_tab_items) + SIGNAL_HANDLER + + if(tutorial_status) + status_tab_items += "Tutorial Objective: " + tutorial_status diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index 933b547aa1f2..ae19a3044678 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -206,8 +206,8 @@ GLOBAL_DATUM_INIT(data_core, /datum/datacore, new) sleep(40) var/list/jobs_to_check = GLOB.ROLES_CIC + GLOB.ROLES_AUXIL_SUPPORT + GLOB.ROLES_MISC + GLOB.ROLES_POLICE + GLOB.ROLES_ENGINEERING + GLOB.ROLES_REQUISITION + GLOB.ROLES_MEDICAL + GLOB.ROLES_MARINES - for(var/mob/living/carbon/human/H in GLOB.human_mob_list) - if(is_admin_level(H.z)) + for(var/mob/living/carbon/human/H as anything in GLOB.human_mob_list) + if(should_block_game_interaction(H)) continue if(H.job in jobs_to_check) manifest_inject(H) diff --git a/code/datums/effects/bleeding.dm b/code/datums/effects/bleeding.dm index e6cb184850d4..2171580a94db 100644 --- a/code/datums/effects/bleeding.dm +++ b/code/datums/effects/bleeding.dm @@ -19,6 +19,13 @@ if(L && istype(L)) limb = L +/datum/effects/bleeding/Destroy() + if(limb) + SEND_SIGNAL(limb, COMSIG_LIMB_STOP_BLEEDING, TRUE, FALSE) + limb.bleeding_effects_list -= src + limb = null + return ..() + /datum/effects/bleeding/validate_atom(atom/A) if(isobj(A)) return FALSE @@ -48,12 +55,6 @@ duration += damage * (blood_duration_multiplier / BLOOD_ADD_PENALTY) blood_loss += damage / (blood_loss_divider * BLOOD_ADD_PENALTY) //Make the first hit count, adding on bleeding has a penalty -/datum/effects/bleeding/Destroy() - if(limb) - limb.bleeding_effects_list -= src - return ..() - - /datum/effects/bleeding/external var/buffer_blood_loss = 0 diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index 207310ac34c5..6a4276208d13 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -177,7 +177,7 @@ teleatom.visible_message(SPAN_DANGER("[teleatom] bounces off of the portal!")) return 0 - if(is_admin_level(destination.z)) + if(should_block_game_interaction(destination)) if(length(teleatom.search_contents_for(/obj/item/storage/backpack/holding))) teleatom.visible_message(SPAN_DANGER("The Bag of Holding bounces off of the portal!")) return 0 diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 205032f46a97..74f445f21597 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -44,8 +44,6 @@ msg_admin_niche("[key]/[ckey] has tried to transfer to deleted [new_character].") return - SEND_SIGNAL(current.client, COMSIG_CLIENT_MIND_TRANSFER, new_character) - if(current) current.mind = null //remove ourself from our old body's mind variable SSnano.nanomanager.user_transferred(current, new_character) // transfer active NanoUI instances to new user diff --git a/code/datums/status_effects/_status_effect_helpers.dm b/code/datums/status_effects/_status_effect_helpers.dm index 0ee952200610..02a4f9a5ccea 100644 --- a/code/datums/status_effects/_status_effect_helpers.dm +++ b/code/datums/status_effects/_status_effect_helpers.dm @@ -40,6 +40,7 @@ // Create the status effect with our mob + our arguments var/datum/status_effect/new_instance = new new_effect(arguments) + SEND_SIGNAL(src, COMSIG_LIVING_APPLY_EFFECT, new_instance) if(!QDELETED(new_instance)) return new_instance diff --git a/code/datums/tutorial/_tutorial.dm b/code/datums/tutorial/_tutorial.dm new file mode 100644 index 000000000000..5423453bbdb9 --- /dev/null +++ b/code/datums/tutorial/_tutorial.dm @@ -0,0 +1,259 @@ +GLOBAL_LIST_EMPTY_TYPED(ongoing_tutorials, /datum/tutorial) + +/// A tutorial datum contains a set of instructions for a player tutorial, such as what to spawn, what's scripted to occur, and so on. +/datum/tutorial + /// What the tutorial is called, is player facing + var/name = "Base" + /// Internal ID of the tutorial, kept for save files + var/tutorial_id = "base" + /// A short 1-2 sentence description of the tutorial itself + var/desc = "" + /// What the tutorial's icon in the UI should look like + var/icon_state = "" + /// What category the tutorial should be under + var/category = TUTORIAL_CATEGORY_BASE + /// Ref to the bottom-left corner tile of the tutorial room + var/turf/bottom_left_corner + /// Ref to the turf reservation for this tutorial + var/datum/turf_reservation/reservation + /// Ref to the player who is doing the tutorial + var/mob/tutorial_mob + /// If the tutorial will be ending soon + var/tutorial_ending = FALSE + /// A dict of type:atom ref for some important junk that should be trackable + var/list/tracking_atoms = list() + /// What map template should be used for the tutorial + var/datum/map_template/tutorial/tutorial_template = /datum/map_template/tutorial/s12x12 + /// What is the parent path of this, to exclude from the tutorial menu + var/parent_path = /datum/tutorial + /// A dictionary of "bind_name" : "keybind_button". The inverse of `key_bindings` on a client's prefs + var/list/player_bind_dict = list() + +/datum/tutorial/Destroy(force, ...) + GLOB.ongoing_tutorials -= src + QDEL_NULL(reservation) // Its Destroy() handles releasing reserved turfs + + tutorial_mob = null // We don't delete it because the turf reservation will typically clean it up + + QDEL_LIST_ASSOC_VAL(tracking_atoms) + + return ..() + +/// The proc to begin doing everything related to the tutorial +/datum/tutorial/proc/start_tutorial(mob/starting_mob) + SHOULD_CALL_PARENT(TRUE) + + if(!starting_mob?.client) + return FALSE + + ADD_TRAIT(starting_mob, TRAIT_IN_TUTORIAL, TRAIT_SOURCE_TUTORIAL) + + tutorial_mob = starting_mob + + reservation = SSmapping.RequestBlockReservation(initial(tutorial_template.width), initial(tutorial_template.height)) + if(!reservation) + return FALSE + + var/turf/bottom_left_corner_reservation = locate(reservation.bottom_left_coords[1], reservation.bottom_left_coords[2], reservation.bottom_left_coords[3]) + var/datum/map_template/tutorial/template = new tutorial_template + template.load(bottom_left_corner_reservation, FALSE, TRUE) + var/obj/landmark = locate(/obj/effect/landmark/tutorial_bottom_left) in GLOB.landmarks_list + bottom_left_corner = get_turf(landmark) + qdel(landmark) + + if(!verify_template_loaded()) + abort_tutorial() + return FALSE + + generate_binds() + + GLOB.ongoing_tutorials |= src + var/area/tutorial_area = get_area(bottom_left_corner) + tutorial_area.update_base_lighting() // this will be entirely dark otherwise + init_map() + if(!tutorial_mob) + end_tutorial() + + return TRUE + +/// The proc used to end and clean up the tutorial +/datum/tutorial/proc/end_tutorial(completed = FALSE) + SHOULD_CALL_PARENT(TRUE) + + if(tutorial_mob) + remove_action(tutorial_mob, /datum/action/tutorial_end) // Just in case to make sure the client can't try and leave the tutorial while it's mid-cleanup + if(tutorial_mob.client?.prefs && completed) + tutorial_mob.client.prefs.completed_tutorials |= tutorial_id + tutorial_mob.client.prefs.save_character() + var/mob/new_player/new_player = new + if(!tutorial_mob.mind) + tutorial_mob.mind_initialize() + + tutorial_mob.mind.transfer_to(new_player) + + if(!QDELETED(src)) + qdel(src) + +/// Verify the template loaded fully and without error. +/datum/tutorial/proc/verify_template_loaded() + // We subtract 1 from x and y because the bottom left corner doesn't start at the walls. + var/turf/true_bottom_left_corner = locate( + reservation.bottom_left_coords[1], + reservation.bottom_left_coords[2], + reservation.bottom_left_coords[3], + ) + // We subtract 1 from x and y here because the bottom left corner counts as the first tile + var/turf/top_right_corner = locate( + true_bottom_left_corner.x + initial(tutorial_template.width) - 1, + true_bottom_left_corner.y + initial(tutorial_template.height) - 1, + true_bottom_left_corner.z + ) + for(var/turf/tile as anything in block(true_bottom_left_corner, top_right_corner)) + // For some reason I'm unsure of, the template will not always fully load, leaving some tiles to be space tiles. So, we check all tiles in the (small) tutorial area + // and tell start_tutorial to abort if there's any space tiles. + if(istype(tile, /turf/open/space)) + return FALSE + + return TRUE + +/// Something went very, very wrong during load so let's abort +/datum/tutorial/proc/abort_tutorial() + to_chat(tutorial_mob, SPAN_BOLDWARNING("Something went wrong during tutorial load, please try again!")) + end_tutorial(FALSE) + +/datum/tutorial/proc/add_highlight(atom/target, color = "#d19a02") + target.add_filter("tutorial_highlight", 2, list("type" = "outline", "color" = color, "size" = 1)) + +/datum/tutorial/proc/remove_highlight(atom/target) + target.remove_filter("tutorial_highlight") + +/datum/tutorial/proc/add_to_tracking_atoms(atom/reference) + tracking_atoms[reference.type] = reference + +/datum/tutorial/proc/remove_from_tracking_atoms(atom/reference) + tracking_atoms -= reference.type + +/// Broadcast a message to the player's screen +/datum/tutorial/proc/message_to_player(message) + playsound_client(tutorial_mob.client, 'sound/effects/radiostatic.ogg', tutorial_mob.loc, 25, FALSE) + tutorial_mob.play_screen_text(message, /atom/movable/screen/text/screen_text/command_order/tutorial, rgb(103, 214, 146)) + to_chat(tutorial_mob, SPAN_NOTICE(message)) + +/// Updates a player's objective in their status tab +/datum/tutorial/proc/update_objective(message) + SEND_SIGNAL(tutorial_mob, COMSIG_MOB_TUTORIAL_UPDATE_OBJECTIVE, message) + +/// Initialize the tutorial mob. +/datum/tutorial/proc/init_mob() + tutorial_mob.AddComponent(/datum/component/tutorial_status) + give_action(tutorial_mob, /datum/action/tutorial_end, null, null, src) + ADD_TRAIT(tutorial_mob, TRAIT_IN_TUTORIAL, TRAIT_SOURCE_TUTORIAL) + +/// Ends the tutorial after a certain amount of time. +/datum/tutorial/proc/tutorial_end_in(time = 5 SECONDS, completed = TRUE) + tutorial_ending = TRUE + addtimer(CALLBACK(src, PROC_REF(end_tutorial), completed), time) + +/// Initialize any objects that need to be in the tutorial area from the beginning. +/datum/tutorial/proc/init_map() + return + +/// Returns a turf offset by offset_x (left-to-right) and offset_y (up-to-down) +/datum/tutorial/proc/loc_from_corner(offset_x = 0, offset_y = 0) + RETURN_TYPE(/turf) + return locate(bottom_left_corner.x + offset_x, bottom_left_corner.y + offset_y, bottom_left_corner.z) + +/// Handle the player ghosting out +/datum/tutorial/proc/on_ghost(datum/source, mob/dead/observer/ghost) + SIGNAL_HANDLER + + var/mob/new_player/new_player = new + if(!ghost.mind) + ghost.mind_initialize() + + ghost.mind.transfer_to(new_player) + + end_tutorial(FALSE) + +/// A wrapper for signals to call end_tutorial() +/datum/tutorial/proc/signal_end_tutorial(datum/source) + SIGNAL_HANDLER + + end_tutorial(FALSE) + +/// Called whenever the tutorial_mob logs out +/datum/tutorial/proc/on_logout(datum/source) + SIGNAL_HANDLER + + if(tutorial_mob.aghosted) + return + + end_tutorial(FALSE) + +/// Generate a dictionary of button : action for use of referencing what keys to press +/datum/tutorial/proc/generate_binds() + if(!tutorial_mob.client?.prefs) + return + + for(var/bind in tutorial_mob.client.prefs.key_bindings) + var/action = tutorial_mob.client.prefs.key_bindings[bind] + // We presume the first action under a certain binding is the one we want. + if(action[1] in player_bind_dict) + player_bind_dict[action[1]] += bind + else + player_bind_dict[action[1]] = list(bind) + +/// Getter for player_bind_dict. Provide an action name like "North" or "quick_equip" +/datum/tutorial/proc/retrieve_bind(action_name) + if(!action_name) + return + + if(!(action_name in player_bind_dict)) + return "Undefined" + + return player_bind_dict[action_name][1] + +/datum/action/tutorial_end + name = "Stop Tutorial" + action_icon_state = "hologram_exit" + /// Weakref to the tutorial this is related to + var/datum/weakref/tutorial + +/datum/action/tutorial_end/New(Target, override_icon_state, datum/tutorial/selected_tutorial) + . = ..() + tutorial = WEAKREF(selected_tutorial) + +/datum/action/tutorial_end/action_activate() + if(!tutorial) + return + + var/datum/tutorial/selected_tutorial = tutorial.resolve() + if(selected_tutorial.tutorial_ending) + return + + selected_tutorial.end_tutorial() + + +/datum/map_template/tutorial + name = "Tutorial Zone (12x12)" + mappath = "maps/tutorial/tutorial_12x12.dmm" + width = 12 + height = 12 + +/datum/map_template/tutorial/s12x12 + +/datum/map_template/tutorial/s8x9 + name = "Tutorial Zone (8x9)" + mappath = "maps/tutorial/tutorial_8x9.dmm" + width = 8 + height = 9 + +/datum/map_template/tutorial/s8x9/no_baselight + name = "Tutorial Zone (8x9) (No Baselight)" + mappath = "maps/tutorial/tutorial_8x9_nb.dmm" + +/datum/map_template/tutorial/s7x7 + name = "Tutorial Zone (7x7)" + mappath = "maps/tutorial/tutorial_7x7.dmm" + width = 7 + height = 7 diff --git a/code/datums/tutorial/_tutorial_menu.dm b/code/datums/tutorial/_tutorial_menu.dm new file mode 100644 index 000000000000..42eb3f6aabfa --- /dev/null +++ b/code/datums/tutorial/_tutorial_menu.dm @@ -0,0 +1,83 @@ +/datum/tutorial_menu + /// List of ["name" = name, "tutorials" = ["name" = name, "path" = "path", "id" = tutorial_id]] + var/static/list/categories = list() + + +/datum/tutorial_menu/New() + if(!length(categories)) + var/list/categories_2 = list() + for(var/datum/tutorial/tutorial as anything in subtypesof(/datum/tutorial)) + if(initial(tutorial.parent_path) == tutorial) + continue + + if(!(initial(tutorial.category) in categories_2)) + categories_2[initial(tutorial.category)] = list() + + categories_2[initial(tutorial.category)] += list(list( + "name" = initial(tutorial.name), + "path" = "[tutorial]", + "id" = initial(tutorial.tutorial_id), + "description" = initial(tutorial.desc), + "image" = initial(tutorial.icon_state), + )) + + for(var/category in categories_2) + categories += list(list( + "name" = category, + "tutorials" = categories_2[category], + )) + + +/datum/tutorial_menu/proc/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TutorialMenu") + ui.open() + +/datum/tutorial_menu/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/tutorial), + ) + +/datum/tutorial_menu/ui_state(mob/user) + if(istype(get_area(user), /area/misc/tutorial)) + return GLOB.never_state + + return GLOB.new_player_state + + +/datum/tutorial_menu/ui_static_data(mob/user) + var/list/data = list() + + data["tutorial_categories"] = categories + if(user.client?.prefs) + data["completed_tutorials"] = user.client.prefs.completed_tutorials + else + data["completed_tutorials"] = list() + + return data + + +/datum/tutorial_menu/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + switch(action) + if("select_tutorial") + var/datum/tutorial/path + if(!params["tutorial_path"]) + return + + path = text2path(params["tutorial_path"]) + + if(!path || !isnewplayer(usr)) + return + + if(HAS_TRAIT(usr, TRAIT_IN_TUTORIAL) || istype(get_area(usr), /area/misc/tutorial)) + to_chat(usr, SPAN_NOTICE("You are currently in a tutorial, or one is loading. Please be patient.")) + return + + path = new path + path.start_tutorial(usr) + return TRUE diff --git a/code/datums/tutorial/creating_a_tutorial.md b/code/datums/tutorial/creating_a_tutorial.md new file mode 100644 index 000000000000..96a7cb886820 --- /dev/null +++ b/code/datums/tutorial/creating_a_tutorial.md @@ -0,0 +1,96 @@ +# Tutorial Creation + +[ToC] + +## Step 1: Identifying the Goal + +Your first objective when making a tutorial should be to have a clear and concise vision of what you want the tutorial to convey to the user. People absorb information better in smaller chunks, so you should ideally keep a tutorial to one section of information at a time. + +For example, if you are making a tutorial for new CM players, it should be split into multiple parts like: + +- Basics +- Medical +- Weaponry +- Requisitions/Communication + +## Step 2: Coding + +For an example of the current code standards for tutorials, see [this](https://github.com/cmss13-devs/cmss13/pull/4442/files#diff-843b2f84360b9b932dfc960027992f2b5117667962bfa8da14f9a35f0179a926) file. + +The API for tutorials is designed to be very simple, so I'll go over all the base `/datum/tutorial` procs and some vars here: + +### Variables +- `name` + - This is the player-facing name of the tutorial. +- `tutorial_id` + - This is the back-end ID of the tutorial, used for save files. Try not to change a tutorial's ID after it's on the live server. +- `category` + - This is what category the tutorial should be under. Use the `TUTORIAL_CATEGORY_XXXX` macros. +- `tutorial_template` + - This is what type the map template of the tutorial should be. The default space is 12x12; ideally make it so it fits the given scale of the tutorial with some wiggle room for the player to move around. +- `parent_path` + - This is the top-most parent `/datum/tutorial` path, used to exclude abstract parents from the tutorial menu. For example, `/datum/tutorial/marine/basic` would have a `parent_path` of `/datum/tutorial/marine`, since that path is the top-most abstract path. + +### Procs +- `start_tutorial(mob/starting_mob)` + - This proc starts the tutorial, setting up the map template and player. This should be overridden with a parent call before any overridden code. +- `end_tutorial(completed = FALSE)` + - This proc ends the tutorial, sending the player back to the lobby and deleting the tutorial itself. A parent call on any subtypes should be at the end of the overridden segment. If `completed` is `TRUE`, then the tutorial will save as a completed one for the user. +- `add_highlight(atom/target, color = "#d19a02")` + - This proc adds a highlight filter around an atom, by default this color. Successive calls of highlight on the same atom will override the last. +- `remove_highlight(atom/target)` + - This proc removes the tutorial highlight from a target. +- `add_to_tracking_atoms(atom/reference)` + - This proc will add a reference to the tutorial's tracked atom dictionary. For what a tracked atom is, see Step 2.1. +- `remove_from_tracking_atoms(atom/reference)` + - This proc will remove a reference from the tutorial's tracked atom dictionary. For what a tracked atom is, see Step 2.1. +- `message_to_player(message)` + - This proc is the ideal way to communicate to a player. It is visually similar to overwatch messages or weather alerts, but appears and disappears much faster. The messages sent should be consise, but can have a degree of dialogue to them. +- `update_objective(message)` + - This proc is used to update the player's objective in their status panel. This should be only what is required and how to do it without any dialogue or extra text. +- `init_mob()` + - This proc is used to initialize the mob and set them up correctly. +- `init_map()` + - This proc does nothing by default, but can be overriden to spawn any atoms necessary for the tutorial from the very start. +- `tutorial_end_in(time = 5 SECONDS, completed = TRUE)` + - This proc will end the tutorial in the given time, defaulting to 5 seconds. Once the proc is called, the player will be booted back to the menu screen after the time is up. Will mark the tutorial as completed if `completed` is `TRUE` +- `loc_from_corner(offset_x = 0, offset_y = 0)` + - This proc will return a turf offset from the bottom left corner of the tutorial zone. Keep in mind, the bottom left corner is NOT on a wall, it is on the first floor on the bottom left corner. `offset_x` and `offset_y` are used to offset what turf you want to get, and should never be negative. + +## Step 2.1: Tracking Atoms +Naturally, you will need to keep track of certain objects or mobs for signal purposes, so the tracking system exists to fill that purpose. When you add a reference to the tracking atom list with `add_to_tracking_atoms()`, it gets put into a dictionary of `{path : reference}`. Because of this limitation, you should not track more than 1 object of the same type. To get a tracked atom, use of the `TUTORIAL_ATOM_FROM_TRACKING(path, varname)` macro is recommended. `path` should be replaced with the precise typepath of the tracked atom, and `varname` should be replaced with the variable name you wish to use. If an object is going to be deleted, remove it with `remove_from_tracking_atoms()` first. + +## Step 2.2: Scripting Format +Any proc whose main purpose is to advance the tutorial will be hereon referred to as a "script proc", as part of the entire "script". In the vast majority of cases, a script proc should hand off to the next using signals. Here is an example from `basic_marine.dm`: + +```javascript +/datum/tutorial/marine/basic/proc/on_cryopod_exit() + SIGNAL_HANDLER + + UnregisterSignal(tracking_atoms[/obj/structure/machinery/cryopod/tutorial], COMSIG_CRYOPOD_GO_OUT) + message_to_player("Good. You may notice the yellow \"food\" icon on the right side of your screen. Proceed to the outlined Food Vendor and vend the USCM Protein Bar.") + update_objective("Vend a USCM Protein Bar from the outlined ColMarTech Food Vendor.") + TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/sorted/marine_food/tutorial, food_vendor) + add_highlight(food_vendor) + food_vendor.req_access = list() + RegisterSignal(food_vendor, COMSIG_VENDOR_SUCCESSFUL_VEND, PROC_REF(on_food_vend)) + +``` + +Line-by-line: + - `SIGNAL_HANDLER` is necessary as this proc was called via signal. + - Here we are unregistering the signal we registered in the previous proc to call this one, which in this case was waiting for the player to leave the tracked cryopod. + - Now, we tell the user the next step in the script, which is sent to their screen. + - Here we update the player's status panel with similar info to the above line, but far more condensed. + - Since we need to access the food vendor, we use the `TUTORIAL_ATOM_FROM_TRACKING()` macro to get a ref to it. + - We add a yellow outline to the food vendor to make it more clear what is wanted of the player + - The tutorial food vendors are locked to `ACCESS_TUTORIAL_LOCKED` by default, so here we remove that access requirement + - And finally, we register a signal for the next script proc, waiting for the user to vend something from the food vendor. + + +## Step 2.3: Quirks & Tips +- Generally speaking, you will want to create `/tutorial` subtypes of anything you add in the tutorial, should it need any special functions or similar. +- Restrict access from players as much as possible. As seen in the example above, restricting access to vendors and similar machines is recommended to prevent sequence breaking. Additionally, avoid adding anything that detracts from the tutorial itself. +- Attempt to avoid softlocks when possible. If someone could reasonably do something (e.g. firing every bullet they have at a ranged target and missing, now unable to kill them and progress) that could softlock them, then there should be a fallback of some sort. However, accomodations don't need to be made for people who purposefully cause a softlock; there's a "stop tutorial" button for a reason. +- When calling `message_to_player()` or `update_objective()`, **bold** the names of objects, items, and keybinds. +- Attempt to bind as many scripting signals to the `tutorial_mob` as possible. The nature of SS13 means something as sequence-heavy as this will always be fragile, so keeping the fragility we can affect to a minimum is imperative. diff --git a/code/datums/tutorial/marine/_marine.dm b/code/datums/tutorial/marine/_marine.dm new file mode 100644 index 000000000000..ceb0ba8ab550 --- /dev/null +++ b/code/datums/tutorial/marine/_marine.dm @@ -0,0 +1,21 @@ +/datum/tutorial/marine + category = TUTORIAL_CATEGORY_MARINE + parent_path = /datum/tutorial/marine + icon_state = "marine" + +/datum/tutorial/marine/init_mob() + var/mob/living/carbon/human/new_character = new(bottom_left_corner) + new_character.lastarea = get_area(bottom_left_corner) + + setup_human(new_character, tutorial_mob) + + //SSround_recording.recorder.track_player(new_character) //zonenote: check if necessary + + new_character.marine_snowflake_points = MARINE_TOTAL_SNOWFLAKE_POINTS + new_character.marine_buyable_categories = MARINE_CAN_BUY_ALL + + tutorial_mob = new_character + RegisterSignal(tutorial_mob, COMSIG_LIVING_GHOSTED, PROC_REF(on_ghost)) + RegisterSignal(tutorial_mob, list(COMSIG_PARENT_QDELETING, COMSIG_MOB_DEATH, COMSIG_MOB_END_TUTORIAL), PROC_REF(signal_end_tutorial)) + RegisterSignal(tutorial_mob, COMSIG_MOB_LOGOUT, PROC_REF(on_logout)) + return ..() diff --git a/code/datums/tutorial/marine/basic_marine.dm b/code/datums/tutorial/marine/basic_marine.dm new file mode 100644 index 000000000000..be49977f7a48 --- /dev/null +++ b/code/datums/tutorial/marine/basic_marine.dm @@ -0,0 +1,208 @@ +/datum/tutorial/marine/basic + name = "Marine - Basic" + desc = "A tutorial to get you acquainted with the very basics of how to play a groundside marine role." + tutorial_id = "marine_basic_1" + tutorial_template = /datum/map_template/tutorial/s8x9/no_baselight + /// How many items need to be vended from the clothing vendor for the script to continue, if something vends 2 items (for example), increase this number by 2. + var/clothing_items_to_vend = 8 + /// How many items need to be vended from the gun vendor to continue + var/gun_items_to_vend = 2 + +// START OF SCRIPTING + +/datum/tutorial/marine/basic/start_tutorial(mob/starting_mob) + . = ..() + if(!.) + return + + var/obj/item/device/flashlight/flashlight = new(loc_from_corner(2, 3)) + flashlight.anchored = TRUE + flashlight.set_light_power(4) + flashlight.set_light_range(12) + flashlight.icon = null + flashlight.set_light_on(TRUE) + add_to_tracking_atoms(flashlight) + + init_mob() + message_to_player("This is the tutorial for marine rifleman. Leave the cryopod by pressing [retrieve_bind("North")] or [retrieve_bind("East")] to continue.") + update_objective("Exit the cryopod by pressing [retrieve_bind("North")] or [retrieve_bind("East")].") + RegisterSignal(tracking_atoms[/obj/structure/machinery/cryopod/tutorial], COMSIG_CRYOPOD_GO_OUT, PROC_REF(on_cryopod_exit)) + +/datum/tutorial/marine/basic/proc/on_cryopod_exit() + SIGNAL_HANDLER + + UnregisterSignal(tracking_atoms[/obj/structure/machinery/cryopod/tutorial], COMSIG_CRYOPOD_GO_OUT) + message_to_player("Good. You may notice the yellow \"food\" icon on the right side of your screen. Proceed to the outlined Food Vendor and vend the USCM Protein Bar.") + update_objective("Vend a USCM Protein Bar from the outlined ColMarTech Food Vendor.") + TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/sorted/marine_food/tutorial, food_vendor) + add_highlight(food_vendor) + food_vendor.req_access = list() + RegisterSignal(food_vendor, COMSIG_VENDOR_SUCCESSFUL_VEND, PROC_REF(on_food_vend)) + +/datum/tutorial/marine/basic/proc/on_food_vend(datum/source, obj/structure/machinery/cm_vending/vendor, list/itemspec, mob/living/carbon/human/user) + SIGNAL_HANDLER + + TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/sorted/marine_food/tutorial, food_vendor) + UnregisterSignal(food_vendor, COMSIG_VENDOR_SUCCESSFUL_VEND) + remove_highlight(food_vendor) + food_vendor.req_access = list(ACCESS_TUTORIAL_LOCKED) + message_to_player("Now click on your character with the USCM Protein Bar in-hand until it is fully eaten. If you accidentally switched hands, switch back with [retrieve_bind("swap_hands")].") + update_objective("Eat the USCM Protein Bar by clicking on yourself while holding it, until it is gone.") + RegisterSignal(tutorial_mob, COMSIG_MOB_EATEN_SNACK, PROC_REF(on_foodbar_eaten)) + +/datum/tutorial/marine/basic/proc/on_foodbar_eaten(datum/source, obj/item/reagent_container/food/snacks/eaten_food) + SIGNAL_HANDLER + + if(!istype(eaten_food, /obj/item/reagent_container/food/snacks/protein_pack) || eaten_food.reagents.total_volume) + return + + UnregisterSignal(source, COMSIG_MOB_EATEN_SNACK) + message_to_player("Good. Now move to the outlined vendor and vend everything inside.") + update_objective("Vend everything inside the ColMarTech Automated Closet.") + TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/clothing/tutorial, clothing_vendor) + add_highlight(clothing_vendor) + clothing_vendor.req_access = list() + RegisterSignal(clothing_vendor, COMSIG_VENDOR_SUCCESSFUL_VEND, PROC_REF(on_clothing_vend)) + +/datum/tutorial/marine/basic/proc/on_clothing_vend(datum/source) + SIGNAL_HANDLER + + clothing_items_to_vend-- + if(clothing_items_to_vend <= 0) + TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/clothing/tutorial, clothing_vendor) + UnregisterSignal(clothing_vendor, COMSIG_VENDOR_SUCCESSFUL_VEND) + clothing_vendor.req_access = list(ACCESS_TUTORIAL_LOCKED) + remove_highlight(clothing_vendor) + message_to_player("Now, the room will darken. Take a flare out of your flare pouch by clicking on it with an empty hand, and then light it by using it in-hand with [retrieve_bind("activate_inhand")].") + update_objective("Click on your flare pouch to remove a flare before using it in-hand.") + var/obj/item/storage/pouch/flare/flare_pouch = locate(/obj/item/storage/pouch/flare) in tutorial_mob.contents + if(flare_pouch) + add_highlight(flare_pouch) + RegisterSignal(tutorial_mob, COMSIG_MOB_ITEM_ATTACK_SELF, PROC_REF(on_flare_light)) + addtimer(CALLBACK(src, PROC_REF(dim_room)), 2.5 SECONDS) + +/datum/tutorial/marine/basic/proc/on_flare_light(datum/source, obj/item/used) + SIGNAL_HANDLER + + if(!istype(used, /obj/item/device/flashlight/flare)) + return + + UnregisterSignal(tutorial_mob, COMSIG_MOB_ITEM_ATTACK_SELF) + var/obj/item/storage/pouch/flare/flare_pouch = locate(/obj/item/storage/pouch/flare) in tutorial_mob.contents + if(flare_pouch) + remove_highlight(flare_pouch) + + message_to_player("Now throw the flare by clicking on a nearby tile, or dropping it with [retrieve_bind("drop_item")].") + update_objective("Throw the flare by clicking on a nearby tile, or dropping it with [retrieve_bind("drop_item")].") + RegisterSignal(tutorial_mob, COMSIG_MOB_ITEM_DROPPED, PROC_REF(on_flare_throw)) + +/datum/tutorial/marine/basic/proc/on_flare_throw(datum/source, obj/item/thrown) + SIGNAL_HANDLER + + if(!istype(thrown, /obj/item/device/flashlight/flare)) + return + + UnregisterSignal(tutorial_mob, COMSIG_MOB_ITEM_DROPPED) + message_to_player("Good. Now, the room will brighten again. Proceed to the highlighted vendor and vend a M41A Pulse Rifle MK2, along with a magazine.") + update_objective("Vend everything from the ColMarTech Automated Weapons Rack.") + addtimer(CALLBACK(src, PROC_REF(brighten_room)), 1.5 SECONDS) + TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep/tutorial, gun_vendor) + gun_vendor.req_access = list() + add_highlight(gun_vendor) + RegisterSignal(gun_vendor, COMSIG_VENDOR_SUCCESSFUL_VEND, PROC_REF(on_gun_vend)) + +/datum/tutorial/marine/basic/proc/on_gun_vend(datum/source) + SIGNAL_HANDLER + + gun_items_to_vend-- + if(gun_items_to_vend <= 0) + TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep/tutorial, gun_vendor) + gun_vendor.req_access = list(ACCESS_TUTORIAL_LOCKED) + remove_highlight(gun_vendor) + UnregisterSignal(gun_vendor, COMSIG_VENDOR_SUCCESSFUL_VEND) + message_to_player("Now insert the magazine into the M41A Pulse Rifle by having the magazine in your active hand and hitting the Pulse Rifle with it. If it is in the off-hand, switch with [retrieve_bind("swap_hands")].") + update_objective("Insert the M41A magazine by hitting the M41A Pulse Rifle with it.") + RegisterSignal(tutorial_mob, COMSIG_MOB_RELOADED_GUN, PROC_REF(on_magazine_insert)) + +/datum/tutorial/marine/basic/proc/on_magazine_insert(datum/source, atom/attacked, obj/item/attacked_with) + SIGNAL_HANDLER + + UnregisterSignal(tutorial_mob, COMSIG_MOB_RELOADED_GUN) + message_to_player("Good. Now wield your gun by using it in-hand with [retrieve_bind("activate_inhand")].") + update_objective("Wield your gun with two hands by pressing [retrieve_bind("activate_inhand")] with the gun in your main hand.") + RegisterSignal(tutorial_mob, COMSIG_MOB_ITEM_ATTACK_SELF, PROC_REF(on_gun_wield)) + +/datum/tutorial/marine/basic/proc/on_gun_wield(datum/source, obj/item/used) + SIGNAL_HANDLER + + if(!istype(used, /obj/item/weapon/gun/rifle/m41a)) + return + + UnregisterSignal(tutorial_mob, COMSIG_MOB_ITEM_ATTACK_SELF) + message_to_player("Now, shoot at the highlighted Xenomorph until it dies.") + update_objective("Shoot at the Xenomorph until it dies.") + var/mob/living/carbon/xenomorph/drone/tutorial/xeno_dummy = new(loc_from_corner(4, 5)) + add_to_tracking_atoms(xeno_dummy) + add_highlight(xeno_dummy, COLOUR_VIVID_RED) + RegisterSignal(xeno_dummy, COMSIG_MOB_DEATH, PROC_REF(on_xeno_death)) + RegisterSignal(tutorial_mob, COMSIG_MOB_GUN_EMPTY, PROC_REF(on_magazine_empty)) // I'd like to prevent unwilling softlocks as much as I can + +/// Non-contiguous part of the script, called if the user manages to run out of ammo in the gun without the xeno dying +/datum/tutorial/marine/basic/proc/on_magazine_empty(obj/item/weapon/gun/empty_gun) + SIGNAL_HANDLER + + UnregisterSignal(tutorial_mob, COMSIG_MOB_GUN_EMPTY) + message_to_player("Your gun's out of ammo. Go grab some more from the Weaponry Vendor and kill the Xenomorph.") + TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep/tutorial, gun_vendor) + gun_vendor.req_access = list() + gun_vendor.load_ammo() // 99 magazines, to make sure that the xeno dies + +/datum/tutorial/marine/basic/proc/on_xeno_death(datum/source) + SIGNAL_HANDLER + + TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/xenomorph/drone/tutorial, xeno_dummy) + UnregisterSignal(xeno_dummy, COMSIG_MOB_DEATH) + UnregisterSignal(tutorial_mob, COMSIG_MOB_GUN_EMPTY) + remove_highlight(xeno_dummy) + addtimer(CALLBACK(src, PROC_REF(disappear_xeno)), 2.5 SECONDS) + message_to_player("Very good. This is the end of the tutorial, proceed to the next one to learn the basics of Medical. You will be sent back to the lobby screen momentarily.") + update_objective("") + tutorial_end_in(7.5 SECONDS, TRUE) + + +// END OF SCRIPTING +// START OF SCRIPT HELPERS + +/datum/tutorial/marine/basic/proc/dim_room() + TUTORIAL_ATOM_FROM_TRACKING(/obj/item/device/flashlight, flashlight) + flashlight.set_light_on(FALSE) + +/datum/tutorial/marine/basic/proc/brighten_room() + TUTORIAL_ATOM_FROM_TRACKING(/obj/item/device/flashlight, flashlight) + flashlight.set_light_on(TRUE) + +/datum/tutorial/marine/basic/proc/disappear_xeno() + TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/xenomorph/drone/tutorial, xeno_dummy) + animate(xeno_dummy, time = 5 SECONDS, alpha = 0) + remove_from_tracking_atoms(xeno_dummy) + QDEL_IN(xeno_dummy, 5.5 SECONDS) + +// END OF SCRIPT HELPERS + +/datum/tutorial/marine/basic/init_mob() + . = ..() + arm_equipment(tutorial_mob, /datum/equipment_preset/tutorial) + + TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cryopod/tutorial, tutorial_pod) + tutorial_pod.go_in_cryopod(tutorial_mob, TRUE, FALSE) + + +/datum/tutorial/marine/basic/init_map() + var/obj/structure/machinery/cryopod/tutorial/tutorial_pod = new(bottom_left_corner) + add_to_tracking_atoms(tutorial_pod) + var/obj/structure/machinery/cm_vending/sorted/marine_food/tutorial/food_vendor = new(loc_from_corner(0, 2)) + add_to_tracking_atoms(food_vendor) + var/obj/structure/machinery/cm_vending/clothing/tutorial/clothing_vendor = new(loc_from_corner(0, 4)) + add_to_tracking_atoms(clothing_vendor) + var/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep/tutorial/gun_vendor = new(loc_from_corner(0, 5)) + add_to_tracking_atoms(gun_vendor) diff --git a/code/datums/tutorial/marine/medical_basic.dm b/code/datums/tutorial/marine/medical_basic.dm new file mode 100644 index 000000000000..3a42a6d2ecc2 --- /dev/null +++ b/code/datums/tutorial/marine/medical_basic.dm @@ -0,0 +1,174 @@ +/datum/tutorial/marine/medical_basic + name = "Marine - Medical (Basic)" + desc = "Learn how to treat common injuries you may face as a marine." + tutorial_id = "marine_medical_1" + tutorial_template = /datum/map_template/tutorial/s7x7 + +// START OF SCRIPTING + +/datum/tutorial/marine/medical_basic/start_tutorial(mob/starting_mob) + . = ..() + if(!.) + return + + init_mob() + message_to_player("This is the tutorial for the basics of medical that you will need to know for playing a marine role.") + addtimer(CALLBACK(src, PROC_REF(brute_tutorial)), 4 SECONDS) + +/datum/tutorial/marine/medical_basic/proc/brute_tutorial() + message_to_player("The first kind of damage is Brute, the most common kind. It represents physical trauma from things like punches, weapons, or guns.") + var/mob/living/living_mob = tutorial_mob + living_mob.adjustBruteLoss(10) + addtimer(CALLBACK(src, PROC_REF(brute_tutorial_2)), 4 SECONDS) + +/datum/tutorial/marine/medical_basic/proc/brute_tutorial_2() + message_to_player("You can observe if you have Brute or Burn damage by clicking on yourself with an empty hand on help intent.") + update_objective("Click on yourself with an empty hand.") + RegisterSignal(tutorial_mob, COMSIG_LIVING_ATTACKHAND_HUMAN, PROC_REF(on_health_examine)) + +/datum/tutorial/marine/medical_basic/proc/on_health_examine(datum/source, mob/living/carbon/human/attacked_mob) + SIGNAL_HANDLER + + if(attacked_mob != tutorial_mob) + return + + UnregisterSignal(tutorial_mob, COMSIG_LIVING_ATTACKHAND_HUMAN) + message_to_player("Good. Now, you have taken some brute damage. Bicaridine is used to fix brute over time. Pick up the bicaridine EZ autoinjector and use it in-hand.") + update_objective("Inject yourself with the bicaridine injector.") + var/obj/item/reagent_container/hypospray/autoinjector/bicaridine/skillless/one_use/brute_injector = new(loc_from_corner(0, 4)) + add_to_tracking_atoms(brute_injector) + add_highlight(brute_injector) + RegisterSignal(tutorial_mob, COMSIG_LIVING_HYPOSPRAY_INJECTED, PROC_REF(on_brute_inject)) + +/datum/tutorial/marine/medical_basic/proc/on_brute_inject(datum/source, obj/item/reagent_container/hypospray/injector) + SIGNAL_HANDLER + + if(!istype(injector, /obj/item/reagent_container/hypospray/autoinjector/bicaridine/skillless/one_use)) + return + + UnregisterSignal(tutorial_mob, COMSIG_LIVING_HYPOSPRAY_INJECTED) + TUTORIAL_ATOM_FROM_TRACKING(/obj/item/reagent_container/hypospray/autoinjector/bicaridine/skillless/one_use, brute_injector) + remove_highlight(brute_injector) + message_to_player("All medicines take time to work after injection. Next is Burn damage. It is obtained from things like acid or being set on fire.") + update_objective("") + var/mob/living/living_mob = tutorial_mob + living_mob.adjustFireLoss(10) + addtimer(CALLBACK(src, PROC_REF(burn_tutorial)), 4 SECONDS) + +/datum/tutorial/marine/medical_basic/proc/burn_tutorial() + message_to_player("Kelotane is used to fix burn over time. Inject yourself with the kelotane EZ autoinjector.") + update_objective("Inject yourself with the kelotane injector.") + var/obj/item/reagent_container/hypospray/autoinjector/kelotane/skillless/one_use/burn_injector = new(loc_from_corner(0, 4)) + add_to_tracking_atoms(burn_injector) + add_highlight(burn_injector) + RegisterSignal(tutorial_mob, COMSIG_LIVING_HYPOSPRAY_INJECTED, PROC_REF(on_burn_inject)) + + +/datum/tutorial/marine/medical_basic/proc/on_burn_inject(datum/source, obj/item/reagent_container/hypospray/injector) + SIGNAL_HANDLER + + if(!istype(injector, /obj/item/reagent_container/hypospray/autoinjector/kelotane/skillless/one_use)) + return + + UnregisterSignal(tutorial_mob, COMSIG_LIVING_HYPOSPRAY_INJECTED) + TUTORIAL_ATOM_FROM_TRACKING(/obj/item/reagent_container/hypospray/autoinjector/kelotane/skillless/one_use, burn_injector) + remove_highlight(burn_injector) + message_to_player("Good. Now, when you normally take damage, you will also feel pain. Pain slows you down and can knock you out if left unchecked.") + update_objective("") + var/mob/living/living_mob = tutorial_mob + living_mob.pain.apply_pain(PAIN_CHESTBURST_STRONG) + addtimer(CALLBACK(src, PROC_REF(pain_tutorial)), 4 SECONDS) + +/datum/tutorial/marine/medical_basic/proc/pain_tutorial() + message_to_player("Tramadol is used to reduce your pain. Inject yourself with the tramadol EZ autoinjector.") + update_objective("Inject yourself with the tramadol injector.") + var/obj/item/reagent_container/hypospray/autoinjector/tramadol/skillless/one_use/pain_injector = new(loc_from_corner(0, 4)) + add_to_tracking_atoms(pain_injector) + add_highlight(pain_injector) + RegisterSignal(tutorial_mob, COMSIG_LIVING_HYPOSPRAY_INJECTED, PROC_REF(on_pain_inject)) + +/datum/tutorial/marine/medical_basic/proc/on_pain_inject(datum/source, obj/item/reagent_container/hypospray/injector) + SIGNAL_HANDLER + + if(!istype(injector, /obj/item/reagent_container/hypospray/autoinjector/tramadol/skillless/one_use)) + return + + UnregisterSignal(tutorial_mob, COMSIG_LIVING_HYPOSPRAY_INJECTED) + TUTORIAL_ATOM_FROM_TRACKING(/obj/item/reagent_container/hypospray/autoinjector/tramadol/skillless/one_use, pain_injector) + remove_highlight(pain_injector) + message_to_player("Good. Keep in mind that you can overdose on chemicals, so don't inject yourself with the same chemical too much too often. In the field, injectors have 3 uses.") + update_objective("Don't overdose! Generally, 3 injections of a chemical will overdose you.") + var/mob/living/living_mob = tutorial_mob + living_mob.pain.apply_pain(-PAIN_CHESTBURST_STRONG) // just to make sure + addtimer(CALLBACK(src, PROC_REF(bleed_tutorial)), 4 SECONDS) + +/datum/tutorial/marine/medical_basic/proc/bleed_tutorial() + message_to_player("You can sometimes start bleeding from things like bullets or slashes. Losing blood will accumulate oxygen damage, eventually causing death.") + update_objective("") + var/mob/living/carbon/human/human_mob = tutorial_mob + var/obj/limb/chest/mob_chest = locate(/obj/limb/chest) in human_mob.limbs + mob_chest.add_bleeding(damage_amount = 15) + addtimer(CALLBACK(src, PROC_REF(bleed_tutorial_2)), 4 SECONDS) + +/datum/tutorial/marine/medical_basic/proc/bleed_tutorial_2() + message_to_player("Bleeding wounds can clot themselves over time, or you can fix it quickly with gauze. Pick up the gauze and click on yourself while targeting your chest.") + update_objective("Gauze your chest, or let it clot on its own.") + var/obj/item/stack/medical/bruise_pack/two/bandage = new(loc_from_corner(0, 4)) + add_to_tracking_atoms(bandage) + add_highlight(bandage) + var/mob/living/carbon/human/human_mob = tutorial_mob + var/obj/limb/chest/mob_chest = locate(/obj/limb/chest) in human_mob.limbs + RegisterSignal(mob_chest, COMSIG_LIMB_STOP_BLEEDING, PROC_REF(on_chest_bleed_stop)) + +/datum/tutorial/marine/medical_basic/proc/on_chest_bleed_stop(datum/source, external, internal) + SIGNAL_HANDLER + + // If you exit on this step, your limbs get deleted, which stops the bleeding, which progresses the tutorial despite it ending + if(!tutorial_mob || QDELETED(src)) + return + + var/mob/living/carbon/human/human_mob = tutorial_mob + var/obj/limb/chest/mob_chest = locate(/obj/limb/chest) in human_mob.limbs + UnregisterSignal(mob_chest, COMSIG_LIMB_STOP_BLEEDING) + + TUTORIAL_ATOM_FROM_TRACKING(/obj/item/stack/medical/bruise_pack/two, bandage) + remove_from_tracking_atoms(bandage) + remove_highlight(bandage) + qdel(bandage) + + message_to_player("Good. Sometimes, a bullet or bone shard can result in you getting shrapnel, dealing damage over time. Pick up the knife and use it in-hand to remove the shrapnel.") + update_objective("Remove your shrapnel by using the knife in-hand.") + var/mob/living/living_mob = tutorial_mob + living_mob.pain.feels_pain = FALSE + + var/obj/item/attachable/bayonet/knife = new(loc_from_corner(0, 4)) + add_to_tracking_atoms(knife) + add_highlight(knife) + + var/obj/item/shard/shrapnel/tutorial/shrapnel = new + shrapnel.on_embed(tutorial_mob, mob_chest, TRUE) + + RegisterSignal(tutorial_mob, COMSIG_HUMAN_SHRAPNEL_REMOVED, PROC_REF(on_shrapnel_removed)) + +/datum/tutorial/marine/medical_basic/proc/on_shrapnel_removed() + SIGNAL_HANDLER + + UnregisterSignal(tutorial_mob, COMSIG_HUMAN_SHRAPNEL_REMOVED) + TUTORIAL_ATOM_FROM_TRACKING(/obj/item/attachable/bayonet, knife) + remove_highlight(knife) + message_to_player("Good. This is the end of the basic marine medical tutorial. The tutorial will end shortly.") + update_objective("Tutorial completed.") + tutorial_end_in(5 SECONDS) + +// END OF SCRIPTING +// START OF SCRIPT HELPERS + +// END OF SCRIPT HELPERS + +/datum/tutorial/marine/medical_basic/init_mob() + . = ..() + arm_equipment(tutorial_mob, /datum/equipment_preset/tutorial/fed) + + +/datum/tutorial/marine/medical_basic/init_map() + new /obj/structure/surface/table/almayer(loc_from_corner(0, 4)) diff --git a/code/datums/tutorial/ss13/_ss13.dm b/code/datums/tutorial/ss13/_ss13.dm new file mode 100644 index 000000000000..53cf5c918ee9 --- /dev/null +++ b/code/datums/tutorial/ss13/_ss13.dm @@ -0,0 +1,41 @@ +/datum/tutorial/ss13 + category = TUTORIAL_CATEGORY_SS13 + parent_path = /datum/tutorial/ss13 + icon_state = "ss13" + +/datum/tutorial/ss13/init_mob() + tutorial_mob.close_spawn_windows() + + var/mob/living/carbon/human/new_character = new(bottom_left_corner) + new_character.lastarea = get_area(bottom_left_corner) + + tutorial_mob.client.prefs.copy_all_to(new_character) + + if(tutorial_mob.client.prefs.be_random_body) + var/datum/preferences/rand_prefs = new() + rand_prefs.randomize_appearance(new_character) + + new_character.job = tutorial_mob.job + new_character.name = tutorial_mob.real_name + new_character.voice = tutorial_mob.real_name + + new_character.sec_hud_set_ID() + new_character.hud_set_squad() + + SSround_recording.recorder.track_player(new_character) + + if(tutorial_mob.mind) + tutorial_mob.mind_initialize() + tutorial_mob.mind.transfer_to(new_character, TRUE) + tutorial_mob.mind.setup_human_stats() + + INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, regenerate_icons)) + INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, update_body), 1, 0) + INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, update_hair)) + + tutorial_mob = new_character + RegisterSignal(tutorial_mob, COMSIG_LIVING_GHOSTED, PROC_REF(on_ghost)) + RegisterSignal(tutorial_mob, list(COMSIG_PARENT_QDELETING, COMSIG_MOB_DEATH, COMSIG_MOB_END_TUTORIAL), PROC_REF(signal_end_tutorial)) + RegisterSignal(tutorial_mob, COMSIG_MOB_LOGOUT, PROC_REF(on_logout)) + arm_equipment(tutorial_mob, /datum/equipment_preset/tutorial/fed) + return ..() diff --git a/code/datums/tutorial/ss13/basic_ss13.dm b/code/datums/tutorial/ss13/basic_ss13.dm new file mode 100644 index 000000000000..65bb0cac94f4 --- /dev/null +++ b/code/datums/tutorial/ss13/basic_ss13.dm @@ -0,0 +1,84 @@ +/datum/tutorial/ss13/basic + name = "Space Station 13 - Basic" + desc = "Learn the very basics of Space Station 13. Recommended if you haven't played before." + tutorial_id = "ss13_basic_1" + tutorial_template = /datum/map_template/tutorial/s7x7 + +// START OF SCRIPTING + +/datum/tutorial/ss13/basic/start_tutorial(mob/starting_mob) + . = ..() + if(!.) + return + + init_mob() + message_to_player("This is the tutorial for the basics of Space Station 13. Any current instructions can be found in the top-right corner, in the status panel.") + update_objective("Here's where it'll be!") + + addtimer(CALLBACK(src, PROC_REF(require_move)), 4 SECONDS) // check if this is a good amount of time + +/datum/tutorial/ss13/basic/proc/require_move() + message_to_player("Now, move in any direction using [retrieve_bind("North")], [retrieve_bind("West")], [retrieve_bind("South")], or [retrieve_bind("East")].") + update_objective("Move in any direction using the [retrieve_bind("North")][retrieve_bind("West")][retrieve_bind("South")][retrieve_bind("East")] keys.") + + RegisterSignal(tutorial_mob, COMSIG_MOB_MOVE_OR_LOOK, PROC_REF(on_move)) + +/datum/tutorial/ss13/basic/proc/on_move(datum/source, actually_moving, direction, specific_direction) + SIGNAL_HANDLER + + if(!actually_moving) // The mob just looked in a different dir instead of moving + return + + UnregisterSignal(tutorial_mob, COMSIG_MOB_MOVE_OR_LOOK) + + message_to_player("Good. Now, switch hands with [retrieve_bind("swap_hands")].") + update_objective("Switch hands with [retrieve_bind("swap_hands")].") + + RegisterSignal(tutorial_mob, COMSIG_MOB_SWAPPED_HAND, PROC_REF(on_hand_swap)) + +/datum/tutorial/ss13/basic/proc/on_hand_swap(datum/source) + SIGNAL_HANDLER + + UnregisterSignal(tutorial_mob, COMSIG_MOB_SWAPPED_HAND) + + message_to_player("Good. Now, pick up the satchel that just spawned and equip it with [retrieve_bind("quick_equip")].") + update_objective("Pick up the satchel and equip it with [retrieve_bind("quick_equip")].") + + var/obj/item/storage/backpack/marine/satchel/satchel = new(loc_from_corner(2, 2)) + add_to_tracking_atoms(satchel) + add_highlight(satchel) + + RegisterSignal(tutorial_mob, COMSIG_HUMAN_EQUIPPED_ITEM, PROC_REF(on_satchel_equip)) + +/datum/tutorial/ss13/basic/proc/on_satchel_equip(datum/source, obj/item/equipped, slot) + SIGNAL_HANDLER + + if(!istype(equipped, /obj/item/storage/backpack/marine/satchel) || (slot != WEAR_BACK)) + return + + UnregisterSignal(tutorial_mob, COMSIG_HUMAN_EQUIPPED_ITEM) + TUTORIAL_ATOM_FROM_TRACKING(/obj/item/storage/backpack/marine/satchel, satchel) + remove_highlight(satchel) + message_to_player("Now, say anything by pressing [retrieve_bind("Say")].") + update_objective("Speak using [retrieve_bind("Say")].") + + RegisterSignal(tutorial_mob, COMSIG_LIVING_SPEAK, PROC_REF(on_speak)) + +/datum/tutorial/ss13/basic/proc/on_speak(datum/source) + SIGNAL_HANDLER + + UnregisterSignal(tutorial_mob, COMSIG_LIVING_SPEAK) + message_to_player("Excellent. The next tutorial will cover intents. The tutorial will end shortly.") + update_objective("") + tutorial_end_in(5 SECONDS, TRUE) + +// END OF SCRIPTING +// START OF SCRIPT HELPERS + + + +// END OF SCRIPT HELPERS + +/datum/tutorial/ss13/basic/init_mob() + . = ..() + tutorial_mob.forceMove(loc_from_corner(2, 1)) diff --git a/code/datums/tutorial/ss13/intents.dm b/code/datums/tutorial/ss13/intents.dm new file mode 100644 index 000000000000..d67b2ac1b4a1 --- /dev/null +++ b/code/datums/tutorial/ss13/intents.dm @@ -0,0 +1,113 @@ +/datum/tutorial/ss13/intents + name = "Space Station 13 - Intents" + desc = "Learn how the intent interaction system works." + icon_state = "intents" + tutorial_id = "ss13_intents_1" + tutorial_template = /datum/map_template/tutorial/s7x7 + +// START OF SCRIPTING + +/datum/tutorial/ss13/intents/start_tutorial(mob/starting_mob) + . = ..() + if(!.) + return + + init_mob() + message_to_player("This is the tutorial for the intents system of Space Station 13. The highlighted UI element in the bottom-right corner is your current intent.") + var/datum/hud/human/human_hud = tutorial_mob.hud_used + add_highlight(human_hud.action_intent) + + addtimer(CALLBACK(src, PROC_REF(require_help)), 4.5 SECONDS) + +/datum/tutorial/ss13/intents/proc/require_help() + tutorial_mob.a_intent_change(INTENT_DISARM) + message_to_player("Your intent has been changed off of help. Change back to it by pressing [retrieve_bind("select_help_intent")].") + update_objective("Change to help intent by pressing [retrieve_bind("select_help_intent")].") + + RegisterSignal(tutorial_mob, COMSIG_MOB_INTENT_CHANGE, PROC_REF(on_help_intent)) + +/datum/tutorial/ss13/intents/proc/on_help_intent(datum/source, new_intent) + SIGNAL_HANDLER + + if(new_intent != INTENT_HELP) + return + + UnregisterSignal(tutorial_mob, COMSIG_MOB_INTENT_CHANGE) + + var/mob/living/carbon/human/dummy/tutorial/tutorial_dummy = new(loc_from_corner(2, 3)) + add_to_tracking_atoms(tutorial_dummy) + + message_to_player("The first of the intents is help intent. It is used to harmlessly touch others, put out fire, give CPR, and similar. Click on the Test Dummy to give them a pat on the back.") + update_objective("Click on the dummy on help intent.") + + RegisterSignal(tutorial_mob, COMSIG_LIVING_ATTACKHAND_HUMAN, PROC_REF(on_help_attack)) + +/datum/tutorial/ss13/intents/proc/on_help_attack(datum/source, mob/living/carbon/human/attacked_mob) + SIGNAL_HANDLER + + if((attacked_mob == src) || (tutorial_mob.a_intent != INTENT_HELP)) + return + + UnregisterSignal(tutorial_mob, COMSIG_LIVING_ATTACKHAND_HUMAN) + TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human/dummy/tutorial, tutorial_dummy) + tutorial_dummy.status_flags = DEFAULT_MOB_STATUS_FLAGS + REMOVE_TRAIT(tutorial_dummy, TRAIT_IMMOBILIZED, TRAIT_SOURCE_TUTORIAL) + tutorial_dummy.anchored = FALSE + + message_to_player("The second intent is disarm, selectable with [retrieve_bind("select_disarm_intent")]. Disarm is used to shove people, which can make them drop items or fall to the ground. Shove the Test Dummy until it falls over.") + update_objective("Switch to disarm intent by pressing [retrieve_bind("select_disarm_intent")] and shove the dummy to the ground.") + + RegisterSignal(tutorial_dummy, COMSIG_LIVING_APPLY_EFFECT, PROC_REF(on_shove_down)) + +/datum/tutorial/ss13/intents/proc/on_shove_down(datum/source, datum/status_effect/new_effect) + SIGNAL_HANDLER + + if(!istype(new_effect, /datum/status_effect/incapacitating/knockdown)) + return + + TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human/dummy/tutorial, tutorial_dummy) + UnregisterSignal(tutorial_dummy, COMSIG_LIVING_APPLY_EFFECT) + tutorial_dummy.rejuvenate() + + message_to_player("The third intent is grab. Grab is used to grab people in either a passive, aggressive, or chokehold grab. Grab successively to \"upgrade\" your grab. Aggressively grab the Test Dummy.") + update_objective("Aggressively grab the dummy by grabbing them twice.") + + + RegisterSignal(tutorial_dummy, COMSIG_MOB_AGGRESSIVELY_GRABBED, PROC_REF(on_aggrograb)) + +/datum/tutorial/ss13/intents/proc/on_aggrograb(datum/source, mob/living/carbon/human/choker) + SIGNAL_HANDLER + + TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human/dummy/tutorial, tutorial_dummy) + UnregisterSignal(tutorial_dummy, COMSIG_MOB_AGGRESSIVELY_GRABBED) + + message_to_player("The final intent is harm. Harm is used to injure people with your fists or a melee weapon. Punch the Test Dummy with an empty hand.") + update_objective("Attack the dummy with an empty hand.") + + RegisterSignal(tutorial_mob, COMSIG_LIVING_ATTACKHAND_HUMAN, PROC_REF(on_harm_attack)) + +/datum/tutorial/ss13/intents/proc/on_harm_attack(datum/source, mob/living/carbon/human/attacked_mob) + SIGNAL_HANDLER + + if((attacked_mob == src) || (tutorial_mob.a_intent != INTENT_HARM)) + return + + UnregisterSignal(tutorial_mob, COMSIG_LIVING_ATTACKHAND_HUMAN) + TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human/dummy/tutorial, tutorial_dummy) + tutorial_dummy.status_flags = GODMODE + + message_to_player("Excellent. Those are the basics of the intent system. The tutorial will end shortly.") + update_objective("") + + tutorial_end_in(5 SECONDS, TRUE) + +// END OF SCRIPTING +// START OF SCRIPT HELPERS + + + +// END OF SCRIPT HELPERS + +/datum/tutorial/ss13/intents/init_mob() + . = ..() + tutorial_mob.forceMove(loc_from_corner(2, 0)) diff --git a/code/datums/tutorial/tutorial_example.dm b/code/datums/tutorial/tutorial_example.dm new file mode 100644 index 000000000000..9042346f8d39 --- /dev/null +++ b/code/datums/tutorial/tutorial_example.dm @@ -0,0 +1,74 @@ +/datum/tutorial/marine/example + name = "Example Tutorial" + tutorial_id = "example" // This won't show up in the list, so this'll be irrelevant anyway. + category = TUTORIAL_CATEGORY_BASE + parent_path = /datum/tutorial/marine/example + +// START OF SCRIPTING + +/datum/tutorial/marine/example/start_tutorial(mob/starting_mob) + // Here, we're calling parent and checking its return value. If it has a falsey one (as done by !.), then something went wrong and we should abort + // There isn't really a reason that you _shouldn't_ have this + . = ..() + if(!.) + return + + // Init_mob() isn't called by default, so we call it here + init_mob() + // As is standard, we give a message to the player and update their status panel with what we want done. + message_to_player("This is an example tutorial. Perform any emote to continue.") + update_objective("Do any emote.") + // This makes the player (tutorial_mob) listen for the COMSIG_MOB_EMOTE event, which will then call on_emote() when it hears it. + RegisterSignal(tutorial_mob, COMSIG_MOB_EMOTE, PROC_REF(on_emote)) + +/datum/tutorial/marine/example/proc/on_emote(datum/source) + // With any proc called via signal (see the RegisterSignal line above for details), we add SIGNAL_HANDLER to it. + SIGNAL_HANDLER + + // Now that we've gotten the signal and started the script, we want to immediately stop listening for it. + UnregisterSignal(tutorial_mob, COMSIG_MOB_EMOTE) + message_to_player("Good. Now, pick up that can of Weyland-Yutani Aspen Beer.") + update_objective("Pick up that can.") + // This macro takes a specific type path (the same used in init_map()) and a variable name to retrieve an object from the tracked object list + TUTORIAL_ATOM_FROM_TRACKING(/obj/item/reagent_container/food/drinks/cans/aspen, beer_can) + // Now we're adding a yellow highlight around the can to make sure people know what we're talking about + add_highlight(beer_can) + // Now, we always prefer to register signals on the tutorial_mob (as opposed to the beer_can) whenever possible + RegisterSignal(tutorial_mob, COMSIG_MOB_PICKUP_ITEM, PROC_REF(on_can_pickup)) + +/// We get these arguments from the signal's definition. If you have VSC, ctrl+click on COMSIG_MOB_PICKUP_ITEM above. When dealing with a signal proc, `datum/source` is always the first argument, then any added ones +/datum/tutorial/marine/example/proc/on_can_pickup(datum/source, obj/item/picked_up) + SIGNAL_HANDLER + + // Since we're just listening for the mob picking anything up, we want to confirm that the picked up item is the can before continuing. If it's not, then we return and keep listening. + if(!istype(picked_up, /obj/item/reagent_container/food/drinks/cans/aspen)) + // If we hit this return here, then the picked up item wasn't the can, so we abort and keep listening. + return + + // Since we passed the above if statement, stop listening for item pickups. + UnregisterSignal(tutorial_mob, COMSIG_MOB_PICKUP_ITEM) + // Let's get the tracked beer can again. + TUTORIAL_ATOM_FROM_TRACKING(/obj/item/reagent_container/food/drinks/cans/aspen, beer_can) + // And remove the highlight now that it's picked up + remove_highlight(beer_can) + message_to_player("Very good. This is the end of the example tutorial. You will be sent back to the lobby screen momentarily.") + // 7.5 seconds after the above message is sent, kick the player out and end the tutorial. + tutorial_end_in(7.5 SECONDS, TRUE) + + +// END OF SCRIPTING +// START OF SCRIPT HELPERS + +// END OF SCRIPT HELPERS + +/datum/tutorial/marine/example/init_mob() + . = ..() + // We give the tutorial mob a basic ID so they can use general vendors and etc. This is here because not all marine tutorials may want to use a naked equipment preset. + arm_equipment(tutorial_mob, /datum/equipment_preset/tutorial) + + +/datum/tutorial/marine/example/init_map() + // Here we're initializing a new can that we want to track, so we spawn it 2 tiles to the left and up from the bottom left corner of the tutorial zone + var/obj/item/reagent_container/food/drinks/cans/aspen/the_can = new(loc_from_corner(2, 2)) + // Now we start tracking it + add_to_tracking_atoms(the_can) diff --git a/code/game/area/admin_level.dm b/code/game/area/admin_level.dm index 00b408c04adf..bfca1481155e 100644 --- a/code/game/area/admin_level.dm +++ b/code/game/area/admin_level.dm @@ -144,3 +144,22 @@ /area/misc/testroom requires_power = FALSE name = "Test Room" + +/area/misc/tutorial + name = "Tutorial Zone" + icon_state = "tutorial" + requires_power = FALSE + flags_area = AREA_NOTUNNEL|AREA_AVOID_BIOSCAN + statistic_exempt = TRUE + ceiling = CEILING_METAL + block_game_interaction = TRUE + unique = TRUE + + base_lighting_alpha = 255 + +/area/misc/tutorial/Initialize(mapload, ...) + . = ..() + update_base_lighting() + +/area/misc/tutorial/no_baselight + base_lighting_alpha = 0 diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 536e29599597..9699db527102 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -79,6 +79,10 @@ var/used_environ = 0 var/used_oneoff = 0 //one-off power usage + /// If this area is outside the game's normal interactivity and should be excluded from things like EOR reports and crew monitors. + /// Doesn't need to be set for areas/Z levels that are marked as admin-only + var/block_game_interaction = FALSE + /area/New() // This interacts with the map loader, so it needs to be set immediately diff --git a/code/game/gamemodes/cm_initialize.dm b/code/game/gamemodes/cm_initialize.dm index 981966082919..c017733de7fd 100644 --- a/code/game/gamemodes/cm_initialize.dm +++ b/code/game/gamemodes/cm_initialize.dm @@ -350,7 +350,7 @@ Additional game mode variables. if(cur_xeno.aghosted) continue //aghosted xenos don't count var/area/area = get_area(cur_xeno) - if(is_admin_level(cur_xeno.z) && (!area || !(area.flags_area & AREA_ALLOW_XENO_JOIN))) + if(should_block_game_interaction(cur_xeno) && (!area || !(area.flags_area & AREA_ALLOW_XENO_JOIN))) continue //xenos on admin z level don't count if(!istype(cur_xeno)) continue diff --git a/code/game/gamemodes/colonialmarines/colonialmarines.dm b/code/game/gamemodes/colonialmarines/colonialmarines.dm index bc5d6b69228c..f64c2432486b 100644 --- a/code/game/gamemodes/colonialmarines/colonialmarines.dm +++ b/code/game/gamemodes/colonialmarines/colonialmarines.dm @@ -329,7 +329,7 @@ var/datum/hive_status/HS for(var/HN in GLOB.hive_datum) HS = GLOB.hive_datum[HN] - if(HS.living_xeno_queen && !is_admin_level(HS.living_xeno_queen.loc.z)) + if(HS.living_xeno_queen && !should_block_game_interaction(HS.living_xeno_queen.loc)) //Some Queen is alive, we shouldn't end the game yet return round_finished = MODE_INFESTATION_M_MINOR diff --git a/code/game/gamemodes/colonialmarines/whiskey_outpost/whiskey_output_waves.dm b/code/game/gamemodes/colonialmarines/whiskey_outpost/whiskey_output_waves.dm index 6e2738a83788..1ec07b9d8fec 100644 --- a/code/game/gamemodes/colonialmarines/whiskey_outpost/whiskey_output_waves.dm +++ b/code/game/gamemodes/colonialmarines/whiskey_outpost/whiskey_output_waves.dm @@ -32,7 +32,7 @@ for(var/mob/living/carbon/xenomorph/X as anything in GLOB.living_xeno_list) var/area/A = get_area(X) - if(is_admin_level(X.z) && (!A || !(A.flags_area & AREA_ALLOW_XENO_JOIN)) || X.aghosted) continue //xenos on admin z level and aghosted ones don't count + if(should_block_game_interaction(X) && (!A || !(A.flags_area & AREA_ALLOW_XENO_JOIN)) || X.aghosted) continue //xenos on admin z level and aghosted ones don't count if(istype(X) && !X.client) if((X.away_timer >= XENO_LEAVE_TIMER) || (islarva(X) && X.away_timer >= XENO_LEAVE_TIMER_LARVA)) available_xenos += X diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index 56decd8f0c02..094b899c1691 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -237,32 +237,10 @@ if(!istype(NP)) return - NP.spawning = TRUE - NP.close_spawn_windows() - var/mob/living/carbon/human/new_character = new(NP.loc) new_character.lastarea = get_area(NP.loc) - NP.client.prefs.copy_all_to(new_character, title) - - if (NP.client.prefs.be_random_body) - var/datum/preferences/TP = new() - TP.randomize_appearance(new_character) - - new_character.job = NP.job - new_character.name = NP.real_name - new_character.voice = NP.real_name - - if(NP.mind) - NP.mind_initialize() - NP.mind.transfer_to(new_character, TRUE) - NP.mind.setup_human_stats() - - // Update the character icons - // This is done in set_species when the mob is created as well, but - INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, regenerate_icons)) - INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, update_body), 1, 0) - INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, update_hair)) + setup_human(new_character, NP) return new_character diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm index b9ea018ba98f..190d51d3f7b8 100644 --- a/code/game/machinery/camera/tracking.dm +++ b/code/game/machinery/camera/tracking.dm @@ -4,7 +4,7 @@ /mob/living/silicon/ai/proc/InvalidTurf(turf/T as turf) if(!T) return 1 - if(is_admin_level(T.z)) + if(should_block_game_interaction(T)) return 1 if(T.z > 6) return 1 diff --git a/code/game/machinery/computer/camera_console.dm b/code/game/machinery/computer/camera_console.dm index cad4fd4fc747..1a00e194b5eb 100644 --- a/code/game/machinery/computer/camera_console.dm +++ b/code/game/machinery/computer/camera_console.dm @@ -69,7 +69,7 @@ return attack_hand(user) /obj/structure/machinery/computer/cameras/attack_hand(mob/user) - if(!admin_console && is_admin_level(z)) + if(!admin_console && should_block_game_interaction(src)) to_chat(user, SPAN_DANGER("Unable to establish a connection: \black You're too far away from the ship!")) return if(inoperable()) diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index ab5dc6448f4b..69c2c897e276 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -519,7 +519,7 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li if(mob.client) to_chat(mob, SPAN_NOTICE("You feel cool air surround you. You go numb as your senses turn inward.")) to_chat(mob, SPAN_BOLDNOTICE("If you log out or close your client now, your character will permanently removed from the round in 10 minutes. If you ghost, timer will be decreased to 2 minutes.")) - if(!is_admin_level(src.z)) // Set their queue time now because the client has to actually leave to despawn and at that point the client is lost + if(!should_block_game_interaction(src)) // Set their queue time now because the client has to actually leave to despawn and at that point the client is lost mob.client.player_details.larva_queue_time = max(mob.client.player_details.larva_queue_time, world.time) var/area/location = get_area(src) if(mob.job != GET_MAPPED_ROLE(JOB_SQUAD_MARINE)) @@ -536,6 +536,7 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li icon_state = "body_scanner_open" set_light(0) playsound(src, 'sound/machines/pod_open.ogg', 30) + SEND_SIGNAL(src, COMSIG_CRYOPOD_GO_OUT) #ifdef OBJECTS_PROXY_SPEECH // Transfers speech to occupant @@ -554,3 +555,40 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li return move_inside(target) + + +/obj/structure/machinery/cryopod/tutorial + silent_exit = TRUE + +/obj/structure/machinery/cryopod/tutorial/process() + return + +/obj/structure/machinery/cryopod/tutorial/go_in_cryopod(mob/mob, silent = FALSE, del_them = TRUE) + if(occupant) + return + mob.forceMove(src) + occupant = mob + icon_state = "body_scanner_closed" + set_light(2) + time_entered = world.time + if(del_them) + despawn_occupant() + +/obj/structure/machinery/cryopod/tutorial/despawn_occupant() + SSminimaps.remove_marker(occupant) + + if(ishuman(occupant)) + var/mob/living/carbon/human/man = occupant + man.species.handle_cryo(man) + + icon_state = "body_scanner_open" + set_light(0) + + + var/mob/new_player/new_player = new + + if(!occupant.mind) + occupant.mind_initialize() + + occupant.mind.transfer_to(new_player) + SEND_SIGNAL(occupant, COMSIG_MOB_END_TUTORIAL) diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm index 942d70f80705..e43598c4e248 100644 --- a/code/game/machinery/telecomms/machine_interactions.dm +++ b/code/game/machinery/telecomms/machine_interactions.dm @@ -177,7 +177,7 @@ if(src.listening_level == TELECOMM_GROUND_Z) // equals the station src.listening_level = position.z return 1 - else if(is_admin_level(position.z)) + else if(should_block_game_interaction(position)) src.listening_level = TELECOMM_GROUND_Z return 1 return 0 @@ -229,7 +229,7 @@ /obj/structure/machinery/telecomms/relay/Options_Menu() var/dat = "" - if(is_admin_level(z)) + if(should_block_game_interaction(src)) dat += "
Signal Locked to Station: [listening_level == TELECOMM_GROUND_Z ? "TRUE" : "FALSE"]" dat += "
Broadcasting: [broadcasting ? "YES" : "NO"]" dat += "
Receiving: [receiving ? "YES" : "NO"]" diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 8ea00ce4061d..8b6622121b86 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -98,7 +98,7 @@ var/turf/T = get_turf(R) if (!T) continue - if(is_admin_level(T.z)) + if(should_block_game_interaction(T)) continue var/tmpname = T.loc.name if(areaindex[tmpname]) @@ -118,7 +118,7 @@ continue var/turf/T = get_turf(M) if(T) continue - if(is_admin_level(T.z)) continue + if(should_block_game_interaction(T)) continue var/tmpname = M.real_name if(areaindex[tmpname]) tmpname = "[tmpname] ([++areaindex[tmpname]])" diff --git a/code/game/machinery/vending/cm_vending.dm b/code/game/machinery/vending/cm_vending.dm index 6415e1d0acd5..5568a5fda600 100644 --- a/code/game/machinery/vending/cm_vending.dm +++ b/code/game/machinery/vending/cm_vending.dm @@ -1239,8 +1239,10 @@ GLOBAL_LIST_INIT(cm_vending_gear_corresponding_types_list, list( if(islist(prod_type)) for(var/each_type in prod_type) vendor_successful_vend_one(each_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM) + SEND_SIGNAL(src, COMSIG_VENDOR_SUCCESSFUL_VEND, src, itemspec, user) else vendor_successful_vend_one(prod_type, user, target_turf, itemspec[4] == MARINE_CAN_BUY_UNIFORM) + SEND_SIGNAL(src, COMSIG_VENDOR_SUCCESSFUL_VEND, src, itemspec, user) if(vend_flags & VEND_LIMITED_INVENTORY) itemspec[2]-- diff --git a/code/game/machinery/vending/vendor_types/food.dm b/code/game/machinery/vending/vendor_types/food.dm index 10e1a035cb0b..62ed5124727e 100644 --- a/code/game/machinery/vending/vendor_types/food.dm +++ b/code/game/machinery/vending/vendor_types/food.dm @@ -25,6 +25,27 @@ list("W-Y Flask", 5, /obj/item/reagent_container/food/drinks/flask/weylandyutani, VENDOR_ITEM_REGULAR) ) +/obj/structure/machinery/cm_vending/sorted/marine_food/tutorial + hackable = FALSE + wrenchable = FALSE + req_access = list(ACCESS_TUTORIAL_LOCKED) + +/obj/structure/machinery/cm_vending/sorted/marine_food/tutorial/populate_product_list(scale) + listed_products = list( + list("PREPARED MEALS", -1, null, null), + list("USCM Prepared Meal (Chicken)", 0, /obj/item/reagent_container/food/snacks/mre_pack/meal5, VENDOR_ITEM_REGULAR), + list("USCM Prepared Meal (Cornbread)", 0, /obj/item/reagent_container/food/snacks/mre_pack/meal1, VENDOR_ITEM_REGULAR), + list("USCM Prepared Meal (Pasta)", 0, /obj/item/reagent_container/food/snacks/mre_pack/meal3, VENDOR_ITEM_REGULAR), + list("USCM Prepared Meal (Pizza)", 0, /obj/item/reagent_container/food/snacks/mre_pack/meal4, VENDOR_ITEM_REGULAR), + list("USCM Prepared Meal (Pork)", 0, /obj/item/reagent_container/food/snacks/mre_pack/meal2, VENDOR_ITEM_REGULAR), + list("USCM Prepared Meal (Tofu)", 0, /obj/item/reagent_container/food/snacks/mre_pack/meal6, VENDOR_ITEM_REGULAR), + list("USCM Protein Bar", 1, /obj/item/reagent_container/food/snacks/protein_pack, VENDOR_ITEM_RECOMMENDED), + list("FLASKS", -1, null, null), + list("Canteen", 0, /obj/item/reagent_container/food/drinks/flask/canteen, VENDOR_ITEM_REGULAR), + list("Metal Flask", 0, /obj/item/reagent_container/food/drinks/flask, VENDOR_ITEM_REGULAR), + list("USCM Flask", 0, /obj/item/reagent_container/food/drinks/flask/marine, VENDOR_ITEM_REGULAR), + list("W-Y Flask", 0, /obj/item/reagent_container/food/drinks/flask/weylandyutani, VENDOR_ITEM_REGULAR) + ) //------------BOOZE-O-MAT VENDOR--------------- /obj/structure/machinery/cm_vending/sorted/boozeomat diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm index 6a770e89984e..e021b6fe0879 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm @@ -53,6 +53,34 @@ list("M94 Marking Flare Pack", round(scale * 10), /obj/item/storage/box/m94, VENDOR_ITEM_RECOMMENDED) ) +/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep/tutorial + name = "\improper ColMarTech Automated Weapons Rack" + desc = "An automated weapon rack hooked up to a big storage of standard-issue weapons." + icon_state = "guns" + req_access = list(ACCESS_TUTORIAL_LOCKED) + req_one_access = list() + hackable = FALSE + vend_flags = VEND_CLUTTER_PROTECTION | VEND_LIMITED_INVENTORY | VEND_TO_HAND + +/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep/tutorial/populate_product_list(scale) + listed_products = list( + list("PRIMARY FIREARMS", -1, null, null), + list("M41A Pulse Rifle MK2", 1, /obj/item/weapon/gun/rifle/m41a, VENDOR_ITEM_RECOMMENDED), + + list("PRIMARY AMMUNITION", -1, null, null), + list("M41A Magazine (10x24mm)", 1, /obj/item/ammo_magazine/rifle, VENDOR_ITEM_RECOMMENDED), + ) + +/// Called if the tutorial mob somehow uses an entire magazine without the xeno dying +/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep/tutorial/proc/load_ammo() + listed_products = list( + list("PRIMARY FIREARMS", -1, null, null), + list("M41A Pulse Rifle MK2", 0, /obj/item/weapon/gun/rifle/m41a, VENDOR_ITEM_RECOMMENDED), + + list("PRIMARY AMMUNITION", -1, null, null), + list("M41A Magazine (10x24mm)", 99, /obj/item/ammo_magazine/rifle, VENDOR_ITEM_RECOMMENDED), + ) + //------------SQUAD PREP UNIFORM VENDOR--------------- diff --git a/code/game/machinery/vending/vendor_types/squad_prep/tutorial.dm b/code/game/machinery/vending/vendor_types/squad_prep/tutorial.dm new file mode 100644 index 000000000000..c1cedd85c7fc --- /dev/null +++ b/code/game/machinery/vending/vendor_types/squad_prep/tutorial.dm @@ -0,0 +1,30 @@ +GLOBAL_LIST_INIT(cm_vending_clothing_tutorial, list( + list("STANDARD EQUIPMENT (TAKE ALL)", 0, null, null, null), + list("Standard Marine Apparel", 0, list(/obj/item/clothing/under/marine, /obj/item/clothing/shoes/marine/knife, /obj/item/clothing/gloves/marine, /obj/item/clothing/head/helmet/marine), MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY), + + list("ARMOR (CHOOSE 1)", 0, null, null, null), + list("Medium Armor", 0, /obj/item/clothing/suit/storage/marine/medium, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR), + + list("BACKPACK (CHOOSE 1)", 0, null, null, null), + list("Satchel", 0, /obj/item/storage/backpack/marine/satchel, MARINE_CAN_BUY_BACKPACK, VENDOR_ITEM_RECOMMENDED), + + list("BELT (CHOOSE 1)", 0, null, null, null), + list("M276 Ammo Load Rig", 0, /obj/item/storage/belt/marine, MARINE_CAN_BUY_BELT, VENDOR_ITEM_RECOMMENDED), + + list("POUCHES (CHOOSE 1)", 0, null, null, null), + list("Flare Pouch (Full)", 0, /obj/item/storage/pouch/flare/full, MARINE_CAN_BUY_GLASSES, VENDOR_ITEM_RECOMMENDED), + + )) // The pouch uses a different category so they only get one + +/obj/structure/machinery/cm_vending/clothing/tutorial + name = "\improper ColMarTech Automated Marine Equipment Rack" + desc = "An automated rack hooked up to a colossal storage of Marine Rifleman standard-issue equipment." + icon_state = "mar_rack" + show_points = TRUE + vendor_theme = VENDOR_THEME_USCM + req_access = list(ACCESS_TUTORIAL_LOCKED) + + vendor_role = list() + +/obj/structure/machinery/cm_vending/clothing/tutorial/get_listed_products(mob/user) + return GLOB.cm_vending_clothing_tutorial diff --git a/code/game/objects/effects/landmarks/landmarks.dm b/code/game/objects/effects/landmarks/landmarks.dm index 5f4a374ba31c..45cc6fd8b5fa 100644 --- a/code/game/objects/effects/landmarks/landmarks.dm +++ b/code/game/objects/effects/landmarks/landmarks.dm @@ -508,3 +508,7 @@ /// In landmarks.dm and not unit_test.dm so it is always active in the mapping tools. /obj/effect/landmark/unit_test_top_right name = "unit test zone top right" + +/// Marks the bottom left of the tutorial zone. +/obj/effect/landmark/tutorial_bottom_left + name = "tutorial bottom left" diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index ef9fcacf5647..7cb2781b253b 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -364,6 +364,7 @@ cases. Override_icon_state should be a list.*/ qdel(src) SEND_SIGNAL(src, COMSIG_ITEM_DROPPED, user) + SEND_SIGNAL(user, COMSIG_MOB_ITEM_DROPPED, src) if(drop_sound && (src.loc?.z)) playsound(src, drop_sound, dropvol, drop_vary) src.do_drop_animation(user) diff --git a/code/game/objects/items/devices/teleportation.dm b/code/game/objects/items/devices/teleportation.dm index 793f399ecdf0..8dea3b872cd1 100644 --- a/code/game/objects/items/devices/teleportation.dm +++ b/code/game/objects/items/devices/teleportation.dm @@ -48,7 +48,7 @@ if (usr.stat || usr.is_mob_restrained()) return var/turf/current_location = get_turf(usr)//What turf is the user on? - if(!current_location || is_admin_level(current_location.z))//If turf was not found or they're on z level 2. + if(!current_location || should_block_game_interaction(current_location))//If turf was not found or they're on z level 2. to_chat(usr, "[src] is malfunctioning.") return if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)))) @@ -140,7 +140,7 @@ ..() var/turf/current_location = get_turf(user)//What turf is the user on? - if(!current_location || is_admin_level(current_location.z))//If turf was not found or they're on z level 2 + if(!current_location || should_block_game_interaction(current_location))//If turf was not found or they're on z level 2 to_chat(user, SPAN_NOTICE("\The [src] is malfunctioning.")) return var/list/L = list( ) diff --git a/code/game/objects/items/reagent_containers/autoinjectors.dm b/code/game/objects/items/reagent_containers/autoinjectors.dm index 46463e628c1d..04a3a15585ab 100644 --- a/code/game/objects/items/reagent_containers/autoinjectors.dm +++ b/code/game/objects/items/reagent_containers/autoinjectors.dm @@ -139,6 +139,12 @@ item_state = "emptyskill" skilllock = SKILL_MEDICAL_DEFAULT +/obj/item/reagent_container/hypospray/autoinjector/tramadol/skillless/one_use + desc = "An EZ autoinjector loaded with 1 use of Tramadol, a weak but effective painkiller for normal wounds. Doesn't require any training to use." + volume = 15 + amount_per_transfer_from_this = 15 + uses_left = 1 + /obj/item/reagent_container/hypospray/autoinjector/oxycodone name = "oxycodone autoinjector (EXTREME PAINKILLER)" chemname = "oxycodone" @@ -164,6 +170,12 @@ item_state = "emptyskill" skilllock = SKILL_MEDICAL_DEFAULT +/obj/item/reagent_container/hypospray/autoinjector/kelotane/skillless/one_use + desc = "An EZ autoinjector loaded with 1 use of Kelotane, a common burn medicine. Doesn't require any training to use." + volume = 15 + amount_per_transfer_from_this = 15 + uses_left = 1 + /obj/item/reagent_container/hypospray/autoinjector/bicaridine name = "bicaridine autoinjector" chemname = "bicaridine" @@ -180,6 +192,12 @@ item_state = "emptyskill" skilllock = SKILL_MEDICAL_DEFAULT +/obj/item/reagent_container/hypospray/autoinjector/bicaridine/skillless/one_use + desc = "An EZ autoinjector loaded with 1 use of Bicaridine, a common brute and circulatory damage medicine. Doesn't require any training to use." + volume = 15 + amount_per_transfer_from_this = 15 + uses_left = 1 + /obj/item/reagent_container/hypospray/autoinjector/inaprovaline name = "inaprovaline autoinjector" chemname = "inaprovaline" diff --git a/code/game/objects/items/reagent_containers/food/snacks.dm b/code/game/objects/items/reagent_containers/food/snacks.dm index 927501286f13..076a4f77cf01 100644 --- a/code/game/objects/items/reagent_containers/food/snacks.dm +++ b/code/game/objects/items/reagent_containers/food/snacks.dm @@ -21,6 +21,7 @@ //Placeholder for effect that trigger on eating that aren't tied to reagents. /obj/item/reagent_container/food/snacks/proc/On_Consume(mob/M) SEND_SIGNAL(src, COMSIG_SNACK_EATEN, M) + SEND_SIGNAL(M, COMSIG_MOB_EATEN_SNACK, src) if(!usr) return if(!reagents.total_volume) diff --git a/code/game/objects/items/reagent_containers/hypospray.dm b/code/game/objects/items/reagent_containers/hypospray.dm index fcea8997f0b5..5e268d35a33d 100644 --- a/code/game/objects/items/reagent_containers/hypospray.dm +++ b/code/game/objects/items/reagent_containers/hypospray.dm @@ -206,6 +206,7 @@ to_chat(user, SPAN_NOTICE(" You inject [M] with [src].")) to_chat(M, SPAN_WARNING("You feel a tiny prick!")) playsound(loc, injectSFX, injectVOL, 1) + SEND_SIGNAL(M, COMSIG_LIVING_HYPOSPRAY_INJECTED, src) reagents.reaction(M, INGEST) if(M.reagents) diff --git a/code/game/objects/items/shards.dm b/code/game/objects/items/shards.dm index 84c3d5b83427..dab573e6f5a5 100644 --- a/code/game/objects/items/shards.dm +++ b/code/game/objects/items/shards.dm @@ -81,7 +81,7 @@ /obj/item/large_shrapnel/proc/on_embedded_movement(mob/living/embedded_mob) return -/obj/item/large_shrapnel/proc/on_embed(mob/embedded_mob, obj/limb/target_organ) +/obj/item/large_shrapnel/proc/on_embed(mob/embedded_mob, obj/limb/target_organ, silent = FALSE) return /obj/item/large_shrapnel/at_rocket_dud @@ -180,14 +180,14 @@ cell_explosion(get_turf(target), 200, 150, EXPLOSION_FALLOFF_SHAPE_LINEAR, direction, create_cause_data("[cause] UXO detonation", user)) qdel(src) -/obj/item/large_shrapnel/at_rocket_dud/on_embed(mob/embedded_mob, obj/limb/target_organ) +/obj/item/large_shrapnel/at_rocket_dud/on_embed(mob/embedded_mob, obj/limb/target_organ, silent = FALSE) if(!ishuman(embedded_mob)) return var/mob/living/carbon/human/H = embedded_mob if(H.species.flags & NO_SHRAPNEL) return if(istype(target_organ)) - target_organ.embed(src) + target_organ.embed(src, silent) /obj/item/large_shrapnel/at_rocket_dud/on_embedded_movement(mob/living/embedded_mob) if(!ishuman(embedded_mob)) @@ -212,14 +212,14 @@ source_sheet_type = null var/damage_on_move = 0.5 -/obj/item/shard/shrapnel/proc/on_embed(mob/embedded_mob, obj/limb/target_organ) +/obj/item/shard/shrapnel/proc/on_embed(mob/embedded_mob, obj/limb/target_organ, silent = FALSE) if(!ishuman(embedded_mob)) return var/mob/living/carbon/human/H = embedded_mob if(H.species.flags & NO_SHRAPNEL) return if(istype(target_organ)) - target_organ.embed(src) + target_organ.embed(src, silent) /obj/item/shard/shrapnel/proc/on_embedded_movement(mob/living/embedded_mob) if(!ishuman(embedded_mob)) @@ -228,7 +228,7 @@ if(H.species.flags & NO_SHRAPNEL) return var/obj/limb/organ = embedded_organ - if(istype(organ)) + if(istype(organ) && damage_on_move) organ.take_damage(damage_on_move * count, 0, 0, no_limb_loss = TRUE) embedded_mob.pain.apply_pain(damage_on_move * count) @@ -261,3 +261,7 @@ name = "alien bone fragments" icon_state = "alienbonechips" desc = "Sharp, jagged fragments of alien bone. Looks like the previous owner exploded violently..." + +/obj/item/shard/shrapnel/tutorial + damage_on_move = 0 + diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index f96903cfb687..5434aa006137 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -95,6 +95,9 @@ to_chat(user, SPAN_WARNING("There are no wounds on [possessive] [affecting.display_name].")) return TRUE +/obj/item/stack/medical/bruise_pack/two + amount = 2 + /obj/item/stack/medical/ointment name = "ointment" desc = "Used to treat burns, infected wounds, and relieve itching in unusual places." diff --git a/code/game/objects/items/weapons/blades.dm b/code/game/objects/items/weapons/blades.dm index 2fe80f123bce..a2a4aa8db75d 100644 --- a/code/game/objects/items/weapons/blades.dm +++ b/code/game/objects/items/weapons/blades.dm @@ -213,6 +213,8 @@ else INVOKE_ASYNC(embedded_human, TYPE_PROC_REF(/mob, emote), "me", 1, pick("winces.", "grimaces.", "flinches.")) + SEND_SIGNAL(embedded_human, COMSIG_HUMAN_SHRAPNEL_REMOVED) + else to_chat(user, SPAN_NOTICE("You couldn't find any shrapnel.")) diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm index 069d932d991b..bfc3c579f36c 100644 --- a/code/game/supplyshuttle.dm +++ b/code/game/supplyshuttle.dm @@ -1442,7 +1442,7 @@ GLOBAL_DATUM_INIT(supply_controller, /datum/controller/supply, new()) world.log << "## ERROR: Eek. The supply/elevator datum is missing somehow." return - if(!is_admin_level(SSshuttle.vehicle_elevator.z)) + if(!should_block_game_interaction(SSshuttle.vehicle_elevator)) to_chat(usr, SPAN_WARNING("The elevator needs to be in the cargo bay dock to call a vehicle up. Ask someone to send it away.")) return diff --git a/code/modules/admin/player_panel/actions/general.dm b/code/modules/admin/player_panel/actions/general.dm index a47a42d44cc2..e4ebc9fb85dd 100644 --- a/code/modules/admin/player_panel/actions/general.dm +++ b/code/modules/admin/player_panel/actions/general.dm @@ -68,17 +68,9 @@ message_admins("[key_name_admin(user)] has sent [key_name_admin(target)] back to the Lobby.") - var/mob/new_player/NP = new() - - if(!target.mind) - target.mind_initialize() - - target.mind.transfer_to(NP) - - qdel(target) + target.send_to_lobby() return TRUE - /datum/player_action/force_say action_tag = "mob_force_say" name = "Force Say" diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm index 300c999b885b..e9587319a160 100644 --- a/code/modules/asset_cache/asset_list_items.dm +++ b/code/modules/asset_cache/asset_list_items.dm @@ -378,6 +378,22 @@ Insert("[icon_name]_big", iconBig) return ..() +/datum/asset/spritesheet/tutorial + name = "tutorial" + +/datum/asset/spritesheet/tutorial/register() + for(var/icon_state in icon_states('icons/misc/tutorial.dmi')) + var/icon/icon_sprite = icon('icons/misc/tutorial.dmi', icon_state) + icon_sprite.Scale(128, 128) + Insert(icon_state, icon_sprite) + + var/icon/retrieved_icon = icon('icons/mob/hud/human_dark.dmi', "intent_all") + retrieved_icon.Scale(128, 128) + Insert("intents", retrieved_icon) + + return ..() + + /datum/asset/spritesheet/gun_lineart name = "gunlineart" diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index c11d35451656..29676ddb4ac8 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -239,6 +239,8 @@ GLOBAL_LIST_INIT(bgstate_options, list( /// if this client has tooltips enabled var/tooltips = TRUE + /// A list of tutorials that the client has completed, saved across rounds + var/list/completed_tutorials = list() /// If this client has auto observe enabled, used by /datum/orbit_menu var/auto_observe = TRUE @@ -1995,7 +1997,8 @@ GLOBAL_LIST_INIT(bgstate_options, list( if(!istype(character)) return - find_assigned_slot(job_title, is_late_join) + if(job_title) + find_assigned_slot(job_title, is_late_join) if(check_datacore && !(be_random_body && be_random_name)) for(var/datum/data/record/record as anything in GLOB.data_core.locked) if(record.fields["name"] == real_name) @@ -2302,6 +2305,22 @@ GLOBAL_LIST_INIT(bgstate_options, list( show_browser(user, dat, "Character Traits", "character_traits") update_preview_icon(TRUE) +/// Converts a client's list of completed tutorials into a string for saving +/datum/preferences/proc/tutorial_list_to_savestring() + if(!length(completed_tutorials)) + return "" + + var/return_string = "" + var/last_id = completed_tutorials[length(completed_tutorials)] + for(var/tutorial_id in completed_tutorials) + return_string += tutorial_id + (tutorial_id != last_id ? ";" : "") + return return_string + +/// Converts a saved string of completed tutorials into a list for in-game use +/datum/preferences/proc/tutorial_savestring_to_list(savestring) + completed_tutorials = splittext(savestring, ";") + return completed_tutorials + #undef MENU_MARINE #undef MENU_XENOMORPH #undef MENU_CO diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index c67effe90eb1..2261ddf5ebfa 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -480,6 +480,10 @@ S["uplinklocation"] >> uplinklocation S["exploit_record"] >> exploit_record + var/tutorial_string = "" + S["completed_tutorials"] >> tutorial_string + tutorial_savestring_to_list(tutorial_string) + //Sanitize metadata = sanitize_text(metadata, initial(metadata)) real_name = reject_bad_name(real_name) @@ -625,6 +629,8 @@ S["uplinklocation"] << uplinklocation S["exploit_record"] << exploit_record + S["completed_tutorials"] << tutorial_list_to_savestring() + return 1 /// checks through keybindings for outdated unbound keys and updates them diff --git a/code/modules/cm_marines/marines_consoles.dm b/code/modules/cm_marines/marines_consoles.dm index 994e9f1ddcb2..00a8c442b770 100644 --- a/code/modules/cm_marines/marines_consoles.dm +++ b/code/modules/cm_marines/marines_consoles.dm @@ -819,7 +819,7 @@ GLOBAL_LIST_EMPTY_TYPED(crewmonitor, /datum/crewmonitor) var/turf/pos = get_turf(H) if(!pos) continue - if(is_admin_level(pos.z)) + if(should_block_game_interaction(H)) continue // The entry for this human diff --git a/code/modules/cm_preds/yaut_items.dm b/code/modules/cm_preds/yaut_items.dm index c646d929d9f7..22e1318a7358 100644 --- a/code/modules/cm_preds/yaut_items.dm +++ b/code/modules/cm_preds/yaut_items.dm @@ -3,7 +3,7 @@ //Thrall subtypes are located in /code/modules/cm_preds/thrall_items.dm /proc/add_to_missing_pred_gear(obj/item/W) - if(!is_admin_level(W.z)) + if(!should_block_game_interaction(W)) GLOB.loose_yautja_gear |= W /proc/remove_from_missing_pred_gear(obj/item/W) @@ -393,7 +393,7 @@ var/mob/living/carbon/human/H = user var/ship_to_tele = list("Yautja Ship" = -1, "Human Ship" = "Human") - if(!HAS_TRAIT(H, TRAIT_YAUTJA_TECH) || is_admin_level(H.z)) + if(!HAS_TRAIT(H, TRAIT_YAUTJA_TECH) || should_block_game_interaction(H)) to_chat(user, SPAN_WARNING("You fiddle with it, but nothing happens!")) return diff --git a/code/modules/gear_presets/other.dm b/code/modules/gear_presets/other.dm index 3f773f90520e..d97a032337ee 100644 --- a/code/modules/gear_presets/other.dm +++ b/code/modules/gear_presets/other.dm @@ -952,3 +952,21 @@ new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/tools/tank(new_human), WEAR_R_STORE) //*****************************************************************************************************/ + + +/datum/equipment_preset/tutorial + name = "Tutorial" + faction = FACTION_MARINE + flags = EQUIPMENT_PRESET_EXTRA + faction_group = FACTION_LIST_MARINE + languages = list(LANGUAGE_ENGLISH) + idtype = /obj/item/card/id + /// If the player should start out underfed + var/underfed = TRUE + +/datum/equipment_preset/tutorial/load_status(mob/living/carbon/human/new_human) + if(underfed) + new_human.nutrition = NUTRITION_LOW + +/datum/equipment_preset/tutorial/fed + underfed = FALSE diff --git a/code/modules/gear_presets/uscm.dm b/code/modules/gear_presets/uscm.dm index 7cee0802e479..8289bdfe09cb 100644 --- a/code/modules/gear_presets/uscm.dm +++ b/code/modules/gear_presets/uscm.dm @@ -30,7 +30,7 @@ /datum/equipment_preset/uscm/load_preset(mob/living/carbon/human/new_human, randomise, count_participant) . = ..() - if(!auto_squad_name || (is_admin_level(new_human.z) && !ert_squad)) + if(!auto_squad_name || (should_block_game_interaction(new_human) && !ert_squad)) return if(!GLOB.data_core.manifest_modify(new_human.real_name, WEAKREF(new_human), assignment, rank)) GLOB.data_core.manifest_inject(new_human) diff --git a/code/modules/maptext_alerts/screen_alerts.dm b/code/modules/maptext_alerts/screen_alerts.dm index b096d3b3718f..8e59574ecf1f 100644 --- a/code/modules/maptext_alerts/screen_alerts.dm +++ b/code/modules/maptext_alerts/screen_alerts.dm @@ -64,6 +64,26 @@ style_open = "" style_close = "" +/atom/movable/screen/text/screen_text/command_order/tutorial + letters_per_update = 4 // overall, pretty fast while not immediately popping in + play_delay = 0.1 + fade_out_delay = 2.5 SECONDS + fade_out_time = 0.5 SECONDS + +/atom/movable/screen/text/screen_text/command_order/tutorial/end_play() + if(!player) + qdel(src) + return + + if(player.mob || HAS_TRAIT(player.mob, TRAIT_IN_TUTORIAL)) + return ..() + + for(var/atom/movable/screen/text/screen_text/command_order/tutorial/tutorial_message in player.screen_texts) + LAZYREMOVE(player.screen_texts, tutorial_message) + qdel(tutorial_message) + + return ..() + ///proc for actually playing this screen_text on a mob. /atom/movable/screen/text/screen_text/proc/play_to_client() player?.add_to_screen(src) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 430f959a7718..83bc0c3750f7 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -463,7 +463,7 @@ Works together with spawning an observer, noted above. ghost.langchat_make_image() SStgui.on_transfer(src, ghost) - if(is_admin_level((get_turf(src))?.z)) // Gibbed humans ghostize the brain in their head which itself is z 0 + if(should_block_game_interaction(src)) // Gibbed humans ghostize the brain in their head which itself is z 0 ghost.timeofdeath = 1 // Bypass respawn limit if you die on the admin zlevel ghost.key = key @@ -547,7 +547,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp msg_admin_niche("[key_name_admin(client)] has ghosted. [ADMIN_JMP(location)]") log_game("[key_name_admin(client)] has ghosted.") var/mob/dead/observer/ghost = ghostize((is_nested && nest && !QDELETED(nest))) //FALSE parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3 - if(ghost && !is_admin_level(z)) + SEND_SIGNAL(src, COMSIG_LIVING_GHOSTED, ghost) + if(ghost && !should_block_game_interaction(src)) ghost.timeofdeath = world.time // Larva queue: We use the larger of their existing queue time or the new timeofdeath except for facehuggers or lesser drone diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 26be5e97f9dd..d2e0db929624 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1748,3 +1748,28 @@ // clamped to max 500 if(dizziness > 100 && !is_dizzy) INVOKE_ASYNC(src, PROC_REF(dizzy_process)) + +/proc/setup_human(mob/living/carbon/human/target, mob/new_player/new_player, is_late_join = FALSE) + new_player.spawning = TRUE + new_player.close_spawn_windows() + new_player.client.prefs.copy_all_to(target, new_player.job, is_late_join) + + if(new_player.client.prefs.be_random_body) + var/datum/preferences/rand_prefs = new() + rand_prefs.randomize_appearance(target) + + target.job = new_player.job + target.name = new_player.real_name + target.voice = new_player.real_name + + if(new_player.mind) + new_player.mind_initialize() + new_player.mind.transfer_to(target, TRUE) + new_player.mind.setup_human_stats() + + target.sec_hud_set_ID() + target.hud_set_squad() + + INVOKE_ASYNC(target, TYPE_PROC_REF(/mob/living/carbon/human, regenerate_icons)) + INVOKE_ASYNC(target, TYPE_PROC_REF(/mob/living/carbon/human, update_body), 1, 0) + INVOKE_ASYNC(target, TYPE_PROC_REF(/mob/living/carbon/human, update_hair)) diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index 8f032288065b..f14b023b81da 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -4,9 +4,11 @@ if(..()) return TRUE + SEND_SIGNAL(attacking_mob, COMSIG_LIVING_ATTACKHAND_HUMAN, src) + if((attacking_mob != src) && check_shields(0, attacking_mob.name)) visible_message(SPAN_DANGER("[attacking_mob] attempted to touch [src]!"), null, null, 5) - return 0 + return FALSE switch(attacking_mob.a_intent) if(INTENT_HELP) diff --git a/code/modules/mob/living/carbon/human/human_dummy.dm b/code/modules/mob/living/carbon/human/human_dummy.dm index 061ac3cea05f..1f90c618fd38 100644 --- a/code/modules/mob/living/carbon/human/human_dummy.dm +++ b/code/modules/mob/living/carbon/human/human_dummy.dm @@ -73,3 +73,12 @@ GLOBAL_LIST_EMPTY(dummy_mob_list) /mob/living/carbon/human/dummy/add_to_all_mob_huds() return + + +/mob/living/carbon/human/dummy/tutorial // Effectively an even more disabled dummy + +/mob/living/carbon/human/dummy/tutorial/Initialize(mapload) + . = ..() + status_flags = GODMODE + ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_SOURCE_TUTORIAL) + anchored = TRUE diff --git a/code/modules/mob/living/carbon/xenomorph/Embryo.dm b/code/modules/mob/living/carbon/xenomorph/Embryo.dm index e799c21d3f20..9a1dfcb0e9a5 100644 --- a/code/modules/mob/living/carbon/xenomorph/Embryo.dm +++ b/code/modules/mob/living/carbon/xenomorph/Embryo.dm @@ -160,7 +160,7 @@ /obj/item/alien_embryo/proc/become_larva() // We do not allow chest bursts on the Centcomm Z-level, to prevent // stranded players from admin experiments and other issues - if(!affected_mob || is_admin_level(affected_mob.z)) + if(!affected_mob || should_block_game_interaction(affected_mob)) return stage = 6 // Increase the stage value to prevent this proc getting repeated diff --git a/code/modules/mob/living/carbon/xenomorph/Evolution.dm b/code/modules/mob/living/carbon/xenomorph/Evolution.dm index a2ade5cd0512..d6f963747e33 100644 --- a/code/modules/mob/living/carbon/xenomorph/Evolution.dm +++ b/code/modules/mob/living/carbon/xenomorph/Evolution.dm @@ -143,7 +143,7 @@ return var/area/xeno_area = get_area(new_xeno) - if(!is_admin_level(new_xeno.z) || (xeno_area.flags_atom & AREA_ALLOW_XENO_JOIN)) + if(!should_block_game_interaction(new_xeno) || (xeno_area.flags_atom & AREA_ALLOW_XENO_JOIN)) switch(new_xeno.tier) //They have evolved, add them to the slot count IF they are in regular game space if(2) hive.tier_2_xenos |= new_xeno diff --git a/code/modules/mob/living/carbon/xenomorph/XenoOverwatch.dm b/code/modules/mob/living/carbon/xenomorph/XenoOverwatch.dm index 3160c5e20bc7..0b0efbc0f34f 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoOverwatch.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoOverwatch.dm @@ -43,12 +43,12 @@ var/list/possible_xenos = list() for(var/mob/living/carbon/xenomorph/T in GLOB.living_xeno_list) - if (T != X && !is_admin_level(T.z) && X.hivenumber == T.hivenumber) // Can't overwatch yourself, Xenos in Thunderdome, or Xenos in other hives + if (T != X && !should_block_game_interaction(T) && X.hivenumber == T.hivenumber) // Can't overwatch yourself, Xenos in Thunderdome, or Xenos in other hives possible_xenos += T var/mob/living/carbon/xenomorph/selected_xeno = tgui_input_list(X, "Target", "Watch which xenomorph?", possible_xenos, theme="hive_status") - if (!selected_xeno || QDELETED(selected_xeno) || selected_xeno == X.observed_xeno || selected_xeno.stat == DEAD || is_admin_level(selected_xeno.z) || !X.check_state(TRUE)) + if (!selected_xeno || QDELETED(selected_xeno) || selected_xeno == X.observed_xeno || selected_xeno.stat == DEAD || should_block_game_interaction(selected_xeno) || !X.check_state(TRUE)) X.overwatch(X.observed_xeno, TRUE) // Cancel OW else if (!isQueen) // Regular Xeno OW vs Queen X.overwatch(selected_xeno) @@ -177,7 +177,7 @@ var/mob/living/carbon/xenomorph/xenoTarget = locate(href_list[XENO_OVERWATCH_TARGET_HREF]) in GLOB.living_xeno_list var/mob/living/carbon/xenomorph/xenoSrc = locate(href_list[XENO_OVERWATCH_SRC_HREF]) in GLOB.living_xeno_list - if(!istype(xenoTarget) || xenoTarget.stat == DEAD || is_admin_level(xenoTarget.z)) + if(!istype(xenoTarget) || xenoTarget.stat == DEAD || should_block_game_interaction(xenoTarget)) return if(!istype(xenoSrc) || xenoSrc.stat == DEAD) diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm index d8f92554c8b3..e924835f5882 100644 --- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm +++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm @@ -476,7 +476,7 @@ lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE // Only handle free slots if the xeno is not in tdome - if(hive && !is_admin_level(z)) + if(hive && !should_block_game_interaction(src)) var/selected_caste = GLOB.xeno_datum_list[caste_type]?.type hive.used_slots[selected_caste]++ @@ -1040,7 +1040,7 @@ /mob/living/carbon/xenomorph/ghostize(can_reenter_corpse = TRUE, aghosted = FALSE) . = ..() - if(. && !can_reenter_corpse && stat != DEAD && !QDELETED(src) && !is_admin_level(z)) + if(. && !can_reenter_corpse && stat != DEAD && !QDELETED(src) && !should_block_game_interaction(src)) handle_ghost_message() /mob/living/carbon/xenomorph/proc/handle_ghost_message() diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm b/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm index 15797041171f..c4c9b11b37e4 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm @@ -73,7 +73,11 @@ icon_xeno = 'icons/mob/xenos/drone.dmi' icon_xenonid = 'icons/mob/xenonids/drone.dmi' - weed_food_icon = 'icons/mob/xenos/weeds_48x48.dmi' weed_food_states = list("Drone_1","Drone_2","Drone_3") weed_food_states_flipped = list("Drone_1","Drone_2","Drone_3") + +/mob/living/carbon/xenomorph/drone/tutorial + +/mob/living/carbon/xenomorph/drone/tutorial/gib(datum/cause_data/cause = create_cause_data("gibbing", src)) + death(cause, 1) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm index 7416b85a13c4..6d082b327b48 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm @@ -58,7 +58,7 @@ if(hive.living_xeno_queen.hivenumber == hive.hivenumber) continue for(var/mob/living/carbon/xenomorph/queen/Q in GLOB.living_xeno_list) - if(Q.hivenumber == hive.hivenumber && !is_admin_level(Q.z)) + if(Q.hivenumber == hive.hivenumber && !should_block_game_interaction(Q)) hive.living_xeno_queen = Q xeno_message(SPAN_XENOANNOUNCE("A new Queen has risen to lead the Hive! Rejoice!"),3,hive.hivenumber) continue outer_loop @@ -396,7 +396,7 @@ /mob/living/carbon/xenomorph/queen/Initialize() . = ..() SStracking.set_leader("hive_[hivenumber]", src) - if(!is_admin_level(z))//so admins can safely spawn Queens in Thunderdome for tests. + if(!should_block_game_interaction(src))//so admins can safely spawn Queens in Thunderdome for tests. xeno_message(SPAN_XENOANNOUNCE("A new Queen has risen to lead the Hive! Rejoice!"),3,hivenumber) notify_ghosts(header = "New Queen", message = "A new Queen has risen.", source = src, action = NOTIFY_ORBIT) playsound(loc, 'sound/voice/alien_queen_command.ogg', 75, 0) @@ -502,7 +502,7 @@ if(hive && hive.living_xeno_queen == src) var/mob/living/carbon/xenomorph/queen/next_queen = null for(var/mob/living/carbon/xenomorph/queen/queen in hive.totalXenos) - if(!is_admin_level(queen.z) && queen != src && !QDELETED(queen)) + if(!should_block_game_interaction(queen) && queen != src && !QDELETED(queen)) next_queen = queen break hive.set_living_xeno_queen(next_queen) // either null or a queen diff --git a/code/modules/mob/living/carbon/xenomorph/death.dm b/code/modules/mob/living/carbon/xenomorph/death.dm index ea1e674a1faf..503ca11a7631 100644 --- a/code/modules/mob/living/carbon/xenomorph/death.dm +++ b/code/modules/mob/living/carbon/xenomorph/death.dm @@ -26,7 +26,7 @@ hud_used.alien_plasma_display.icon_state = "power_display_empty" update_icons() - if(!is_admin_level(z)) //so xeno players don't get death messages from admin tests + if(!should_block_game_interaction(src)) //so xeno players don't get death messages from admin tests if(isqueen(src)) var/mob/living/carbon/xenomorph/queen/XQ = src playsound(loc, 'sound/voice/alien_queen_died.ogg', 75, 0) diff --git a/code/modules/mob/living/carbon/xenomorph/hive_status.dm b/code/modules/mob/living/carbon/xenomorph/hive_status.dm index c035dd255ce1..83a90ded4205 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_status.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_status.dm @@ -206,7 +206,7 @@ // Can only have one queen. if(isqueen(X)) - if(!living_xeno_queen && !is_admin_level(X.z)) // Don't consider xenos in admin level + if(!living_xeno_queen && !should_block_game_interaction(X)) // Don't consider xenos in admin level set_living_xeno_queen(X) X.hivenumber = hivenumber @@ -218,7 +218,7 @@ X.hud_update() var/area/A = get_area(X) - if(!is_admin_level(X.z) || (A.flags_atom & AREA_ALLOW_XENO_JOIN)) + if(!should_block_game_interaction(X) || (A.flags_atom & AREA_ALLOW_XENO_JOIN)) totalXenos += X if(X.tier == 2) tier_2_xenos += X @@ -241,7 +241,7 @@ if(living_xeno_queen == xeno) var/mob/living/carbon/xenomorph/queen/next_queen = null for(var/mob/living/carbon/xenomorph/queen/queen in totalXenos) - if(!is_admin_level(queen.z) && queen != src && !QDELETED(queen)) + if(!should_block_game_interaction(queen) && queen != src && !QDELETED(queen)) next_queen = queen break @@ -264,7 +264,7 @@ tier_3_xenos -= xeno // Only handle free slots if the xeno is not in tdome - if(!is_admin_level(xeno.z)) + if(!should_block_game_interaction(xeno)) var/selected_caste = GLOB.xeno_datum_list[xeno.caste_type]?.type if(used_slots[selected_caste]) used_slots[selected_caste]-- @@ -408,7 +408,7 @@ for(var/mob/living/carbon/xenomorph/X in totalXenos) //don't show xenos in the thunderdome when admins test stuff. - if(is_admin_level(X.z)) + if(should_block_game_interaction(X)) var/area/A = get_area(X) if(!(A.flags_atom & AREA_ALLOW_XENO_JOIN)) continue @@ -427,7 +427,7 @@ var/index = 1 var/useless_slots = 0 for(var/mob/living/carbon/xenomorph/X in totalXenos) - if(is_admin_level(X.z)) + if(should_block_game_interaction(X)) var/area/A = get_area(X) if(!(A.flags_atom & AREA_ALLOW_XENO_JOIN)) useless_slots++ @@ -509,7 +509,7 @@ var/list/xenos = list() for(var/mob/living/carbon/xenomorph/X in totalXenos) - if(is_admin_level(X.z)) + if(should_block_game_interaction(X)) var/area/A = get_area(X) if(!(A.flags_atom & AREA_ALLOW_XENO_JOIN)) continue @@ -540,7 +540,7 @@ var/list/xenos = list() for(var/mob/living/carbon/xenomorph/X in totalXenos) - if(is_admin_level(X.z)) + if(should_block_game_interaction(X)) var/area/A = get_area(X) if(!(A.flags_atom & AREA_ALLOW_XENO_JOIN)) continue diff --git a/code/modules/mob/living/carbon/xenomorph/hive_status_ui.dm b/code/modules/mob/living/carbon/xenomorph/hive_status_ui.dm index 4fe1be51bfff..a71ddb7de292 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_status_ui.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_status_ui.dm @@ -175,7 +175,7 @@ var/mob/living/carbon/xenomorph/xenoTarget = locate(params["target_ref"]) in GLOB.living_xeno_list var/mob/living/carbon/xenomorph/xenoSrc = ui.user - if(QDELETED(xenoTarget) || xenoTarget.stat == DEAD || is_admin_level(xenoTarget.z)) + if(QDELETED(xenoTarget) || xenoTarget.stat == DEAD || should_block_game_interaction(xenoTarget)) return if(xenoSrc.stat == DEAD) @@ -188,7 +188,7 @@ var/mob/living/carbon/xenomorph/xenoTarget = locate(params["target_ref"]) in GLOB.living_xeno_list var/mob/living/carbon/xenomorph/xenoSrc = ui.user - if(QDELETED(xenoTarget) || xenoTarget.stat == DEAD || is_admin_level(xenoTarget.z)) + if(QDELETED(xenoTarget) || xenoTarget.stat == DEAD || should_block_game_interaction(xenoTarget)) return if(xenoSrc.stat == DEAD) @@ -201,7 +201,7 @@ var/mob/living/carbon/xenomorph/xenoTarget = locate(params["target_ref"]) in GLOB.living_xeno_list var/mob/living/carbon/xenomorph/xenoSrc = ui.user - if(QDELETED(xenoTarget) || xenoTarget.stat == DEAD || is_admin_level(xenoTarget.z)) + if(QDELETED(xenoTarget) || xenoTarget.stat == DEAD || should_block_game_interaction(xenoTarget)) return if(xenoSrc.stat == DEAD) diff --git a/code/modules/mob/living/carbon/xenomorph/mark_menu.dm b/code/modules/mob/living/carbon/xenomorph/mark_menu.dm index 5f7c1f8bc8c8..dd63f8a4fa70 100644 --- a/code/modules/mob/living/carbon/xenomorph/mark_menu.dm +++ b/code/modules/mob/living/carbon/xenomorph/mark_menu.dm @@ -180,7 +180,7 @@ var/list/possible_xenos = list() possible_xenos |= FunkTownOhyea for(var/mob/living/carbon/xenomorph/T in GLOB.living_xeno_list) - if (T != X && !is_admin_level(T.z) && X.hivenumber == T.hivenumber) + if (T != X && !should_block_game_interaction(T) && X.hivenumber == T.hivenumber) possible_xenos += T var/mob/living/carbon/xenomorph/selected_xeno = tgui_input_list(X, "Target", "Watch which xenomorph?", possible_xenos, theme="hive_status") @@ -195,7 +195,7 @@ . = TRUE update_all_data() return - if (!selected_xeno || QDELETED(selected_xeno) || selected_xeno.stat == DEAD || is_admin_level(selected_xeno.z) || !X.check_state(1)) + if (!selected_xeno || QDELETED(selected_xeno) || selected_xeno.stat == DEAD || should_block_game_interaction(selected_xeno) || !X.check_state(1)) return else selected_xeno.stop_tracking_resin_mark(FALSE, TRUE) diff --git a/code/modules/mob/living/silicon/ai/freelook/update_triggers.dm b/code/modules/mob/living/silicon/ai/freelook/update_triggers.dm index 7ecaab1c3e79..abb044d474e8 100644 --- a/code/modules/mob/living/silicon/ai/freelook/update_triggers.dm +++ b/code/modules/mob/living/silicon/ai/freelook/update_triggers.dm @@ -1,5 +1,3 @@ -#define BORG_CAMERA_BUFFER 5 - //UPDATE TRIGGERS, when the chunk (and the surrounding chunks) should update. // TURFS @@ -66,10 +64,9 @@ if(src.camera && src.camera.network.len) if(!updating) updating = 1 - spawn(BORG_CAMERA_BUFFER) - if(oldLoc != src.loc) - GLOB.cameranet.updatePortableCamera(src.camera) - updating = 0 + if(oldLoc != src.loc) + GLOB.cameranet.updatePortableCamera(src.camera) + updating = 0 /mob/living/carbon/human/var/updating = 0 @@ -83,10 +80,9 @@ if (updating) continue updating = TRUE - spawn(BORG_CAMERA_BUFFER) - if (oldLoc != loc) - GLOB.cameranet.updatePortableCamera(H.camera) - updating = FALSE + if (oldLoc != loc) + GLOB.cameranet.updatePortableCamera(H.camera) + updating = FALSE // CAMERA @@ -114,4 +110,3 @@ GLOB.cameranet.removeCamera(src) . = ..() -//#undef BORG_CAMERA_BUFFER diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 2ed1ee5e126c..5785197fdcd6 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -463,6 +463,7 @@ /mob/proc/swap_hand() hand = !hand + SEND_SIGNAL(src, COMSIG_MOB_SWAPPED_HAND) //attempt to pull/grab something. Returns true upon success. /mob/proc/start_pulling(atom/movable/AM, lunge, no_msg) @@ -989,6 +990,7 @@ note dizziness decrements automatically in the mob's Life() proc. /// Adds this list to the output to the stat browser /mob/proc/get_status_tab_items() . = list() + SEND_SIGNAL(src, COMSIG_MOB_GET_STATUS_TAB_ITEMS, .) /mob/proc/get_role_name() return @@ -1056,3 +1058,14 @@ note dizziness decrements automatically in the mob's Life() proc. /mob/proc/update_stat() return + +/// Send src back to the lobby as a `/mob/new_player()` +/mob/proc/send_to_lobby() + var/mob/new_player/new_player = new + + if(!mind) + mind_initialize() + + mind.transfer_to(new_player) + + qdel(src) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index f0e5bc48a855..f7f062295778 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -174,7 +174,7 @@ mouse_drag_pointer = MOUSE_ACTIVE_POINTER - var/status_flags = CANKNOCKDOWN|CANPUSH|STATUS_FLAGS_DEBILITATE //bitflags defining which status effects can be inflicted (replaces canweaken, canstun, etc) + var/status_flags = DEFAULT_MOB_STATUS_FLAGS //bitflags defining which status effects can be inflicted (replaces canweaken, canstun, etc) var/area/lastarea = null var/obj/control_object //Used by admins to possess objects. All mobs should have this var diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index e918a00b0984..b9c5dd12a8aa 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -87,6 +87,10 @@ ADD_TRAIT(victim, TRAIT_FLOORED, CHOKEHOLD_TRAIT) /obj/item/grab/proc/progress_passive(mob/living/carbon/human/user, mob/living/victim) + if(SEND_SIGNAL(victim, COMSIG_MOB_AGGRESSIVELY_GRABBED, user) & COMSIG_MOB_AGGRESIVE_GRAB_CANCEL) + to_chat(user, SPAN_WARNING("You can't grab [victim] aggressively!")) + return + user.grab_level = GRAB_AGGRESSIVE playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 25, 1, 7) user.visible_message(SPAN_WARNING("[user] has grabbed [victim] aggressively!"), null, null, 5) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 6abe12eee9b1..693eebabcb99 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -308,6 +308,8 @@ GLOBAL_LIST_INIT(limb_types_by_name, list( if(hud_used && hud_used.action_intent) hud_used.action_intent.icon_state = "intent_[intent_text(a_intent)]" + SEND_SIGNAL(src, COMSIG_MOB_INTENT_CHANGE, a_intent) + /mob/proc/is_mob_restrained() return diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 5e997db240c0..ccf649fb0509 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -42,6 +42,7 @@ var/output = "
Welcome," output +="
[(client.prefs && client.prefs.real_name) ? client.prefs.real_name : client.key]" output +="
[xeno_text]" + output += "

Tutorial

" output += "

Setup Character

" output += "

View Playtimes

" @@ -63,7 +64,7 @@ output += "
" if (refresh) close_browser(src, "playersetup") - show_browser(src, output, null, "playersetup", "size=240x[round_start ? 360 : 460];can_close=0;can_minimize=0") + show_browser(src, output, null, "playersetup", "size=240x[round_start ? 500 : 610];can_close=0;can_minimize=0") return /mob/new_player/Topic(href, href_list[]) @@ -162,6 +163,11 @@ to_chat(src, SPAN_WARNING("Sorry, you cannot late join during [SSticker.mode.name]. You have to start at the beginning of the round. You may observe or try to join as an alien, if possible.")) return + if(client.player_data?.playtime_loaded && (client.get_total_human_playtime() < CONFIG_GET(number/notify_new_player_age)) && !length(client.prefs.completed_tutorials)) + if(tgui_alert(src, "You have little playtime and haven't completed any tutorials. Would you like to go to the tutorial menu?", "Tutorial", list("Yes", "No")) == "Yes") + tutorial_menu() + return + if(client.prefs.species != "Human") if(!is_alien_whitelisted(src, client.prefs.species) && CONFIG_GET(flag/usealienwhitelist)) to_chat(src, "You are currently not whitelisted to play [client.prefs.species].") @@ -224,9 +230,28 @@ AttemptLateSpawn(href_list["job_selected"]) return + if("tutorial") + tutorial_menu() + else new_player_panel() +/mob/new_player/proc/tutorial_menu() + if(SSticker.current_state <= GAME_STATE_SETTING_UP) + to_chat(src, SPAN_WARNING("Please wait for the round to start before entering a tutorial.")) + return + + if(SSticker.current_state == GAME_STATE_FINISHED) + to_chat(src, SPAN_WARNING("The round has ended. Please wait for the next round to enter a tutorial.")) + return + + if(SSticker.tutorial_disabled) + to_chat(src, SPAN_WARNING("Tutorials are currently disabled because something broke, sorry!")) + return + + var/datum/tutorial_menu/menu = new(src) + menu.ui_interact(src) + /mob/new_player/proc/AttemptLateSpawn(rank) var/datum/job/player_rank = GLOB.RoleAuthority.roles_for_mode[rank] if (src != usr) @@ -280,7 +305,7 @@ var/client/client = character.client if(client.player_data && client.player_data.playtime_loaded && length(client.player_data.playtimes) == 0) msg_admin_niche("NEW PLAYER: [key_name(character, 1, 1, 0)]. IP: [character.lastKnownIP], CID: [character.computer_id]") - if(client.player_data && client.player_data.playtime_loaded && ((round(client.get_total_human_playtime() DECISECONDS_TO_HOURS, 0.1)) <= 5)) + if(client.player_data && client.player_data.playtime_loaded && ((round(client.get_total_human_playtime() DECISECONDS_TO_HOURS, 0.1)) <= CONFIG_GET(number/notify_new_player_age))) msg_sea("NEW PLAYER: [key_name(character, 0, 1, 0)] only has [(round(client.get_total_human_playtime() DECISECONDS_TO_HOURS, 0.1))] hours as a human. Current role: [get_actual_job_name(character)] - Current location: [get_area(character)]") character.client.init_verbs() @@ -370,30 +395,8 @@ new_character.lastarea = get_area(loc) - client.prefs.copy_all_to(new_character, job, is_late_join) - - if (client.prefs.be_random_body) - var/datum/preferences/TP = new() - TP.randomize_appearance(new_character) - - if(mind) - mind_initialize() - mind.active = 0 //we wish to transfer the key manually - mind.original = new_character - mind.transfer_to(new_character) //won't transfer key since the mind is not active - mind.setup_human_stats() - - new_character.job = job - new_character.name = real_name - new_character.voice = real_name - - // Update the character icons - // This is done in set_species when the mob is created as well, but - INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, regenerate_icons)) - INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, update_body), 1, 0) - INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, update_hair)) + setup_human(new_character, src, is_late_join) - new_character.key = key //Manually transfer the key to log them in new_character.client?.change_view(GLOB.world_view_size) return new_character diff --git a/code/modules/organs/limbs.dm b/code/modules/organs/limbs.dm index 8df96650ac50..718aba208f5a 100644 --- a/code/modules/organs/limbs.dm +++ b/code/modules/organs/limbs.dm @@ -547,6 +547,7 @@ This function completely restores a damaged organ to perfect condition. /obj/limb/proc/remove_all_bleeding(external = FALSE, internal = FALSE) + SEND_SIGNAL(src, COMSIG_LIMB_STOP_BLEEDING, external, internal) if(external) for(var/datum/effects/bleeding/external/B in bleeding_effects_list) qdel(B) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index c41a57f53527..3a444e1ad1fc 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -843,6 +843,7 @@ User can be passed as null, (a gun reloading itself for instance), so we need to to_chat(user, SPAN_WARNING("Your reload was interrupted!")) return replace_magazine(user, magazine) + SEND_SIGNAL(user, COMSIG_MOB_RELOADED_GUN, src) else current_mag = magazine magazine.forceMove(src) @@ -1048,6 +1049,7 @@ and you're good to go. user.swap_hand() unload(user, TRUE, drop_to_ground) // We want to quickly autoeject the magazine. This proc does the rest based on magazine type. User can be passed as null. playsound(src, empty_sound, 25, 1) + SEND_SIGNAL(user, COMSIG_MOB_GUN_EMPTY, src) else // Just fired a chambered bullet with no magazine in the gun update_icon() diff --git a/colonialmarines.dme b/colonialmarines.dme index ca8e80ef5067..814674c57f06 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -78,6 +78,7 @@ #include "code\__DEFINES\MC.dm" #include "code\__DEFINES\minimap.dm" #include "code\__DEFINES\misc.dm" +#include "code\__DEFINES\mob.dm" #include "code\__DEFINES\mob_hud.dm" #include "code\__DEFINES\mobs.dm" #include "code\__DEFINES\mode.dm" @@ -111,6 +112,7 @@ #include "code\__DEFINES\tgui.dm" #include "code\__DEFINES\traits.dm" #include "code\__DEFINES\turf_flags.dm" +#include "code\__DEFINES\tutorial.dm" #include "code\__DEFINES\unit_tests.dm" #include "code\__DEFINES\urls.dm" #include "code\__DEFINES\vehicle.dm" @@ -403,6 +405,7 @@ #include "code\datums\components\rename.dm" #include "code\datums\components\speed_modifier.dm" #include "code\datums\components\toxin_buildup.dm" +#include "code\datums\components\tutorial_status.dm" #include "code\datums\components\weed_damage_reduction.dm" #include "code\datums\components\weed_food.dm" #include "code\datums\components\autofire\_automated_fire.dm" @@ -663,6 +666,15 @@ #include "code\datums\supply_packs\spec_ammo.dm" #include "code\datums\supply_packs\vehicle_ammo.dm" #include "code\datums\supply_packs\weapons.dm" +#include "code\datums\tutorial\_tutorial.dm" +#include "code\datums\tutorial\_tutorial_menu.dm" +#include "code\datums\tutorial\tutorial_example.dm" +#include "code\datums\tutorial\marine\_marine.dm" +#include "code\datums\tutorial\marine\basic_marine.dm" +#include "code\datums\tutorial\marine\medical_basic.dm" +#include "code\datums\tutorial\ss13\_ss13.dm" +#include "code\datums\tutorial\ss13\basic_ss13.dm" +#include "code\datums\tutorial\ss13\intents.dm" #include "code\datums\weather\weather_event.dm" #include "code\datums\weather\weather_map_holder.dm" #include "code\datums\weather\weather_events\big_red.dm" @@ -972,6 +984,7 @@ #include "code\game\machinery\vending\vendor_types\squad_prep\squad_smartgunner.dm" #include "code\game\machinery\vending\vendor_types\squad_prep\squad_specialist.dm" #include "code\game\machinery\vending\vendor_types\squad_prep\squad_tl.dm" +#include "code\game\machinery\vending\vendor_types\squad_prep\tutorial.dm" #include "code\game\objects\empulse.dm" #include "code\game\objects\explosion.dm" #include "code\game\objects\explosion_recursive.dm" diff --git a/icons/misc/tutorial.dmi b/icons/misc/tutorial.dmi new file mode 100644 index 0000000000000000000000000000000000000000..d4a4e65963bae84566e373354e0fe2535b60bebc GIT binary patch literal 938 zcmV;b16BNqP)A|G{004JLA3P`!=BJhIv6#4xhgm5AKsqoE7$rG8RU|4vU~7{{QgR~~2x47D zjErpA+3@`Q{0ImW1_%u;EiEi7D>pSYWkoHpf=+m2M{id+Nk~YPaz=w+K*q+kpP-5l z4;~Q_5e*Fu9UUDuHa1dHQcO%tBqSsp9307#Jox|s00DGTPE!Ct=GbNc0044&R9JLG zWpiV4X>fFDZ*Bkpc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGjE%TB zGg33tGfE(w;*!LYR3K9+H?b%)FI9<)GbOXA7${)K#hF%=n41b=!<7{m8ye$Mq^#iT z=K{7I01MS5Z(0qL_W%F_AW1|)R7i=PREu)jFc8$sk=ukMZCpf&SeaDFiwjV{guDqd>gp(UXZTwYyYUH`bG1Q4k_phKka^8hkMc@zD@b3+wj-11{8 z1v81F-%&I%L<-}Urv#XpVn;NY8frt!Q#3Q!F#%5sv^=#U7(>-R2}zvdiCx^x0}43D zIagsADxMFW<|IXMnr5k=v%Wxa$GI?aHlIl&IKL}8JbXJ80Kpic5O)P^VVN|u`}zIM z$Y#~ez@dux>nv`5^(<(sA#iXYn^i}^E$})xa4umB*AplomZiwW98WIFwe1VA zvSb#mlxU&#i!N3bLje<)_#RgMcn@v4N3VciNDzwIF(^b literal 0 HcmV?d00001 diff --git a/icons/turf/areas.dmi b/icons/turf/areas.dmi index 8b525fd568d68530afa65fc0f304825857e600cd..c8bf32b00b40b7efdb62aa216bf501c068db2792 100644 GIT binary patch delta 4454 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 tVBwGL{qiPgPefqB=~!`LLf!ghrO$PJMRf { + const { data, act } = useBackend(context); + const { tutorial_categories, completed_tutorials } = data; + const [chosenTutorial, setTutorial] = useLocalState( + context, + 'tutorial', + null + ); + const [categoryIndex, setCategoryIndex] = useLocalState( + context, + 'category_index', + 'Space Station 13' + ); + return ( + + + + + + + {tutorial_categories.map((item, key) => ( + { + setCategoryIndex(item.name); + }}> + {item.name} + + ))} + + + + + +
+ {tutorial_categories.map( + (tutorial_category) => + tutorial_category.name === categoryIndex && + tutorial_category.tutorials.map((tutorial) => ( +
+ +
+ )) + )} +
+
+ + +
+ {chosenTutorial !== null ? ( + + +
+ + + +
+
+ {chosenTutorial.description} + {completed_tutorials.indexOf(chosenTutorial.id) === -1 ? ( +
+ ) : ( + + Tutorial has been completed. + + )} + +
+
+
+
+
+
+ ); +}; From d7feab9569e83acb54a66c77b102d50de4ea5a1c Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 29 Dec 2023 18:04:48 +0000 Subject: [PATCH 20/28] Automatic changelog for PR #5030 [ci skip] --- html/changelogs/AutoChangeLog-pr-5030.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-5030.yml diff --git a/html/changelogs/AutoChangeLog-pr-5030.yml b/html/changelogs/AutoChangeLog-pr-5030.yml new file mode 100644 index 000000000000..0cce25ff019a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-5030.yml @@ -0,0 +1,4 @@ +author: "Zonespace27" +delete-after: True +changes: + - rscadd: "Added a tutorial system for various roles (and just general information), find it in the lobby screen." \ No newline at end of file From 0ff2e6f1bb00d03b3d1f417849c3df724f7634d0 Mon Sep 17 00:00:00 2001 From: Cthulhu80 <122310258+Cthulhu80@users.noreply.github.com> Date: Fri, 29 Dec 2023 11:13:51 -0800 Subject: [PATCH 21/28] Fixes immobilized mobs being able to buckle onto chairs (#5317) # About the pull request #5277, fixes the issue outlined here, incapacitated marines should not be able to buckle themselves. # Explain why it's good for the game bug bad # Changelog :cl: fix: fixes immobilized mobs being able to buckle themselves /:cl: --- code/game/objects/objs.dm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index cc9f1fe53fea..7747a45ed9da 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -278,6 +278,11 @@ if (iszombie(user)) return + // mobs that become immobilized should not be able to buckle themselves. + if(M == user && HAS_TRAIT(user, TRAIT_IMMOBILIZED)) + to_chat(user, SPAN_WARNING("You are unable to do this in your current state.")) + return + if(density) density = FALSE if(!step(M, get_dir(M, src)) && loc != M.loc) From 68ccb744450d397030e494751cf258b3208309d0 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 29 Dec 2023 19:21:35 +0000 Subject: [PATCH 22/28] Automatic changelog for PR #5317 [ci skip] --- html/changelogs/AutoChangeLog-pr-5317.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-5317.yml diff --git a/html/changelogs/AutoChangeLog-pr-5317.yml b/html/changelogs/AutoChangeLog-pr-5317.yml new file mode 100644 index 000000000000..b5f7cd72accb --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-5317.yml @@ -0,0 +1,4 @@ +author: "Cthulhu80" +delete-after: True +changes: + - bugfix: "fixes immobilized mobs being able to buckle themselves" \ No newline at end of file From adb5b8e46a8bb488be2a952db5ca1e24c15b7345 Mon Sep 17 00:00:00 2001 From: Paul Mullen <101871009+mullenpaul@users.noreply.github.com> Date: Fri, 29 Dec 2023 19:31:51 +0000 Subject: [PATCH 23/28] migrated js components to jsx (#5307) # About the pull request First round of refactors for TGUI-5 migration. Here all TGUI interfaces and components have been changed from .js to .jsx. This is to closer align us to the standards of tgstation. Within the components themselves there are no functional changes. Files of interest: - tgui/webpack.config.js - tgui/packages/tgui/routes.jsx - tgui/packages/tgui/interfaces/Filteriffic.jsx - tgui/packages/tgui/debug/KitchenSink.jsx The rest of the file changes should just be .js -> .jsx # Explain why it's good for the game Groundwork prep for TGUI 5 # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: refactor: tgui js components now jsx /:cl: --- tgui/packages/tgui/components/{Blink.js => Blink.jsx} | 0 .../tgui/components/{BlockQuote.js => BlockQuote.jsx} | 0 tgui/packages/tgui/components/{Button.js => Button.jsx} | 0 tgui/packages/tgui/components/{ByondUi.js => ByondUi.jsx} | 0 tgui/packages/tgui/components/{Chart.js => Chart.jsx} | 0 .../tgui/components/{Collapsible.js => Collapsible.jsx} | 0 tgui/packages/tgui/components/{ColorBox.js => ColorBox.jsx} | 0 tgui/packages/tgui/components/{Dimmer.js => Dimmer.jsx} | 0 tgui/packages/tgui/components/{Divider.js => Divider.jsx} | 0 .../components/{DraggableControl.js => DraggableControl.jsx} | 0 tgui/packages/tgui/components/{Dropdown.js => Dropdown.jsx} | 0 tgui/packages/tgui/components/{Grid.js => Grid.jsx} | 0 tgui/packages/tgui/components/{Icon.js => Icon.jsx} | 0 .../tgui/components/{InfinitePlane.js => InfinitePlane.jsx} | 0 tgui/packages/tgui/components/{Input.js => Input.jsx} | 0 tgui/packages/tgui/components/{Knob.js => Knob.jsx} | 0 .../components/{LabeledControls.js => LabeledControls.jsx} | 0 tgui/packages/tgui/components/{Modal.js => Modal.jsx} | 0 tgui/packages/tgui/components/{NoticeBox.js => NoticeBox.jsx} | 0 .../tgui/components/{NumberInput.js => NumberInput.jsx} | 0 .../tgui/components/{ProgressBar.js => ProgressBar.jsx} | 0 .../components/{RestrictedInput.js => RestrictedInput.jsx} | 0 .../tgui/components/{RoundGauge.js => RoundGauge.jsx} | 0 tgui/packages/tgui/components/{Slider.js => Slider.jsx} | 0 tgui/packages/tgui/components/{Table.js => Table.jsx} | 0 tgui/packages/tgui/components/{Tabs.js => Tabs.jsx} | 0 tgui/packages/tgui/components/{TextArea.js => TextArea.jsx} | 0 .../tgui/components/{TimeDisplay.js => TimeDisplay.jsx} | 0 tgui/packages/tgui/components/{index.js => index.jsx} | 0 tgui/packages/tgui/debug/{KitchenSink.js => KitchenSink.jsx} | 2 +- tgui/packages/tgui/interfaces/{AcidVest.js => AcidVest.jsx} | 0 .../tgui/interfaces/{AlmayerControl.js => AlmayerControl.jsx} | 0 .../{AltitudeControlConsole.js => AltitudeControlConsole.jsx} | 0 .../tgui/interfaces/{AntiAirConsole.js => AntiAirConsole.jsx} | 0 tgui/packages/tgui/interfaces/{Apc.js => Apc.jsx} | 0 .../tgui/interfaces/{AresInterface.js => AresInterface.jsx} | 0 .../tgui/interfaces/{Autodispenser.js => Autodispenser.jsx} | 0 tgui/packages/tgui/interfaces/{Autolathe.js => Autolathe.jsx} | 0 .../tgui/interfaces/{Binoculars.js => Binoculars.jsx} | 0 .../{BioSyntheticPrinter.js => BioSyntheticPrinter.jsx} | 0 .../tgui/interfaces/{BotanyEditor.js => BotanyEditor.jsx} | 0 .../interfaces/{BotanyExtractor.js => BotanyExtractor.jsx} | 0 tgui/packages/tgui/interfaces/{BrigCell.js => BrigCell.jsx} | 0 .../tgui/interfaces/{CameraConsole.js => CameraConsole.jsx} | 0 .../tgui/interfaces/{CanvasLayer.js => CanvasLayer.jsx} | 0 tgui/packages/tgui/interfaces/{CardMod.js => CardMod.jsx} | 0 .../tgui/interfaces/{Centrifuge.js => Centrifuge.jsx} | 0 tgui/packages/tgui/interfaces/{Changelog.js => Changelog.jsx} | 0 .../tgui/interfaces/{ChemDispenser.js => ChemDispenser.jsx} | 0 .../tgui/interfaces/{ChooseFruit.js => ChooseFruit.jsx} | 0 .../tgui/interfaces/{ChooseResin.js => ChooseResin.jsx} | 0 .../tgui/interfaces/{CommandTablet.js => CommandTablet.jsx} | 0 .../tgui/interfaces/{CrewConsole.js => CrewConsole.jsx} | 0 tgui/packages/tgui/interfaces/{Cryo.js => Cryo.jsx} | 0 tgui/packages/tgui/interfaces/{DemoSim.js => DemoSim.jsx} | 0 tgui/packages/tgui/interfaces/{Disposals.js => Disposals.jsx} | 0 tgui/packages/tgui/interfaces/{DrawnMap.js => DrawnMap.jsx} | 0 .../tgui/interfaces/{FaxMachine.js => FaxMachine.jsx} | 0 .../tgui/interfaces/{Filteriffic.js => Filteriffic.jsx} | 2 +- .../{FiltrationControl.js => FiltrationControl.jsx} | 0 .../tgui/interfaces/{HealthScan.js => HealthScan.jsx} | 0 .../tgui/interfaces/{HiveFaction.js => HiveFaction.jsx} | 0 .../tgui/interfaces/{HiveLeaders.js => HiveLeaders.jsx} | 0 .../tgui/interfaces/{HiveStatus.js => HiveStatus.jsx} | 0 tgui/packages/tgui/interfaces/{KeyBinds.js => KeyBinds.jsx} | 0 tgui/packages/tgui/interfaces/{KillPanel.js => KillPanel.jsx} | 0 .../tgui/interfaces/{LanguageMenu.js => LanguageMenu.jsx} | 0 tgui/packages/tgui/interfaces/{ListInput.js => ListInput.jsx} | 0 .../tgui/interfaces/{MedalsPanel.js => MedalsPanel.jsx} | 0 tgui/packages/tgui/interfaces/{Mortar.js => Mortar.jsx} | 0 .../tgui/interfaces/{NuclearBomb.js => NuclearBomb.jsx} | 0 .../{OrbitalCannonConsole.js => OrbitalCannonConsole.jsx} | 0 .../interfaces/{OverwatchConsole.js => OverwatchConsole.jsx} | 0 .../tgui/interfaces/{PartFabricator.js => PartFabricator.jsx} | 0 tgui/packages/tgui/interfaces/{PhoneMenu.js => PhoneMenu.jsx} | 0 .../tgui/interfaces/{PlayerPanel.js => PlayerPanel.jsx} | 0 .../tgui/interfaces/{PodLauncher.js => PodLauncher.jsx} | 0 tgui/packages/tgui/interfaces/{Proximity.js => Proximity.jsx} | 0 tgui/packages/tgui/interfaces/{Radio.js => Radio.jsx} | 0 .../{ResearchDoorDisplay.js => ResearchDoorDisplay.jsx} | 0 .../interfaces/{ResearchMemories.js => ResearchMemories.jsx} | 0 tgui/packages/tgui/interfaces/{STUI.js => STUI.jsx} | 0 .../{SelfDestructConsole.js => SelfDestructConsole.jsx} | 0 .../tgui/interfaces/{Sentencing.js => Sentencing.jsx} | 0 tgui/packages/tgui/interfaces/{Signaller.js => Signaller.jsx} | 0 .../tgui/interfaces/{SkillsMenu.js => SkillsMenu.jsx} | 0 tgui/packages/tgui/interfaces/{Sleeper.js => Sleeper.jsx} | 0 tgui/packages/tgui/interfaces/{Smes.js => Smes.jsx} | 0 tgui/packages/tgui/interfaces/{SquadMod.js => SquadMod.jsx} | 0 .../{StatbrowserOptions.js => StatbrowserOptions.jsx} | 0 .../{StationAlertConsole.js => StationAlertConsole.jsx} | 0 .../{SupplyDropConsole.js => SupplyDropConsole.jsx} | 0 .../interfaces/{TacmapAdminPanel.js => TacmapAdminPanel.jsx} | 0 tgui/packages/tgui/interfaces/{Tank.js => Tank.jsx} | 0 .../tgui/interfaces/{TechControl.js => TechControl.jsx} | 0 .../tgui/interfaces/{TechMemories.js => TechMemories.jsx} | 0 tgui/packages/tgui/interfaces/{TechNode.js => TechNode.jsx} | 0 .../{TeleporterConsole.js => TeleporterConsole.jsx} | 0 tgui/packages/tgui/interfaces/{Timer.js => Timer.jsx} | 0 .../tgui/interfaces/{VehicleStatus.js => VehicleStatus.jsx} | 0 tgui/packages/tgui/interfaces/{VoteMenu.js => VoteMenu.jsx} | 0 tgui/packages/tgui/interfaces/{VoxPanel.js => VoxPanel.jsx} | 0 .../tgui/interfaces/{WeaponStats.js => WeaponStats.jsx} | 0 tgui/packages/tgui/interfaces/{Wires.js => Wires.jsx} | 0 .../tgui/interfaces/{WorkingJoe.js => WorkingJoe.jsx} | 0 .../tgui/interfaces/common/{AccessList.js => AccessList.jsx} | 0 .../common/{BeakerContents.js => BeakerContents.jsx} | 0 .../{InterfaceLockNoticeBox.js => InterfaceLockNoticeBox.jsx} | 0 tgui/packages/tgui/layouts/{Layout.js => Layout.jsx} | 0 tgui/packages/tgui/layouts/{NtosWindow.js => NtosWindow.jsx} | 0 tgui/packages/tgui/layouts/{Pane.js => Pane.jsx} | 0 tgui/packages/tgui/layouts/{Window.js => Window.jsx} | 0 tgui/packages/tgui/{routes.js => routes.jsx} | 1 + .../tgui/stories/{Blink.stories.js => Blink.stories.jsx} | 0 .../stories/{BlockQuote.stories.js => BlockQuote.stories.jsx} | 0 .../packages/tgui/stories/{Box.stories.js => Box.stories.jsx} | 0 .../tgui/stories/{Button.stories.js => Button.stories.jsx} | 0 .../tgui/stories/{ByondUi.stories.js => ByondUi.stories.jsx} | 0 .../{Collapsible.stories.js => Collapsible.stories.jsx} | 0 .../tgui/stories/{Flex.stories.js => Flex.stories.jsx} | 0 .../tgui/stories/{Input.stories.js => Input.stories.jsx} | 0 .../{LabeledList.stories.js => LabeledList.stories.jsx} | 0 .../tgui/stories/{Popper.stories.js => Popper.stories.jsx} | 0 .../{ProgressBar.stories.js => ProgressBar.stories.jsx} | 0 .../tgui/stories/{Stack.stories.js => Stack.stories.jsx} | 0 .../tgui/stories/{Storage.stories.js => Storage.stories.jsx} | 0 .../tgui/stories/{Tabs.stories.js => Tabs.stories.jsx} | 0 .../tgui/stories/{Themes.stories.js => Themes.stories.jsx} | 0 .../tgui/stories/{Tooltip.stories.js => Tooltip.stories.jsx} | 0 tgui/packages/tgui/stories/{common.js => common.jsx} | 0 tgui/webpack.config.js | 4 ++-- 131 files changed, 5 insertions(+), 4 deletions(-) rename tgui/packages/tgui/components/{Blink.js => Blink.jsx} (100%) rename tgui/packages/tgui/components/{BlockQuote.js => BlockQuote.jsx} (100%) rename tgui/packages/tgui/components/{Button.js => Button.jsx} (100%) rename tgui/packages/tgui/components/{ByondUi.js => ByondUi.jsx} (100%) rename tgui/packages/tgui/components/{Chart.js => Chart.jsx} (100%) rename tgui/packages/tgui/components/{Collapsible.js => Collapsible.jsx} (100%) rename tgui/packages/tgui/components/{ColorBox.js => ColorBox.jsx} (100%) rename tgui/packages/tgui/components/{Dimmer.js => Dimmer.jsx} (100%) rename tgui/packages/tgui/components/{Divider.js => Divider.jsx} (100%) rename tgui/packages/tgui/components/{DraggableControl.js => DraggableControl.jsx} (100%) rename tgui/packages/tgui/components/{Dropdown.js => Dropdown.jsx} (100%) rename tgui/packages/tgui/components/{Grid.js => Grid.jsx} (100%) rename tgui/packages/tgui/components/{Icon.js => Icon.jsx} (100%) rename tgui/packages/tgui/components/{InfinitePlane.js => InfinitePlane.jsx} (100%) rename tgui/packages/tgui/components/{Input.js => Input.jsx} (100%) rename tgui/packages/tgui/components/{Knob.js => Knob.jsx} (100%) rename tgui/packages/tgui/components/{LabeledControls.js => LabeledControls.jsx} (100%) rename tgui/packages/tgui/components/{Modal.js => Modal.jsx} (100%) rename tgui/packages/tgui/components/{NoticeBox.js => NoticeBox.jsx} (100%) rename tgui/packages/tgui/components/{NumberInput.js => NumberInput.jsx} (100%) rename tgui/packages/tgui/components/{ProgressBar.js => ProgressBar.jsx} (100%) rename tgui/packages/tgui/components/{RestrictedInput.js => RestrictedInput.jsx} (100%) rename tgui/packages/tgui/components/{RoundGauge.js => RoundGauge.jsx} (100%) rename tgui/packages/tgui/components/{Slider.js => Slider.jsx} (100%) rename tgui/packages/tgui/components/{Table.js => Table.jsx} (100%) rename tgui/packages/tgui/components/{Tabs.js => Tabs.jsx} (100%) rename tgui/packages/tgui/components/{TextArea.js => TextArea.jsx} (100%) rename tgui/packages/tgui/components/{TimeDisplay.js => TimeDisplay.jsx} (100%) rename tgui/packages/tgui/components/{index.js => index.jsx} (100%) rename tgui/packages/tgui/debug/{KitchenSink.js => KitchenSink.jsx} (95%) rename tgui/packages/tgui/interfaces/{AcidVest.js => AcidVest.jsx} (100%) rename tgui/packages/tgui/interfaces/{AlmayerControl.js => AlmayerControl.jsx} (100%) rename tgui/packages/tgui/interfaces/{AltitudeControlConsole.js => AltitudeControlConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{AntiAirConsole.js => AntiAirConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{Apc.js => Apc.jsx} (100%) rename tgui/packages/tgui/interfaces/{AresInterface.js => AresInterface.jsx} (100%) rename tgui/packages/tgui/interfaces/{Autodispenser.js => Autodispenser.jsx} (100%) rename tgui/packages/tgui/interfaces/{Autolathe.js => Autolathe.jsx} (100%) rename tgui/packages/tgui/interfaces/{Binoculars.js => Binoculars.jsx} (100%) rename tgui/packages/tgui/interfaces/{BioSyntheticPrinter.js => BioSyntheticPrinter.jsx} (100%) rename tgui/packages/tgui/interfaces/{BotanyEditor.js => BotanyEditor.jsx} (100%) rename tgui/packages/tgui/interfaces/{BotanyExtractor.js => BotanyExtractor.jsx} (100%) rename tgui/packages/tgui/interfaces/{BrigCell.js => BrigCell.jsx} (100%) rename tgui/packages/tgui/interfaces/{CameraConsole.js => CameraConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{CanvasLayer.js => CanvasLayer.jsx} (100%) rename tgui/packages/tgui/interfaces/{CardMod.js => CardMod.jsx} (100%) rename tgui/packages/tgui/interfaces/{Centrifuge.js => Centrifuge.jsx} (100%) rename tgui/packages/tgui/interfaces/{Changelog.js => Changelog.jsx} (100%) rename tgui/packages/tgui/interfaces/{ChemDispenser.js => ChemDispenser.jsx} (100%) rename tgui/packages/tgui/interfaces/{ChooseFruit.js => ChooseFruit.jsx} (100%) rename tgui/packages/tgui/interfaces/{ChooseResin.js => ChooseResin.jsx} (100%) rename tgui/packages/tgui/interfaces/{CommandTablet.js => CommandTablet.jsx} (100%) rename tgui/packages/tgui/interfaces/{CrewConsole.js => CrewConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{Cryo.js => Cryo.jsx} (100%) rename tgui/packages/tgui/interfaces/{DemoSim.js => DemoSim.jsx} (100%) rename tgui/packages/tgui/interfaces/{Disposals.js => Disposals.jsx} (100%) rename tgui/packages/tgui/interfaces/{DrawnMap.js => DrawnMap.jsx} (100%) rename tgui/packages/tgui/interfaces/{FaxMachine.js => FaxMachine.jsx} (100%) rename tgui/packages/tgui/interfaces/{Filteriffic.js => Filteriffic.jsx} (99%) rename tgui/packages/tgui/interfaces/{FiltrationControl.js => FiltrationControl.jsx} (100%) rename tgui/packages/tgui/interfaces/{HealthScan.js => HealthScan.jsx} (100%) rename tgui/packages/tgui/interfaces/{HiveFaction.js => HiveFaction.jsx} (100%) rename tgui/packages/tgui/interfaces/{HiveLeaders.js => HiveLeaders.jsx} (100%) rename tgui/packages/tgui/interfaces/{HiveStatus.js => HiveStatus.jsx} (100%) rename tgui/packages/tgui/interfaces/{KeyBinds.js => KeyBinds.jsx} (100%) rename tgui/packages/tgui/interfaces/{KillPanel.js => KillPanel.jsx} (100%) rename tgui/packages/tgui/interfaces/{LanguageMenu.js => LanguageMenu.jsx} (100%) rename tgui/packages/tgui/interfaces/{ListInput.js => ListInput.jsx} (100%) rename tgui/packages/tgui/interfaces/{MedalsPanel.js => MedalsPanel.jsx} (100%) rename tgui/packages/tgui/interfaces/{Mortar.js => Mortar.jsx} (100%) rename tgui/packages/tgui/interfaces/{NuclearBomb.js => NuclearBomb.jsx} (100%) rename tgui/packages/tgui/interfaces/{OrbitalCannonConsole.js => OrbitalCannonConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{OverwatchConsole.js => OverwatchConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{PartFabricator.js => PartFabricator.jsx} (100%) rename tgui/packages/tgui/interfaces/{PhoneMenu.js => PhoneMenu.jsx} (100%) rename tgui/packages/tgui/interfaces/{PlayerPanel.js => PlayerPanel.jsx} (100%) rename tgui/packages/tgui/interfaces/{PodLauncher.js => PodLauncher.jsx} (100%) rename tgui/packages/tgui/interfaces/{Proximity.js => Proximity.jsx} (100%) rename tgui/packages/tgui/interfaces/{Radio.js => Radio.jsx} (100%) rename tgui/packages/tgui/interfaces/{ResearchDoorDisplay.js => ResearchDoorDisplay.jsx} (100%) rename tgui/packages/tgui/interfaces/{ResearchMemories.js => ResearchMemories.jsx} (100%) rename tgui/packages/tgui/interfaces/{STUI.js => STUI.jsx} (100%) rename tgui/packages/tgui/interfaces/{SelfDestructConsole.js => SelfDestructConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{Sentencing.js => Sentencing.jsx} (100%) rename tgui/packages/tgui/interfaces/{Signaller.js => Signaller.jsx} (100%) rename tgui/packages/tgui/interfaces/{SkillsMenu.js => SkillsMenu.jsx} (100%) rename tgui/packages/tgui/interfaces/{Sleeper.js => Sleeper.jsx} (100%) rename tgui/packages/tgui/interfaces/{Smes.js => Smes.jsx} (100%) rename tgui/packages/tgui/interfaces/{SquadMod.js => SquadMod.jsx} (100%) rename tgui/packages/tgui/interfaces/{StatbrowserOptions.js => StatbrowserOptions.jsx} (100%) rename tgui/packages/tgui/interfaces/{StationAlertConsole.js => StationAlertConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{SupplyDropConsole.js => SupplyDropConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{TacmapAdminPanel.js => TacmapAdminPanel.jsx} (100%) rename tgui/packages/tgui/interfaces/{Tank.js => Tank.jsx} (100%) rename tgui/packages/tgui/interfaces/{TechControl.js => TechControl.jsx} (100%) rename tgui/packages/tgui/interfaces/{TechMemories.js => TechMemories.jsx} (100%) rename tgui/packages/tgui/interfaces/{TechNode.js => TechNode.jsx} (100%) rename tgui/packages/tgui/interfaces/{TeleporterConsole.js => TeleporterConsole.jsx} (100%) rename tgui/packages/tgui/interfaces/{Timer.js => Timer.jsx} (100%) rename tgui/packages/tgui/interfaces/{VehicleStatus.js => VehicleStatus.jsx} (100%) rename tgui/packages/tgui/interfaces/{VoteMenu.js => VoteMenu.jsx} (100%) rename tgui/packages/tgui/interfaces/{VoxPanel.js => VoxPanel.jsx} (100%) rename tgui/packages/tgui/interfaces/{WeaponStats.js => WeaponStats.jsx} (100%) rename tgui/packages/tgui/interfaces/{Wires.js => Wires.jsx} (100%) rename tgui/packages/tgui/interfaces/{WorkingJoe.js => WorkingJoe.jsx} (100%) rename tgui/packages/tgui/interfaces/common/{AccessList.js => AccessList.jsx} (100%) rename tgui/packages/tgui/interfaces/common/{BeakerContents.js => BeakerContents.jsx} (100%) rename tgui/packages/tgui/interfaces/common/{InterfaceLockNoticeBox.js => InterfaceLockNoticeBox.jsx} (100%) rename tgui/packages/tgui/layouts/{Layout.js => Layout.jsx} (100%) rename tgui/packages/tgui/layouts/{NtosWindow.js => NtosWindow.jsx} (100%) rename tgui/packages/tgui/layouts/{Pane.js => Pane.jsx} (100%) rename tgui/packages/tgui/layouts/{Window.js => Window.jsx} (100%) rename tgui/packages/tgui/{routes.js => routes.jsx} (98%) rename tgui/packages/tgui/stories/{Blink.stories.js => Blink.stories.jsx} (100%) rename tgui/packages/tgui/stories/{BlockQuote.stories.js => BlockQuote.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Box.stories.js => Box.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Button.stories.js => Button.stories.jsx} (100%) rename tgui/packages/tgui/stories/{ByondUi.stories.js => ByondUi.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Collapsible.stories.js => Collapsible.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Flex.stories.js => Flex.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Input.stories.js => Input.stories.jsx} (100%) rename tgui/packages/tgui/stories/{LabeledList.stories.js => LabeledList.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Popper.stories.js => Popper.stories.jsx} (100%) rename tgui/packages/tgui/stories/{ProgressBar.stories.js => ProgressBar.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Stack.stories.js => Stack.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Storage.stories.js => Storage.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Tabs.stories.js => Tabs.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Themes.stories.js => Themes.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Tooltip.stories.js => Tooltip.stories.jsx} (100%) rename tgui/packages/tgui/stories/{common.js => common.jsx} (100%) diff --git a/tgui/packages/tgui/components/Blink.js b/tgui/packages/tgui/components/Blink.jsx similarity index 100% rename from tgui/packages/tgui/components/Blink.js rename to tgui/packages/tgui/components/Blink.jsx diff --git a/tgui/packages/tgui/components/BlockQuote.js b/tgui/packages/tgui/components/BlockQuote.jsx similarity index 100% rename from tgui/packages/tgui/components/BlockQuote.js rename to tgui/packages/tgui/components/BlockQuote.jsx diff --git a/tgui/packages/tgui/components/Button.js b/tgui/packages/tgui/components/Button.jsx similarity index 100% rename from tgui/packages/tgui/components/Button.js rename to tgui/packages/tgui/components/Button.jsx diff --git a/tgui/packages/tgui/components/ByondUi.js b/tgui/packages/tgui/components/ByondUi.jsx similarity index 100% rename from tgui/packages/tgui/components/ByondUi.js rename to tgui/packages/tgui/components/ByondUi.jsx diff --git a/tgui/packages/tgui/components/Chart.js b/tgui/packages/tgui/components/Chart.jsx similarity index 100% rename from tgui/packages/tgui/components/Chart.js rename to tgui/packages/tgui/components/Chart.jsx diff --git a/tgui/packages/tgui/components/Collapsible.js b/tgui/packages/tgui/components/Collapsible.jsx similarity index 100% rename from tgui/packages/tgui/components/Collapsible.js rename to tgui/packages/tgui/components/Collapsible.jsx diff --git a/tgui/packages/tgui/components/ColorBox.js b/tgui/packages/tgui/components/ColorBox.jsx similarity index 100% rename from tgui/packages/tgui/components/ColorBox.js rename to tgui/packages/tgui/components/ColorBox.jsx diff --git a/tgui/packages/tgui/components/Dimmer.js b/tgui/packages/tgui/components/Dimmer.jsx similarity index 100% rename from tgui/packages/tgui/components/Dimmer.js rename to tgui/packages/tgui/components/Dimmer.jsx diff --git a/tgui/packages/tgui/components/Divider.js b/tgui/packages/tgui/components/Divider.jsx similarity index 100% rename from tgui/packages/tgui/components/Divider.js rename to tgui/packages/tgui/components/Divider.jsx diff --git a/tgui/packages/tgui/components/DraggableControl.js b/tgui/packages/tgui/components/DraggableControl.jsx similarity index 100% rename from tgui/packages/tgui/components/DraggableControl.js rename to tgui/packages/tgui/components/DraggableControl.jsx diff --git a/tgui/packages/tgui/components/Dropdown.js b/tgui/packages/tgui/components/Dropdown.jsx similarity index 100% rename from tgui/packages/tgui/components/Dropdown.js rename to tgui/packages/tgui/components/Dropdown.jsx diff --git a/tgui/packages/tgui/components/Grid.js b/tgui/packages/tgui/components/Grid.jsx similarity index 100% rename from tgui/packages/tgui/components/Grid.js rename to tgui/packages/tgui/components/Grid.jsx diff --git a/tgui/packages/tgui/components/Icon.js b/tgui/packages/tgui/components/Icon.jsx similarity index 100% rename from tgui/packages/tgui/components/Icon.js rename to tgui/packages/tgui/components/Icon.jsx diff --git a/tgui/packages/tgui/components/InfinitePlane.js b/tgui/packages/tgui/components/InfinitePlane.jsx similarity index 100% rename from tgui/packages/tgui/components/InfinitePlane.js rename to tgui/packages/tgui/components/InfinitePlane.jsx diff --git a/tgui/packages/tgui/components/Input.js b/tgui/packages/tgui/components/Input.jsx similarity index 100% rename from tgui/packages/tgui/components/Input.js rename to tgui/packages/tgui/components/Input.jsx diff --git a/tgui/packages/tgui/components/Knob.js b/tgui/packages/tgui/components/Knob.jsx similarity index 100% rename from tgui/packages/tgui/components/Knob.js rename to tgui/packages/tgui/components/Knob.jsx diff --git a/tgui/packages/tgui/components/LabeledControls.js b/tgui/packages/tgui/components/LabeledControls.jsx similarity index 100% rename from tgui/packages/tgui/components/LabeledControls.js rename to tgui/packages/tgui/components/LabeledControls.jsx diff --git a/tgui/packages/tgui/components/Modal.js b/tgui/packages/tgui/components/Modal.jsx similarity index 100% rename from tgui/packages/tgui/components/Modal.js rename to tgui/packages/tgui/components/Modal.jsx diff --git a/tgui/packages/tgui/components/NoticeBox.js b/tgui/packages/tgui/components/NoticeBox.jsx similarity index 100% rename from tgui/packages/tgui/components/NoticeBox.js rename to tgui/packages/tgui/components/NoticeBox.jsx diff --git a/tgui/packages/tgui/components/NumberInput.js b/tgui/packages/tgui/components/NumberInput.jsx similarity index 100% rename from tgui/packages/tgui/components/NumberInput.js rename to tgui/packages/tgui/components/NumberInput.jsx diff --git a/tgui/packages/tgui/components/ProgressBar.js b/tgui/packages/tgui/components/ProgressBar.jsx similarity index 100% rename from tgui/packages/tgui/components/ProgressBar.js rename to tgui/packages/tgui/components/ProgressBar.jsx diff --git a/tgui/packages/tgui/components/RestrictedInput.js b/tgui/packages/tgui/components/RestrictedInput.jsx similarity index 100% rename from tgui/packages/tgui/components/RestrictedInput.js rename to tgui/packages/tgui/components/RestrictedInput.jsx diff --git a/tgui/packages/tgui/components/RoundGauge.js b/tgui/packages/tgui/components/RoundGauge.jsx similarity index 100% rename from tgui/packages/tgui/components/RoundGauge.js rename to tgui/packages/tgui/components/RoundGauge.jsx diff --git a/tgui/packages/tgui/components/Slider.js b/tgui/packages/tgui/components/Slider.jsx similarity index 100% rename from tgui/packages/tgui/components/Slider.js rename to tgui/packages/tgui/components/Slider.jsx diff --git a/tgui/packages/tgui/components/Table.js b/tgui/packages/tgui/components/Table.jsx similarity index 100% rename from tgui/packages/tgui/components/Table.js rename to tgui/packages/tgui/components/Table.jsx diff --git a/tgui/packages/tgui/components/Tabs.js b/tgui/packages/tgui/components/Tabs.jsx similarity index 100% rename from tgui/packages/tgui/components/Tabs.js rename to tgui/packages/tgui/components/Tabs.jsx diff --git a/tgui/packages/tgui/components/TextArea.js b/tgui/packages/tgui/components/TextArea.jsx similarity index 100% rename from tgui/packages/tgui/components/TextArea.js rename to tgui/packages/tgui/components/TextArea.jsx diff --git a/tgui/packages/tgui/components/TimeDisplay.js b/tgui/packages/tgui/components/TimeDisplay.jsx similarity index 100% rename from tgui/packages/tgui/components/TimeDisplay.js rename to tgui/packages/tgui/components/TimeDisplay.jsx diff --git a/tgui/packages/tgui/components/index.js b/tgui/packages/tgui/components/index.jsx similarity index 100% rename from tgui/packages/tgui/components/index.js rename to tgui/packages/tgui/components/index.jsx diff --git a/tgui/packages/tgui/debug/KitchenSink.js b/tgui/packages/tgui/debug/KitchenSink.jsx similarity index 95% rename from tgui/packages/tgui/debug/KitchenSink.js rename to tgui/packages/tgui/debug/KitchenSink.jsx index 246b4f50b478..e25751722c52 100644 --- a/tgui/packages/tgui/debug/KitchenSink.js +++ b/tgui/packages/tgui/debug/KitchenSink.jsx @@ -8,7 +8,7 @@ import { useLocalState } from '../backend'; import { Flex, Section, Tabs } from '../components'; import { Pane, Window } from '../layouts'; -const r = require.context('../stories', false, /\.stories\.js$/); +const r = require.context('../stories', false, /\.stories\.jsx$/); /** * @returns {{ diff --git a/tgui/packages/tgui/interfaces/AcidVest.js b/tgui/packages/tgui/interfaces/AcidVest.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/AcidVest.js rename to tgui/packages/tgui/interfaces/AcidVest.jsx diff --git a/tgui/packages/tgui/interfaces/AlmayerControl.js b/tgui/packages/tgui/interfaces/AlmayerControl.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/AlmayerControl.js rename to tgui/packages/tgui/interfaces/AlmayerControl.jsx diff --git a/tgui/packages/tgui/interfaces/AltitudeControlConsole.js b/tgui/packages/tgui/interfaces/AltitudeControlConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/AltitudeControlConsole.js rename to tgui/packages/tgui/interfaces/AltitudeControlConsole.jsx diff --git a/tgui/packages/tgui/interfaces/AntiAirConsole.js b/tgui/packages/tgui/interfaces/AntiAirConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/AntiAirConsole.js rename to tgui/packages/tgui/interfaces/AntiAirConsole.jsx diff --git a/tgui/packages/tgui/interfaces/Apc.js b/tgui/packages/tgui/interfaces/Apc.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Apc.js rename to tgui/packages/tgui/interfaces/Apc.jsx diff --git a/tgui/packages/tgui/interfaces/AresInterface.js b/tgui/packages/tgui/interfaces/AresInterface.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/AresInterface.js rename to tgui/packages/tgui/interfaces/AresInterface.jsx diff --git a/tgui/packages/tgui/interfaces/Autodispenser.js b/tgui/packages/tgui/interfaces/Autodispenser.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Autodispenser.js rename to tgui/packages/tgui/interfaces/Autodispenser.jsx diff --git a/tgui/packages/tgui/interfaces/Autolathe.js b/tgui/packages/tgui/interfaces/Autolathe.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Autolathe.js rename to tgui/packages/tgui/interfaces/Autolathe.jsx diff --git a/tgui/packages/tgui/interfaces/Binoculars.js b/tgui/packages/tgui/interfaces/Binoculars.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Binoculars.js rename to tgui/packages/tgui/interfaces/Binoculars.jsx diff --git a/tgui/packages/tgui/interfaces/BioSyntheticPrinter.js b/tgui/packages/tgui/interfaces/BioSyntheticPrinter.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/BioSyntheticPrinter.js rename to tgui/packages/tgui/interfaces/BioSyntheticPrinter.jsx diff --git a/tgui/packages/tgui/interfaces/BotanyEditor.js b/tgui/packages/tgui/interfaces/BotanyEditor.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/BotanyEditor.js rename to tgui/packages/tgui/interfaces/BotanyEditor.jsx diff --git a/tgui/packages/tgui/interfaces/BotanyExtractor.js b/tgui/packages/tgui/interfaces/BotanyExtractor.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/BotanyExtractor.js rename to tgui/packages/tgui/interfaces/BotanyExtractor.jsx diff --git a/tgui/packages/tgui/interfaces/BrigCell.js b/tgui/packages/tgui/interfaces/BrigCell.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/BrigCell.js rename to tgui/packages/tgui/interfaces/BrigCell.jsx diff --git a/tgui/packages/tgui/interfaces/CameraConsole.js b/tgui/packages/tgui/interfaces/CameraConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CameraConsole.js rename to tgui/packages/tgui/interfaces/CameraConsole.jsx diff --git a/tgui/packages/tgui/interfaces/CanvasLayer.js b/tgui/packages/tgui/interfaces/CanvasLayer.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CanvasLayer.js rename to tgui/packages/tgui/interfaces/CanvasLayer.jsx diff --git a/tgui/packages/tgui/interfaces/CardMod.js b/tgui/packages/tgui/interfaces/CardMod.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CardMod.js rename to tgui/packages/tgui/interfaces/CardMod.jsx diff --git a/tgui/packages/tgui/interfaces/Centrifuge.js b/tgui/packages/tgui/interfaces/Centrifuge.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Centrifuge.js rename to tgui/packages/tgui/interfaces/Centrifuge.jsx diff --git a/tgui/packages/tgui/interfaces/Changelog.js b/tgui/packages/tgui/interfaces/Changelog.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Changelog.js rename to tgui/packages/tgui/interfaces/Changelog.jsx diff --git a/tgui/packages/tgui/interfaces/ChemDispenser.js b/tgui/packages/tgui/interfaces/ChemDispenser.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ChemDispenser.js rename to tgui/packages/tgui/interfaces/ChemDispenser.jsx diff --git a/tgui/packages/tgui/interfaces/ChooseFruit.js b/tgui/packages/tgui/interfaces/ChooseFruit.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ChooseFruit.js rename to tgui/packages/tgui/interfaces/ChooseFruit.jsx diff --git a/tgui/packages/tgui/interfaces/ChooseResin.js b/tgui/packages/tgui/interfaces/ChooseResin.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ChooseResin.js rename to tgui/packages/tgui/interfaces/ChooseResin.jsx diff --git a/tgui/packages/tgui/interfaces/CommandTablet.js b/tgui/packages/tgui/interfaces/CommandTablet.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CommandTablet.js rename to tgui/packages/tgui/interfaces/CommandTablet.jsx diff --git a/tgui/packages/tgui/interfaces/CrewConsole.js b/tgui/packages/tgui/interfaces/CrewConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/CrewConsole.js rename to tgui/packages/tgui/interfaces/CrewConsole.jsx diff --git a/tgui/packages/tgui/interfaces/Cryo.js b/tgui/packages/tgui/interfaces/Cryo.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Cryo.js rename to tgui/packages/tgui/interfaces/Cryo.jsx diff --git a/tgui/packages/tgui/interfaces/DemoSim.js b/tgui/packages/tgui/interfaces/DemoSim.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/DemoSim.js rename to tgui/packages/tgui/interfaces/DemoSim.jsx diff --git a/tgui/packages/tgui/interfaces/Disposals.js b/tgui/packages/tgui/interfaces/Disposals.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Disposals.js rename to tgui/packages/tgui/interfaces/Disposals.jsx diff --git a/tgui/packages/tgui/interfaces/DrawnMap.js b/tgui/packages/tgui/interfaces/DrawnMap.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/DrawnMap.js rename to tgui/packages/tgui/interfaces/DrawnMap.jsx diff --git a/tgui/packages/tgui/interfaces/FaxMachine.js b/tgui/packages/tgui/interfaces/FaxMachine.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/FaxMachine.js rename to tgui/packages/tgui/interfaces/FaxMachine.jsx diff --git a/tgui/packages/tgui/interfaces/Filteriffic.js b/tgui/packages/tgui/interfaces/Filteriffic.jsx similarity index 99% rename from tgui/packages/tgui/interfaces/Filteriffic.js rename to tgui/packages/tgui/interfaces/Filteriffic.jsx index a967efafca98..8bda997dff1b 100644 --- a/tgui/packages/tgui/interfaces/Filteriffic.js +++ b/tgui/packages/tgui/interfaces/Filteriffic.jsx @@ -1,6 +1,6 @@ import { map } from 'common/collections'; import { toFixed } from 'common/math'; -import { numberOfDecimalDigits } from '../../common/math'; +import { numberOfDecimalDigits } from 'common/math'; import { useBackend, useLocalState } from '../backend'; import { Box, Button, Collapsible, ColorBox, Dropdown, Input, LabeledList, NoticeBox, NumberInput, Section } from '../components'; import { Window } from '../layouts'; diff --git a/tgui/packages/tgui/interfaces/FiltrationControl.js b/tgui/packages/tgui/interfaces/FiltrationControl.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/FiltrationControl.js rename to tgui/packages/tgui/interfaces/FiltrationControl.jsx diff --git a/tgui/packages/tgui/interfaces/HealthScan.js b/tgui/packages/tgui/interfaces/HealthScan.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/HealthScan.js rename to tgui/packages/tgui/interfaces/HealthScan.jsx diff --git a/tgui/packages/tgui/interfaces/HiveFaction.js b/tgui/packages/tgui/interfaces/HiveFaction.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/HiveFaction.js rename to tgui/packages/tgui/interfaces/HiveFaction.jsx diff --git a/tgui/packages/tgui/interfaces/HiveLeaders.js b/tgui/packages/tgui/interfaces/HiveLeaders.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/HiveLeaders.js rename to tgui/packages/tgui/interfaces/HiveLeaders.jsx diff --git a/tgui/packages/tgui/interfaces/HiveStatus.js b/tgui/packages/tgui/interfaces/HiveStatus.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/HiveStatus.js rename to tgui/packages/tgui/interfaces/HiveStatus.jsx diff --git a/tgui/packages/tgui/interfaces/KeyBinds.js b/tgui/packages/tgui/interfaces/KeyBinds.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/KeyBinds.js rename to tgui/packages/tgui/interfaces/KeyBinds.jsx diff --git a/tgui/packages/tgui/interfaces/KillPanel.js b/tgui/packages/tgui/interfaces/KillPanel.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/KillPanel.js rename to tgui/packages/tgui/interfaces/KillPanel.jsx diff --git a/tgui/packages/tgui/interfaces/LanguageMenu.js b/tgui/packages/tgui/interfaces/LanguageMenu.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/LanguageMenu.js rename to tgui/packages/tgui/interfaces/LanguageMenu.jsx diff --git a/tgui/packages/tgui/interfaces/ListInput.js b/tgui/packages/tgui/interfaces/ListInput.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ListInput.js rename to tgui/packages/tgui/interfaces/ListInput.jsx diff --git a/tgui/packages/tgui/interfaces/MedalsPanel.js b/tgui/packages/tgui/interfaces/MedalsPanel.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/MedalsPanel.js rename to tgui/packages/tgui/interfaces/MedalsPanel.jsx diff --git a/tgui/packages/tgui/interfaces/Mortar.js b/tgui/packages/tgui/interfaces/Mortar.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Mortar.js rename to tgui/packages/tgui/interfaces/Mortar.jsx diff --git a/tgui/packages/tgui/interfaces/NuclearBomb.js b/tgui/packages/tgui/interfaces/NuclearBomb.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/NuclearBomb.js rename to tgui/packages/tgui/interfaces/NuclearBomb.jsx diff --git a/tgui/packages/tgui/interfaces/OrbitalCannonConsole.js b/tgui/packages/tgui/interfaces/OrbitalCannonConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/OrbitalCannonConsole.js rename to tgui/packages/tgui/interfaces/OrbitalCannonConsole.jsx diff --git a/tgui/packages/tgui/interfaces/OverwatchConsole.js b/tgui/packages/tgui/interfaces/OverwatchConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/OverwatchConsole.js rename to tgui/packages/tgui/interfaces/OverwatchConsole.jsx diff --git a/tgui/packages/tgui/interfaces/PartFabricator.js b/tgui/packages/tgui/interfaces/PartFabricator.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/PartFabricator.js rename to tgui/packages/tgui/interfaces/PartFabricator.jsx diff --git a/tgui/packages/tgui/interfaces/PhoneMenu.js b/tgui/packages/tgui/interfaces/PhoneMenu.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/PhoneMenu.js rename to tgui/packages/tgui/interfaces/PhoneMenu.jsx diff --git a/tgui/packages/tgui/interfaces/PlayerPanel.js b/tgui/packages/tgui/interfaces/PlayerPanel.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/PlayerPanel.js rename to tgui/packages/tgui/interfaces/PlayerPanel.jsx diff --git a/tgui/packages/tgui/interfaces/PodLauncher.js b/tgui/packages/tgui/interfaces/PodLauncher.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/PodLauncher.js rename to tgui/packages/tgui/interfaces/PodLauncher.jsx diff --git a/tgui/packages/tgui/interfaces/Proximity.js b/tgui/packages/tgui/interfaces/Proximity.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Proximity.js rename to tgui/packages/tgui/interfaces/Proximity.jsx diff --git a/tgui/packages/tgui/interfaces/Radio.js b/tgui/packages/tgui/interfaces/Radio.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Radio.js rename to tgui/packages/tgui/interfaces/Radio.jsx diff --git a/tgui/packages/tgui/interfaces/ResearchDoorDisplay.js b/tgui/packages/tgui/interfaces/ResearchDoorDisplay.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ResearchDoorDisplay.js rename to tgui/packages/tgui/interfaces/ResearchDoorDisplay.jsx diff --git a/tgui/packages/tgui/interfaces/ResearchMemories.js b/tgui/packages/tgui/interfaces/ResearchMemories.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/ResearchMemories.js rename to tgui/packages/tgui/interfaces/ResearchMemories.jsx diff --git a/tgui/packages/tgui/interfaces/STUI.js b/tgui/packages/tgui/interfaces/STUI.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/STUI.js rename to tgui/packages/tgui/interfaces/STUI.jsx diff --git a/tgui/packages/tgui/interfaces/SelfDestructConsole.js b/tgui/packages/tgui/interfaces/SelfDestructConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/SelfDestructConsole.js rename to tgui/packages/tgui/interfaces/SelfDestructConsole.jsx diff --git a/tgui/packages/tgui/interfaces/Sentencing.js b/tgui/packages/tgui/interfaces/Sentencing.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Sentencing.js rename to tgui/packages/tgui/interfaces/Sentencing.jsx diff --git a/tgui/packages/tgui/interfaces/Signaller.js b/tgui/packages/tgui/interfaces/Signaller.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Signaller.js rename to tgui/packages/tgui/interfaces/Signaller.jsx diff --git a/tgui/packages/tgui/interfaces/SkillsMenu.js b/tgui/packages/tgui/interfaces/SkillsMenu.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/SkillsMenu.js rename to tgui/packages/tgui/interfaces/SkillsMenu.jsx diff --git a/tgui/packages/tgui/interfaces/Sleeper.js b/tgui/packages/tgui/interfaces/Sleeper.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Sleeper.js rename to tgui/packages/tgui/interfaces/Sleeper.jsx diff --git a/tgui/packages/tgui/interfaces/Smes.js b/tgui/packages/tgui/interfaces/Smes.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Smes.js rename to tgui/packages/tgui/interfaces/Smes.jsx diff --git a/tgui/packages/tgui/interfaces/SquadMod.js b/tgui/packages/tgui/interfaces/SquadMod.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/SquadMod.js rename to tgui/packages/tgui/interfaces/SquadMod.jsx diff --git a/tgui/packages/tgui/interfaces/StatbrowserOptions.js b/tgui/packages/tgui/interfaces/StatbrowserOptions.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/StatbrowserOptions.js rename to tgui/packages/tgui/interfaces/StatbrowserOptions.jsx diff --git a/tgui/packages/tgui/interfaces/StationAlertConsole.js b/tgui/packages/tgui/interfaces/StationAlertConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/StationAlertConsole.js rename to tgui/packages/tgui/interfaces/StationAlertConsole.jsx diff --git a/tgui/packages/tgui/interfaces/SupplyDropConsole.js b/tgui/packages/tgui/interfaces/SupplyDropConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/SupplyDropConsole.js rename to tgui/packages/tgui/interfaces/SupplyDropConsole.jsx diff --git a/tgui/packages/tgui/interfaces/TacmapAdminPanel.js b/tgui/packages/tgui/interfaces/TacmapAdminPanel.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/TacmapAdminPanel.js rename to tgui/packages/tgui/interfaces/TacmapAdminPanel.jsx diff --git a/tgui/packages/tgui/interfaces/Tank.js b/tgui/packages/tgui/interfaces/Tank.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Tank.js rename to tgui/packages/tgui/interfaces/Tank.jsx diff --git a/tgui/packages/tgui/interfaces/TechControl.js b/tgui/packages/tgui/interfaces/TechControl.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/TechControl.js rename to tgui/packages/tgui/interfaces/TechControl.jsx diff --git a/tgui/packages/tgui/interfaces/TechMemories.js b/tgui/packages/tgui/interfaces/TechMemories.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/TechMemories.js rename to tgui/packages/tgui/interfaces/TechMemories.jsx diff --git a/tgui/packages/tgui/interfaces/TechNode.js b/tgui/packages/tgui/interfaces/TechNode.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/TechNode.js rename to tgui/packages/tgui/interfaces/TechNode.jsx diff --git a/tgui/packages/tgui/interfaces/TeleporterConsole.js b/tgui/packages/tgui/interfaces/TeleporterConsole.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/TeleporterConsole.js rename to tgui/packages/tgui/interfaces/TeleporterConsole.jsx diff --git a/tgui/packages/tgui/interfaces/Timer.js b/tgui/packages/tgui/interfaces/Timer.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Timer.js rename to tgui/packages/tgui/interfaces/Timer.jsx diff --git a/tgui/packages/tgui/interfaces/VehicleStatus.js b/tgui/packages/tgui/interfaces/VehicleStatus.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/VehicleStatus.js rename to tgui/packages/tgui/interfaces/VehicleStatus.jsx diff --git a/tgui/packages/tgui/interfaces/VoteMenu.js b/tgui/packages/tgui/interfaces/VoteMenu.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/VoteMenu.js rename to tgui/packages/tgui/interfaces/VoteMenu.jsx diff --git a/tgui/packages/tgui/interfaces/VoxPanel.js b/tgui/packages/tgui/interfaces/VoxPanel.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/VoxPanel.js rename to tgui/packages/tgui/interfaces/VoxPanel.jsx diff --git a/tgui/packages/tgui/interfaces/WeaponStats.js b/tgui/packages/tgui/interfaces/WeaponStats.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/WeaponStats.js rename to tgui/packages/tgui/interfaces/WeaponStats.jsx diff --git a/tgui/packages/tgui/interfaces/Wires.js b/tgui/packages/tgui/interfaces/Wires.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/Wires.js rename to tgui/packages/tgui/interfaces/Wires.jsx diff --git a/tgui/packages/tgui/interfaces/WorkingJoe.js b/tgui/packages/tgui/interfaces/WorkingJoe.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/WorkingJoe.js rename to tgui/packages/tgui/interfaces/WorkingJoe.jsx diff --git a/tgui/packages/tgui/interfaces/common/AccessList.js b/tgui/packages/tgui/interfaces/common/AccessList.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/common/AccessList.js rename to tgui/packages/tgui/interfaces/common/AccessList.jsx diff --git a/tgui/packages/tgui/interfaces/common/BeakerContents.js b/tgui/packages/tgui/interfaces/common/BeakerContents.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/common/BeakerContents.js rename to tgui/packages/tgui/interfaces/common/BeakerContents.jsx diff --git a/tgui/packages/tgui/interfaces/common/InterfaceLockNoticeBox.js b/tgui/packages/tgui/interfaces/common/InterfaceLockNoticeBox.jsx similarity index 100% rename from tgui/packages/tgui/interfaces/common/InterfaceLockNoticeBox.js rename to tgui/packages/tgui/interfaces/common/InterfaceLockNoticeBox.jsx diff --git a/tgui/packages/tgui/layouts/Layout.js b/tgui/packages/tgui/layouts/Layout.jsx similarity index 100% rename from tgui/packages/tgui/layouts/Layout.js rename to tgui/packages/tgui/layouts/Layout.jsx diff --git a/tgui/packages/tgui/layouts/NtosWindow.js b/tgui/packages/tgui/layouts/NtosWindow.jsx similarity index 100% rename from tgui/packages/tgui/layouts/NtosWindow.js rename to tgui/packages/tgui/layouts/NtosWindow.jsx diff --git a/tgui/packages/tgui/layouts/Pane.js b/tgui/packages/tgui/layouts/Pane.jsx similarity index 100% rename from tgui/packages/tgui/layouts/Pane.js rename to tgui/packages/tgui/layouts/Pane.jsx diff --git a/tgui/packages/tgui/layouts/Window.js b/tgui/packages/tgui/layouts/Window.jsx similarity index 100% rename from tgui/packages/tgui/layouts/Window.js rename to tgui/packages/tgui/layouts/Window.jsx diff --git a/tgui/packages/tgui/routes.js b/tgui/packages/tgui/routes.jsx similarity index 98% rename from tgui/packages/tgui/routes.js rename to tgui/packages/tgui/routes.jsx index eb4ddff15393..0ad869fc63cb 100644 --- a/tgui/packages/tgui/routes.js +++ b/tgui/packages/tgui/routes.jsx @@ -74,6 +74,7 @@ export const getRoutedComponent = (store) => { const name = config?.interface; const interfacePathBuilders = [ (name) => `./${name}.tsx`, + (name) => `./${name}.jsx`, (name) => `./${name}.js`, (name) => `./${name}/index.tsx`, (name) => `./${name}/index.js`, diff --git a/tgui/packages/tgui/stories/Blink.stories.js b/tgui/packages/tgui/stories/Blink.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Blink.stories.js rename to tgui/packages/tgui/stories/Blink.stories.jsx diff --git a/tgui/packages/tgui/stories/BlockQuote.stories.js b/tgui/packages/tgui/stories/BlockQuote.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/BlockQuote.stories.js rename to tgui/packages/tgui/stories/BlockQuote.stories.jsx diff --git a/tgui/packages/tgui/stories/Box.stories.js b/tgui/packages/tgui/stories/Box.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Box.stories.js rename to tgui/packages/tgui/stories/Box.stories.jsx diff --git a/tgui/packages/tgui/stories/Button.stories.js b/tgui/packages/tgui/stories/Button.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Button.stories.js rename to tgui/packages/tgui/stories/Button.stories.jsx diff --git a/tgui/packages/tgui/stories/ByondUi.stories.js b/tgui/packages/tgui/stories/ByondUi.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/ByondUi.stories.js rename to tgui/packages/tgui/stories/ByondUi.stories.jsx diff --git a/tgui/packages/tgui/stories/Collapsible.stories.js b/tgui/packages/tgui/stories/Collapsible.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Collapsible.stories.js rename to tgui/packages/tgui/stories/Collapsible.stories.jsx diff --git a/tgui/packages/tgui/stories/Flex.stories.js b/tgui/packages/tgui/stories/Flex.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Flex.stories.js rename to tgui/packages/tgui/stories/Flex.stories.jsx diff --git a/tgui/packages/tgui/stories/Input.stories.js b/tgui/packages/tgui/stories/Input.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Input.stories.js rename to tgui/packages/tgui/stories/Input.stories.jsx diff --git a/tgui/packages/tgui/stories/LabeledList.stories.js b/tgui/packages/tgui/stories/LabeledList.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/LabeledList.stories.js rename to tgui/packages/tgui/stories/LabeledList.stories.jsx diff --git a/tgui/packages/tgui/stories/Popper.stories.js b/tgui/packages/tgui/stories/Popper.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Popper.stories.js rename to tgui/packages/tgui/stories/Popper.stories.jsx diff --git a/tgui/packages/tgui/stories/ProgressBar.stories.js b/tgui/packages/tgui/stories/ProgressBar.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/ProgressBar.stories.js rename to tgui/packages/tgui/stories/ProgressBar.stories.jsx diff --git a/tgui/packages/tgui/stories/Stack.stories.js b/tgui/packages/tgui/stories/Stack.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Stack.stories.js rename to tgui/packages/tgui/stories/Stack.stories.jsx diff --git a/tgui/packages/tgui/stories/Storage.stories.js b/tgui/packages/tgui/stories/Storage.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Storage.stories.js rename to tgui/packages/tgui/stories/Storage.stories.jsx diff --git a/tgui/packages/tgui/stories/Tabs.stories.js b/tgui/packages/tgui/stories/Tabs.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Tabs.stories.js rename to tgui/packages/tgui/stories/Tabs.stories.jsx diff --git a/tgui/packages/tgui/stories/Themes.stories.js b/tgui/packages/tgui/stories/Themes.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Themes.stories.js rename to tgui/packages/tgui/stories/Themes.stories.jsx diff --git a/tgui/packages/tgui/stories/Tooltip.stories.js b/tgui/packages/tgui/stories/Tooltip.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Tooltip.stories.js rename to tgui/packages/tgui/stories/Tooltip.stories.jsx diff --git a/tgui/packages/tgui/stories/common.js b/tgui/packages/tgui/stories/common.jsx similarity index 100% rename from tgui/packages/tgui/stories/common.js rename to tgui/packages/tgui/stories/common.jsx diff --git a/tgui/webpack.config.js b/tgui/webpack.config.js index 19e2975715fa..f90b80926e44 100644 --- a/tgui/webpack.config.js +++ b/tgui/webpack.config.js @@ -55,13 +55,13 @@ module.exports = (env = {}, argv) => { chunkLoadTimeout: 15000, }, resolve: { - extensions: ['.tsx', '.ts', '.js'], + extensions: ['.jsx', '.tsx', '.ts', '.js'], alias: {}, }, module: { rules: [ { - test: /\.(js|cjs|ts|tsx)$/, + test: /\.(js|jsx|cjs|ts|tsx)$/, use: [ { loader: require.resolve('babel-loader'), From 84f65d0c592c3a88da3cdb52498bea6dc57f2079 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 29 Dec 2023 19:43:11 +0000 Subject: [PATCH 24/28] Automatic changelog for PR #5307 [ci skip] --- html/changelogs/AutoChangeLog-pr-5307.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-5307.yml diff --git a/html/changelogs/AutoChangeLog-pr-5307.yml b/html/changelogs/AutoChangeLog-pr-5307.yml new file mode 100644 index 000000000000..3047d03d8e82 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-5307.yml @@ -0,0 +1,4 @@ +author: "mullenpaul" +delete-after: True +changes: + - refactor: "tgui js components now jsx" \ No newline at end of file From 483f5ae363ff5bcf5f32c2b32b2dcf80c98ff899 Mon Sep 17 00:00:00 2001 From: Birdtalon Date: Fri, 29 Dec 2023 19:33:16 +0000 Subject: [PATCH 25/28] Fixes runtime in stripping (#5320) # About the pull request The dummy as an example doesn't have skills so we runtime when stripping them. ``` [2023-12-27 21:52:42.147] runtime error: Cannot execute null.get skill level(). - proc name: get strip delay (/mob/living/carbon/human/proc/get_strip_delay) - source file: code/modules/mob/living/carbon/human/inventory.dm,498 - usr: (src) - src: Jack Samerus (/mob/living/carbon/human) - src.loc: the floor (140,46,3) (/turf/open/floor/almayer) - call stack: - Jack Samerus (/mob/living/carbon/human): get strip delay(Jack Samerus (/mob/living/carbon/human), Professor DUMMY the Medical Ma... (/mob/living/carbon/human)) - Jack Samerus (/mob/living/carbon/human): stripPanelUnequip(Professor DUMMY tablet (/obj/item/device/professor_dummy_tablet), Professor DUMMY the Medical Ma... (/mob/living/carbon/human), "r_hand") - Professor DUMMY the Medical Ma... (/mob/living/carbon/human): Topic("src=\[0x3000232];item=r_hand", /list (/list)) - **** (/client): Topic("src=\[0x3000232];item=r_hand", /list (/list), Professor DUMMY the Medical Ma... (/mob/living/carbon/human)) ``` # Explain why it's good for the game # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: fix: Runtime in inventory.dm /:cl: --- code/modules/mob/living/carbon/human/inventory.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index 34b80d1ce6f9..3d372376d1e7 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -494,7 +494,8 @@ /// Multiplier for how quickly the user can strip things. var/user_speed = user.get_skill_duration_multiplier(SKILL_CQC) /// The total skill level of CQC & Police - var/target_skills = (target.skills.get_skill_level(SKILL_CQC) + target.skills.get_skill_level(SKILL_POLICE)) + var/target_skills = 0 + target_skills += (target.skills?.get_skill_level(SKILL_CQC) + target.skills?.get_skill_level(SKILL_POLICE)) /// Delay then gets + 0.5s per skill level, so long as not dead or cuffed. if(!(target.stat || target.handcuffed)) From 2e87d43ac83abece3fe6ff4098a0c8bc471296e6 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 29 Dec 2023 19:57:35 +0000 Subject: [PATCH 26/28] Automatic changelog for PR #5320 [ci skip] --- html/changelogs/AutoChangeLog-pr-5320.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-5320.yml diff --git a/html/changelogs/AutoChangeLog-pr-5320.yml b/html/changelogs/AutoChangeLog-pr-5320.yml new file mode 100644 index 000000000000..32cd4fc8943d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-5320.yml @@ -0,0 +1,4 @@ +author: "Birdtalon" +delete-after: True +changes: + - bugfix: "Runtime in inventory.dm" \ No newline at end of file From 5a24a69b1d6a17e63f928d51c6ce636b5c24cb12 Mon Sep 17 00:00:00 2001 From: SabreML <57483089+SabreML@users.noreply.github.com> Date: Fri, 29 Dec 2023 19:33:51 +0000 Subject: [PATCH 27/28] Fixes the failure message when trying to switch pyro fuels (#5321) # About the pull request Edits the pyro spec's fuel pack a bit to make it *slightly* more bug-proof, and to fix it sometimes giving weird failure messages like these: ![image](https://github.com/cmss13-devs/cmss13/assets/57483089/2fa746d0-acc6-402b-ad17-e8fff5f4e3cd) ![image](https://github.com/cmss13-devs/cmss13/assets/57483089/67cef060-55a4-4897-9e52-f6d01e43d3d1) This was caused by me in #5121, presumably because I misread how the check was handled. # Explain why it's good for the game I broked it (sorry) # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: fix: Fixed the pyro spec's fuel pack sometimes giving weird failure messages when trying to switch fuel. /:cl: --- code/game/objects/items/storage/large_holster.dm | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/code/game/objects/items/storage/large_holster.dm b/code/game/objects/items/storage/large_holster.dm index b02dff1bdbcc..3f653926f8b3 100644 --- a/code/game/objects/items/storage/large_holster.dm +++ b/code/game/objects/items/storage/large_holster.dm @@ -253,9 +253,12 @@ to_chat(user, SPAN_WARNING("[src] must be equipped before you can switch types.")) return - var/obj/item/weapon/gun/flamer/M240T/flamer = user.get_active_hand() - if(!istype(flamer)) - to_chat(user, SPAN_WARNING("You must be holding [flamer] to use [src].")) + if(!linked_flamer) + to_chat(user, SPAN_WARNING("An incinerator unit must be linked in order to switch fuel types.")) + return + + if(user.get_active_hand() != linked_flamer) + to_chat(user, SPAN_WARNING("You must be holding [linked_flamer] to use [src].")) return if(!active_fuel) @@ -276,8 +279,8 @@ to_chat(user, "You switch the fuel tank to [active_fuel.caliber]") playsound(src, 'sound/machines/click.ogg', 25, TRUE) - flamer.current_mag = active_fuel - flamer.update_icon() + linked_flamer.current_mag = active_fuel + linked_flamer.update_icon() return TRUE From d46e38c9318d258de40eac4b530924b9fb4a4b42 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 29 Dec 2023 20:13:00 +0000 Subject: [PATCH 28/28] Automatic changelog for PR #5321 [ci skip] --- html/changelogs/AutoChangeLog-pr-5321.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-5321.yml diff --git a/html/changelogs/AutoChangeLog-pr-5321.yml b/html/changelogs/AutoChangeLog-pr-5321.yml new file mode 100644 index 000000000000..e9e39a2c8c87 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-5321.yml @@ -0,0 +1,4 @@ +author: "SabreML" +delete-after: True +changes: + - bugfix: "Fixed the pyro spec's fuel pack sometimes giving weird failure messages when trying to switch fuel." \ No newline at end of file