Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moving unarmed attacks onto limbs. #4738

Merged
merged 2 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion code/game/machinery/camera/camera.dm
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@
/obj/machinery/camera/physical_attack_hand(mob/living/human/user)
if(!istype(user))
return TRUE
if(user.species.can_shred(user))
if(user.can_shred())
user.do_attack_animation(src)
visible_message(SPAN_WARNING("\The [user] slashes at [src]!"))
playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
Expand Down
12 changes: 5 additions & 7 deletions code/game/machinery/doors/windowdoor.dm
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,11 @@
return

/obj/machinery/door/window/physical_attack_hand(mob/user)
if(ishuman(user))
var/mob/living/human/H = user
if(H.species.can_shred(H))
playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1)
visible_message("<span class='danger'>\The [user] smashes against \the [src].</span>", 1)
take_damage(25)
return TRUE
if(user.can_shred())
playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1)
visible_message(SPAN_DANGER("\The [user] smashes against \the [src]."))
take_damage(25)
return TRUE
return ..()

/obj/machinery/door/window/emag_act(var/remaining_charges, var/mob/user)
Expand Down
10 changes: 3 additions & 7 deletions code/game/objects/items/weapons/weaponry.dm
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,9 @@
/obj/effect/energy_net/attack_hand(var/mob/user)
if(!user.check_intent(I_FLAG_HARM))
return ..()
var/decl/species/my_species = user.get_species()
if(my_species)
if(my_species.can_shred(user))
playsound(src.loc, 'sound/weapons/slash.ogg', 80, 1)
current_health -= rand(10, 20)
else
current_health -= rand(1,3)
if(user.can_shred())
playsound(src.loc, 'sound/weapons/slash.ogg', 80, 1)
current_health -= rand(10, 20)
else
current_health -= rand(5,8)
to_chat(user, SPAN_DANGER("You claw at the energy net."))
Expand Down
3 changes: 1 addition & 2 deletions code/game/objects/structures/defensive_barrier.dm
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,7 @@
if(!user.check_dexterity(DEXTERITY_HOLD_ITEM, TRUE))
return ..()

var/decl/species/species = user.get_species()
if(ishuman(user) && species?.can_shred(user) && user.check_intent(I_FLAG_HARM))
if(user.can_shred() && user.check_intent(I_FLAG_HARM))
take_damage(20)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
return TRUE
Expand Down
10 changes: 4 additions & 6 deletions code/game/objects/structures/grille.dm
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,10 @@

var/damage_dealt = 1
var/attack_message = "kicks"
if(ishuman(user))
var/mob/living/human/H = user
if(H.species.can_shred(H))
attack_message = "mangles"
damage_dealt = 5
attack_generic(user,damage_dealt,attack_message)
if(user.can_shred())
attack_message = "mangles"
damage_dealt = 5
attack_generic(user, damage_dealt, attack_message)
return TRUE

/obj/structure/grille/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
Expand Down
22 changes: 12 additions & 10 deletions code/game/objects/structures/window.dm
Original file line number Diff line number Diff line change
Expand Up @@ -147,21 +147,23 @@
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if (user.check_intent(I_FLAG_HARM))

if (ishuman(user))
var/mob/living/human/H = user
if(H.species.can_shred(H))
return attack_generic(H,25)
if(user.can_shred())
return attack_generic(user, 25)

playsound(src.loc, 'sound/effects/glassknock.ogg', 80, 1)
user.do_attack_animation(src)
user.visible_message(SPAN_DANGER("\The [user] bangs against \the [src]!"),
SPAN_DANGER("You bang against \the [src]!"),
"You hear a banging sound.")
user.visible_message(
SPAN_DANGER("\The [user] bangs against \the [src]!"),
SPAN_DANGER("You bang against \the [src]!"),
"You hear a banging sound."
)
else
playsound(src.loc, 'sound/effects/glassknock.ogg', 80, 1)
user.visible_message("[user.name] knocks on \the [src].",
"You knock on \the [src].",
"You hear a knocking sound.")
user.visible_message(
SPAN_NOTICE("\The [user] knocks on \the [src]."),
SPAN_NOTICE("You knock on \the [src]."),
"You hear a knocking sound."
)
return TRUE

/obj/structure/window/do_simple_ranged_interaction(var/mob/user)
Expand Down
24 changes: 9 additions & 15 deletions code/modules/mob/living/human/human_attackhand.dm
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
/mob/living/human/proc/get_unarmed_attack(var/mob/target, var/hit_zone = null)
if(!hit_zone)
hit_zone = get_target_zone()
var/list/available_attacks = get_natural_attacks()
var/list/available_attacks = get_mob_natural_attacks()
var/decl/natural_attack/use_attack = default_attack
if(!use_attack || !use_attack.is_usable(src, target, hit_zone) || !(use_attack.type in available_attacks))
use_attack = null
var/list/other_attacks = list()
for(var/u_attack_type in available_attacks)
var/decl/natural_attack/u_attack = GET_DECL(u_attack_type)
for(var/decl/natural_attack/u_attack as anything in available_attacks)
if(!u_attack.is_usable(src, target, hit_zone))
continue
if(u_attack.is_starting_default)
Expand All @@ -18,11 +17,8 @@
use_attack = pick(other_attacks)
. = use_attack?.resolve_to_soft_variant(src)

/mob/living/human/proc/get_natural_attacks()
. = list()
for(var/obj/item/organ/external/limb in get_external_organs())
if(length(limb.unarmed_attacks) && limb.is_usable())
. |= limb.unarmed_attacks
/obj/item/organ/external/proc/get_natural_attacks()
return null

/obj/item/organ/external/proc/get_injury_status(include_pain = TRUE, include_visible = TRUE)
. = list()
Expand Down Expand Up @@ -409,14 +405,12 @@
set src = usr

var/list/choices
for(var/thing in get_natural_attacks())
var/decl/natural_attack/u_attack = GET_DECL(thing)
if(istype(u_attack))
var/image/radial_button = new
radial_button.name = capitalize(u_attack.name)
LAZYSET(choices, u_attack, radial_button)
for(var/decl/natural_attack/u_attack as anything in get_mob_natural_attacks())
var/image/radial_button = new
radial_button.name = capitalize(u_attack.name)
LAZYSET(choices, u_attack, radial_button)
var/decl/natural_attack/new_attack = show_radial_menu(src, (attack_selector || src), choices, radius = 42, use_labels = RADIAL_LABELS_OFFSET)
if(QDELETED(src) || !istype(new_attack) || !(new_attack.type in get_natural_attacks()))
if(QDELETED(src) || !istype(new_attack) || !(new_attack in get_mob_natural_attacks()))
return
default_attack = new_attack
to_chat(src, SPAN_NOTICE("Your default unarmed attack is now <b>[default_attack?.name || "cleared"]</b>."))
Expand Down
2 changes: 0 additions & 2 deletions code/modules/mob/living/human/human_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
var/mob/remoteview_target = null
var/hand_blood_color
var/list/flavor_texts = list()
/// Are you trying not to hurt your opponent?
var/pulling_punches
/// We are a robutt.
var/full_prosthetic
/// Number of robot limbs.
Expand Down
6 changes: 0 additions & 6 deletions code/modules/mob/living/human/human_verbs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -319,9 +319,3 @@
"<span class='danger'>[self ? "You pop" : "[U] pops"] your [current_limb.joint] back in!</span>" \
)
current_limb.undislocate()

/mob/living/human/verb/pull_punches()
set name = "Switch Stance"
set desc = "Try not to hurt them."
set category = "IC"
species.toggle_stance(src)
8 changes: 8 additions & 0 deletions code/modules/mob/living/living.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2023,3 +2023,11 @@ default behaviour is:
// or things should just update their worn slot when coating is added
update_equipment_overlay(slot_shoes_str)
return TRUE

/mob/living/verb/pull_punches()
set name = "Switch Stance"
set desc = "Try not to hurt them."
set category = "IC"
if(!incapacitated())
pulling_punches = !pulling_punches
to_chat(src, SPAN_NOTICE("You are now [pulling_punches ? "pulling your punches" : "not pulling your punches"]."))
3 changes: 1 addition & 2 deletions code/modules/mob/living/living_resist.dm
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@
return 1

/mob/living/proc/can_break_restraints()
var/decl/species/my_species = get_species()
return my_species?.can_shred(src, 1)
return can_shred(ignore_intent = TRUE)

/mob/living/proc/get_special_resist_time()
return 0
Expand Down
3 changes: 1 addition & 2 deletions code/modules/mob/living/silicon/robot/robot.dm
Original file line number Diff line number Diff line change
Expand Up @@ -643,8 +643,7 @@
return user?.attempt_hug(src)

/mob/living/silicon/robot/default_hurt_interaction(mob/user)
var/decl/species/user_species = user.get_species()
if(user_species?.can_shred(user))
if(user.can_shred())
attack_generic(user, rand(30,50), "slashed")
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
return TRUE
Expand Down
21 changes: 21 additions & 0 deletions code/modules/mob/mob.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1392,3 +1392,24 @@
paw = GET_EXTERNAL_ORGAN(src, BP_R_HAND)
if(istype(paw) && paw.is_usable())
return paw

// Called when using the shredding behavior.
/mob/proc/can_shred(var/mob/living/human/H, var/ignore_intent, var/ignore_antag)
if((!ignore_intent && !check_intent(I_FLAG_HARM)) || pulling_punches)
return FALSE
if(!ignore_antag && mind && !player_is_antag(mind))
return FALSE
if(get_equipped_item(slot_handcuffed_str) || buckled)
return FALSE
for(var/decl/natural_attack/attack as anything in get_mob_natural_attacks())
if(attack.is_usable(src) && attack.shredding)
return TRUE
return FALSE

/mob/proc/get_mob_natural_attacks()
for(var/obj/item/organ/external/limb in get_external_organs())
if(!limb.is_usable())
continue
var/list/limb_unarmed_attacks = limb.get_natural_attacks()
if(istype(limb_unarmed_attacks, /decl/natural_attack) || (islist(limb_unarmed_attacks) && length(limb_unarmed_attacks)))
LAZYDISTINCTADD(., limb_unarmed_attacks)
3 changes: 3 additions & 0 deletions code/modules/mob/mob_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,6 @@
// Offset the overhead text if necessary.
var/offset_overhead_text_x = 0
var/offset_overhead_text_y = 0

/// Are you trying not to hurt your opponent?
var/pulling_punches
6 changes: 0 additions & 6 deletions code/modules/organs/external/_external.dm
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@
var/stage = 0
var/cavity = 0

var/list/unarmed_attacks

var/atom/movable/applied_pressure
var/atom/movable/splinted

Expand Down Expand Up @@ -141,10 +139,6 @@
_icon_cache_key = null
. = ..()
skin_blend = bodytype.limb_blend
for(var/attack_type in species.unarmed_attacks)
var/decl/natural_attack/attack = GET_DECL(attack_type)
if(istype(attack) && (organ_tag in attack.usable_with_limbs))
LAZYADD(unarmed_attacks, attack_type)
update_icon()

/obj/item/organ/external/set_bodytype(decl/bodytype/new_bodytype, override_material = null, apply_to_internal_organs = TRUE)
Expand Down
18 changes: 18 additions & 0 deletions code/modules/organs/external/head.dm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,24 @@
var/forehead_graffiti
var/graffiti_style

/obj/item/organ/external/head/get_natural_attacks()
if(!can_intake_reagents)
return null
var/static/unarmed_attack = GET_DECL(/decl/natural_attack/bite)
return unarmed_attack

/obj/item/organ/external/head/sharp_bite/get_natural_attacks()
if(!can_intake_reagents)
return null
var/static/unarmed_attack = GET_DECL(/decl/natural_attack/bite/sharp)
return unarmed_attack

/obj/item/organ/external/head/strong_bite/get_natural_attacks()
if(!can_intake_reagents)
return null
var/static/unarmed_attack = GET_DECL(/decl/natural_attack/bite/strong)
return unarmed_attack

/obj/item/organ/external/head/proc/get_organ_eyes_overlay()
if(!glowing_eyes && !owner?.has_chemical_effect(CE_GLOWINGEYES, 1))
return
Expand Down
19 changes: 19 additions & 0 deletions code/modules/organs/external/standard.dm
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@
limb_flags = ORGAN_FLAG_CAN_AMPUTATE | ORGAN_FLAG_CAN_STAND | ORGAN_FLAG_HAS_TENDON | ORGAN_FLAG_CAN_BREAK | ORGAN_FLAG_CAN_DISLOCATE
organ_category = ORGAN_CATEGORY_STANCE

/obj/item/organ/external/foot/get_natural_attacks()
var/static/list/unarmed_attacks = list(
GET_DECL(/decl/natural_attack/stomp),
GET_DECL(/decl/natural_attack/kick)
)
return unarmed_attacks

/obj/item/organ/external/foot/right
organ_tag = BP_R_FOOT
name = "right foot"
Expand All @@ -139,6 +146,10 @@
is_washable = TRUE
var/gripper_type = /datum/inventory_slot/gripper/left_hand

/obj/item/organ/external/hand/get_natural_attacks()
var/static/unarmed_attack = GET_DECL(/decl/natural_attack/punch)
return unarmed_attack

/obj/item/organ/external/hand/do_install(mob/living/human/target, affected, in_place, update_icon, detached)
. = ..()
if(. && owner && gripper_type)
Expand All @@ -158,3 +169,11 @@
joint = "right wrist"
amputation_point = "right wrist"
gripper_type = /datum/inventory_slot/gripper/right_hand

/obj/item/organ/external/hand/clawed/get_natural_attacks()
var/static/unarmed_attack = GET_DECL(/decl/natural_attack/claws)
return unarmed_attack

/obj/item/organ/external/hand/right/clawed/get_natural_attacks()
var/static/unarmed_attack = GET_DECL(/decl/natural_attack/claws)
return unarmed_attack
4 changes: 2 additions & 2 deletions code/modules/paperwork/papershredder.dm
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
/obj/machinery/papershredder/proc/is_bin_empty()
return !(length(shredder_bin) > 0 && cached_total_matter)

/obj/machinery/papershredder/proc/can_shred(var/obj/item/I, var/mob/user = null)
/obj/machinery/papershredder/proc/can_shred_document(var/obj/item/I, var/mob/user = null)
if(!istype(I))
if(user)
to_chat(user, SPAN_WARNING("\The [I] cannot be shredded by \the [src]!"))
Expand Down Expand Up @@ -120,7 +120,7 @@
empty_bin(user, used_item)
return TRUE

else if(!trying_to_smack && can_shred(used_item))
else if(!trying_to_smack && can_shred_document(used_item))
shred(used_item, user)
return TRUE
return ..()
Expand Down
29 changes: 14 additions & 15 deletions code/modules/power/apc.dm
Original file line number Diff line number Diff line change
Expand Up @@ -491,21 +491,20 @@ var/global/list/all_apcs = list()

/obj/machinery/power/apc/physical_attack_hand(mob/user)
//Human mob special interaction goes here.
if(ishuman(user))
var/mob/living/human/H = user

if(H.species.can_shred(H))
user.visible_message("<span class='warning'>\The [user] slashes at \the [src]!</span>", "<span class='notice'>You slash at \the [src]!</span>")
playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)

var/allcut = wires.IsAllCut()
if(beenhit >= pick(3, 4) && allcut == 0)
wires.CutAll()
src.update_icon()
src.visible_message("<span class='warning'>\The [src]'s wires are shredded!</span>")
else
beenhit += 1
return TRUE
if(user.can_shred())
user.visible_message(
SPAN_DANGER("\The [user] slashes at \the [src]!"),
SPAN_DANGER("You slash at \the [src]!")
)
playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
var/allcut = wires.IsAllCut()
if(beenhit >= pick(3, 4) && allcut == 0)
wires.CutAll()
update_icon()
visible_message(SPAN_DANGER("\The [src]'s wires are shredded!"))
else
beenhit += 1
return TRUE
return FALSE

/obj/machinery/power/apc/interface_interact(mob/user)
Expand Down
13 changes: 7 additions & 6 deletions code/modules/power/lighting.dm
Original file line number Diff line number Diff line change
Expand Up @@ -316,12 +316,13 @@
to_chat(user, "There is no [get_fitting_name()] in this light.")
return TRUE

if(ishuman(user))
var/mob/living/human/H = user
if(H.species.can_shred(H))
visible_message("<span class='warning'>[user.name] smashed the light!</span>", 3, "You hear a tinkle of breaking glass.")
broken()
return TRUE
if(user.can_shred())
visible_message(
SPAN_DANGER("\The [user] smashes the light!"),
blind_message = "You hear a tinkle of breaking glass."
)
broken()
return TRUE

// make it burn hands if not wearing fire-insulated gloves
if(on)
Expand Down
Loading