mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-11 10:11:09 +00:00
* Fixes typos in span, other html elements (#63510) Atomizes a much larger PR for another time... There are typos in span and other html messages that causes them to not render correctly or at all. Bug fixes Converts those instances of span to use the macro * Fixes typos in span, other html elements Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com>
164 lines
6.9 KiB
Plaintext
164 lines
6.9 KiB
Plaintext
/datum/component/butchering
|
|
/// Time in deciseconds taken to butcher something
|
|
var/speed = 8 SECONDS
|
|
/// Percentage effectiveness; numbers above 100 yield extra drops
|
|
var/effectiveness = 100
|
|
/// Percentage increase to bonus item chance
|
|
var/bonus_modifier = 0
|
|
/// Sound played when butchering
|
|
var/butcher_sound = 'sound/effects/butcher.ogg'
|
|
/// Whether or not this component can be used to butcher currently. Used to temporarily disable butchering
|
|
var/butchering_enabled = TRUE
|
|
/// Whether or not this component is compatible with blunt tools.
|
|
var/can_be_blunt = FALSE
|
|
/// Callback for butchering
|
|
var/datum/callback/butcher_callback
|
|
|
|
/datum/component/butchering/Initialize(_speed, _effectiveness, _bonus_modifier, _butcher_sound, disabled, _can_be_blunt, _butcher_callback)
|
|
if(_speed)
|
|
speed = _speed
|
|
if(_effectiveness)
|
|
effectiveness = _effectiveness
|
|
if(_bonus_modifier)
|
|
bonus_modifier = _bonus_modifier
|
|
if(_butcher_sound)
|
|
butcher_sound = _butcher_sound
|
|
if(disabled)
|
|
butchering_enabled = FALSE
|
|
if(_can_be_blunt)
|
|
can_be_blunt = _can_be_blunt
|
|
if(_butcher_callback)
|
|
butcher_callback = _butcher_callback
|
|
if(isitem(parent))
|
|
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/onItemAttack)
|
|
|
|
/datum/component/butchering/proc/onItemAttack(obj/item/source, mob/living/M, mob/living/user)
|
|
SIGNAL_HANDLER
|
|
|
|
if(M.stat == DEAD && (M.butcher_results || M.guaranteed_butcher_results)) //can we butcher it?
|
|
if(butchering_enabled && (can_be_blunt || source.get_sharpness()))
|
|
INVOKE_ASYNC(src, .proc/startButcher, source, M, user)
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
|
|
if(ishuman(M) && source.force && source.get_sharpness())
|
|
var/mob/living/carbon/human/H = M
|
|
if((user.pulling == H && user.grab_state >= GRAB_AGGRESSIVE) && user.zone_selected == BODY_ZONE_HEAD) // Only aggressive grabbed can be sliced.
|
|
if(H.has_status_effect(/datum/status_effect/neck_slice))
|
|
user.show_message(span_warning("[H]'s neck has already been already cut, you can't make the bleeding any worse!"), MSG_VISUAL, \
|
|
span_warning("Their neck has already been already cut, you can't make the bleeding any worse!"))
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
INVOKE_ASYNC(src, .proc/startNeckSlice, source, H, user)
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
|
|
/datum/component/butchering/proc/startButcher(obj/item/source, mob/living/M, mob/living/user)
|
|
to_chat(user, span_notice("You begin to butcher [M]..."))
|
|
playsound(M.loc, butcher_sound, 50, TRUE, -1)
|
|
if(do_mob(user, M, speed) && M.Adjacent(source))
|
|
Butcher(user, M)
|
|
|
|
/datum/component/butchering/proc/startNeckSlice(obj/item/source, mob/living/carbon/human/H, mob/living/user)
|
|
if(DOING_INTERACTION_WITH_TARGET(user, H))
|
|
to_chat(user, span_warning("You're already interacting with [H]!"))
|
|
return
|
|
|
|
user.visible_message(span_danger("[user] is slitting [H]'s throat!"), \
|
|
span_danger("You start slicing [H]'s throat!"), \
|
|
span_hear("You hear a cutting noise!"), ignored_mobs = H)
|
|
H.show_message(span_userdanger("Your throat is being slit by [user]!"), MSG_VISUAL, \
|
|
span_userdanger("Something is cutting into your neck!"), NONE)
|
|
log_combat(user, H, "attempted throat slitting", source)
|
|
|
|
playsound(H.loc, butcher_sound, 50, TRUE, -1)
|
|
if(do_mob(user, H, clamp(500 / source.force, 30, 100)) && H.Adjacent(source))
|
|
if(H.has_status_effect(/datum/status_effect/neck_slice))
|
|
user.show_message(span_warning("[H]'s neck has already been already cut, you can't make the bleeding any worse!"), MSG_VISUAL, \
|
|
span_warning("Their neck has already been already cut, you can't make the bleeding any worse!"))
|
|
return
|
|
|
|
H.visible_message(span_danger("[user] slits [H]'s throat!"), \
|
|
span_userdanger("[user] slits your throat..."))
|
|
log_combat(user, H, "wounded via throat slitting", source)
|
|
H.apply_damage(source.force, BRUTE, BODY_ZONE_HEAD, wound_bonus=CANT_WOUND) // easy tiger, we'll get to that in a sec
|
|
var/obj/item/bodypart/slit_throat = H.get_bodypart(BODY_ZONE_HEAD)
|
|
if(slit_throat)
|
|
var/datum/wound/slash/critical/screaming_through_a_slit_throat = new
|
|
screaming_through_a_slit_throat.apply_wound(slit_throat)
|
|
H.apply_status_effect(/datum/status_effect/neck_slice)
|
|
|
|
/**
|
|
* Handles a user butchering a target
|
|
*
|
|
* Arguments:
|
|
* - [butcher][/mob/living]: The mob doing the butchering
|
|
* - [meat][/mob/living]: The mob being butchered
|
|
*/
|
|
/datum/component/butchering/proc/Butcher(mob/living/butcher, mob/living/meat)
|
|
var/list/results = list()
|
|
var/turf/T = meat.drop_location()
|
|
var/final_effectiveness = effectiveness - meat.butcher_difficulty
|
|
var/bonus_chance = max(0, (final_effectiveness - 100) + bonus_modifier) //so 125 total effectiveness = 25% extra chance
|
|
for(var/V in meat.butcher_results)
|
|
var/obj/bones = V
|
|
var/amount = meat.butcher_results[bones]
|
|
for(var/_i in 1 to amount)
|
|
if(!prob(final_effectiveness))
|
|
if(butcher)
|
|
to_chat(butcher, span_warning("You fail to harvest some of the [initial(bones.name)] from [meat]."))
|
|
continue
|
|
|
|
if(prob(bonus_chance))
|
|
if(butcher)
|
|
to_chat(butcher, span_info("You harvest some extra [initial(bones.name)] from [meat]!"))
|
|
results += new bones (T)
|
|
results += new bones (T)
|
|
|
|
meat.butcher_results.Remove(bones) //in case you want to, say, have it drop its results on gib
|
|
|
|
for(var/V in meat.guaranteed_butcher_results)
|
|
var/obj/sinew = V
|
|
var/amount = meat.guaranteed_butcher_results[sinew]
|
|
for(var/i in 1 to amount)
|
|
results += new sinew (T)
|
|
meat.guaranteed_butcher_results.Remove(sinew)
|
|
|
|
for(var/obj/item/carrion in results)
|
|
var/list/meat_mats = carrion.has_material_type(/datum/material/meat)
|
|
if(!length(meat_mats))
|
|
continue
|
|
carrion.set_custom_materials((carrion.custom_materials - meat_mats) + list(GET_MATERIAL_REF(/datum/material/meat/mob_meat, meat) = counterlist_sum(meat_mats)))
|
|
|
|
if(butcher)
|
|
butcher.visible_message(span_notice("[butcher] butchers [meat]."), \
|
|
span_notice("You butcher [meat]."))
|
|
butcher_callback?.Invoke(butcher, meat)
|
|
meat.harvest(butcher)
|
|
meat.gib(FALSE, FALSE, TRUE)
|
|
|
|
///Special snowflake component only used for the recycler.
|
|
/datum/component/butchering/recycler
|
|
|
|
|
|
/datum/component/butchering/recycler/Initialize(_speed, _effectiveness, _bonus_modifier, _butcher_sound, disabled, _can_be_blunt)
|
|
if(!istype(parent, /obj/machinery/recycler)) //EWWW
|
|
return COMPONENT_INCOMPATIBLE
|
|
. = ..()
|
|
if(. == COMPONENT_INCOMPATIBLE)
|
|
return
|
|
|
|
var/static/list/loc_connections = list(
|
|
COMSIG_ATOM_ENTERED = .proc/on_entered,
|
|
)
|
|
AddComponent(/datum/component/connect_loc_behalf, parent, loc_connections)
|
|
|
|
/datum/component/butchering/recycler/proc/on_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs)
|
|
SIGNAL_HANDLER
|
|
|
|
if(!isliving(arrived))
|
|
return
|
|
var/mob/living/victim = arrived
|
|
var/obj/machinery/recycler/eater = parent
|
|
if(eater.safety_mode || (eater.machine_stat & (BROKEN|NOPOWER))) //I'm so sorry.
|
|
return
|
|
if(victim.stat == DEAD && (victim.butcher_results || victim.guaranteed_butcher_results))
|
|
Butcher(parent, victim)
|