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 0a9e00b59e04..90e6db45dbaa 100644 --- a/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm +++ b/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm @@ -63,3 +63,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/signals_obj.dm b/code/__DEFINES/dcs/signals/atom/signals_obj.dm index c43105fc516f..0f761ef64494 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_obj.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_obj.dm @@ -35,3 +35,6 @@ /// 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" diff --git a/code/datums/tutorial/_tutorial.dm b/code/datums/tutorial/_tutorial.dm index e93634d0f19d..887971a33854 100644 --- a/code/datums/tutorial/_tutorial.dm +++ b/code/datums/tutorial/_tutorial.dm @@ -81,6 +81,7 @@ GLOBAL_LIST_EMPTY(ongoing_tutorials) REMOVE_TRAIT(tutorial_mob, TRAIT_IN_TUTORIAL, TRAIT_SOURCE_TUTORIAL) if(tutorial_mob.client?.prefs && completed) tutorial_mob.client.prefs.completed_tutorials |= tutorial_id + tutorial_mob.client.prefs.save_preferences() var/mob/new_player/new_player = new if(!tutorial_mob.mind) tutorial_mob.mind_initialize() diff --git a/code/datums/tutorial/marine/basic_marine.dm b/code/datums/tutorial/marine/basic_marine.dm index b5699ece68c9..d98c94111a92 100644 --- a/code/datums/tutorial/marine/basic_marine.dm +++ b/code/datums/tutorial/marine/basic_marine.dm @@ -145,7 +145,8 @@ 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.load_ammo() // 99 magazines, just to make sure that the xeno dies + 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 diff --git a/code/datums/tutorial/marine/medical_basic.dm b/code/datums/tutorial/marine/medical_basic.dm index 6ee18c341912..2ec7437ff832 100644 --- a/code/datums/tutorial/marine/medical_basic.dm +++ b/code/datums/tutorial/marine/medical_basic.dm @@ -51,11 +51,11 @@ 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.adjustBurnLoss(10) + 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 overtime. Inject yourself with the kelotane EZ autoinjector.") + 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) @@ -75,9 +75,85 @@ 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_BONE_BREAK) - addtimer(CALLBACK(src, PROC_REF(pain_tutorial)), 4 SECONDS) // add tram injecting + 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 + + 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) + + 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 @@ -86,7 +162,7 @@ /datum/tutorial/marine/medical_basic/init_mob() . = ..() - arm_equipment(tutorial_mob, /datum/equipment_preset/tutorial) + arm_equipment(tutorial_mob, /datum/equipment_preset/tutorial/fed) TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cryopod/tutorial, tutorial_pod) tutorial_pod.go_in_cryopod(tutorial_mob, TRUE, FALSE) diff --git a/code/datums/tutorial/ss13/_ss13.dm b/code/datums/tutorial/ss13/_ss13.dm index 24165316378f..dd66b9be03a5 100644 --- a/code/datums/tutorial/ss13/_ss13.dm +++ b/code/datums/tutorial/ss13/_ss13.dm @@ -35,5 +35,5 @@ tutorial_mob = new_character RegisterSignal(tutorial_mob, list(COMSIG_PARENT_QDELETING, COMSIG_MOB_DEATH, COMSIG_LIVING_GHOSTED), PROC_REF(end_tutorial)) RegisterSignal(tutorial_mob.client, COMSIG_PARENT_QDELETING, PROC_REF(end_tutorial)) - arm_equipment(tutorial_mob, /datum/equipment_preset/tutorial) + arm_equipment(tutorial_mob, /datum/equipment_preset/tutorial/fed) return ..() diff --git a/code/datums/tutorial/tutorial_example.dm b/code/datums/tutorial/tutorial_example.dm index 067c705f623c..9042346f8d39 100644 --- a/code/datums/tutorial/tutorial_example.dm +++ b/code/datums/tutorial/tutorial_example.dm @@ -8,6 +8,7 @@ /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 diff --git a/code/game/objects/items/reagent_containers/autoinjectors.dm b/code/game/objects/items/reagent_containers/autoinjectors.dm index 4a5d4866354e..14dd156571b7 100644 --- a/code/game/objects/items/reagent_containers/autoinjectors.dm +++ b/code/game/objects/items/reagent_containers/autoinjectors.dm @@ -143,6 +143,7 @@ desc = "An EZ autoinjector loaded with 3 uses 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)" @@ -173,6 +174,7 @@ 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" @@ -194,6 +196,7 @@ 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" diff --git a/code/game/objects/items/shards.dm b/code/game/objects/items/shards.dm index 84c3d5b83427..37dfdcca337a 100644 --- a/code/game/objects/items/shards.dm +++ b/code/game/objects/items/shards.dm @@ -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,15 @@ 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 + +/obj/item/shard/shrapnel/tutorial/on_embed(mob/embedded_mob, obj/limb/target_organ) + 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, TRUE) 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 4b4b31539064..0abe77616f1c 100644 --- a/code/game/objects/items/weapons/blades.dm +++ b/code/game/objects/items/weapons/blades.dm @@ -223,6 +223,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/modules/gear_presets/other.dm b/code/modules/gear_presets/other.dm index 2192a26d6d8c..b7f70517dfd2 100644 --- a/code/modules/gear_presets/other.dm +++ b/code/modules/gear_presets/other.dm @@ -961,6 +961,12 @@ 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) - new_human.nutrition = NUTRITION_LOW + if(underfed) + new_human.nutrition = NUTRITION_LOW + +/datum/equipment_preset/tutorial/fed + underfed = FALSE diff --git a/code/modules/maptext_alerts/screen_alerts.dm b/code/modules/maptext_alerts/screen_alerts.dm index 3a25f9c07381..9c88dac5c52e 100644 --- a/code/modules/maptext_alerts/screen_alerts.dm +++ b/code/modules/maptext_alerts/screen_alerts.dm @@ -65,10 +65,10 @@ style_close = "" /atom/movable/screen/text/screen_text/command_order/tutorial - letters_per_update = 5 // overall, pretty fast while not immediately popping in + letters_per_update = 4 // overall, pretty fast while not immediately popping in play_delay = 0.1 - fade_out_delay = 1.5 SECONDS - fade_out_time = 0.2 SECONDS + fade_out_delay = 2 SECONDS + fade_out_time = 0.4 SECONDS ///proc for actually playing this screen_text on a mob. /atom/movable/screen/text/screen_text/proc/play_to_client() diff --git a/code/modules/organs/limbs.dm b/code/modules/organs/limbs.dm index 58d0a4780681..a68aa0d0abc4 100644 --- a/code/modules/organs/limbs.dm +++ b/code/modules/organs/limbs.dm @@ -546,6 +546,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)