From 6331ced3e5d4507b60a5512675f6242a678f4d14 Mon Sep 17 00:00:00 2001 From: keronshb Date: Wed, 13 Oct 2021 22:13:33 -0400 Subject: [PATCH] The rest of the offering stuff --- code/__DEFINES/_flags/obj_flags.dm | 1 + code/__DEFINES/dcs/signals.dm | 4 +- code/__DEFINES/role_preferences.dm | 2 +- code/__DEFINES/status_effects.dm | 2 + code/__HELPERS/mobs.dm | 3 + code/_onclick/hud/alert.dm | 60 +++++++-------- code/datums/status_effects/neutral.dm | 82 +++++++++++++++++++++ code/datums/status_effects/status_effect.dm | 6 +- code/game/objects/items.dm | 26 ++++++- code/game/objects/items/weaponry.dm | 20 +++-- code/modules/mob/living/carbon/inventory.dm | 63 ++++++++-------- 11 files changed, 190 insertions(+), 79 deletions(-) diff --git a/code/__DEFINES/_flags/obj_flags.dm b/code/__DEFINES/_flags/obj_flags.dm index ac772c6e8e..5f5ea12aaa 100644 --- a/code/__DEFINES/_flags/obj_flags.dm +++ b/code/__DEFINES/_flags/obj_flags.dm @@ -16,6 +16,7 @@ #define SHOVABLE_ONTO (1<<13)//called on turf.shove_act() to consider whether an object should have a niche effect (defined in their own shove_act()) when someone is pushed onto it, or do a sanity CanPass() check. #define EXAMINE_SKIP (1<<14) /// Makes the Examine proc not read out this item. #define IN_STORAGE (1<<15) //is this item in the storage item, such as backpack? used for tooltips +#define HAND_ITEM (1<<16) // If an item is just your hand (circled hand, slapper) and shouldn't block things like riding /// Integrity defines for clothing (not flags but close enough) #define CLOTHING_PRISTINE 0 // We have no damage on the clothing diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index e92fa3ce34..060e8a2d4c 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -455,11 +455,11 @@ #define COMSIG_MINE_TRIGGERED "minegoboom" ///from [/obj/effect/mine/proc/triggermine]: // Uncovered information #define COMPONENT_DEEPSCAN_UNCOVERED_INFORMATION 1 -///Called when an item is being offered, from [/obj/item/proc/on_offered(mob/living/carbon/giver)] +///Called when an item is being offered, from [/obj/item/proc/on_offered(mob/living/carbon/offerer)] #define COMSIG_ITEM_OFFERING "item_offering" ///Interrupts the offer proc #define COMPONENT_OFFER_INTERRUPT (1<<0) -///Called when an someone tries accepting an offered item, from [/obj/item/proc/on_offer_taken(mob/living/carbon/giver, mob/living/carbon/taker)] +///Called when an someone tries accepting an offered item, from [/obj/item/proc/on_offer_taken(mob/living/carbon/offer, mob/living/carbon/taker)] #define COMSIG_ITEM_OFFER_TAKEN "item_offer_taken" ///Interrupts the offer acceptance #define COMPONENT_OFFER_TAKE_INTERRUPT (1<<0) diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 3c0cdc2d39..3204a39b89 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -36,7 +36,7 @@ #define ROLE_DEATHSQUAD "deathsquad" #define ROLE_LAVALAND "lavaland" #define ROLE_INTERNAL_AFFAIRS "internal affairs agent" -#define ROLE_FAMILIES "gangster" +#define ROLE_FAMILIES "family boss" #define ROLE_FAMILY_HEAD_ASPIRANT "family head aspirant" #define ROLE_BLOODSUCKER "bloodsucker" #define ROLE_SPACE_DRAGON "Space Dragon" diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 5accbd959f..01d7794638 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -134,6 +134,8 @@ #define STATUS_EFFECT_INLOVE /datum/status_effect/in_love //Displays you as being in love with someone else, and makes hearts appear around them. +#define STATUS_EFFECT_OFFERING /datum/status_effect/offering // you are offering up an item to people + #define STATUS_EFFECT_HANDSHAKE /datum/status_effect/offering/secret_handshake // you are attempting to perform a secret Family handshake ///////////// diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 4693041f18..5026fe1030 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -461,3 +461,6 @@ GLOBAL_LIST_EMPTY(species_datums) /// Gets the client of the mob, allowing for mocking of the client. /// You only need to use this if you know you're going to be mocking clients somewhere else. #define GET_CLIENT(mob) (##mob.client || ##mob.mock_client) + +//check if the person is dead, not sure where to put this +#define IS_DEAD_OR_INCAP(source) (source.incapacitated() || source.stat) diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 54e4478cae..b6324d75f0 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -2,9 +2,6 @@ //PUBLIC - call these wherever you want - -/mob/proc/throw_alert(category, type, severity, obj/new_master, override = FALSE) - /* Proc to create or update an alert. Returns the alert if the alert is new or updated, 0 if it was thrown already category is a text string. Each mob may only have one alert per category; the previous one will be replaced path is a type path of the actual alert type to throw @@ -14,6 +11,7 @@ Clicks are forwarded to master Override makes it so the alert is not replaced until cleared by a clear_alert with clear_override, and it's used for hallucinations. */ +/mob/proc/throw_alert(category, type, severity, obj/new_master, override = FALSE) if(!category || QDELETED(src)) return @@ -309,37 +307,33 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." /atom/movable/screen/alert/give // information set when the give alert is made icon_state = "default" - var/mob/living/carbon/giver + var/mob/living/carbon/offerer var/obj/item/receiving /** - * Handles assigning most of the variables for the alert that pops up when an item is offered - * - * Handles setting the name, description and icon of the alert and tracking the person giving - * and the item being offered, also registers a signal that removes the alert from anyone who moves away from the giver - * Arguments: - * * taker - The person receiving the alert - * * giver - The person giving the alert and item - * * receiving - The item being given by the giver - */ -/atom/movable/screen/alert/give/proc/setup(mob/living/carbon/taker, mob/living/carbon/giver, obj/item/receiving) - name = "[giver] is offering [receiving]" - desc = "[giver] is offering [receiving]. Click this alert to take it." + * Handles assigning most of the variables for the alert that pops up when an item is offered + * + * Handles setting the name, description and icon of the alert and tracking the person giving + * and the item being offered, also registers a signal that removes the alert from anyone who moves away from the offerer + * Arguments: + * * taker - The person receiving the alert + * * offerer - The person giving the alert and item + * * receiving - The item being given by the offerer + */ +/atom/movable/screen/alert/give/proc/setup(mob/living/carbon/taker, mob/living/carbon/offerer, obj/item/receiving) + name = "[offerer] is offering [receiving]" + desc = "[offerer] is offering [receiving]. Click this alert to take it." icon_state = "template" cut_overlays() add_overlay(receiving) src.receiving = receiving - src.giver = giver - RegisterSignal(taker, COMSIG_MOVABLE_MOVED, .proc/removeAlert) - -/atom/movable/screen/alert/give/proc/removeAlert() - to_chat(usr, "You moved out of range of [giver]!") - usr.clear_alert("[giver]") + src.offerer = offerer + RegisterSignal(taker, COMSIG_MOVABLE_MOVED, .proc/check_in_range, override = TRUE) //Override to prevent runtimes when people offer a item multiple times /atom/movable/screen/alert/give/Click(location, control, params) . = ..() - var/mob/living/carbon/C = usr - C.take(giver, receiving) + if(!.) + return if(!iscarbon(usr)) CRASH("User for [src] is of type \[[usr.type]\]. This should never happen.") @@ -349,27 +343,27 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." /// An overrideable proc used simply to hand over the item when claimed, this is a proc so that high-fives can override them since nothing is actually transferred /atom/movable/screen/alert/give/proc/handle_transfer() var/mob/living/carbon/taker = owner - taker.take(giver, receiving) + taker.take(offerer, receiving) /// Simply checks if the other person is still in range /atom/movable/screen/alert/give/proc/check_in_range(atom/taker) SIGNAL_HANDLER - - if(!giver.CanReach(taker)) - to_chat(owner, span_warning("You moved out of range of [giver]!")) - owner.clear_alert("[giver]") + + if(!offerer.CanReach(taker)) + to_chat(owner, span_warning("You moved out of range of [offerer]!")) + owner.clear_alert("[offerer]") /atom/movable/screen/alert/give/secret_handshake icon_state = "default" -/atom/movable/screen/alert/give/secret_handshake/setup(mob/living/carbon/taker, mob/living/carbon/giver, obj/item/receiving) - name = "[giver] is offering a Handshake" - desc = "[giver] wants to teach you the Secret Handshake for their Family and induct you! Click on this alert to accept." +/atom/movable/screen/alert/give/secret_handshake/setup(mob/living/carbon/taker, mob/living/carbon/offerer, obj/item/receiving) + name = "[offerer] is offering a Handshake" + desc = "[offerer] wants to teach you the Secret Handshake for their Family and induct you! Click on this alert to accept." icon_state = "template" cut_overlays() add_overlay(receiving) src.receiving = receiving - src.giver = giver + src.offerer = offerer RegisterSignal(taker, COMSIG_MOVABLE_MOVED, .proc/check_in_range, override = TRUE) //Override to prevent runtimes when people offer a item multiple times //ALIENS diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index 22cafd5f36..291761a197 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -84,6 +84,88 @@ REMOVE_TRAIT(owner, TRAIT_SOOTHED_THROAT, "[STATUS_EFFECT_TRAIT]_[id]") return ..() +// this status effect is used to negotiate the high-fiving capabilities of all concerned parties +/datum/status_effect/offering + id = "offering" + duration = -1 + tick_interval = -1 + status_type = STATUS_EFFECT_UNIQUE + alert_type = null + /// The people who were offered this item at the start + var/list/possible_takers + /// The actual item being offered + var/obj/item/offered_item + /// The type of alert given to people when offered, in case you need to override some behavior (like for high-fives) + var/give_alert_type = /atom/movable/screen/alert/give + +/datum/status_effect/offering/on_creation(mob/living/new_owner, obj/item/offer, give_alert_override) + . = ..() + if(!.) + return + + offered_item = offer + if(give_alert_override) + give_alert_type = give_alert_override + + for(var/mob/living/carbon/possible_taker in orange(1, owner)) + if(!owner.CanReach(possible_taker) || IS_DEAD_OR_INCAP(possible_taker) || !possible_taker.can_hold_items()) + continue + register_candidate(possible_taker) + + if(!possible_takers) // no one around + qdel(src) + return + + RegisterSignal(owner, COMSIG_MOVABLE_MOVED, .proc/check_owner_in_range) + RegisterSignal(offered_item, list(COMSIG_PARENT_QDELETING, COMSIG_ITEM_DROPPED), .proc/dropped_item) + //RegisterSignal(owner, COMSIG_PARENT_EXAMINE_MORE, .proc/check_fake_out) + +/datum/status_effect/offering/Destroy() + for(var/i in possible_takers) + var/mob/living/carbon/removed_taker = i + remove_candidate(removed_taker) + LAZYCLEARLIST(possible_takers) + return ..() + +/// Hook up the specified carbon mob to be offered the item in question, give them the alert and signals and all +/datum/status_effect/offering/proc/register_candidate(mob/living/carbon/possible_candidate) + var/atom/movable/screen/alert/give/G = possible_candidate.throw_alert("[owner]", give_alert_type) + if(!G) + return + LAZYADD(possible_takers, possible_candidate) + RegisterSignal(possible_candidate, COMSIG_MOVABLE_MOVED, .proc/check_taker_in_range) + G.setup(possible_candidate, owner, offered_item) + +/// Remove the alert and signals for the specified carbon mob. Automatically removes the status effect when we lost the last taker +/datum/status_effect/offering/proc/remove_candidate(mob/living/carbon/removed_candidate) + removed_candidate.clear_alert("[owner]") + LAZYREMOVE(possible_takers, removed_candidate) + UnregisterSignal(removed_candidate, COMSIG_MOVABLE_MOVED) + if(!possible_takers && !QDELING(src)) + qdel(src) + +/// One of our possible takers moved, see if they left us hanging +/datum/status_effect/offering/proc/check_taker_in_range(mob/living/carbon/taker) + SIGNAL_HANDLER + if(owner.CanReach(taker) && !IS_DEAD_OR_INCAP(taker)) + return + + remove_candidate(taker) + +/// The offerer moved, see if anyone is out of range now +/datum/status_effect/offering/proc/check_owner_in_range(mob/living/carbon/source) + SIGNAL_HANDLER + + for(var/i in possible_takers) + var/mob/living/carbon/checking_taker = i + if(!istype(checking_taker) || !owner.CanReach(checking_taker) || IS_DEAD_OR_INCAP(checking_taker)) + remove_candidate(checking_taker) + +/// We lost the item, give it up +/datum/status_effect/offering/proc/dropped_item(obj/item/source) + SIGNAL_HANDLER + qdel(src) + /datum/status_effect/offering/secret_handshake id = "secret_handshake" alert_type = /atom/movable/screen/alert/give/secret_handshake diff --git a/code/datums/status_effects/status_effect.dm b/code/datums/status_effects/status_effect.dm index fe605ba4a6..f5ceff09aa 100644 --- a/code/datums/status_effects/status_effect.dm +++ b/code/datums/status_effects/status_effect.dm @@ -25,11 +25,11 @@ /datum/status_effect/proc/on_creation(mob/living/new_owner, ...) if(new_owner) owner = new_owner - if(owner) - LAZYADD(owner.status_effects, src) - if(!owner || !on_apply()) + if(QDELETED(owner) || !on_apply()) qdel(src) return + if(owner) + LAZYADD(owner.status_effects, src) if(duration != -1) duration = world.time + duration next_tick = world.time + tick_interval diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index aab06c875b..1420a8c078 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1196,6 +1196,28 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb embed_chance_turf_mod = (!isnull(embedding["embed_chance_turf_mod"]) ? embedding["embed_chance_turf_mod"] : EMBED_CHANCE_TURF_MOD)) return TRUE -/obj/item/proc/on_offer_taken(mob/living/carbon/giver, mob/living/carbon/taker) - if(SEND_SIGNAL(src, COMSIG_ITEM_OFFER_TAKEN, giver, taker) & COMPONENT_OFFER_INTERRUPT) + +/** + * * An interrupt for offering an item to other people, called mainly from [/mob/living/carbon/proc/give], in case you want to run your own offer behavior instead. + * + * * Return TRUE if you want to interrupt the offer. + * + * * Arguments: + * * offerer - the person offering the item + */ +/obj/item/proc/on_offered(mob/living/carbon/offerer) + if(SEND_SIGNAL(src, COMSIG_ITEM_OFFERING, offerer) & COMPONENT_OFFER_INTERRUPT) + return TRUE + +/** + * * An interrupt for someone trying to accept an offered item, called mainly from [/mob/living/carbon/proc/take], in case you want to run your own take behavior instead. + * + * * Return TRUE if you want to interrupt the taking. + * + * * Arguments: + * * offerer - the person offering the item + * * taker - the person trying to accept the offer + */ +/obj/item/proc/on_offer_taken(mob/living/carbon/offerer, mob/living/carbon/taker) + if(SEND_SIGNAL(src, COMSIG_ITEM_OFFER_TAKEN, offerer, taker) & COMPONENT_OFFER_INTERRUPT) return TRUE diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 5e5c55eab4..c89c0ce735 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -1105,7 +1105,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 icon_state = "madeyoulook" force = 0 throwforce = 0 - item_flags = DROPDEL | ABSTRACT // | HAND_ITEM + item_flags = DROPDEL | ABSTRACT | HAND_ITEM attack_verb = list("bopped") /obj/item/circlegame/Initialize() @@ -1207,7 +1207,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 item_state = "nothing" force = 0 throwforce = 0 - item_flags = DROPDEL | ABSTRACT // | HAND_ITEM + item_flags = DROPDEL | ABSTRACT | HAND_ITEM attack_verb = list("slapped") hitsound = 'sound/effects/snap.ogg' @@ -1227,6 +1227,12 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 return FALSE return TRUE +/obj/item/slapper/on_offered(mob/living/carbon/offerer) + . = TRUE + +/obj/item/slapper/on_offer_taken(mob/living/carbon/offerer, mob/living/carbon/taker) + . = TRUE + /// Gangster secret handshakes. /obj/item/slapper/secret_handshake name = "Secret Handshake" @@ -1268,10 +1274,10 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 user.mind.remove_antag_datum(/datum/antagonist/gang) add_to_gang(user, real_name_backup) -/obj/item/slapper/secret_handshake/on_offer_taken(mob/living/carbon/giver, mob/living/carbon/taker) +/obj/item/slapper/secret_handshake/on_offer_taken(mob/living/carbon/offerer, mob/living/carbon/taker) . = TRUE if (!(null in taker.held_items)) - to_chat(taker, span_warning("You can't get taught the secret handshake if [giver] has no free hands!")) + to_chat(taker, span_warning("You can't get taught the secret handshake if [offerer] has no free hands!")) return if(HAS_TRAIT(taker, TRAIT_MINDSHIELD)) @@ -1286,9 +1292,9 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 to_chat(taker, "You started your family. You can't turn your back on it now.") return - giver.visible_message(span_notice("[taker] is taught the secret handshake by [giver]!"), span_nicegreen("All right! You've taught the secret handshake to [taker]!"), span_hear("You hear a bunch of weird shuffling and flesh slapping sounds!"), ignored_mobs=taker) - to_chat(taker, span_nicegreen("You get taught the secret handshake by [giver]!")) - var/datum/antagonist/gang/owner_gang_datum = giver.mind.has_antag_datum(/datum/antagonist/gang) + offerer.visible_message(span_notice("[taker] is taught the secret handshake by [offerer]!"), span_nicegreen("All right! You've taught the secret handshake to [taker]!"), span_hear("You hear a bunch of weird shuffling and flesh slapping sounds!"), ignored_mobs=taker) + to_chat(taker, span_nicegreen("You get taught the secret handshake by [offerer]!")) + var/datum/antagonist/gang/owner_gang_datum = offerer.mind.has_antag_datum(/datum/antagonist/gang) handler = owner_gang_datum.handler gang_to_use = owner_gang_datum.type team_to_use = owner_gang_datum.my_gang diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index 48bb0ead0e..13f811196e 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -161,57 +161,58 @@ return index && hand_bodyparts[index] /** - * Proc called when giving an item to another player + * Proc called when offering an item to another player * * This handles creating an alert and adding an overlay to it */ /mob/living/carbon/proc/give(target) - var/obj/item/receiving = get_active_held_item() - if(!receiving) + var/obj/item/offered_item = get_active_held_item() + if(!offered_item) to_chat(src, "You're not holding anything to give!") return - visible_message("[src] is offering [receiving]", \ - "You offer [receiving]", null, 2) - var/mob/living/carbon/targets = list() - if(!target) - for(var/mob/living/carbon/C in orange(1, src)) - if(!CanReach(C)) - return - targets += C - else - targets += target - if(!targets) + + if(IS_DEAD_OR_INCAP(src)) + to_chat(src, span_warning("You're unable to offer anything in your current state!")) return - for(var/mob/living/carbon/C in targets) - var/atom/movable/screen/alert/give/G = C.throw_alert("[src]", /atom/movable/screen/alert/give) - if(!G) - return - G.setup(C, src, receiving) + + if(has_status_effect(STATUS_EFFECT_OFFERING)) + to_chat(src, span_warning("You're already offering up something!")) + return + + if(offered_item.on_offered(src)) // see if the item interrupts with its own behavior + return + + visible_message(span_notice("[src] is offering [offered_item]."), \ + span_notice("You offer [offered_item]."), null, 2) + + apply_status_effect(STATUS_EFFECT_OFFERING, offered_item) /** * Proc called when the player clicks the give alert * - * Handles checking if the player taking the item has open slots and is in range of the giver + * Handles checking if the player taking the item has open slots and is in range of the offerer * Also deals with the actual transferring of the item to the players hands * Arguments: - * * giver - The person giving the original item - * * I - The item being given by the giver + * * offerer - The person giving the original item + * * I - The item being given by the offerer */ -/mob/living/carbon/proc/take(mob/living/carbon/giver, obj/item/I) - clear_alert("[giver]") - if(get_dist(src, giver) > 1) - to_chat(src, "[giver] is out of range! ") +/mob/living/carbon/proc/take(mob/living/carbon/offerer, obj/item/I) + clear_alert("[offerer]") + if(get_dist(src, offerer) > 1) + to_chat(src, span_warning("[offerer] is out of range!")) return - if(!I || giver.get_active_held_item() != I) - to_chat(src, "[giver] is no longer holding the item they were offering! ") + if(!I || offerer.get_active_held_item() != I) + to_chat(src, span_warning("[offerer] is no longer holding the item they were offering!")) return if(!get_empty_held_indexes()) to_chat(src, "You have no empty hands!") return - if(I.on_offer_taken(giver, src)) // see if the item has special behavior for being accepted + if(I.on_offer_taken(offerer, src)) // see if the item has special behavior for being accepted return - if(!giver.temporarilyRemoveItemFromInventory(I)) - visible_message("[src] tries to hand over [I] but it's stuck to them....", \ + if(!offerer.temporarilyRemoveItemFromInventory(I)) + visible_message("[offerer] tries to hand over [I] but it's stuck to them....", \ " You make a fool of yourself trying to give away an item stuck to your hands") return + visible_message(span_notice("[src] takes [I] from [offerer]"), \ + span_notice("You take [I] from [offerer]")) put_in_hands(I)