From 7f17505e48a2f462f857d23adc3b49b1f7872b06 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Tue, 18 Aug 2015 21:58:52 -0400 Subject: [PATCH 1/2] Cleans up mob_grab.dm Moves all of the grab abilities into their own proc instead of having them all dumped into /obj/item/weapon/grab/attack(). --- baystation12.dme | 1 + code/modules/mob/mob_grab.dm | 225 ++++++-------------------- code/modules/mob/mob_grab_specials.dm | 165 +++++++++++++++++++ code/modules/mob/mob_movement.dm | 10 -- 4 files changed, 218 insertions(+), 183 deletions(-) create mode 100644 code/modules/mob/mob_grab_specials.dm diff --git a/baystation12.dme b/baystation12.dme index e0333a2e08..2e5a2cc8ea 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -1096,6 +1096,7 @@ #include "code\modules\mob\mob_cleanup.dm" #include "code\modules\mob\mob_defines.dm" #include "code\modules\mob\mob_grab.dm" +#include "code\modules\mob\mob_grab_specials.dm" #include "code\modules\mob\mob_helpers.dm" #include "code\modules\mob\mob_movement.dm" #include "code\modules\mob\mob_transformation_simple.dm" diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index acc95fbe40..af17182d7f 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -1,6 +1,13 @@ #define UPGRADE_COOLDOWN 40 #define UPGRADE_KILL_TIMER 100 +///Process_Grab() +///Called by client/Move() +///Checks to see if you are grabbing anything and if moving will affect your grab. +/client/proc/Process_Grab() + for(var/obj/item/weapon/grab/G in list(mob.l_hand, mob.r_hand)) + G.reset_kill_state() //no wandering across the station/asteroid while choking someone + /obj/item/weapon/grab name = "grab" icon = 'icons/mob/screen1.dmi' @@ -69,7 +76,6 @@ else hud.screen_loc = ui_lhand - /obj/item/weapon/grab/process() if(gcDestroyed) // GC is trying to delete us, we'll kill our processing so we can cleanly GC return PROCESS_KILL @@ -116,23 +122,9 @@ affecting.drop_l_hand() affecting.drop_r_hand() - var/hit_zone = assailant.zone_sel.selecting - var/announce = 0 - if(hit_zone != last_hit_zone) - announce = 1 - last_hit_zone = hit_zone - if(ishuman(affecting)) - switch(hit_zone) - if("mouth") - if(announce) - assailant.visible_message("[assailant] covers [affecting]'s mouth!") - if(affecting:silent < 3) - affecting:silent = 3 - if("eyes") - if(announce) - assailant.visible_message("[assailant] covers [affecting]'s eyes!") - if(affecting:eye_blind < 3) - affecting:eye_blind = 3 + if(iscarbon(affecting)) + handle_eye_mouth_covering(affecting, assailant, assailant.zone_sel.selecting) + if(force_down) if(affecting.loc != assailant.loc) force_down = 0 @@ -153,6 +145,21 @@ adjust_position() +/obj/item/weapon/grab/proc/handle_eye_mouth_covering(mob/living/carbon/target, mob/user, var/target_zone) + var/announce = (target_zone != last_hit_zone) //only display messages when switching between different target zones + last_hit_zone = target_zone + + switch(target_zone) + if("mouth") + if(announce) + user.visible_message("\The [user] covers [target]'s mouth!") + if(target.silent < 3) + target.silent = 3 + if("eyes") + if(announce) + assailant.visible_message("[assailant] covers [affecting]'s eyes!") + if(affecting.eye_blind < 3) + affecting.eye_blind = 3 /obj/item/weapon/grab/attack_self() return s_click(hud) @@ -202,8 +209,6 @@ if(EAST) animate(affecting, pixel_x =-shift, pixel_y = 0, 5, 1, LINEAR_EASING) - - /obj/item/weapon/grab/proc/s_click(obj/screen/S) if(!affecting) return @@ -226,11 +231,8 @@ assailant.visible_message("[assailant] has grabbed [affecting] aggressively (now hands)!") else assailant.visible_message("[assailant] pins [affecting] down to the ground (now hands)!") - force_down = 1 - affecting.Weaken(3) - step_to(assailant, affecting) - assailant.set_dir(EAST) //face the victim - affecting.set_dir(SOUTH) //face up + apply_pinning(affecting, assailant) + state = GRAB_AGGRESSIVE icon_state = "grabbed1" hud.icon_state = "reinforce1" @@ -264,7 +266,6 @@ affecting.set_dir(WEST) adjust_position() - //This is used to make sure the victim hasn't managed to yackety sax away before using the grab. /obj/item/weapon/grab/proc/confirm() if(!assailant || !affecting) @@ -278,17 +279,18 @@ return 1 - /obj/item/weapon/grab/attack(mob/M, mob/living/user) if(!affecting) return - if(world.time < (last_action + 20)) return - + + last_action = world.time + reset_kill_state() //using special grab moves will interrupt choking them + + //clicking on the victim while grabbing them if(M == affecting) - if(ishuman(M)) - last_action = world.time + if(ishuman(affecting)) var/hit_zone = assailant.zone_sel.selecting flick(hud.icon_state, hud) switch(assailant.a_intent) @@ -297,160 +299,37 @@ assailant << "You are no longer pinning [affecting] to the ground." force_down = 0 return - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/E = H.get_organ(hit_zone) - if(E && !(E.status & ORGAN_DESTROYED)) - assailant.visible_message("[assailant] starts inspecting [affecting]'s [E.name] carefully.") - if(do_mob(assailant,H, 10)) - if(E.wounds.len) - assailant << "You find [E.get_wounds_desc()]" - else - assailant << "You find no visible wounds." - else - assailant << "You must stand still to inspect [E] for wounds." - assailant << "Checking bones now..." - if(do_mob(assailant, H, 20)) - if(E.status & ORGAN_BROKEN) - assailant << "The [E.encased ? E.encased : "bone in the [E.name]"] moves slightly when you poke it!" - H.custom_pain("Your [E.name] hurts where it's poked.") - else - assailant << "The [E.encased ? E.encased : "bones in the [E.name]"] seem to be fine." - else - assailant << "You must stand still to feel [E] for fractures." - assailant << "Checking skin now..." - if(do_mob(assailant, H, 10)) - var/bad = 0 - if(H.getToxLoss() >= 40) - assailant << "[H] has an unhealthy skin discoloration." - bad = 1 - if(H.getOxyLoss() >= 20) - assailant << "[H]'s skin is unusaly pale." - bad = 1 - if(E.status & ORGAN_DEAD) - assailant << "[E] is decaying!" - bad = 1 - if(!bad) - assailant << "[H]'s skin is normal." - else - assailant << "You must stand still to check [H]'s skin for abnormalities." - else - assailant << "[H] is missing that bodypart." + inspect_organ(affecting, assailant, hit_zone) + if(I_GRAB) - if(state < GRAB_AGGRESSIVE) - assailant << "You require a better grab to do this." - return - var/obj/item/organ/external/organ = affecting:get_organ(check_zone(hit_zone)) - if(!organ || organ.dislocated == -1) - return - assailant.visible_message("[assailant] [pick("bent", "twisted")] [affecting]'s [organ.name] into a jointlock!") - var/armor = affecting:run_armor_check(affecting, "melee") - if(armor < 2) - affecting << "You feel extreme pain!" - affecting.adjustHalLoss(Clamp(0, 40-affecting.halloss, 40)) //up to 40 halloss - return + jointlock(affecting, assailant, hit_zone) + if(I_HURT) - if(hit_zone == "eyes") - var/mob/living/carbon/human/H = affecting - var/datum/unarmed_attack/attack = H.get_unarmed_attack(src, hit_zone) - if(!attack) - return - - if(state < GRAB_NECK) - assailant << "You require a better grab to do this." - return - if((affecting:head && affecting:head.flags & HEADCOVERSEYES) || \ - (affecting:wear_mask && affecting:wear_mask.flags & MASKCOVERSEYES) || \ - (affecting:glasses && affecting:glasses.flags & GLASSESCOVERSEYES)) - assailant << "You're going to need to remove the eye covering first." - return - if(!affecting.has_eyes()) - assailant << "You cannot locate any eyes on [affecting]!" - return - assailant.attack_log += text("\[[time_stamp()]\] Attacked [affecting.name]'s eyes using grab ([affecting.ckey])") - affecting.attack_log += text("\[[time_stamp()]\] Had eyes attacked by [assailant.name]'s grab ([assailant.ckey])") - msg_admin_attack("[key_name(assailant)] attacked [key_name(affecting)]'s eyes using a grab action.") - - attack.handle_eye_attack(assailant, affecting) - else if(hit_zone != "head") - if(state < GRAB_NECK) - assailant << "You require a better grab to do this." - return - if(affecting:grab_joint(assailant)) - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - return + attack_eye(affecting, assailant) + else if(hit_zone == "head") + headbut(affecting, assailant) else - if(affecting.lying) - return - assailant.visible_message("[assailant] thrusts \his head into [affecting]'s skull!") - var/damage = 20 - var/obj/item/clothing/hat = assailant.head - if(istype(hat)) - damage += hat.force * 10 - var/armor = affecting:run_armor_check(affecting, "melee") - affecting.apply_damage(damage*rand(90, 110)/100, BRUTE, "head", armor) - assailant.apply_damage(10*rand(90, 110)/100, BRUTE, "head", assailant:run_armor_check("head", "melee")) - if(!armor && prob(damage)) - affecting.apply_effect(20, PARALYZE) - affecting.visible_message("[affecting] has been knocked unconscious!") - playsound(assailant.loc, "swing_hit", 25, 1, -1) - assailant.attack_log += text("\[[time_stamp()]\] Headbutted [affecting.name] ([affecting.ckey])") - affecting.attack_log += text("\[[time_stamp()]\] Headbutted by [assailant.name] ([assailant.ckey])") - msg_admin_attack("[key_name(assailant)] has headbutted [key_name(affecting)]") - assailant.drop_from_inventory(src) - src.loc = null - qdel(src) - return + dislocate(affecting, assailant, hit_zone) + if(I_DISARM) - if(state < GRAB_AGGRESSIVE) - assailant << "You require a better grab to do this." - return - assailant << "You start forcing [affecting] to the ground." - if(!force_down) - if(do_after(assailant, 20) && affecting) - assailant.visible_message("[assailant] is forcing [affecting] to the ground!") - force_down = 1 - affecting.Weaken(3) - affecting.lying = 1 - step_to(assailant, affecting) - assailant.set_dir(EAST) //face the victim - affecting.set_dir(SOUTH) //face up - return - else - assailant << "You are already pinning [affecting] to the ground." - return - + pin_down(affecting, assailant) + + //clicking on yourself while grabbing them if(M == assailant && state >= GRAB_AGGRESSIVE) - - var/can_eat - if((FAT in user.mutations) && issmall(affecting)) - can_eat = 1 - else - var/mob/living/carbon/human/H = user - if(istype(H) && H.species.gluttonous) - if(H.species.gluttonous == 2) - can_eat = 2 - else if(!ishuman(affecting) && !issmall(affecting) && (affecting.small || iscarbon(affecting))) - can_eat = 1 - - if(can_eat) - var/mob/living/carbon/attacker = user - user.visible_message("[user] is attempting to devour [affecting]!") - if(can_eat == 2) - if(!do_mob(user, affecting)||!do_after(user, 30)) return - else - if(!do_mob(user, affecting)||!do_after(user, 100)) return - user.visible_message("[user] devours [affecting]!") - affecting.loc = user - attacker.stomach_contents.Add(affecting) - qdel(src) - + devour(affecting, assailant) /obj/item/weapon/grab/dropped() loc = null if(!destroying) qdel(src) +/obj/item/weapon/grab/proc/reset_kill_state() + if(state == GRAB_KILL) + assailant.visible_message("[assailant] lost \his tight grip on [affecting]'s neck!") + hud.icon_state = "kill" + state = GRAB_NECK + /obj/item/weapon/grab var/destroying = 0 diff --git a/code/modules/mob/mob_grab_specials.dm b/code/modules/mob/mob_grab_specials.dm new file mode 100644 index 0000000000..f4364dc684 --- /dev/null +++ b/code/modules/mob/mob_grab_specials.dm @@ -0,0 +1,165 @@ + +/obj/item/weapon/grab/proc/inspect_organ(mob/living/carbon/human/H, mob/user, var/target_zone) + + var/obj/item/organ/external/E = H.get_organ(target_zone) + + if(!E || (E.status & ORGAN_DESTROYED)) + user << "[H] is missing that bodypart." + return + + user.visible_message("[user] starts inspecting [affecting]'s [E.name] carefully.") + if(!do_mob(user,H, 10)) + user << "You must stand still to inspect [E] for wounds." + else if(E.wounds.len) + user << "You find [E.get_wounds_desc()]" + else + user << "You find no visible wounds." + + user << "Checking bones now..." + if(!do_mob(user, H, 20)) + user << "You must stand still to feel [E] for fractures." + else if(E.status & ORGAN_BROKEN) + user << "The [E.encased ? E.encased : "bone in the [E.name]"] moves slightly when you poke it!" + H.custom_pain("Your [E.name] hurts where it's poked.") + else + user << "The [E.encased ? E.encased : "bones in the [E.name]"] seem to be fine." + + user << "Checking skin now..." + if(!do_mob(user, H, 10)) + user << "You must stand still to check [H]'s skin for abnormalities." + else + var/bad = 0 + if(H.getToxLoss() >= 40) + user << "[H] has an unhealthy skin discoloration." + bad = 1 + if(H.getOxyLoss() >= 20) + user << "[H]'s skin is unusaly pale." + bad = 1 + if(E.status & ORGAN_DEAD) + user << "[E] is decaying!" + bad = 1 + if(!bad) + user << "[H]'s skin is normal." + +/obj/item/weapon/grab/proc/jointlock(mob/living/carbon/human/target, mob/attacker, var/target_zone) + if(state < GRAB_AGGRESSIVE) + attacker << "You require a better grab to do this." + return + + var/obj/item/organ/external/organ = target.get_organ(check_zone(target_zone)) + if(!organ || organ.dislocated == -1) + return + + attacker.visible_message("[attacker] [pick("bent", "twisted")] [target]'s [organ.name] into a jointlock!") + var/armor = target.run_armor_check(target, "melee") + if(armor < 2) + target << "You feel extreme pain!" + affecting.adjustHalLoss(Clamp(0, 60-affecting.halloss, 30)) //up to 60 halloss + +/obj/item/weapon/grab/proc/attack_eye(mob/living/carbon/human/target, mob/living/carbon/human/attacker) + if(!istype(attacker)) + return + + var/datum/unarmed_attack/attack = attacker.get_unarmed_attack(target, "eyes") + + if(!attack) + return + if(state < GRAB_NECK) + attacker << "You require a better grab to do this." + return + for(var/obj/item/protection in list(target.head, target.wear_mask, target.glasses)) + if(protection && (protection.flags & HEADCOVERSEYES)) + attacker << "You're going to need to remove the eye covering first." + return + if(!target.has_eyes()) + attacker << "You cannot locate any eyes on [target]!" + return + + attacker.attack_log += text("\[[time_stamp()]\] Attacked [target.name]'s eyes using grab ([target.ckey])") + target.attack_log += text("\[[time_stamp()]\] Had eyes attacked by [attacker.name]'s grab ([attacker.ckey])") + msg_admin_attack("[key_name(attacker)] attacked [key_name(target)]'s eyes using a grab action.") + + attack.handle_eye_attack(attacker, target) + +/obj/item/weapon/grab/proc/headbut(mob/living/carbon/human/target, mob/living/carbon/human/attacker) + if(!istype(attacker)) + return + if(target.lying) + return + attacker.visible_message("[attacker] thrusts \his head into [target]'s skull!") + + var/damage = 20 + var/obj/item/clothing/hat = attacker.head + if(istype(hat)) + damage += hat.force * 10 + + var/armor = target.run_armor_check("head", "melee") + target.apply_damage(damage*rand(90, 110)/100, BRUTE, "head", armor) + attacker.apply_damage(10*rand(90, 110)/100, BRUTE, "head", attacker.run_armor_check("head", "melee")) + + if(!armor && prob(damage)) + target.apply_effect(20, PARALYZE) + target.visible_message("[target] has been knocked unconscious!") + + playsound(attacker.loc, "swing_hit", 25, 1, -1) + attacker.attack_log += text("\[[time_stamp()]\] Headbutted [target.name] ([target.ckey])") + target.attack_log += text("\[[time_stamp()]\] Headbutted by [attacker.name] ([attacker.ckey])") + msg_admin_attack("[key_name(attacker)] has headbutted [key_name(target)]") + + attacker.drop_from_inventory(src) + src.loc = null + qdel(src) + return + +/obj/item/weapon/grab/proc/dislocate(mob/living/carbon/human/target, mob/living/attacker, var/target_zone) + if(state < GRAB_NECK) + attacker << "You require a better grab to do this." + return + if(target.grab_joint(attacker, target_zone)) + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + return + +/obj/item/weapon/grab/proc/pin_down(mob/target, mob/attacker) + if(state < GRAB_AGGRESSIVE) + attacker << "You require a better grab to do this." + return + if(force_down) + attacker << "You are already pinning [target] to the ground." + + attacker.visible_message("[attacker] starts forcing [target] to the ground!") + if(do_after(attacker, 20) && target) + last_action = world.time + attacker.visible_message("[attacker] forces [target] to the ground!") + apply_pinning(target, attacker) + +/obj/item/weapon/grab/proc/apply_pinning(mob/target, mob/attacker) + force_down = 1 + target.Weaken(3) + target.lying = 1 + step_to(attacker, target) + attacker.set_dir(EAST) //face the victim + target.set_dir(SOUTH) //face up + +/obj/item/weapon/grab/proc/devour(mob/target, mob/user) + var/can_eat + if((FAT in user.mutations) && issmall(target)) + can_eat = 1 + else + var/mob/living/carbon/human/H = user + if(istype(H) && H.species.gluttonous) + if(H.species.gluttonous == 2) + can_eat = 2 + else if(!ishuman(target) && !issmall(target) && (target.small || iscarbon(target))) + can_eat = 1 + + if(can_eat) + var/mob/living/carbon/attacker = user + user.visible_message("[user] is attempting to devour [target]!") + if(can_eat == 2) + if(!do_mob(user, target)||!do_after(user, 30)) return + else + if(!do_mob(user, target)||!do_after(user, 100)) return + user.visible_message("[user] devours [target]!") + target.loc = user + attacker.stomach_contents.Add(target) + qdel(src) \ No newline at end of file diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 0404131642..7ed4f4d280 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -360,16 +360,6 @@ return Move(n, direct) -///Process_Grab() -///Called by client/Move() -///Checks to see if you are grabbing anything and if moving will affect your grab. -/client/proc/Process_Grab() - for(var/obj/item/weapon/grab/G in list(mob.l_hand, mob.r_hand)) - if(G.state == GRAB_KILL) //no wandering across the station/asteroid while choking someone - mob.visible_message("[mob] lost \his tight grip on [G.affecting]'s neck!") - G.hud.icon_state = "kill" - G.state = GRAB_NECK - ///Process_Incorpmove ///Called by client/Move() ///Allows mobs to run though walls From 3e967872a3d45b34dca828353fd09e777c66dd3f Mon Sep 17 00:00:00 2001 From: mwerezak Date: Wed, 26 Aug 2015 14:55:38 -0400 Subject: [PATCH 2/2] Allows grabs to be resisted while weakened --- code/modules/mob/living/living.dm | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 2c19a5a9df..173dd91516 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -576,12 +576,14 @@ default behaviour is: if(can_resist()) next_move = world.time + 20 - process_resist() + resist_grab() + if(!weakened && !restrained()) + process_resist() /mob/living/proc/can_resist() //need to allow !canmove, or otherwise neck grabs can't be resisted - //so just check weakened instead. - if(stat || weakened) + //similar thing with weakened and pinning + if(stat) return 0 if(next_move > world.time) return 0 @@ -593,10 +595,6 @@ default behaviour is: escape_inventory(src.loc) return - //resisting grabs (as if it helps anyone...) - if (!restrained()) - resist_grab() - //unbuckling yourself if(buckled) spawn() escape_buckle()