Refactor: Moves throwing and giving items from /mob/living/carbon to /mob/living (#91049)

Given the existence of basic mobs with hand slots, it feels like
throwing and giving items shouldn't be something exclusive to carbon
mobs, so I've pulled things around to make this happen. The only basic
mobs with hands at time of writing are gorillas and dextrous
holoparasites, but the inability to throw things when you're a gorilla
just doesn't seem right to me.

Some more details about what I've done here:

- Made the dextrous component optionally enable throwing for the mob
it's added to.
- Moved offer/give item functionality to /mob/living (I can't see any
reason why only carbon mobs should have this option)
- Moved throwing and give item hotkeys from carbon to "human" (where all
the other /mob/living hotkeys go) and, as a result, removed carbon
hotkeys (nothing is left in them).
- Moved throwing code and item offering code to its own file because
living.dm is 3000+ lines long and should probably be broken up some day
(I'm not brave enough for that)
- Cleaned up an unused global signal that hasn't been used since dogs
got moved to basic mobs.
- Other miscellaneous cleanup where I noticed it.
- In terms of testing: Tested using gorillas (only checked the dextrous
holoparasite to confirm the button and hotkeys worked). Things that were
working:
  - Can throw items if the mob is set up to allow it.
- Can give items as a gorilla to a human, as a human to a gorilla, and
as a human to a human.
- Can give a high five to a gorilla (and the gorilla can receive it).
Gorillas can't give a high five back, though (they don't have the
emote), this already ballooned in scope, someone else can make that
happen.
- There are an alarmingly high amount of niche
emote-into-item-into-giving behaviours I suspect half the playerbase or
more aren't even aware of (does anyone offer their hand to someone to
get them up off of the ground?) and I don't know if I broke any of them
with this, but the fact high fives work gives me some hope they're
probably still fine.

Lets gorillas and dextrous holoparasites throw things and give things,
but most importantly sets up more framework for any future dextrous
basic mobs to also be able to do this. There's no real reason to keep
this functionality confined to carbon mobs when dextrous basic mobs are
a thing.

🆑
add: Gorillas can now throw things and offer items to players.
refactor: Moved throwing and offering item code to be based on living
mobs, not just carbon mobs.
/🆑

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
This commit is contained in:
Cirrial
2025-05-22 21:35:53 -04:00
committed by Roxy
co-authored by Copilot Ghom
parent 0060c53767
commit fb69fbb8a2
26 changed files with 380 additions and 337 deletions
@@ -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!
@@ -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
@@ -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()
+2 -2
View File
@@ -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)
+3 -3
View File
@@ -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
+2
View File
@@ -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.
+1
View File
@@ -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,
+1
View File
@@ -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,
+15 -16
View File
@@ -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!"
+5
View File
@@ -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
+3 -3
View File
@@ -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"
+3 -1
View File
@@ -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))
+2 -2
View File
@@ -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
-58
View File
@@ -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
+62
View File
@@ -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()
+19 -19
View File
@@ -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)
@@ -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
+15 -8
View File
@@ -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
+10 -2
View File
@@ -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("<b>[offerer]</b> 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" : ""]!"))
+1 -1
View File
@@ -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
@@ -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(
@@ -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)
+1 -122
View File
@@ -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
@@ -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)
@@ -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)
+1 -1
View File
@@ -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"