diff --git a/code/modules/mob/living/carbon/human/alien/alien_species.dm b/code/modules/mob/living/carbon/human/alien/alien_species.dm index 79df1553c4..3e6fada92c 100644 --- a/code/modules/mob/living/carbon/human/alien/alien_species.dm +++ b/code/modules/mob/living/carbon/human/alien/alien_species.dm @@ -5,8 +5,7 @@ default_language = "Xenomorph" language = "Hivemind" - unarmed_type = /datum/unarmed_attack/claws/strong - secondary_unarmed_type = /datum/unarmed_attack/bite/strong + unarmed_types = list(/datum/unarmed_attack/claws/strong, /datum/unarmed_attack/bite/strong) hud_type = /datum/hud_data/alien rarity_value = 3 diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index 9ba667faac..9e20c29d0e 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -94,14 +94,7 @@ attack_generic(H,rand(1,3),"punched") return - // See if they can attack, and which attacks to use. - var/datum/unarmed_attack/attack = H.species.unarmed - if(!attack.is_usable(H)) - attack = H.species.secondary_unarmed - if(!attack.is_usable(H)) - return 0 - - var/damage = rand(1, 5) + var/rand_damage = rand(1, 5) var/block = 0 var/accurate = 0 var/hit_zone = H.zone_sel.selecting @@ -110,7 +103,7 @@ switch(src.a_intent) if("help") // We didn't see this coming, so we get the full blow - damage = 5 + rand_damage = 5 accurate = 1 if("hurt", "grab") // We're in a fighting stance, there's a chance we block @@ -119,7 +112,7 @@ if (M.grabbed_by.len) // Someone got a good grip on them, they won't be able to do much damage - damage = max(1, damage - 2) + rand_damage = max(1, rand_damage - 2) if(src.grabbed_by.len || src.buckled || !src.canmove || src==H) accurate = 1 // certain circumstances make it impossible for us to evade punches @@ -155,17 +148,30 @@ if(prob(80)) hit_zone = ran_zone(hit_zone) if(prob(15) && hit_zone != "chest") // Missed! - attack_message = "[H] attempted to strike [src], but missed!" + if(!src.lying) + attack_message = "[H] attempted to strike [src], but missed!" + else + attack_message = "[H] attempted to strike [src], but \he rolled out of the way!" + src.set_dir(pick(cardinal)) miss_type = 1 - else - hit_zone = ran_zone(hit_zone) if(!miss_type && block) attack_message = "[H] went for [src]'s [affecting.display_name] but was blocked!" miss_type = 2 + // See what attack they use + var/datum/unarmed_attack/attack = null + for(var/datum/unarmed_attack/u_attack in H.species.unarmed_attacks) + if(!u_attack.is_usable(H, src, hit_zone)) + continue + else + attack = u_attack + break + if(!attack) + return 0 + if(!attack_message) - attack.show_attack(H, src, hit_zone, damage) + attack.show_attack(H, src, hit_zone, rand_damage) else H.visible_message("[attack_message]") @@ -177,18 +183,21 @@ if(miss_type) return 0 - damage += attack.damage // Adding species attack base damage - damage *= damage_multiplier + var/real_damage = rand_damage + real_damage += attack.damage // Adding species attack base damage + real_damage *= damage_multiplier + rand_damage *= damage_multiplier if(HULK in H.mutations) - damage *= 2 // Hulks do twice the damage - damage = max(1, damage) + real_damage *= 2 // Hulks do twice the damage + rand_damage *= 2 + real_damage = max(1, real_damage) var/armour = run_armor_check(affecting, "melee") // Apply additional unarmed effects. - attack.apply_effects(H,src,armour,damage,hit_zone) + attack.apply_effects(H, src, armour, rand_damage, hit_zone) // Finally, apply damage to target - apply_damage(damage, BRUTE, affecting, armour, sharp=attack.sharp, edge=attack.edge) + apply_damage(real_damage, BRUTE, affecting, armour, sharp=attack.sharp, edge=attack.edge) if("disarm") M.attack_log += text("\[[time_stamp()]\] Disarmed [src.name] ([src.ckey])") diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 67eb8f86e0..0409cdfc1b 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -12,17 +12,15 @@ var/prone_icon // If set, draws this from icobase when mob is prone. var/eyes = "eyes_s" // Icon for eyes. - var/primitive // Lesser form, if any (ie. monkey for humans) - var/tail // Name of tail image in species effects icon file. - var/datum/unarmed_attack/unarmed // For empty hand harm-intent attack - var/datum/unarmed_attack/secondary_unarmed // For empty hand harm-intent attack if the first fails. + var/primitive // Lesser form, if any (ie. monkey for humans) + var/tail // Name of tail image in species effects icon file. + var/list/unarmed_attacks = null // For empty hand harm-intent attack var/datum/hud_data/hud var/hud_type var/slowdown = 0 var/gluttonous // Can eat some mobs. 1 for monkeys, 2 for people. var/rarity_value = 1 // Relative rarity/collector value for this species. Only used by ninja and cultists atm. - var/unarmed_type = /datum/unarmed_attack - var/secondary_unarmed_type = /datum/unarmed_attack/bite + var/list/unarmed_types = list(/datum/unarmed_attack, /datum/unarmed_attack/bite) var/language // Default racial language, if any. // Default language is used when 'say' is used without modifiers. @@ -98,8 +96,9 @@ else hud = new() - if(unarmed_type) unarmed = new unarmed_type() - if(secondary_unarmed_type) secondary_unarmed = new secondary_unarmed_type() + unarmed_attacks = list() + for(var/u_type in unarmed_types) + unarmed_attacks += new u_type() /datum/species/proc/create_organs(var/mob/living/carbon/human/H) //Handles creation of mob organs. @@ -207,7 +206,7 @@ name_plural = "Humans" language = "Sol Common" primitive = /mob/living/carbon/monkey - unarmed_type = /datum/unarmed_attack/punch + unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/punch, /datum/unarmed_attack/bite) flags = HAS_SKIN_TONE | HAS_LIPS | HAS_UNDERWEAR | HAS_EYE_COLOR @@ -221,8 +220,7 @@ deform = 'icons/mob/human_races/r_def_lizard.dmi' language = "Sinta'unathi" tail = "sogtail" - unarmed_type = /datum/unarmed_attack/claws - secondary_unarmed_type = /datum/unarmed_attack/bite/sharp + unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws, /datum/unarmed_attack/bite/sharp) primitive = /mob/living/carbon/monkey/unathi darksight = 3 gluttonous = 1 @@ -249,8 +247,7 @@ deform = 'icons/mob/human_races/r_def_tajaran.dmi' language = "Siik'tajr" tail = "tajtail" - unarmed_type = /datum/unarmed_attack/claws - secondary_unarmed_type = /datum/unarmed_attack/bite/sharp + unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws, /datum/unarmed_attack/bite/sharp) darksight = 8 cold_level_1 = 200 //Default 260 @@ -276,7 +273,7 @@ eyes = "skrell_eyes_s" language = "Skrellian" primitive = /mob/living/carbon/monkey/skrell - unarmed_type = /datum/unarmed_attack/punch + unarmed_types = list(/datum/unarmed_attack/punch) flags = IS_WHITELISTED | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR @@ -292,8 +289,7 @@ deform = 'icons/mob/human_races/r_def_vox.dmi' default_language = "Vox-pidgin" language = "Galactic Common" - unarmed_type = /datum/unarmed_attack/claws/strong - secondary_unarmed_type = /datum/unarmed_attack/bite/strong + unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws/strong, /datum/unarmed_attack/bite/strong) rarity_value = 2 speech_sounds = list('sound/voice/shriek1.ogg') @@ -380,8 +376,7 @@ icobase = 'icons/mob/human_races/r_diona.dmi' deform = 'icons/mob/human_races/r_def_plant.dmi' language = "Rootspeak" - unarmed_type = /datum/unarmed_attack/diona - secondary_unarmed_type = null //Does a walking mass of dionaea even have jaws, as we understand them? + unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/diona) primitive = /mob/living/carbon/alien/diona slowdown = 7 rarity_value = 3 @@ -447,8 +442,7 @@ icobase = 'icons/mob/human_races/r_machine.dmi' deform = 'icons/mob/human_races/r_machine.dmi' language = "Tradeband" - unarmed_type = /datum/unarmed_attack/punch - secondary_unarmed_type = null + unarmed_types = list(/datum/unarmed_attack/punch) rarity_value = 2 eyes = "blank_eyes" @@ -484,11 +478,10 @@ if(H.a_intent != "hurt") return 0 - if(unarmed.is_usable(H)) - if(unarmed.shredding) - return 1 - else if(secondary_unarmed.is_usable(H)) - if(secondary_unarmed.shredding) + for(var/datum/unarmed_attack/attack in unarmed_attacks) + if(!attack.is_usable(H)) + continue + if(attack.shredding) return 1 return 0 diff --git a/code/modules/mob/living/carbon/human/unarmed_attack.dm b/code/modules/mob/living/carbon/human/unarmed_attack.dm index f381cfd6a1..3986c39a44 100644 --- a/code/modules/mob/living/carbon/human/unarmed_attack.dm +++ b/code/modules/mob/living/carbon/human/unarmed_attack.dm @@ -28,9 +28,6 @@ var/stun_chance = rand(0, 100) - // Reduce effective damage to normalize stun chance across species. - attack_damage = min(1,attack_damage - damage) - if(attack_damage >= 5 && armour < 2 && !(target == user) && stun_chance <= attack_damage * 5) // 25% standard chance switch(zone) // strong punches can have effects depending on where they hit if("head", "mouth", "eyes") @@ -49,12 +46,14 @@ target.drop_r_hand() if("chest") if(!target.lying) - target.visible_message("[pick("[target] was sent flying backward!", "[target] staggers back from the impact!")]") - var/turf/T = step(src, get_dir(get_turf(user), get_turf(target))) - if(T.density) // This will need to be expanded to check for structures etc. - target.visible_message("[target] slams into [T]!") + var/turf/T = get_step(get_turf(target), get_dir(get_turf(user), get_turf(target))) + if(!T.density) + step(target, get_dir(get_turf(user), get_turf(target))) + target.visible_message("[pick("[target] was sent flying backward!", "[target] staggers back from the impact!")]") else - target.loc = T + target.visible_message("[target] slams into [T]!") + if(prob(50)) + target.set_dir(reverse_dir[target.dir]) target.apply_effect(attack_damage * 0.4, WEAKEN, armour) if("groin") target.visible_message("[target] looks like \he is in pain!", "[(target.gender=="female") ? "Oh god that hurt!" : "Oh no, not your[pick("testicles", "crown jewels", "clockweights", "family jewels", "marbles", "bean bags", "teabags", "sweetmeats", "goolies")]!"]") @@ -63,9 +62,9 @@ if(!target.lying) target.visible_message("[src] gives way slightly.") target.apply_effect(attack_damage*3, AGONY, armour) - else if(attack_damage >= 5 && !(target == user) && (stun_chance + attack_damage) * 5 >= 100 && armour < 2) // Chance to get the usual throwdown as well (25% standard chance) + else if(attack_damage >= 5 && !(target == user) && (stun_chance + attack_damage * 5 >= 100) && armour < 2) // Chance to get the usual throwdown as well (25% standard chance) if(!target.lying) - target.visible_message("[pick("slumps", "falls", "drops")] down to the ground!") + target.visible_message("[target] [pick("slumps", "falls", "drops")] down to the ground!") else target.visible_message("[target] has been weakened!") target.apply_effect(3, WEAKEN, armour) @@ -91,9 +90,11 @@ sharp = 1 edge = 1 -/datum/unarmed_attack/bite/is_usable(var/mob/living/carbon/human/user) +/datum/unarmed_attack/bite/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone) if (user.wear_mask && istype(user.wear_mask, /obj/item/clothing/mask/muzzle)) return 0 + if (user == target && (zone == "head" || zone == "eyes" || zone == "mouth")) + return 0 return 1 /datum/unarmed_attack/punch @@ -119,28 +120,89 @@ if(1 to 2) user.visible_message("[user] slapped [target] across \his cheek!") if(3 to 4) user.visible_message("[user] struck [target] in the head[pick("", " with a closed fist")]!") if(5) user.visible_message("[user] gave [target] a resounding slap to the face!") - if("chest", "l_arm", "r_arm", "l_hand", "r_hand") - // -- UPPER BODY -- // + if("chest", "l_arm", "r_arm", "l_hand", "r_hand", "groin", "l_leg", "r_let", "l_foot", "r_foot") + // ----- BODY ----- // switch(attack_damage) if(1 to 2) user.visible_message("[user] slapped [target]'s [organ]!") if(3 to 4) user.visible_message("[user] [pick(attack_verb)] [target] in \his [organ]!") if(5) user.visible_message("[user] slammed \his [pick(attack_noun)] into [target]'s [organ]!") - if("groin", "l_leg", "r_leg") - // -- LOWER BODY -- // - switch(attack_damage) - if(1 to 2) user.visible_message("[user] gave [target] a light kick to the [organ]!") - if(3 to 4) user.visible_message("[user] [pick("kicked", "kneed")] [target] in \his [organ]!") - if(5) user.visible_message("[user] landed a strong kick against [target]'s [organ]!") - if("l_foot", "r_foot") - // ----- FEET ----- // - switch(attack_damage) - if(1 to 4) user.visible_message("[user] kicked [target] in \his [organ]!") - if(5) user.visible_message("[user] stomped down hard on [target]'s [organ]!") - else if (user.loc != target.loc) - user.visible_message("[user] [pick("stomped down hard on", "kicked against", "gave a strong kick against", "slammed their foot into")] [target]'s [organ]!") else user.visible_message("[user] [pick("punched", "threw a punch", "struck", "slapped", "rammed their [pick(attack_noun)] into")] [target]'s [organ]!") +/datum/unarmed_attack/kick + attack_verb = list("kicked", "kneed") + attack_noun = list("kick") + attack_sound = "swing_hit" + damage = 1 + +/datum/unarmed_attack/kick/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone) + if (target.legcuffed) + return 0 + + if(!(zone in list("l_leg", "r_leg", "l_foot", "r_foot", "groin"))) + return 0 + + var/datum/organ/external/E = user.organs_by_name["l_foot"] + if(E && !(E.status & ORGAN_DESTROYED)) + return 1 + + E = user.organs_by_name["r_foot"] + if(E && !(E.status & ORGAN_DESTROYED)) + return 1 + + return 0 + +/datum/unarmed_attack/kick/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage) + var/datum/organ/external/affecting = target.get_organ(zone) + var/organ = affecting.display_name + + attack_damage = Clamp(attack_damage, 1, 5) + + switch(zone) + if("groin", "l_leg", "r_leg") + // -- LOWER BODY -- // + switch(attack_damage) + if(1 to 2) user.visible_message("[user] gave [target] a light [pick(attack_noun)] to the [organ]!") + if(3 to 4) user.visible_message("[user] [pick(attack_verb)] [target] in \his [organ]!") + if(5) user.visible_message("[user] landed a strong [pick(attack_noun)] against [target]'s [organ]!") + if("l_foot", "r_foot") + // ----- FEET ----- // + switch(attack_damage) + if(1 to 4) user.visible_message("[user] kicked [target] in \his [organ]!") + if(5) user.visible_message("[user] stomped down hard on [target]'s [organ]!") + +/datum/unarmed_attack/stomp + attack_verb = null + attack_noun = list("kick") + attack_sound = "swing_hit" + damage = 3 + +/datum/unarmed_attack/stomp/is_usable(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone) + if (target.legcuffed) + return 0 + + if (target.lying && !user.lying) + var/datum/organ/external/E = user.organs_by_name["l_foot"] + if(E && !(E.status & ORGAN_DESTROYED)) + return 1 + + E = user.organs_by_name["r_foot"] + if(E && !(E.status & ORGAN_DESTROYED)) + return 1 + + return 0 + +/datum/unarmed_attack/stomp/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage) + var/datum/organ/external/affecting = target.get_organ(zone) + var/organ = affecting.display_name + + attack_damage = Clamp(attack_damage, 1, 5) + + switch(attack_damage) + if(1 to 3) + user.visible_message("[user] [pick("gave a kick against", "kicked against", "stomped down on", "slammed their foot into")] [target]'s [organ]!") + if(4 to 5) + user.visible_message("[user] [pick("landed a strong kick against", "kicked against", "stomped down hard on", "rammed their foot into")] [target]'s [organ]!") /datum/unarmed_attack/diona attack_verb = list("lashed", "bludgeoned") diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index fba2447b40..a45106b7e0 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -146,9 +146,17 @@ help_shake_act(M) else if (M.a_intent == "hurt") - var/datum/unarmed_attack/attack = M.species.unarmed + var/datum/unarmed_attack/attack = null + for(var/datum/unarmed_attack/u_attack in M.species.unarmed_attacks) + if(!u_attack.is_usable(M, src)) + continue + else + attack = u_attack + break + if(!attack) + return 0 if ((prob(75) && health > 0)) - visible_message("\red [M] [pick(attack.attack_verb)]ed [src]!") + visible_message("\red [M] [pick(attack.attack_verb)] [src]!") playsound(loc, "punch", 25, 1, -1) var/damage = rand(5, 10) @@ -284,4 +292,4 @@ message = capitalize(trim_left(message)) - ..(message, speaking, verb, alt_name, italics, message_range, used_radios) + ..(message, speaking, verb, alt_name, italics, message_range, used_radios)