From 6755a031e4b804a6651ba5dfdc0fa04284bef588 Mon Sep 17 00:00:00 2001 From: AlManiak Date: Fri, 31 Jan 2025 12:15:56 +0100 Subject: [PATCH] Initial commit collar works with food and drinks --- .../code/clothing/bluespace_collar.dm | 145 ++++++++++++++++++ code/datums/components/edible.dm | 18 ++- code/modules/food_and_drinks/drinks/drinks.dm | 38 +++-- code/modules/food_and_drinks/food/snacks.dm | 54 ++++--- tgstation.dme | 1 + 5 files changed, 215 insertions(+), 41 deletions(-) create mode 100644 GainStation13/code/clothing/bluespace_collar.dm diff --git a/GainStation13/code/clothing/bluespace_collar.dm b/GainStation13/code/clothing/bluespace_collar.dm new file mode 100644 index 0000000000..5a16a2ac3b --- /dev/null +++ b/GainStation13/code/clothing/bluespace_collar.dm @@ -0,0 +1,145 @@ +/obj/item/clothing/neck/petcollar/locked/bluespace_collar_receiver + name = "bluespace collar receiver" + desc = "A collar containing a miniaturized bluespace whitehole. Other bluespace transmitter collars can connect to this, causing the wearer to receive food from other transmitter collars directly into the stomach. " + slot_flags = ITEM_SLOT_NECK + var/mob/victim = 0 + +/obj/item/clothing/neck/petcollar/locked/bluespace_collar_receiver/equipped(mob/user, slot) + . = ..() + var/mob/living/carbon/wearer = user + if(!iscarbon(wearer) || slot !=ITEM_SLOT_NECK || !wearer?.client?.prefs?.weight_gain_items) + return FALSE + victim = user; + +/obj/item/clothing/neck/petcollar/locked/bluespace_collar_receiver/dropped(mob/user) + . = ..() + var/mob/living/carbon/wearer = user + if(!iscarbon(wearer) || !(wearer.get_item_by_slot(ITEM_SLOT_NECK) == src) || !wearer?.client?.prefs?.weight_gain_items) + return FALSE + victim = 0 + +/obj/item/clothing/neck/petcollar/locked/bluespace_collar_receiver/attackby(obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter/K, mob/user, params) + if(istype(K, /obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter)) + K.linked_receiver = src + var/mob/living/carbon/U = user + to_chat(U, "You link the bluespace collar with the other transmitter") + return + +/obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter + name = "bluespace collar transmitter" + desc = "A collar containing a miniaturized bluespace blackhole. Can be connected to a bluespace collar receiver to transmit food to a linked receiver collar. " + slot_flags = ITEM_SLOT_NECK + var/obj/item/clothing/neck/petcollar/locked/bluespace_collar_receiver/linked_receiver = 0 + +/obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter/equipped(mob/user, slot) + . = ..() + var/mob/living/carbon/wearer = user + if(!iscarbon(wearer) || slot !=ITEM_SLOT_NECK || !wearer?.client?.prefs?.weight_gain_items) + return FALSE + +/obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter/dropped(mob/user) + . = ..() + var/mob/living/carbon/wearer = user + if(!iscarbon(wearer) || !(wearer.get_item_by_slot(ITEM_SLOT_NECK) == src) || !wearer?.client?.prefs?.weight_gain_items) + return FALSE + +/obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter/attackby(obj/item/K, mob/user, params) + if(istype(K, /obj/item/clothing/neck/petcollar/locked/bluespace_collar_receiver)) + linked_receiver = K + var/mob/living/carbon/U = user + to_chat(U, "You link the bluespace collar to the other receiver") + return + +// For food +/obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter/proc/transpose_food(obj/item/reagent_containers/food/snacks/owner, mob/living/original_eater, mob/living/feeder) + if (!linked_receiver) + return FALSE + + var/mob/living/carbon/human/eater = linked_receiver.victim + if(owner.reagents) + if(eater.satiety > -200) + eater.satiety -= owner.junkiness + playsound(eater.loc,'sound/items/eatfood.ogg', rand(10,50), 1) + playsound(original_eater.loc,'sound/items/eatfood.ogg', rand(10,50), 1) + eater.visible_message("[eater]'s belly seems to visibly distend a bit further'!", "You feel your stomach get filled by something!") + var/bitevolume = 1 + if(HAS_TRAIT(original_eater, TRAIT_VORACIOUS)) + bitevolume = bitevolume * 0.67 + var/mob/living/carbon/human/human_eater = eater + if(istype(human_eater)) + human_eater.fullness += bitevolume; + + if(owner.reagents.total_volume) + SEND_SIGNAL(owner, COMSIG_FOOD_EATEN, eater, feeder) + var/fraction = min(owner.bitesize / owner.reagents.total_volume, 1) + owner.reagents.reaction(eater, INGEST, fraction) + owner.reagents.trans_to(eater, owner.bitesize, log = TRUE) + owner.bitecount++ + owner.On_Consume(eater) + owner.checkLiked(fraction, original_eater) + return TRUE + +// For the alternative edible functionality +/obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter/proc/transpose_edible(datum/component/edible/foodstuff, mob/living/original_eater, mob/living/feeder) + if (!linked_receiver) + return FALSE + + var/atom/owner = foodstuff.parent + var/mob/living/carbon/human/eater = linked_receiver.victim + + if(!owner?.reagents) + return FALSE + if(eater.satiety > -200) + eater.satiety -= foodstuff.junkiness + playsound(original_eater.loc,'sound/items/eatfood.ogg', rand(10,50), TRUE) + playsound(eater.loc,'sound/items/eatfood.ogg', rand(10,50), TRUE) + eater.visible_message("[eater]'s belly seems to visibly distend a bit further'!", "You feel your stomach get filled by something!") + var/mob/living/carbon/human/human_eater = original_eater + if(istype(human_eater)) + var/bitevolume = 1 + if(HAS_TRAIT(human_eater, TRAIT_VORACIOUS)) + bitevolume = bitevolume * 0.67 + if(istype(eater)) + eater.fullness += bitevolume; + + if(owner.reagents.total_volume) + SEND_SIGNAL(foodstuff.parent, COMSIG_FOOD_EATEN, eater, original_eater) + var/fraction = min(foodstuff.bite_consumption / owner.reagents.total_volume, 1) + owner.reagents.reaction(eater, INGEST, fraction) + owner.reagents.trans_to(eater, foodstuff.bite_consumption) + foodstuff.bitecount++ + foodstuff.On_Consume(eater) + foodstuff.checkLiked(fraction, original_eater) + + //Invoke our after eat callback if it is valid + if(foodstuff.after_eat) + foodstuff.after_eat.Invoke(eater, feeder) + return TRUE + +// For Drinks +/obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter/proc/transpose_drink(obj/item/reagent_containers/food/drinks/owner, mob/living/original_eater, mob/living/feeder) + if (!linked_receiver) + return FALSE + + var/mob/living/carbon/human/eater = linked_receiver.victim + var/fraction = min(owner.gulp_size/owner.reagents.total_volume, 1) + owner.checkLiked(fraction, eater) + owner.reagents.reaction(eater, INGEST, fraction) + owner.reagents.trans_to(eater, owner.gulp_size, log = TRUE) + //GS13 Port - Fullness + if(iscarbon(eater)) + var/mob/living/carbon/human/human_eater = eater + var/mob/living/carbon/human/human_original_eater = original_eater + if(HAS_TRAIT(human_original_eater, TRAIT_VORACIOUS)) + human_eater.fullness += min(owner.gulp_size * 0.67, owner.reagents.total_volume * 0.67) + else + human_eater.fullness += min(owner.gulp_size, owner.reagents.total_volume) // GS13 drinks will fill your stomach + playsound(original_eater.loc,'sound/items/drink.ogg', rand(10,50), 1) + playsound(eater.loc,'sound/items/drink.ogg', rand(10,50), 1) + eater.visible_message("[eater]'s belly seems to visibly distend a bit further, emitting an audible sloshing noise!", "You feel your stomach get filled by liquid, hearing sloshing noises coming from within!") + return TRUE + +/obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter/attack_self(mob/user) + linked_receiver = 0 + var/mob/living/carbon/U = user + to_chat(U, "You remove the currently linked receiver collar from the buffer") diff --git a/code/datums/components/edible.dm b/code/datums/components/edible.dm index 95ca5eaef6..a6cb4cfb53 100644 --- a/code/datums/components/edible.dm +++ b/code/datums/components/edible.dm @@ -111,12 +111,18 @@ Behavior that's still missing from this component that original food items had t . = COMPONENT_ITEM_NO_ATTACK //Point of no return I suppose + var/obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter/K = human_eater.wear_neck //GS13 - Bluespace collar if(eater == feeder)//If you're eating it yourself. if(!do_mob(feeder, eater, eat_time)) //Gotta pass the minimal eat time return var/eatverb = pick(eatverbs) - if(junkiness && eater.satiety < -150 && eater.nutrition > NUTRITION_LEVEL_STARVING + 50 && !HAS_TRAIT(eater, TRAIT_VORACIOUS)) + //GS13 - Bluespace collar addition + if (istype(K, /obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter)) + eater.visible_message("[eater] effortlessly [eatverb]s \the [parent].", "You effortlessly [eatverb] \the [parent], feeling as if you haven't eaten anything at all.") + //GS13 - End + else if(junkiness && eater.satiety < -150 && eater.nutrition > NUTRITION_LEVEL_STARVING + 50 && !HAS_TRAIT(eater, TRAIT_VORACIOUS)) to_chat(eater, "You don't feel like eating any more junk food at the moment!") + return else if(fullness <= FULLNESS_LEVEL_HALF_FULL) eater.visible_message("[eater] hungrily [eatverb]s \the [parent], gobbling it down!", "You hungrily [eatverb] \the [parent], gobbling it down!") @@ -133,7 +139,12 @@ Behavior that's still missing from this component that original food items had t if(isbrain(eater)) to_chat(feeder, "[eater] doesn't seem to have a mouth!") return - if(fullness <= (600 * (1 + eater.overeatduration / 1000))) + //GS13 - Bluespace collar addition + if (istype(K, /obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter)) + eater.visible_message("[feeder] attempts to feed [eater] [parent].", \ + "[feeder] attempts to feed you [parent].") + //GS13 - End + else if(fullness <= (600 * (1 + eater.overeatduration / 1000))) eater.visible_message("[feeder] attempts to feed [eater] [parent].", \ "[feeder] attempts to feed you [parent].") else @@ -147,7 +158,8 @@ Behavior that's still missing from this component that original food items had t eater.visible_message("[feeder] forces [eater] to eat [parent]!", \ "[feeder] forces you to eat [parent]!") - TakeBite(eater, feeder) + if (!(istype(K, /obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter) && K.transpose_food(src, eater, feeder))) + TakeBite(eater, feeder) ///This function lets the eater take a bite and transfers the reagents to the eater. /datum/component/edible/proc/TakeBite(mob/living/eater, mob/living/feeder) diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm index 61a872fed9..49205a54a6 100644 --- a/code/modules/food_and_drinks/drinks/drinks.dm +++ b/code/modules/food_and_drinks/drinks/drinks.dm @@ -30,9 +30,17 @@ if (!is_drainable()) to_chat(user, "[src]'s lid hasn't been opened!") return FALSE - + //GS13 - Bluespace collar addition + var/obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter/K = 0 + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/human_eater = M + K = human_eater.wear_neck if(M == user) - user.visible_message("[user] swallows a gulp of [src].", "You swallow a gulp of [src].") + if (istype(K, /obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter)) + user.visible_message("[user] effortlessly swallows a gulp of [src].", "You effortlessly swallow a gulp of [src].") + //GS13 - End + else + user.visible_message("[user] swallows a gulp of [src].", "You swallow a gulp of [src].") else M.visible_message("[user] attempts to feed the contents of [src] to [M].", "[user] attempts to feed the contents of [src] to [M].") if(!do_mob(user, M)) @@ -41,19 +49,19 @@ return // The drink might be empty after the delay, such as by spam-feeding M.visible_message("[user] feeds the contents of [src] to [M].", "[user] feeds the contents of [src] to [M].") log_combat(user, M, "fed", reagents.log_list()) - - var/fraction = min(gulp_size/reagents.total_volume, 1) - checkLiked(fraction, M) - reagents.reaction(M, INGEST, fraction) - reagents.trans_to(M, gulp_size, log = TRUE) - //GS13 Port - Fullness - if(iscarbon(M)) - var/mob/living/carbon/human/human_eater = M - if(HAS_TRAIT(M, TRAIT_VORACIOUS)) - human_eater.fullness += min(gulp_size * 0.67, reagents.total_volume * 0.67) - else - human_eater.fullness += min(gulp_size, reagents.total_volume) // GS13 drinks will fill your stomach - playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1) + if (!(istype(K, /obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter) && K.transpose_drink(src, M, user))) //GS13 - Bluespace Collar + var/fraction = min(gulp_size/reagents.total_volume, 1) + checkLiked(fraction, M) + reagents.reaction(M, INGEST, fraction) + reagents.trans_to(M, gulp_size, log = TRUE) + //GS13 Port - Fullness + if(iscarbon(M)) + var/mob/living/carbon/human/human_eater = M + if(HAS_TRAIT(M, TRAIT_VORACIOUS)) + human_eater.fullness += min(gulp_size * 0.67, reagents.total_volume * 0.67) + else + human_eater.fullness += min(gulp_size, reagents.total_volume) // GS13 drinks will fill your stomach + playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1) return TRUE /obj/item/reagent_containers/food/drinks/CheckAttackCooldown(mob/user, atom/target) diff --git a/code/modules/food_and_drinks/food/snacks.dm b/code/modules/food_and_drinks/food/snacks.dm index fbc8403bee..38c14fdc1a 100644 --- a/code/modules/food_and_drinks/food/snacks.dm +++ b/code/modules/food_and_drinks/food/snacks.dm @@ -122,9 +122,13 @@ All foods are distributed among various categories. Use common sense. var/mob/living/carbon/human/human_eater = M if(istype(human_eater)) fullness = human_eater.fullness - + var/obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter/K = human_eater.wear_neck //GS13 - Bluespace collar if(M == user) //If you're eating it yourself. - if(junkiness && M.satiety < -150 && M.nutrition > NUTRITION_LEVEL_STARVING + 50 ) + //GS13 - Bluespace collar addition + if (istype(K, /obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter)) + user.visible_message("[user] effortlessly [eatverb]s \the [src].", "You effortlessly [eatverb] \the [src], feeling as if you haven't eaten anything at all.") + //GS13 - End + else if(junkiness && M.satiety < -150 && M.nutrition > NUTRITION_LEVEL_STARVING + 50 ) to_chat(M, "You don't feel like eating any more junk food at the moment.") return FALSE else if(fullness <= 50) @@ -142,7 +146,12 @@ All foods are distributed among various categories. Use common sense. M.SetNextAction(CLICK_CD_MELEE * 0.5) //nom nom nom else if(!isbrain(M)) //If you're feeding it to someone else. - if(fullness <= (FULLNESS_LEVEL_BEEG * (1 + M.overeatduration / 1000))) + //GS13 - Bluespace collar addition + if (istype(K, /obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter)) + M.visible_message("[user] attempts to feed [M] [src].", \ + "[user] attempts to feed you [src].") + //GS13 - End + else if(fullness <= (FULLNESS_LEVEL_BEEG * (1 + M.overeatduration / 1000))) M.visible_message("[user] attempts to feed [M] [src].", \ "[user] attempts to feed [M] [src].") else @@ -159,27 +168,26 @@ All foods are distributed among various categories. Use common sense. else to_chat(user, "[M] doesn't seem to have a mouth!") return + if (!(istype(K, /obj/item/clothing/neck/petcollar/locked/bluespace_collar_transmitter) && K.transpose_food(src, M, user))) + if(reagents) //Handle ingestion of the reagent. + if(M.satiety > -200) + M.satiety -= junkiness + playsound(M.loc,'sound/items/eatfood.ogg', rand(10,50), 1) + var/bitevolume = 1 + if(HAS_TRAIT(M, TRAIT_VORACIOUS)) + bitevolume = bitevolume * 0.67 + if(istype(human_eater)) + human_eater.fullness += bitevolume; - if(reagents) //Handle ingestion of the reagent. - if(M.satiety > -200) - M.satiety -= junkiness - playsound(M.loc,'sound/items/eatfood.ogg', rand(10,50), 1) - var/bitevolume = 1 - if(HAS_TRAIT(M, TRAIT_VORACIOUS)) - bitevolume = bitevolume * 0.67 - human_eater.fullness += bitevolume; - if(istype(human_eater)) - human_eater.fullness += bitevolume; - - if(reagents.total_volume) - SEND_SIGNAL(src, COMSIG_FOOD_EATEN, M, user) - var/fraction = min(bitesize / reagents.total_volume, 1) - reagents.reaction(M, INGEST, fraction) - reagents.trans_to(M, bitesize, log = TRUE) - bitecount++ - On_Consume(M) - checkLiked(fraction, M) - return TRUE + if(reagents.total_volume) + SEND_SIGNAL(src, COMSIG_FOOD_EATEN, M, user) + var/fraction = min(bitesize / reagents.total_volume, 1) + reagents.reaction(M, INGEST, fraction) + reagents.trans_to(M, bitesize, log = TRUE) + bitecount++ + On_Consume(M) + checkLiked(fraction, M) + return TRUE return FALSE diff --git a/tgstation.dme b/tgstation.dme index e6836a43b0..1673ed4705 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3927,6 +3927,7 @@ #include "GainStation13\code\__HELPERS\transformation.dm" #include "GainStation13\code\clothing\accessory.dm" #include "GainStation13\code\clothing\backpacks.dm" +#include "GainStation13\code\clothing\bluespace_collar.dm" #include "GainStation13\code\clothing\calorite_collar.dm" #include "GainStation13\code\clothing\fat_mask.dm" #include "GainStation13\code\clothing\gloves.dm"