diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm index 0c2c4be8685..4e5a8938fec 100644 --- a/code/__DEFINES/dcs/signals/signals_global.dm +++ b/code/__DEFINES/dcs/signals/signals_global.dm @@ -43,8 +43,6 @@ #define COMSIG_GLOB_RANDOM_EVENT "!random_event" /// Do not allow this random event to continue. #define CANCEL_RANDOM_EVENT (1<<0) -/// a person somewhere has thrown something : (mob/living/carbon/carbon_thrower, target) -#define COMSIG_GLOB_CARBON_THROW_THING "!throw_thing" /// a trapdoor remote has sent out a signal to link with a trapdoor #define COMSIG_GLOB_TRAPDOOR_LINK "!trapdoor_link" ///successfully linked to a trapdoor! diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm index 650dc560a4a..1aa28be695a 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm @@ -146,9 +146,6 @@ ///from base of /mob/living/carbon/regenerate_limbs(): (excluded_limbs) #define COMSIG_CARBON_REGENERATE_LIMBS "living_regen_limbs" -///from /atom/movable/screen/alert/give/proc/handle_transfer(): (taker, item) -#define COMSIG_CARBON_ITEM_GIVEN "carbon_item_given" - /// Sent from /mob/living/carbon/human/handle_blood(): (seconds_per_tick, times_fired) #define COMSIG_HUMAN_ON_HANDLE_BLOOD "human_on_handle_blood" /// Return to prevent all default blood handling diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index f849817d24c..5a6e982d32a 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -293,8 +293,10 @@ ///cancel post eating #define COMSIG_MOB_TERMINATE_EAT (1<<0) -///From mob/living/carbon/proc/throw_mode_on and throw_mode_off +///From mob/living/proc/throw_mode_on and throw_mode_off #define COMSIG_LIVING_THROW_MODE_TOGGLE "living_throw_mode_toggle" +///from /atom/movable/screen/alert/give/proc/handle_transfer(): (taker, item) +#define COMSIG_LIVING_ITEM_GIVEN "living_item_given" /// From mob/living/proc/on_fall #define COMSIG_LIVING_THUD "living_thud" ///From /datum/component/happiness() diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index a113f0b88e8..b693999cddb 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -179,11 +179,11 @@ #define COMSIG_ARMOR_PLATED "armor_plated" ///Called when an item gets recharged by the ammo powerup #define COMSIG_ITEM_RECHARGED "item_recharged" -///Called when an item is being offered, from [/obj/item/proc/on_offered(mob/living/carbon/offerer)] +///Called when an item is being offered, from [/obj/item/proc/on_offered(mob/living/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/offerer, mob/living/carbon/taker)] +///Called when an someone tries accepting an offered item, from [/obj/item/proc/on_offer_taken(mob/living/offerer, mob/living/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/keybinding.dm b/code/__DEFINES/keybinding.dm index 8ae95933e64..61f73e5c584 100644 --- a/code/__DEFINES/keybinding.dm +++ b/code/__DEFINES/keybinding.dm @@ -22,9 +22,6 @@ //Carbon #define COMSIG_KB_CARBON_HOLDRUNMOVEINTENT_DOWN "keybinding_carbon_holdrunmoveintent_down" #define COMSIG_KB_CARBON_HOLDRUNMOVEINTENT_UP "keybinding_carbon_holdrunmoveintent_up" -#define COMSIG_KB_CARBON_TOGGLETHROWMODE_DOWN "keybinding_carbon_togglethrowmode_down" -#define COMSIG_KB_CARBON_HOLDTHROWMODE_DOWN "keybinding_carbon_holdthrowmode_down" -#define COMSIG_KB_CARBON_GIVEITEM_DOWN "keybinding_carbon_giveitem_down" //Client #define COMSIG_KB_CLIENT_GETHELP_DOWN "keybinding_client_gethelp_down" @@ -57,6 +54,9 @@ #define COMSIG_KB_LIVING_DISABLE_COMBAT_DOWN "keybinding_living_disable_combat_down" #define COMSIG_KB_LIVING_TOGGLEMOVEINTENT_DOWN "keybinding_mob_togglemoveintent_down" #define COMSIG_KB_LIVING_TOGGLEMOVEINTENTALT_DOWN "keybinding_mob_togglemoveintentalt_down" +#define COMSIG_KB_LIVING_TOGGLETHROWMODE_DOWN "keybinding_living_togglethrowmode_down" +#define COMSIG_KB_LIVING_HOLDTHROWMODE_DOWN "keybinding_living_holdthrowmode_down" +#define COMSIG_KB_LIVING_GIVEITEM_DOWN "keybinding_living_giveitem_down" #define COMSIG_KB_LIVING_VIEW_PET_COMMANDS "keybinding_living_view_pet_commands" //Mob diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 1ec5a3191ff..9203aa63286 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -60,6 +60,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_CLUMSY "clumsy" /// Trait that means you are capable of holding items in some form #define TRAIT_CAN_HOLD_ITEMS "can_hold_items" +/// Trait that means you're capable of throwing things +#define TRAIT_CAN_THROW_ITEMS "can_throw_items" /// Trait which lets you clamber over a barrier #define TRAIT_FENCE_CLIMBER "can_climb_fences" /// means that you can't use weapons with normal trigger guards. diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index e26587019ea..a8df896fa82 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -210,6 +210,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_CAN_MOUNT_HUMANS" = TRAIT_CAN_MOUNT_HUMANS, "TRAIT_CAN_SIGN_ON_COMMS" = TRAIT_CAN_SIGN_ON_COMMS, "TRAIT_CAN_STRIP" = TRAIT_CAN_STRIP, + "TRAIT_CAN_THROW_ITEMS" = TRAIT_CAN_THROW_ITEMS, "TRAIT_CAN_USE_NUKE" = TRAIT_CAN_USE_NUKE, "TRAIT_CATLIKE_GRACE" = TRAIT_CATLIKE_GRACE, "TRAIT_CHANGELING_HIVEMIND_MUTE" = TRAIT_CHANGELING_HIVEMIND_MUTE, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index 74c2b86e291..5f90572f0c5 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -62,6 +62,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_BYPASS_MEASURES" = TRAIT_BYPASS_MEASURES, "TRAIT_CAN_HOLD_ITEMS" = TRAIT_CAN_HOLD_ITEMS, "TRAIT_CAN_STRIP" = TRAIT_CAN_STRIP, + "TRAIT_CAN_THROW_ITEMS" = TRAIT_CAN_THROW_ITEMS, "TRAIT_CAN_USE_NUKE" = TRAIT_CAN_USE_NUKE, "TRAIT_CANNOT_BE_UNBUCKLED" = TRAIT_CANNOT_BE_UNBUCKLED, "TRAIT_CANNOT_OPEN_PRESENTS" = TRAIT_CANNOT_OPEN_PRESENTS, diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 2178554bf00..1b4a043678a 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -343,14 +343,13 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." /** * 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 + * Handles setting the name, description and icon of the alert and tracking the living mob giving * and the item being offered. * Arguments: - * * taker - The person receiving the alert - * * offerer - The person giving the alert and item - * * receiving - The item being given by the offerer + * * taker - The living mob receiving the alert + * * offer - The status effect connected to the offer being made */ -/atom/movable/screen/alert/give/proc/setup(mob/living/carbon/taker, datum/status_effect/offering/offer) +/atom/movable/screen/alert/give/proc/setup(mob/living/taker, datum/status_effect/offering/offer) src.offer = offer var/mob/living/offerer = offer.owner @@ -377,7 +376,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." * Returns a string that will be displayed in the alert, which is `receiving.name` * by default. */ -/atom/movable/screen/alert/give/proc/get_receiving_name(mob/living/carbon/taker, mob/living/carbon/offerer, obj/item/receiving) +/atom/movable/screen/alert/give/proc/get_receiving_name(mob/living/taker, mob/living/offerer, obj/item/receiving) return receiving.name /atom/movable/screen/alert/give/Click(location, control, params) @@ -385,7 +384,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." if(!.) return - if(!iscarbon(usr)) + if(!isliving(usr)) CRASH("User for [src] is of type \[[usr.type]\]. This should never happen.") handle_transfer() @@ -402,11 +401,11 @@ 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 + var/mob/living/taker = owner var/mob/living/offerer = offer.owner var/obj/item/receiving = offer.offered_item taker.take(offerer, receiving) - SEND_SIGNAL(offerer, COMSIG_CARBON_ITEM_GIVEN, taker, receiving) + SEND_SIGNAL(offerer, COMSIG_LIVING_ITEM_GIVEN, taker, receiving) /atom/movable/screen/alert/give/highfive additional_desc_text = "Click this alert to slap it." @@ -415,10 +414,10 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." /// Tracks active "to slow"ing so we can't spam click var/too_slowing_this_guy = FALSE -/atom/movable/screen/alert/give/highfive/get_receiving_name(mob/living/carbon/taker, mob/living/carbon/offerer, obj/item/receiving) +/atom/movable/screen/alert/give/highfive/get_receiving_name(mob/living/taker, mob/living/offerer, obj/item/receiving) return "a high-five" -/atom/movable/screen/alert/give/highfive/setup(mob/living/carbon/taker, datum/status_effect/offering/offer) +/atom/movable/screen/alert/give/highfive/setup(mob/living/taker, datum/status_effect/offering/offer) . = ..() RegisterSignal(offer.owner, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(check_fake_out)) @@ -426,7 +425,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." if(too_slowing_this_guy) return - var/mob/living/carbon/taker = owner + var/mob/living/taker = owner var/mob/living/offerer = offer.owner var/obj/item/receiving = offer.offered_item if(!QDELETED(receiving) && offerer.is_holding(receiving)) @@ -437,7 +436,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." /// If the person who offered the high five no longer has it when we try to accept it, we get pranked hard /atom/movable/screen/alert/give/highfive/proc/too_slow_p1() - var/mob/living/carbon/rube = owner + var/mob/living/rube = owner var/mob/living/offerer = offer?.owner if(QDELETED(rube) || QDELETED(offerer)) qdel(src) @@ -450,7 +449,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." /// Part two of the ultimate prank /atom/movable/screen/alert/give/highfive/proc/too_slow_p2() - var/mob/living/carbon/rube = owner + var/mob/living/rube = owner var/mob/living/offerer = offer?.owner if(!QDELETED(rube) && !QDELETED(offerer)) offerer.visible_message(span_danger("[offerer] pulls away from [rube]'s slap at the last second, dodging the high-five entirely!"), span_nicegreen("[rube] fails to make contact with your hand, making an utter fool of [rube.p_them()]self!"), span_hear("You hear a disappointing sound of flesh not hitting flesh!"), ignored_mobs=rube) @@ -474,13 +473,13 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." screentip_override_text = "Take Hand" examinable = FALSE -/atom/movable/screen/alert/give/hand/get_receiving_name(mob/living/carbon/taker, mob/living/carbon/offerer, obj/item/receiving) +/atom/movable/screen/alert/give/hand/get_receiving_name(mob/living/taker, mob/living/offerer, obj/item/receiving) additional_desc_text = "Click this alert to take it and let [offerer.p_them()] pull you around!" return "[offerer.p_their()] [receiving.name]" /atom/movable/screen/alert/give/hand/helping -/atom/movable/screen/alert/give/hand/helping/get_receiving_name(mob/living/carbon/taker, mob/living/carbon/offerer, obj/item/receiving) +/atom/movable/screen/alert/give/hand/helping/get_receiving_name(mob/living/taker, mob/living/offerer, obj/item/receiving) . = ..() additional_desc_text = "Click this alert to let them help you up!" diff --git a/code/_onclick/hud/generic_dextrous.dm b/code/_onclick/hud/generic_dextrous.dm index 134f91a2b8d..b7f7f7af739 100644 --- a/code/_onclick/hud/generic_dextrous.dm +++ b/code/_onclick/hud/generic_dextrous.dm @@ -31,6 +31,11 @@ floor_change.icon = 'icons/hud/screen_midnight.dmi' static_inventory += floor_change + if(HAS_TRAIT(owner, TRAIT_CAN_THROW_ITEMS)) + throw_icon = new /atom/movable/screen/throw_catch(null, src) + throw_icon.icon = ui_style + throw_icon.screen_loc = ui_drop_throw + static_inventory += throw_icon zone_select = new /atom/movable/screen/zone_sel(null, src) zone_select.icon = ui_style diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index a7eab74eebc..036e2e4b988 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -544,9 +544,9 @@ mouse_over_pointer = MOUSE_HAND_POINTER /atom/movable/screen/throw_catch/Click() - if(iscarbon(usr)) - var/mob/living/carbon/C = usr - C.toggle_throw_mode() + if(isliving(usr)) + var/mob/living/user = usr + user.toggle_throw_mode() /atom/movable/screen/zone_sel name = "damage zone" diff --git a/code/datums/elements/dextrous.dm b/code/datums/elements/dextrous.dm index 1896257eeec..f242a7e9163 100644 --- a/code/datums/elements/dextrous.dm +++ b/code/datums/elements/dextrous.dm @@ -4,13 +4,15 @@ */ /datum/element/dextrous -/datum/element/dextrous/Attach(datum/target, hands_count = 2, hud_type = /datum/hud/dextrous) +/datum/element/dextrous/Attach(datum/target, hands_count = 2, hud_type = /datum/hud/dextrous, can_throw = FALSE) . = ..() if (!isliving(target) || iscarbon(target)) return ELEMENT_INCOMPATIBLE // Incompatible with the carbon typepath because that already has its own hand handling and doesn't need hand holding var/mob/living/mob_parent = target set_available_hands(mob_parent, hands_count) + if(can_throw) + ADD_TRAIT(target, TRAIT_CAN_THROW_ITEMS, REF(src)) // need to add before hud setup mob_parent.hud_type = hud_type if (mob_parent.hud_used) mob_parent.set_hud_used(new hud_type(target)) diff --git a/code/datums/elements/high_fiver.dm b/code/datums/elements/high_fiver.dm index 249a9f4059d..09372937725 100644 --- a/code/datums/elements/high_fiver.dm +++ b/code/datums/elements/high_fiver.dm @@ -18,7 +18,7 @@ UnregisterSignal(source, list(COMSIG_ITEM_OFFERING, COMSIG_ITEM_OFFER_TAKEN)) /// Signal proc for [COMSIG_ITEM_OFFERING] to set up the high-five on offer -/datum/element/high_fiver/proc/on_offer(obj/item/source, mob/living/carbon/offerer) +/datum/element/high_fiver/proc/on_offer(obj/item/source, mob/living/offerer) SIGNAL_HANDLER offerer.visible_message( @@ -31,7 +31,7 @@ return COMPONENT_OFFER_INTERRUPT /// Signal proc for [COMSIG_ITEM_OFFER_TAKEN] to continue through with the high-five on take -/datum/element/high_fiver/proc/on_offer_taken(obj/item/source, mob/living/carbon/offerer, mob/living/carbon/taker) +/datum/element/high_fiver/proc/on_offer_taken(obj/item/source, mob/living/offerer, mob/living/taker) SIGNAL_HANDLER var/open_hands_taker = 0 diff --git a/code/datums/keybinding/carbon.dm b/code/datums/keybinding/carbon.dm deleted file mode 100644 index 92f36b06529..00000000000 --- a/code/datums/keybinding/carbon.dm +++ /dev/null @@ -1,58 +0,0 @@ -/datum/keybinding/carbon - category = CATEGORY_CARBON - weight = WEIGHT_MOB - -/datum/keybinding/carbon/can_use(client/user) - return iscarbon(user.mob) - -/datum/keybinding/carbon/toggle_throw_mode - hotkey_keys = list("R", "Southwest") // END - name = "toggle_throw_mode" - full_name = "Toggle throw mode" - description = "Toggle throwing the current item or not." - category = CATEGORY_CARBON - keybind_signal = COMSIG_KB_CARBON_TOGGLETHROWMODE_DOWN - -/datum/keybinding/carbon/toggle_throw_mode/down(client/user, turf/target) - . = ..() - if(.) - return - var/mob/living/carbon/C = user.mob - C.toggle_throw_mode() - return TRUE - -/datum/keybinding/carbon/hold_throw_mode - hotkey_keys = list("Space") - name = "hold_throw_mode" - full_name = "Hold throw mode" - description = "Hold this to turn on throw mode, and release it to turn off throw mode" - category = CATEGORY_CARBON - keybind_signal = COMSIG_KB_CARBON_HOLDTHROWMODE_DOWN - -/datum/keybinding/carbon/hold_throw_mode/down(client/user, turf/target) - . = ..() - if(.) - return - var/mob/living/carbon/carbon_user = user.mob - carbon_user.throw_mode_on(THROW_MODE_HOLD) - -/datum/keybinding/carbon/hold_throw_mode/up(client/user, turf/target) - . = ..() - if(.) - return - var/mob/living/carbon/carbon_user = user.mob - carbon_user.throw_mode_off(THROW_MODE_HOLD) -/datum/keybinding/carbon/give - hotkey_keys = list("G") - name = "Give_Item" - full_name = "Give item" - description = "Give the item you're currently holding" - keybind_signal = COMSIG_KB_CARBON_GIVEITEM_DOWN - -/datum/keybinding/carbon/give/down(client/user, turf/target) - . = ..() - if(.) - return - var/mob/living/carbon/carbon_user = user.mob - carbon_user.give() - return TRUE diff --git a/code/datums/keybinding/living.dm b/code/datums/keybinding/living.dm index 43369700fc1..d1f2031ea3b 100644 --- a/code/datums/keybinding/living.dm +++ b/code/datums/keybinding/living.dm @@ -167,3 +167,65 @@ var/mob/living/M = user.mob M.toggle_move_intent() return TRUE + +/datum/keybinding/living/toggle_throw_mode + hotkey_keys = list("R", "Southwest") // END + name = "toggle_throw_mode" + full_name = "Toggle throw mode" + description = "Toggle throwing the current item or not." + keybind_signal = COMSIG_KB_LIVING_TOGGLETHROWMODE_DOWN + +/datum/keybinding/living/toggle_throw_mode/down(client/user) + . = ..() + if(.) + return + var/mob/living/living_user = user.mob + living_user.toggle_throw_mode() + return TRUE + +/datum/keybinding/living/hold_throw_mode + hotkey_keys = list("Space") + name = "hold_throw_mode" + full_name = "Hold throw mode" + description = "Hold this to turn on throw mode, and release it to turn off throw mode" + keybind_signal = COMSIG_KB_LIVING_HOLDTHROWMODE_DOWN + +/datum/keybinding/living/hold_throw_mode/down(client/user, turf/target) + . = ..() + if(.) + return + var/mob/living/living_user = user.mob + living_user.throw_mode_on(THROW_MODE_HOLD) + +/datum/keybinding/living/hold_throw_mode/up(client/user, turf/target) + . = ..() + if(.) + return + var/mob/living/living_user = user.mob + living_user.throw_mode_off(THROW_MODE_HOLD) + +/datum/keybinding/living/give + hotkey_keys = list("G") + name = "Give_Item" + full_name = "Give item" + description = "Give the item you're currently holding" + keybind_signal = COMSIG_KB_LIVING_GIVEITEM_DOWN + +/datum/keybinding/living/give/can_use(client/user) + . = ..() + if (!.) + return FALSE + if(!user.mob) + return FALSE + if(!HAS_TRAIT(user.mob, TRAIT_CAN_HOLD_ITEMS)) + return FALSE + return TRUE + +/datum/keybinding/living/give/down(client/user, turf/target) + . = ..() + if(.) + return + var/mob/living/living_user = user.mob + if(!HAS_TRAIT(living_user, TRAIT_CAN_HOLD_ITEMS)) + return + living_user.give() diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index fb83ade3aa3..673eb71a350 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -200,7 +200,7 @@ /// 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, mob/living/carbon/offered) +/datum/status_effect/offering/on_creation(mob/living/new_owner, obj/item/offer, give_alert_override, mob/living/offered) . = ..() if(!.) return @@ -211,7 +211,7 @@ if(offered && is_taker_elligible(offered)) register_candidate(offered) else - for(var/mob/living/carbon/possible_taker in orange(1, owner)) + for(var/mob/living/possible_taker in orange(1, owner)) if(!is_taker_elligible(possible_taker)) continue @@ -225,14 +225,14 @@ RegisterSignals(offered_item, list(COMSIG_QDELETING, COMSIG_ITEM_DROPPED), PROC_REF(dropped_item)) /datum/status_effect/offering/Destroy() - for(var/mob/living/carbon/removed_taker as anything in possible_takers) + for(var/mob/living/removed_taker as anything in possible_takers) remove_candidate(removed_taker) LAZYCLEARLIST(possible_takers) offered_item = null 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) +/// Hook up the specified living 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/possible_candidate) var/atom/movable/screen/alert/give/G = possible_candidate.throw_alert("[owner]", give_alert_type) if(!G) return @@ -240,8 +240,8 @@ RegisterSignal(possible_candidate, COMSIG_MOVABLE_MOVED, PROC_REF(check_taker_in_range)) G.setup(possible_candidate, src) -/// 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) +/// Remove the alert and signals for the specified living mob. Automatically removes the status effect when we lost the last taker +/datum/status_effect/offering/proc/remove_candidate(mob/living/removed_candidate) removed_candidate.clear_alert("[owner]") LAZYREMOVE(possible_takers, removed_candidate) UnregisterSignal(removed_candidate, COMSIG_MOVABLE_MOVED) @@ -249,7 +249,7 @@ 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) +/datum/status_effect/offering/proc/check_taker_in_range(mob/living/taker) SIGNAL_HANDLER if(owner.CanReach(taker) && !IS_DEAD_OR_INCAP(taker)) return @@ -258,10 +258,10 @@ 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) +/datum/status_effect/offering/proc/check_owner_in_range(mob/living/source) SIGNAL_HANDLER - for(var/mob/living/carbon/checking_taker as anything in possible_takers) + for(var/mob/living/checking_taker as anything in possible_takers) if(!istype(checking_taker) || !owner.CanReach(checking_taker) || IS_DEAD_OR_INCAP(checking_taker)) remove_candidate(checking_taker) @@ -276,7 +276,7 @@ * * Returns `TRUE` if the taker is valid as a target for the offering. */ -/datum/status_effect/offering/proc/is_taker_elligible(mob/living/carbon/taker) +/datum/status_effect/offering/proc/is_taker_elligible(mob/living/taker) return owner.CanReach(taker) && !IS_DEAD_OR_INCAP(taker) && additional_taker_check(taker) /** @@ -287,7 +287,7 @@ * Returns `TRUE` if the taker is valid as a target for the offering based on these * additional checks. */ -/datum/status_effect/offering/proc/additional_taker_check(mob/living/carbon/taker) +/datum/status_effect/offering/proc/additional_taker_check(mob/living/taker) return taker.can_hold_items() /** @@ -296,7 +296,7 @@ */ /datum/status_effect/offering/no_item_received -/datum/status_effect/offering/no_item_received/additional_taker_check(mob/living/carbon/taker) +/datum/status_effect/offering/no_item_received/additional_taker_check(mob/living/taker) return taker.usable_hands > 0 /** @@ -307,23 +307,23 @@ */ /datum/status_effect/offering/no_item_received/needs_resting -/datum/status_effect/offering/no_item_received/needs_resting/additional_taker_check(mob/living/carbon/taker) +/datum/status_effect/offering/no_item_received/needs_resting/additional_taker_check(mob/living/taker) return taker.body_position == LYING_DOWN -/datum/status_effect/offering/no_item_received/needs_resting/on_creation(mob/living/new_owner, obj/item/offer, give_alert_override, mob/living/carbon/offered) +/datum/status_effect/offering/no_item_received/needs_resting/on_creation(mob/living/new_owner, obj/item/offer, give_alert_override, mob/living/offered) . = ..() RegisterSignal(owner, COMSIG_LIVING_SET_BODY_POSITION, PROC_REF(check_owner_standing)) -/datum/status_effect/offering/no_item_received/needs_resting/register_candidate(mob/living/carbon/possible_candidate) +/datum/status_effect/offering/no_item_received/needs_resting/register_candidate(mob/living/possible_candidate) . = ..() RegisterSignal(possible_candidate, COMSIG_LIVING_SET_BODY_POSITION, PROC_REF(check_candidate_resting)) -/datum/status_effect/offering/no_item_received/needs_resting/remove_candidate(mob/living/carbon/removed_candidate) +/datum/status_effect/offering/no_item_received/needs_resting/remove_candidate(mob/living/removed_candidate) UnregisterSignal(removed_candidate, COMSIG_LIVING_SET_BODY_POSITION) return ..() /// Simple signal handler that ensures that, if the owner stops standing, the offer no longer stands either! -/datum/status_effect/offering/no_item_received/needs_resting/proc/check_owner_standing(mob/living/carbon/owner) +/datum/status_effect/offering/no_item_received/needs_resting/proc/check_owner_standing(mob/living/owner) if(src.owner.body_position == STANDING_UP) return @@ -331,7 +331,7 @@ qdel(src) /// Simple signal handler that ensures that, should a candidate now be standing up, the offer won't be standing for them anymore! -/datum/status_effect/offering/no_item_received/needs_resting/proc/check_candidate_resting(mob/living/carbon/candidate) +/datum/status_effect/offering/no_item_received/needs_resting/proc/check_candidate_resting(mob/living/candidate) SIGNAL_HANDLER if(candidate.body_position == LYING_DOWN) diff --git a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm index d9034ac5687..a39b43643e8 100644 --- a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm @@ -113,11 +113,11 @@ /obj/item/organ/tongue/rat/on_mob_insert(mob/living/carbon/tongue_owner, special, movement_flags) . = ..() - RegisterSignal(tongue_owner, COMSIG_CARBON_ITEM_GIVEN, PROC_REF(its_on_the_mouse)) + RegisterSignal(tongue_owner, COMSIG_LIVING_ITEM_GIVEN, PROC_REF(its_on_the_mouse)) /obj/item/organ/tongue/rat/on_mob_remove(mob/living/carbon/tongue_owner) . = ..() - UnregisterSignal(tongue_owner, COMSIG_CARBON_ITEM_GIVEN) + UnregisterSignal(tongue_owner, COMSIG_LIVING_ITEM_GIVEN) /obj/item/organ/tongue/rat/proc/on_item_given(mob/living/carbon/offerer, mob/living/taker, obj/item/given) SIGNAL_HANDLER diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index c4be7baa14f..6548001e09c 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1482,28 +1482,35 @@ stack_trace("Undefined handle_openspace_click() behaviour. Ascertain the openspace_item_click_handler element has been attached to the right item and that its proc override doesn't call parent.") /** - * * 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. + * * An interrupt for offering an item to other people, called mainly from [/mob/living/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. - * * offered - The person being offered the item. + * * offerer - The living mob offering the item. + * * offered - The living mob being offered the item. */ -/obj/item/proc/on_offered(mob/living/carbon/offerer, mob/living/carbon/offered) +/obj/item/proc/on_offered(mob/living/offerer, mob/living/offered) + if(!offered) // item has just been offered to anyone around + if(!(HAS_TRAIT(offerer, TRAIT_CAN_HOLD_ITEMS))) + return TRUE + else if(!(HAS_TRAIT(offerer, TRAIT_CAN_HOLD_ITEMS) && HAS_TRAIT(offered, TRAIT_CAN_HOLD_ITEMS))) + return TRUE // both must be able to hold items for this to make sense 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. + * * An interrupt for someone trying to accept an offered item, called mainly from [/mob/living/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 + * * offerer - the living mob offering the item + * * taker - the living mob trying to accept the offer */ -/obj/item/proc/on_offer_taken(mob/living/carbon/offerer, mob/living/carbon/taker) +/obj/item/proc/on_offer_taken(mob/living/offerer, mob/living/taker) + if(!(HAS_TRAIT(offerer, TRAIT_CAN_HOLD_ITEMS) && HAS_TRAIT(taker, TRAIT_CAN_HOLD_ITEMS))) + return TRUE // both must be able to hold items for this to make sense if(SEND_SIGNAL(src, COMSIG_ITEM_OFFER_TAKEN, offerer, taker) & COMPONENT_OFFER_INTERRUPT) return TRUE diff --git a/code/game/objects/items/hand_items.dm b/code/game/objects/items/hand_items.dm index 0e9ea7a28c5..1f6e888394c 100644 --- a/code/game/objects/items/hand_items.dm +++ b/code/game/objects/items/hand_items.dm @@ -341,7 +341,7 @@ // Successful takes will qdel our hand after /obj/item/hand_item/slapper/on_offer_taken(mob/living/carbon/offerer, mob/living/carbon/taker) . = ..() - if(!.) + if(.) return qdel(src) @@ -408,7 +408,11 @@ /obj/item/hand_item/hand/on_offer_taken(mob/living/carbon/offerer, mob/living/carbon/taker) - . = TRUE + . = ..() + if(!offerer || !taker) + return TRUE // this doesn't make sense unless both are carbons + if(.) + return if(taker.body_position == LYING_DOWN) taker.help_shake_act(offerer) @@ -518,6 +522,10 @@ return TRUE /obj/item/hand_item/kisser/on_offer_taken(mob/living/carbon/offerer, mob/living/carbon/taker) + . = ..() + if(.) + return + var/obj/projectile/blown_kiss = new kiss_type(get_turf(offerer)) offerer.visible_message("[offerer] gives [taker] \a [blown_kiss][cheek_kiss ? " on the cheek" : ""]!!", span_notice("You give [taker] \a [blown_kiss][cheek_kiss ? " on the cheek" : ""]!"), ignored_mobs = taker) to_chat(taker, span_nicegreen("[offerer] gives you \a [blown_kiss][cheek_kiss ? " on the cheek" : ""]!")) diff --git a/code/modules/basketball/basketball.dm b/code/modules/basketball/basketball.dm index 919d26daeee..274a9602546 100644 --- a/code/modules/basketball/basketball.dm +++ b/code/modules/basketball/basketball.dm @@ -56,7 +56,7 @@ // unlike on_equip, this signal is triggered after the ball is removed from hands // so we can just use is_holding_item_of_type() proc to check for multiple balls if(!wielder.is_holding_item_of_type(/obj/item/toy/basketball)) - UnregisterSignal(wielder, list(COMSIG_MOVABLE_MOVED, COMSIG_MOB_EMOTED("spin"), COMSIG_LIVING_DISARM_HIT, COMSIG_LIVING_STATUS_KNOCKDOWN, COMSIG_MOB_THROW)) + UnregisterSignal(wielder, list(COMSIG_MOVABLE_MOVED, COMSIG_MOB_EMOTED("spin"), COMSIG_LIVING_DISARM_HIT, COMSIG_LIVING_STATUS_KNOCKDOWN)) wielder = null diff --git a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm index dd8805fbf8c..6fb3c5ea9af 100644 --- a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm +++ b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm @@ -57,7 +57,7 @@ . = ..() add_traits(list(TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, TRAIT_CHUNKYFINGERS), ROUNDSTART_TRAIT) AddElement(/datum/element/wall_tearer, allow_reinforced = FALSE) - AddElement(/datum/element/dextrous) + AddElement(/datum/element/dextrous, can_throw = TRUE) AddElement(/datum/element/footstep, FOOTSTEP_MOB_BAREFOOT) AddElement(/datum/element/basic_eating, heal_amt = 10, food_types = gorilla_food) AddComponent( diff --git a/code/modules/mob/living/basic/guardian/guardian_types/dextrous.dm b/code/modules/mob/living/basic/guardian/guardian_types/dextrous.dm index fb6fa276d98..3abafd5be1b 100644 --- a/code/modules/mob/living/basic/guardian/guardian_types/dextrous.dm +++ b/code/modules/mob/living/basic/guardian/guardian_types/dextrous.dm @@ -16,7 +16,7 @@ /mob/living/basic/guardian/dextrous/Initialize(mapload, datum/guardian_fluff/theme) . = ..() add_traits(list(TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP), ROUNDSTART_TRAIT) - AddElement(/datum/element/dextrous, hud_type = hud_type) + AddElement(/datum/element/dextrous, hud_type = hud_type, can_throw = TRUE) AddComponent(/datum/component/personal_crafting) AddComponent(/datum/component/basic_inhands) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 5dd394e2439..c4e40c78ad2 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -8,6 +8,7 @@ GLOB.carbon_list += src ADD_TRAIT(src, TRAIT_CAN_HOLD_ITEMS, INNATE_TRAIT) // Carbons are assumed to be innately capable of having arms, we check their arms count instead + ADD_TRAIT(src, TRAIT_CAN_THROW_ITEMS, INNATE_TRAIT) // same here breathing_loop = new(src, _direct = TRUE) /mob/living/carbon/Destroy() @@ -39,11 +40,6 @@ return ITEM_INTERACT_SUCCESS return . -/mob/living/carbon/click_ctrl_shift(mob/user) - if(iscarbon(user)) - var/mob/living/carbon/carbon_user = user - carbon_user.give(src) - /mob/living/carbon/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) . = ..() var/hurt = TRUE @@ -105,123 +101,6 @@ if(oof_noise) playsound(src,'sound/items/weapons/punch1.ogg',50,TRUE) -//Throwing stuff -/mob/living/carbon/proc/toggle_throw_mode() - if(stat) - return - if(throw_mode) - throw_mode_off(THROW_MODE_TOGGLE) - else - throw_mode_on(THROW_MODE_TOGGLE) - - -/mob/living/carbon/proc/throw_mode_off(method) - if(throw_mode > method) //A toggle doesnt affect a hold - return - throw_mode = THROW_MODE_DISABLED - if(hud_used) - hud_used.throw_icon.icon_state = "act_throw" - SEND_SIGNAL(src, COMSIG_LIVING_THROW_MODE_TOGGLE, throw_mode) - - -/mob/living/carbon/proc/throw_mode_on(mode = THROW_MODE_TOGGLE) - throw_mode = mode - if(hud_used) - hud_used.throw_icon.icon_state = "act_throw_on" - SEND_SIGNAL(src, COMSIG_LIVING_THROW_MODE_TOGGLE, throw_mode) - -/mob/proc/throw_item(atom/target) - SEND_SIGNAL(src, COMSIG_MOB_THROW, target) - SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CARBON_THROW_THING, src, target) - return TRUE - -/mob/living/carbon/throw_item(atom/target) - . = ..() - throw_mode_off(THROW_MODE_TOGGLE) - if(!target || !isturf(loc)) - return FALSE - if(istype(target, /atom/movable/screen)) - return FALSE - var/atom/movable/thrown_thing - var/obj/item/held_item = get_active_held_item() - var/verb_text = pick("throw", "toss", "hurl", "chuck", "fling") - if(prob(0.5)) - verb_text = "yeet" - var/neckgrab_throw = FALSE // we can't check for if it's a neckgrab throw when totaling up power_throw since we've already stopped pulling them by then, so get it early - var/frequency_number = 1 //We assign a default frequency number for the sound of the throw. - if(!held_item) - if(pulling && isliving(pulling) && grab_state >= GRAB_AGGRESSIVE) - var/mob/living/throwable_mob = pulling - if(!throwable_mob.buckled) - thrown_thing = throwable_mob - if(grab_state >= GRAB_NECK) - neckgrab_throw = TRUE - stop_pulling() - if(HAS_TRAIT(src, TRAIT_PACIFISM) || HAS_TRAIT(src, TRAIT_NO_THROWING)) - to_chat(src, span_notice("You gently let go of [throwable_mob].")) - return FALSE - else - thrown_thing = held_item.on_thrown(src, target) - if(!thrown_thing) - return FALSE - if(isliving(thrown_thing)) - var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors - var/turf/end_T = get_turf(target) - if(start_T && end_T) - log_combat(src, thrown_thing, "thrown", addition="grab from tile in [AREACOORD(start_T)] towards tile at [AREACOORD(end_T)]") - var/power_throw = 0 - var/extra_throw_range = HAS_TRAIT(src, TRAIT_THROWINGARM) ? 2 : 0 - - var/obj/item/organ/cyberimp/chest/spine/potential_spine = get_organ_slot(ORGAN_SLOT_SPINE) - if(istype(potential_spine)) - power_throw += potential_spine.added_throw_speed - extra_throw_range += potential_spine.added_throw_range - - if(HAS_TRAIT(src, TRAIT_HULK)) - power_throw++ - if(HAS_TRAIT(src, TRAIT_DWARF)) - power_throw-- - if(HAS_TRAIT(thrown_thing, TRAIT_DWARF)) - power_throw++ - //SKYRAT EDIT ADDITION - if(HAS_TRAIT(src, TRAIT_OVERSIZED)) - power_throw++ - if(HAS_TRAIT(thrown_thing, TRAIT_OVERSIZED)) - power_throw-- - //SKYRAT EDIT END - if(neckgrab_throw) - power_throw++ - if(HAS_TRAIT(src, TRAIT_TOSS_GUN_HARD) && isgun(thrown_thing)) - power_throw++ - if(isitem(thrown_thing)) - var/obj/item/thrown_item = thrown_thing - frequency_number = 1-(thrown_item.w_class-3)/8 //At normal weight, the frequency is at 1. For tiny, it is 1.25. For huge, it is 0.75. - if(thrown_item.throw_verb) - verb_text = thrown_item.throw_verb - do_attack_animation(target, no_effect = 1) - var/sound/throwsound = 'sound/items/weapons/throw.ogg' - var/power_throw_text = "." - if(power_throw > 0) //If we have anything that boosts our throw power like hulk, we use the rougher heavier variant. - throwsound = 'sound/items/weapons/throwhard.ogg' - power_throw_text = " really hard!" - if(power_throw < 0) //if we have anything that weakens our throw power like dward, we use a slower variant. - throwsound = 'sound/items/weapons/throwsoft.ogg' - power_throw_text = " flimsily." - frequency_number = frequency_number + (rand(-5,5)/100); //Adds a bit of randomness in the frequency to not sound exactly the same. - //The volume of the sound takes the minimum between the distance thrown or the max range an item, but no more than 50. Short throws are quieter. A fast throwing speed also makes the noise sharper. - playsound(src, throwsound, clamp(8*min(get_dist(loc,target),thrown_thing.throw_range), 10, 50), vary = TRUE, extrarange = -1, frequency = frequency_number) - visible_message(span_danger("[src] [verb_text][plural_s(verb_text)] [thrown_thing][power_throw_text]"), \ - span_danger("You [verb_text] [thrown_thing][power_throw_text]")) - log_message("has thrown [thrown_thing] [power_throw_text]", LOG_ATTACK) - - var/drift_force = max(0.5 NEWTONS, 1 NEWTONS + power_throw) - if (isitem(thrown_thing)) - var/obj/item/thrown_item = thrown_thing - drift_force *= WEIGHT_TO_NEWTONS(thrown_item.w_class) - - newtonian_move(get_angle(target, src), drift_force = drift_force) - thrown_thing.safe_throw_at(target, thrown_thing.throw_range + extra_throw_range, max(1,thrown_thing.throw_speed + power_throw), src, null, null, null, move_force) - /mob/living/carbon/proc/canBeHandcuffed() return FALSE diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index 546c7fa35d6..f21aad08c28 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -417,95 +417,6 @@ var/index = get_held_index_of_item(I) return index && hand_bodyparts[index] -/** - * 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(mob/living/carbon/offered) - if(has_status_effect(/datum/status_effect/offering)) - to_chat(src, span_warning("You're already offering something!")) - return - - if(IS_DEAD_OR_INCAP(src)) - to_chat(src, span_warning("You're unable to offer anything in your current state!")) - return - - var/obj/item/offered_item = get_active_held_item() - // if it's an abstract item, should consider it to be non-existent (unless it's a HAND_ITEM, which means it's an obj/item that is just a representation of our hand) - if(!offered_item || ((offered_item.item_flags & ABSTRACT) && !(offered_item.item_flags & HAND_ITEM))) - to_chat(src, span_warning("You're not holding anything to offer!")) - return - - if(offered) - if(offered == src) - if(!swap_hand(get_inactive_hand_index())) //have to swap hands first to take something - to_chat(src, span_warning("You try to take [offered_item] from yourself, but fail.")) - return - if(!put_in_active_hand(offered_item)) - to_chat(src, span_warning("You try to take [offered_item] from yourself, but fail.")) - return - else - to_chat(src, span_notice("You take [offered_item] from yourself.")) - return - - if(IS_DEAD_OR_INCAP(offered)) - to_chat(src, span_warning("[offered.p_Theyre()] unable to take anything in [offered.p_their()] current state!")) - return - - if(!CanReach(offered)) - to_chat(src, span_warning("You have to be beside [offered.p_them()]!")) - return - else - if(!(locate(/mob/living/carbon) in orange(1, src))) - to_chat(src, span_warning("There's nobody beside you to take it!")) - return - - if(offered_item.on_offered(src)) // see if the item interrupts with its own behavior - return - - balloon_alert_to_viewers("offers something") - visible_message(span_notice("[src] is offering [offered ? "[offered] " : ""][offered_item]."), \ - span_notice("You offer [offered ? "[offered] " : ""][offered_item]."), null, 2) - - apply_status_effect(/datum/status_effect/offering, offered_item, null, offered) - -/** - * 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 offerer - * Also deals with the actual transferring of the item to the players hands - * Arguments: - * * offerer - The person giving the original item - * * I - The item being given by the offerer - */ -/mob/living/carbon/proc/take(mob/living/carbon/offerer, obj/item/I) - clear_alert("[offerer]") - if(IS_DEAD_OR_INCAP(src)) - to_chat(src, span_warning("You're unable to take anything in your current state!")) - return - if(get_dist(src, offerer) > 1) - to_chat(src, span_warning("[offerer] is out of range!")) - return - 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, span_warning("You have no empty hands!")) - return - - if(I.on_offer_taken(offerer, src)) // see if the item has special behavior for being accepted - return - - if(!offerer.temporarilyRemoveItemFromInventory(I)) - visible_message(span_notice("[offerer] tries to hand over [I] but it's stuck to them....")) - return - - visible_message(span_notice("[src] takes [I] from [offerer]."), \ - span_notice("You take [I] from [offerer].")) - I.do_pickup_animation(src, offerer) - put_in_hands(I) - ///Returns a list of all body_zones covered by clothing /mob/living/carbon/proc/get_covered_body_zones() RETURN_TYPE(/list) diff --git a/code/modules/mob/living/living_item_handling.dm b/code/modules/mob/living/living_item_handling.dm new file mode 100644 index 00000000000..60d683887b1 --- /dev/null +++ b/code/modules/mob/living/living_item_handling.dm @@ -0,0 +1,227 @@ +// Throwing stuff +/mob/living/proc/toggle_throw_mode() + if(stat) + return + if(!HAS_TRAIT(src, TRAIT_CAN_THROW_ITEMS)) + return + if(throw_mode) + throw_mode_off(THROW_MODE_TOGGLE) + else + throw_mode_on(THROW_MODE_TOGGLE) + + +/mob/living/proc/throw_mode_off(method) + if(!HAS_TRAIT(src, TRAIT_CAN_THROW_ITEMS)) + return + if(throw_mode > method) //A toggle doesnt affect a hold + return + throw_mode = THROW_MODE_DISABLED + if(hud_used) + hud_used.throw_icon.icon_state = "act_throw" + SEND_SIGNAL(src, COMSIG_LIVING_THROW_MODE_TOGGLE, throw_mode) + + +/mob/living/proc/throw_mode_on(mode = THROW_MODE_TOGGLE) + if(!HAS_TRAIT(src, TRAIT_CAN_THROW_ITEMS)) + return + throw_mode = mode + if(hud_used) + hud_used.throw_icon.icon_state = "act_throw_on" + SEND_SIGNAL(src, COMSIG_LIVING_THROW_MODE_TOGGLE, throw_mode) + +/mob/proc/throw_item(atom/target) + if(!HAS_TRAIT(src, TRAIT_CAN_THROW_ITEMS)) + return FALSE + SEND_SIGNAL(src, COMSIG_MOB_THROW, target) + return TRUE + +/mob/living/throw_item(atom/target) + . = ..() + throw_mode_off(THROW_MODE_TOGGLE) + if(!HAS_TRAIT(src, TRAIT_CAN_THROW_ITEMS)) + stack_trace("[src] tried to throw [target], but they shouldn't be able to throw things") + return FALSE + if(!target || !isturf(loc)) + return FALSE + if(istype(target, /atom/movable/screen)) + return FALSE + var/atom/movable/thrown_thing + var/obj/item/held_item = get_active_held_item() + var/verb_text = pick("throw", "toss", "hurl", "chuck", "fling") + if(prob(0.5)) + verb_text = "yeet" + var/neckgrab_throw = FALSE // we can't check for if it's a neckgrab throw when totaling up power_throw since we've already stopped pulling them by then, so get it early + var/frequency_number = 1 //We assign a default frequency number for the sound of the throw. + if(!held_item) + if(pulling && isliving(pulling) && grab_state >= GRAB_AGGRESSIVE) + var/mob/living/throwable_mob = pulling + if(!throwable_mob.buckled) + thrown_thing = throwable_mob + if(grab_state >= GRAB_NECK) + neckgrab_throw = TRUE + stop_pulling() + if(HAS_TRAIT(src, TRAIT_PACIFISM) || HAS_TRAIT(src, TRAIT_NO_THROWING)) + to_chat(src, span_notice("You gently let go of [throwable_mob].")) + return FALSE + else + thrown_thing = held_item.on_thrown(src, target) + if(!thrown_thing) + return FALSE + if(isliving(thrown_thing)) + var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors + var/turf/end_T = get_turf(target) + if(start_T && end_T) + log_combat(src, thrown_thing, "thrown", addition="grab from tile in [AREACOORD(start_T)] towards tile at [AREACOORD(end_T)]") + var/power_throw = 0 + var/extra_throw_range = HAS_TRAIT(src, TRAIT_THROWINGARM) ? 2 : 0 + + var/obj/item/organ/cyberimp/chest/spine/potential_spine = get_organ_slot(ORGAN_SLOT_SPINE) + if(istype(potential_spine)) + power_throw += potential_spine.added_throw_speed + extra_throw_range += potential_spine.added_throw_range + + if(HAS_TRAIT(src, TRAIT_HULK)) + power_throw++ + if(HAS_TRAIT(src, TRAIT_DWARF)) + power_throw-- + if(HAS_TRAIT(thrown_thing, TRAIT_DWARF)) + power_throw++ + //SKYRAT EDIT ADDITION + if(HAS_TRAIT(src, TRAIT_OVERSIZED)) + power_throw++ + if(HAS_TRAIT(thrown_thing, TRAIT_OVERSIZED)) + power_throw-- + //SKYRAT EDIT END + if(neckgrab_throw) + power_throw++ + if(HAS_TRAIT(src, TRAIT_TOSS_GUN_HARD) && isgun(thrown_thing)) + power_throw++ + if(isitem(thrown_thing)) + var/obj/item/thrown_item = thrown_thing + frequency_number = 1-(thrown_item.w_class-3)/8 //At normal weight, the frequency is at 1. For tiny, it is 1.25. For huge, it is 0.75. + if(thrown_item.throw_verb) + verb_text = thrown_item.throw_verb + do_attack_animation(target, no_effect = 1) + var/sound/throwsound = 'sound/items/weapons/throw.ogg' + var/power_throw_text = "." + if(power_throw > 0) //If we have anything that boosts our throw power like hulk, we use the rougher heavier variant. + throwsound = 'sound/items/weapons/throwhard.ogg' + power_throw_text = " really hard!" + if(power_throw < 0) //if we have anything that weakens our throw power like dward, we use a slower variant. + throwsound = 'sound/items/weapons/throwsoft.ogg' + power_throw_text = " flimsily." + frequency_number = frequency_number + (rand(-5,5)/100); //Adds a bit of randomness in the frequency to not sound exactly the same. + //The volume of the sound takes the minimum between the distance thrown or the max range an item, but no more than 50. Short throws are quieter. A fast throwing speed also makes the noise sharper. + playsound(src, throwsound, clamp(8*min(get_dist(loc,target),thrown_thing.throw_range), 10, 50), vary = TRUE, extrarange = -1, frequency = frequency_number) + visible_message(span_danger("[src] [verb_text][plural_s(verb_text)] [thrown_thing][power_throw_text]"), \ + span_danger("You [verb_text] [thrown_thing][power_throw_text]")) + log_message("has thrown [thrown_thing] [power_throw_text]", LOG_ATTACK) + + var/drift_force = max(0.5 NEWTONS, 1 NEWTONS + power_throw) + if (isitem(thrown_thing)) + var/obj/item/thrown_item = thrown_thing + drift_force *= WEIGHT_TO_NEWTONS(thrown_item.w_class) + + newtonian_move(get_angle(target, src), drift_force = drift_force) + thrown_thing.safe_throw_at(target, thrown_thing.throw_range + extra_throw_range, max(1,thrown_thing.throw_speed + power_throw), src, null, null, null, move_force) + +// Giving stuff +/** + * Proc called when offering an item to another player + * + * This handles creating an alert and adding an overlay to it + * Arguments: + * * offered - The player being offered the item (optional, if null the offer is to everyone around) + */ +/mob/living/proc/give(mob/living/offered) + if(has_status_effect(/datum/status_effect/offering)) + to_chat(src, span_warning("You're already offering something!")) + return + + if(IS_DEAD_OR_INCAP(src)) + to_chat(src, span_warning("You're unable to offer anything in your current state!")) + return + + var/obj/item/offered_item = get_active_held_item() + // if it's an abstract item, should consider it to be non-existent (unless it's a HAND_ITEM, which means it's an obj/item that is just a representation of our hand) + if(!offered_item || ((offered_item.item_flags & ABSTRACT) && !(offered_item.item_flags & HAND_ITEM))) + to_chat(src, span_warning("You're not holding anything to offer!")) + return + + if(offered) + if(offered == src) + if(!swap_hand(get_inactive_hand_index())) //have to swap hands first to take something + to_chat(src, span_warning("You try to take [offered_item] from yourself, but fail.")) + return + if(!put_in_active_hand(offered_item)) + to_chat(src, span_warning("You try to take [offered_item] from yourself, but fail.")) + return + else + to_chat(src, span_notice("You take [offered_item] from yourself.")) + return + + if(IS_DEAD_OR_INCAP(offered)) + to_chat(src, span_warning("[offered.p_Theyre()] unable to take anything in [offered.p_their()] current state!")) + return + + if(!CanReach(offered)) + to_chat(src, span_warning("You have to be beside [offered.p_them()]!")) + return + + if(!HAS_TRAIT(offered, TRAIT_CAN_HOLD_ITEMS)) + to_chat(src, span_warning("[offered.p_They()] can't hold anything you offer!")) + return + else if(!(locate(/mob/living) in orange(1, src))) + to_chat(src, span_warning("There's nobody beside you to take it!")) + return + + if(offered_item.on_offered(src)) // see if the item interrupts with its own behavior + return + + balloon_alert_to_viewers("offers something") + visible_message(span_notice("[src] is offering [offered ? "[offered] " : ""][offered_item]."), \ + span_notice("You offer [offered ? "[offered] " : ""][offered_item]."), null, 2) + + apply_status_effect(/datum/status_effect/offering, offered_item, null, offered) + +/** + * 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 offerer + * Also deals with the actual transferring of the item to the players hands + * Arguments: + * * offerer - The living mob giving the original item + * * offered_item - The item being given by the offerer + */ +/mob/living/proc/take(mob/living/offerer, obj/item/offered_item) + clear_alert("[offerer]") + if(IS_DEAD_OR_INCAP(src)) + to_chat(src, span_warning("You're unable to take anything in your current state!")) + return + if(get_dist(src, offerer) > 1) + to_chat(src, span_warning("[offerer] is out of range!")) + return + if(!offered_item || offerer.get_active_held_item() != offered_item) + to_chat(src, span_warning("[offerer] is no longer holding the item they were offering!")) + return + if(!get_empty_held_indexes()) + to_chat(src, span_warning("You have no empty hands!")) + return + + if(offered_item.on_offer_taken(offerer, src)) // see if the item has special behavior for being accepted + return + + if(!offerer.temporarilyRemoveItemFromInventory(offered_item)) + visible_message(span_notice("[offerer] tries to hand over [offered_item] but it's stuck to them....")) + return + + visible_message(span_notice("[src] takes [offered_item] from [offerer]."), \ + span_notice("You take [offered_item] from [offerer].")) + offered_item.do_pickup_animation(src, offerer) + put_in_hands(offered_item) + + +/mob/living/click_ctrl_shift(mob/user) + if(HAS_TRAIT(src, TRAIT_CAN_HOLD_ITEMS)) + var/mob/living/living_user = user + living_user.give(src) diff --git a/tgstation.dme b/tgstation.dme index 951b52b3531..67afb96f3a6 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1835,7 +1835,6 @@ #include "code\datums\keybinding\_keybindings.dm" #include "code\datums\keybinding\admin.dm" #include "code\datums\keybinding\artificial_intelligence.dm" -#include "code\datums\keybinding\carbon.dm" #include "code\datums\keybinding\client.dm" #include "code\datums\keybinding\communication.dm" #include "code\datums\keybinding\emote.dm" @@ -5083,6 +5082,7 @@ #include "code\modules\mob\living\living_defense.dm" #include "code\modules\mob\living\living_defines.dm" #include "code\modules\mob\living\living_fov.dm" +#include "code\modules\mob\living\living_item_handling.dm" #include "code\modules\mob\living\living_movement.dm" #include "code\modules\mob\living\living_say.dm" #include "code\modules\mob\living\living_update_icons.dm"