diff --git a/beestation.dme b/beestation.dme index fef444dac67fa..2b1dc71f5d9c9 100644 --- a/beestation.dme +++ b/beestation.dme @@ -389,7 +389,6 @@ #include "code\_onclick\hud\alien_larva.dm" #include "code\_onclick\hud\blob_overmind.dm" #include "code\_onclick\hud\blobbernauthud.dm" -#include "code\_onclick\hud\constructs.dm" #include "code\_onclick\hud\credits.dm" #include "code\_onclick\hud\drones.dm" #include "code\_onclick\hud\fullscreen.dm" @@ -398,7 +397,7 @@ #include "code\_onclick\hud\holoparasite.dm" #include "code\_onclick\hud\hud.dm" #include "code\_onclick\hud\human.dm" -#include "code\_onclick\hud\lavaland_elite.dm" +#include "code\_onclick\hud\living.dm" #include "code\_onclick\hud\map_popups.dm" #include "code\_onclick\hud\minebot.dm" #include "code\_onclick\hud\monkey.dm" @@ -412,7 +411,6 @@ #include "code\_onclick\hud\revenanthud.dm" #include "code\_onclick\hud\robot.dm" #include "code\_onclick\hud\screen_objects.dm" -#include "code\_onclick\hud\slime.dm" #include "code\_onclick\hud\swarmer.dm" #include "code\_onclick\hud\rendering\plane_master.dm" #include "code\_onclick\hud\rendering\plane_master_controller.dm" diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 44f9bfb1e656f..520f5eb5df0f3 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -295,6 +295,15 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( #define NICE_SHOT_RICOCHET_BONUS 10 //if the shooter has the NICE_SHOT trait and they fire a ricocheting projectile, add this to the ricochet chance and auto aim angle +/// Martial arts attack requested but is not available, allow a check for a regular attack. +#define MARTIAL_ATTACK_INVALID -1 + +/// Martial arts attack happened but failed, do not allow a check for a regular attack. +#define MARTIAL_ATTACK_FAIL FALSE + +/// Martial arts attack happened and succeeded, do not allow a check for a regular attack. +#define MARTIAL_ATTACK_SUCCESS TRUE + // Flags for energy shields /// Energy shields will block projectiles #define ENERGY_SHIELD_BLOCK_PROJECTILES (1 << 0) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 813fedfa18630..05781a250ae1c 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -44,6 +44,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_HUSK "husk" #define TRAIT_BADDNA "baddna" #define TRAIT_CLUMSY "clumsy" +//means that you can't use weapons with normal trigger guards. +#define TRAIT_CHUNKYFINGERS "chunkyfingers" #define TRAIT_DUMB "dumb" #define TRAIT_DISCOORDINATED "discoordinated" //sets IsAdvancedToolUser to FALSE on humans and monkies #define TRAIT_PACIFISM "pacifism" @@ -68,6 +70,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_RESISTCOLD "resist_cold" #define TRAIT_RESISTHIGHPRESSURE "resist_high_pressure" #define TRAIT_RESISTLOWPRESSURE "resist_low_pressure" +#define TRAIT_BOMBIMMUNE "bomb_immunity" #define TRAIT_RADIMMUNE "rad_immunity" #define TRAIT_NORADDAMAGE "no_rad_damage" #define TRAIT_VIRUSIMMUNE "virus_immunity" @@ -172,6 +175,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_NO_BLOOD "no_blood" // Bleeding heals itself and bleeding is impossible #define TRAIT_NO_BLEEDING "no_bleed" // The user can acquire the bleeding status effect, but will no lose blood #define TRAIT_BLOOD_COOLANT "blood_coolant" // Replaces blood with coolant, meaning we overheat instead of losing air +#define TRAIT_MARTIAL_ARTS_IMMUNE "martial_arts_immune" // nobody can use martial arts on this mob // You can stare into the abyss, but it does not stare back. // You're immune to the hallucination effect of the supermatter, either diff --git a/code/__DEFINES/traits/sources.dm b/code/__DEFINES/traits/sources.dm index 9cd1e59e7144d..2564ac55af483 100644 --- a/code/__DEFINES/traits/sources.dm +++ b/code/__DEFINES/traits/sources.dm @@ -85,6 +85,7 @@ #define ANTI_DROP_IMPLANT_TRAIT "anti-drop-implant" #define HIVEMIND_TRAIT "hivemind-trait" #define VR_ZONE_TRAIT "vr_zone_trait" +#define SLEEPING_CARP_TRAIT "sleeping_carp" #define GLUED_ITEM_TRAIT "glued-item" #define LEGION_CORE_TRAIT "legion_core_trait" #define MIRROR_TRAIT "mirror_trait" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index d75e959633899..45e1334d4b09b 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -48,6 +48,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_RESISTCOLD" = TRAIT_RESISTCOLD, "TRAIT_RESISTHIGHPRESSURE" = TRAIT_RESISTHIGHPRESSURE, "TRAIT_RESISTLOWPRESSURE" = TRAIT_RESISTLOWPRESSURE, + "TRAIT_BOMBIMMUNE" = TRAIT_BOMBIMMUNE, "TRAIT_RADIMMUNE" = TRAIT_RADIMMUNE, "TRAIT_VIRUSIMMUNE" = TRAIT_VIRUSIMMUNE, "TRAIT_PIERCEIMMUNE" = TRAIT_PIERCEIMMUNE, @@ -184,7 +185,9 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_IGNORING_GRAVITY" = TRAIT_IGNORING_GRAVITY, "TRAIT_FORCED_GRAVITY" = TRAIT_FORCED_GRAVITY, "TRAIT_MOVE_UPSIDE_DOWN" = TRAIT_MOVE_UPSIDE_DOWN, - "TRAIT_NEGATES_GRAVITY" = TRAIT_NEGATES_GRAVITY + "TRAIT_NEGATES_GRAVITY" = TRAIT_NEGATES_GRAVITY, + "TRAIT_MARTIAL_ARTS_IMMUNE" = TRAIT_MARTIAL_ARTS_IMMUNE, + "TRAIT_CHUNKYFINGERS" = TRAIT_CHUNKYFINGERS, ), /obj/item/integrated_circuit = list( "TRAIT_COMPONENT_MMI" = TRAIT_COMPONENT_MMI, diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 027d1f498fc82..7ebe16a641a05 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -337,15 +337,34 @@ if(istype(ML)) ML.pulled(src) +/mob/living/CtrlClick(mob/user) + if(!isliving(user) || !Adjacent(user) || user.incapacitated()) + return ..() + + if(world.time < user.next_move) + return FALSE + + var/mob/living/user_living = user + if(user_living.apply_martial_art(src, null) == MARTIAL_ATTACK_SUCCESS) + user_living.changeNext_move(CLICK_CD_MELEE) + return TRUE + + return ..() + /mob/living/carbon/human/CtrlClick(mob/user) - if(ishuman(user) && Adjacent(user) && !user.incapacitated()) - if(world.time < user.next_move) - return FALSE - var/mob/living/carbon/human/H = user - H.dna.species.grab(H, src, H.mind.martial_art) - H.changeNext_move(CLICK_CD_MELEE) - else - ..() + + if(!ishuman(user) ||!Adjacent(user) || user.incapacitated()) + return ..() + + if(world.time < user.next_move) + return FALSE + + var/mob/living/carbon/human/human_user = user + if(human_user.dna.species.grab(human_user, src, human_user.mind.martial_art)) + human_user.changeNext_move(CLICK_CD_MELEE) + return TRUE + + return ..() /mob/proc/CtrlMiddleClickOn(atom/A) // specifically made for admin feature. diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm index d2f077fc6aa6d..a08c17b36cb17 100644 --- a/code/_onclick/hud/_defines.dm +++ b/code/_onclick/hud/_defines.dm @@ -17,21 +17,6 @@ Therefore, the top right corner (except during admin shenanigans) is at "17,15" */ -//Lower left, persistent menu -#define ui_inventory "WEST:6,SOUTH:5" - -//Middle left indicators -#define ui_lingchemdisplay "WEST,CENTER-1:15" -#define ui_lingstingdisplay "WEST:6,CENTER-3:11" - -#define ui_devilsouldisplay "WEST:6,CENTER-1:15" - -//Lower center, persistent menu -#define ui_sstore1 "CENTER-5:10,SOUTH:5" -#define ui_id "CENTER-4:12,SOUTH:5" -#define ui_belt "CENTER-3:14,SOUTH:5" -#define ui_back "CENTER-2:14,SOUTH:5" - /proc/ui_hand_position(i) //values based on old hand ui positions (CENTER:-/+16,SOUTH:5) var/x_off = -(!(i % 2)) var/y_off = round((i-1) / 2) @@ -46,8 +31,22 @@ var/y_off = round((M.held_items.len-1) / 2) return "CENTER+[x_off]:16,SOUTH+[y_off+1]:5" +//Lower left, persistent menu +#define ui_inventory "WEST:6,SOUTH:5" + +//Middle left indicators +#define ui_lingchemdisplay "WEST,CENTER-1:15" +#define ui_lingstingdisplay "WEST:6,CENTER-3:11" +#define ui_devilsouldisplay "WEST:6,CENTER-1:15" + +//Lower center, persistent menu +#define ui_sstore1 "CENTER-5:10,SOUTH:5" +#define ui_id "CENTER-4:12,SOUTH:5" +#define ui_belt "CENTER-3:14,SOUTH:5" +#define ui_back "CENTER-2:14,SOUTH:5" #define ui_storage1 "CENTER+1:18,SOUTH:5" #define ui_storage2 "CENTER+2:20,SOUTH:5" +#define ui_combo "CENTER+4:24,SOUTH+1:7" //combo meter for martial arts #define ui_borg_lamp "CENTER-3:16, SOUTH:5" //borgs #define ui_borg_tablet "CENTER-4:16, SOUTH:5" //borgs @@ -61,6 +60,10 @@ #define ui_borg_crew_manifest "CENTER+5:21,SOUTH:5" //borgs #define ui_borg_language_menu "CENTER+4:21,SOUTH+1:5" //borgs +//Generic living +#define ui_living_pull "EAST-1:28,CENTER-3:15" +#define ui_living_healthdoll "EAST-1:28,CENTER-1:15" + #define ui_monkey_body "CENTER-6:12,SOUTH:5" //monkey #define ui_monkey_head "CENTER-5:14,SOUTH:5" //monkey #define ui_monkey_mask "CENTER-4:15,SOUTH:5" //monkey @@ -117,12 +120,9 @@ #define ui_alienplasmadisplay "EAST,CENTER-2:15" #define ui_alien_queen_finder "EAST,CENTER-3:15" -//constructs +//Constructs #define ui_construct_pull "EAST,CENTER-2:15" -#define ui_construct_health "EAST,CENTER:15" //same as borgs and humans - -//slimes -#define ui_slime_health "EAST,CENTER:15" //same as borgs, constructs and humans +#define ui_construct_health "EAST,CENTER:15" // AI diff --git a/code/_onclick/hud/constructs.dm b/code/_onclick/hud/constructs.dm deleted file mode 100644 index bee898ea489c8..0000000000000 --- a/code/_onclick/hud/constructs.dm +++ /dev/null @@ -1,15 +0,0 @@ -/datum/hud/constructs - ui_style = 'icons/hud/screen_construct.dmi' - -/datum/hud/constructs/New(mob/owner) - ..() - pull_icon = new /atom/movable/screen/pull() - pull_icon.icon = ui_style - pull_icon.update_icon() - pull_icon.screen_loc = ui_construct_pull - pull_icon.hud = src - static_inventory += pull_icon - - healths = new /atom/movable/screen/healths/construct() - healths.hud = src - infodisplay += healths diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 6d94886e3f886..e817dfd21e940 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -35,7 +35,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list( var/atom/movable/screen/alien_plasma_display var/atom/movable/screen/alien_queen_finder - var/atom/movable/screen/devil/soul_counter/devilsouldisplay + var/atom/movable/screen/combo/combo_display var/atom/movable/screen/action_intent var/atom/movable/screen/zone_select @@ -117,11 +117,11 @@ GLOBAL_LIST_INIT(available_ui_styles, list( stamina = null healthdoll = null lingchemdisplay = null - devilsouldisplay = null lingstingdisplay = null blobpwrdisplay = null alien_plasma_display = null alien_queen_finder = null + combo_display = null QDEL_LIST_ASSOC_VAL(plane_masters) QDEL_LIST_ASSOC_VAL(plane_master_controllers) diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 3a4c8dfda6cb5..13ea00ba8cc29 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -336,16 +336,15 @@ lingstingdisplay.hud = src infodisplay += lingstingdisplay - devilsouldisplay = new /atom/movable/screen/devil/soul_counter - devilsouldisplay.hud = src - infodisplay += devilsouldisplay - zone_select = new /atom/movable/screen/zone_sel() zone_select.icon = ui_style zone_select.update_icon() zone_select.hud = src static_inventory += zone_select + combo_display = new /atom/movable/screen/combo() + infodisplay += combo_display + for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory)) if(inv.slot_id) inv.hud = src diff --git a/code/_onclick/hud/lavaland_elite.dm b/code/_onclick/hud/lavaland_elite.dm deleted file mode 100644 index 526e48ba87ba0..0000000000000 --- a/code/_onclick/hud/lavaland_elite.dm +++ /dev/null @@ -1,7 +0,0 @@ -/datum/hud/lavaland_elite - ui_style = 'icons/hud/screen_slime.dmi' - -/datum/hud/lavaland_elite/New(mob/living/simple_animal/hostile/asteroid/elite) - ..() - healths = new /atom/movable/screen/healths/lavaland_elite() - infodisplay += healths diff --git a/code/_onclick/hud/living.dm b/code/_onclick/hud/living.dm new file mode 100644 index 0000000000000..366079f233d10 --- /dev/null +++ b/code/_onclick/hud/living.dm @@ -0,0 +1,20 @@ +/datum/hud/living + ui_style = 'icons/hud/screen_gen.dmi' + +/datum/hud/living/New(mob/living/owner) + ..() + + pull_icon = new /atom/movable/screen/pull() + pull_icon.icon = ui_style + pull_icon.update_appearance() + pull_icon.screen_loc = ui_living_pull + pull_icon.hud = src + static_inventory += pull_icon + + combo_display = new /atom/movable/screen/combo() + infodisplay += combo_display + + //mob health doll! assumes whatever sprite the mob is + healthdoll = new /atom/movable/screen/healthdoll/living() + healthdoll.hud = src + infodisplay += healthdoll diff --git a/code/_onclick/hud/monkey.dm b/code/_onclick/hud/monkey.dm index 542b496d3459a..f44dd3c5ddf4e 100644 --- a/code/_onclick/hud/monkey.dm +++ b/code/_onclick/hud/monkey.dm @@ -124,6 +124,9 @@ zone_select.hud = src static_inventory += zone_select + combo_display = new /atom/movable/screen/combo() + infodisplay += combo_display + mymob.client.screen = list() using = new /atom/movable/screen/resist() diff --git a/code/_onclick/hud/revenanthud.dm b/code/_onclick/hud/revenanthud.dm index 708b1d49154d7..0e7b795965539 100644 --- a/code/_onclick/hud/revenanthud.dm +++ b/code/_onclick/hud/revenanthud.dm @@ -1,7 +1,16 @@ +/datum/hud/revenant + ui_style = 'icons/hud/screen_gen.dmi' /datum/hud/revenant/New(mob/owner) ..() + pull_icon = new /atom/movable/screen/pull() + pull_icon.icon = ui_style + pull_icon.update_icon() + pull_icon.screen_loc = ui_living_pull + pull_icon.hud = src + static_inventory += pull_icon + healths = new /atom/movable/screen/healths/revenant() healths.hud = src infodisplay += healths diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index effec7721c770..29bc98cf12070 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -566,7 +566,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/atom/movable/screen/storage) /atom/movable/screen/healths/minebot icon = 'icons/hud/screen_cyborg.dmi' - screen_loc = ui_health + screen_loc = ui_borg_health /atom/movable/screen/healths/blob name = "blob health" @@ -581,8 +581,8 @@ CREATION_TEST_IGNORE_SUBTYPES(/atom/movable/screen/storage) /atom/movable/screen/healths/blob/naut/core name = "overmind health" - screen_loc = ui_health icon_state = "corehealth" + screen_loc = ui_health /atom/movable/screen/healths/clock icon = 'icons/hud/actions/action_generic.dmi' @@ -599,25 +599,6 @@ CREATION_TEST_IGNORE_SUBTYPES(/atom/movable/screen/storage) name = "essence" icon = 'icons/hud/actions/action_generic.dmi' icon_state = "bg_revenant" - screen_loc = ui_health - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - -/atom/movable/screen/healths/construct - icon = 'icons/hud/screen_construct.dmi' - icon_state = "artificer_health0" - screen_loc = ui_construct_health - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - -/atom/movable/screen/healths/slime - icon = 'icons/hud/screen_slime.dmi' - icon_state = "slime_health0" - screen_loc = ui_slime_health - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - -/atom/movable/screen/healths/lavaland_elite - icon = 'icons/hud/screen_elite.dmi' - icon_state = "elite_health0" - screen_loc = ui_health mouse_opacity = MOUSE_OPACITY_TRANSPARENT /atom/movable/screen/healthdoll @@ -629,6 +610,11 @@ CREATION_TEST_IGNORE_SUBTYPES(/atom/movable/screen/storage) var/mob/living/carbon/C = usr C.check_self_for_injuries() +/atom/movable/screen/healthdoll/living + icon_state = "fullhealth0" + screen_loc = ui_living_healthdoll + var/filtered = FALSE //so we don't repeatedly create the mask of the mob every update + /atom/movable/screen/mood name = "mood" icon_state = "mood5" @@ -701,6 +687,37 @@ CREATION_TEST_IGNORE_SUBTYPES(/atom/movable/screen/component_button) if(parent) parent.component_click(src, params) +/atom/movable/screen/combo + icon_state = "" + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + screen_loc = ui_combo + plane = ABOVE_HUD_PLANE + var/timerid + +/atom/movable/screen/combo/proc/clear_streak() + animate(src, alpha = 0, 2 SECONDS, SINE_EASING) + timerid = addtimer(CALLBACK(src, PROC_REF(reset_icons)), 2 SECONDS, TIMER_UNIQUE | TIMER_STOPPABLE) + +/atom/movable/screen/combo/proc/reset_icons() + cut_overlays() + icon_state = "" + +/atom/movable/screen/combo/update_icon_state(streak = "", time = 2 SECONDS) + reset_icons() + if(timerid) + deltimer(timerid) + alpha = 255 + if(!streak) + return ..() + timerid = addtimer(CALLBACK(src, PROC_REF(clear_streak)), time, TIMER_UNIQUE | TIMER_STOPPABLE) + icon_state = "combo" + for (var/i = 1; i <= length(streak); ++i) + var/intent_text = copytext(streak, i, i + 1) + var/image/intent_icon = image(icon,src,"combo_[intent_text]") + intent_icon.pixel_x = 16 * (i - 1) - 8 * length(streak) + add_overlay(intent_icon) + return ..() + /atom/movable/screen/stamina name = "stamina" icon_state = "stamina0" diff --git a/code/_onclick/hud/slime.dm b/code/_onclick/hud/slime.dm deleted file mode 100644 index 35845b64a24ec..0000000000000 --- a/code/_onclick/hud/slime.dm +++ /dev/null @@ -1,8 +0,0 @@ -/datum/hud/slime - ui_style = 'icons/hud/screen_slime.dmi' - -/datum/hud/slime/New(mob/living/simple_animal/slime/owner) - ..() - healths = new /atom/movable/screen/healths/slime() - healths.hud = src - infodisplay += healths diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 2aff31691887e..4aea3d0590d89 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -111,7 +111,7 @@ if(item_flags & NOBLUDGEON) nonharmfulhit = TRUE - if(force && HAS_TRAIT(user, TRAIT_PACIFISM) && !nonharmfulhit) + if(damtype != STAMINA && force && HAS_TRAIT(user, TRAIT_PACIFISM) && !nonharmfulhit) to_chat(user, span_warning("You don't want to harm other living beings!")) nonharmfulhit = TRUE diff --git a/code/datums/cinematic.dm b/code/datums/cinematic.dm index cf6db650d0d00..9038bd1e875c0 100644 --- a/code/datums/cinematic.dm +++ b/code/datums/cinematic.dm @@ -72,7 +72,7 @@ ooc_toggled = TRUE toggle_ooc(FALSE) - //Place /obj/screen/cinematic into everyone's screens, prevent them from moving + //Place /atom/movable/cinematic into everyone's screens, prevent them from moving for(var/MM in watchers) var/mob/M = MM show_to(M, M.client) diff --git a/code/datums/martial/_martial.dm b/code/datums/martial/_martial.dm index fd989179d9d9a..1c0ef2688ea09 100644 --- a/code/datums/martial/_martial.dm +++ b/code/datums/martial/_martial.dm @@ -5,114 +5,93 @@ var/max_streak_length = 6 var/current_target var/datum/martial_art/base // The permanent style. This will be null unless the martial art is temporary - var/deflection_chance = 0 //Chance to deflect projectiles - var/reroute_deflection = FALSE //Delete the bullet, or actually deflect it in some direction? var/block_chance = 0 //Chance to block melee attacks using items while on throw mode. - var/restraining = 0 //used in cqc's disarm_act to check if the disarmed is being restrained and so whether they should be put in a chokehold or not var/help_verb - var/no_guns = FALSE var/allow_temp_override = TRUE //if this martial art can be overridden by temporary martial arts var/smashes_tables = FALSE //If the martial art smashes tables when performing table slams and head smashes + var/datum/weakref/holder //owner of the martial art + var/display_combos = FALSE //shows combo meter if true + var/combo_timer = 6 SECONDS // period of time after which the combo streak is reset. + var/timerid + /// If set to true this style allows you to punch people despite being a pacifist (for instance Boxing, which does no damage) + var/pacifist_style = FALSE -/datum/martial_art/proc/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) - return 0 +/datum/martial_art/proc/help_act(mob/living/A, mob/living/D) + return MARTIAL_ATTACK_INVALID -/datum/martial_art/proc/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) - return 0 +/datum/martial_art/proc/disarm_act(mob/living/A, mob/living/D) + return MARTIAL_ATTACK_INVALID -/datum/martial_art/proc/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D) - return 0 +/datum/martial_art/proc/harm_act(mob/living/A, mob/living/D) + return MARTIAL_ATTACK_INVALID -/datum/martial_art/proc/can_use(mob/living/carbon/human/H) +/datum/martial_art/proc/grab_act(mob/living/A, mob/living/D) + return MARTIAL_ATTACK_INVALID + +/datum/martial_art/proc/can_use(mob/living/L) return TRUE -/datum/martial_art/proc/add_to_streak(element,mob/living/carbon/human/D) +/datum/martial_art/proc/add_to_streak(element, mob/living/D) if(D != current_target) - current_target = D - streak = "" - restraining = 0 + reset_streak(D) streak = streak+element if(length(streak) > max_streak_length) streak = copytext(streak, 1 + length(streak[1])) - return - -/datum/martial_art/proc/basic_hit(mob/living/carbon/human/A,mob/living/carbon/human/D) - - var/damage = A.dna.species.punchdamage - - var/atk_verb = A.dna.species.attack_verb - if(D.body_position == LYING_DOWN) - atk_verb = "kick" - - switch(atk_verb) - if("kick") - A.do_attack_animation(D, ATTACK_EFFECT_KICK) - if("slash") - A.do_attack_animation(D, ATTACK_EFFECT_CLAW) - if("smash") - A.do_attack_animation(D, ATTACK_EFFECT_SMASH) - else - A.do_attack_animation(D, ATTACK_EFFECT_PUNCH) - - if(!damage) - playsound(D.loc, A.dna.species.miss_sound, 25, 1, -1) - D.visible_message(span_warning("[A]'s [atk_verb] misses [D]!"), \ - span_danger("You avoid [A]'s [atk_verb]!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, A) - to_chat(A, span_warning("Your [atk_verb] misses [D]!")) - log_combat(A, D, "attempted to [atk_verb]", important = FALSE) - return 0 - - var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.get_combat_bodyzone(D))) - var/armor_block = D.run_armor_check(affecting, MELEE) - - playsound(D.loc, A.dna.species.attack_sound, 25, 1, -1) - D.visible_message(span_danger("[A] [atk_verb]ed [D]!"), \ - span_userdanger("You're [atk_verb]ed by [A]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, A) - to_chat(A, span_danger("You [atk_verb]ed [D]!")) - - D.apply_damage(damage, A.dna.species.attack_type, affecting, armor_block) - - log_combat(A, D, "punched", name) - - if(D.body_position == LYING_DOWN) - D.force_say(A) - return 1 - -/datum/martial_art/proc/teach(mob/living/carbon/human/H,make_temporary=0) - if(!istype(H) || !H.mind) + if (display_combos) + var/mob/living/holder_living = holder.resolve() + timerid = addtimer(CALLBACK(src, PROC_REF(reset_streak), null, FALSE), combo_timer, TIMER_UNIQUE | TIMER_STOPPABLE) + holder_living?.hud_used?.combo_display.update_icon_state(streak, combo_timer - 2 SECONDS) + +/datum/martial_art/proc/reset_streak(mob/living/new_target, update_icon = TRUE) + if(timerid) + deltimer(timerid) + current_target = new_target + streak = "" + if(update_icon) + var/mob/living/holder_living = holder?.resolve() + holder_living?.hud_used?.combo_display.update_icon_state(streak) + +/datum/martial_art/proc/teach(mob/living/holder_living, make_temporary=FALSE) + if(!istype(holder_living) || !holder_living.mind) return FALSE - if(H.mind.martial_art) + if(holder_living.mind.martial_art) if(make_temporary) - if(!H.mind.martial_art.allow_temp_override) + if(!holder_living.mind.martial_art.allow_temp_override) return FALSE - store(H.mind.martial_art,H) + store(holder_living.mind.martial_art, holder_living) else - H.mind.martial_art.on_remove(H) + holder_living.mind.martial_art.on_remove(holder_living) else if(make_temporary) - base = H.mind.default_martial_art + base = holder_living.mind.default_martial_art if(help_verb) - H.add_verb(help_verb) - H.mind.martial_art = src + holder_living.add_verb(help_verb) + holder_living.mind.martial_art = src + holder = WEAKREF(holder_living) return TRUE -/datum/martial_art/proc/store(datum/martial_art/M,mob/living/carbon/human/H) - M.on_remove(H) - if(M.base) //Checks if M is temporary, if so it will not be stored. - base = M.base - else //Otherwise, M is stored. - base = M +/datum/martial_art/proc/store(datum/martial_art/old, mob/living/holder_living) + old.on_remove(holder_living) + if (old.base) //Checks if old is temporary, if so it will not be stored. + base = old.base + else //Otherwise, old is stored. + base = old -/datum/martial_art/proc/remove(mob/living/carbon/human/H) - if(!istype(H) || !H.mind || H.mind.martial_art != src) +/datum/martial_art/proc/remove(mob/living/holder_living) + if(!istype(holder_living) || !holder_living.mind || holder_living.mind.martial_art != src) return - on_remove(H) + on_remove(holder_living) if(base) - base.teach(H) + base.teach(holder_living) else - var/datum/martial_art/X = H.mind.default_martial_art - X.teach(H) + var/datum/martial_art/default = holder_living.mind.default_martial_art + default.teach(holder_living) + holder = null -/datum/martial_art/proc/on_remove(mob/living/carbon/human/H) +/datum/martial_art/proc/on_remove(mob/living/holder_living) if(help_verb) - H.remove_verb(help_verb) + holder_living.remove_verb(help_verb) return + +///Gets called when a projectile hits the owner. Returning anything other than BULLET_ACT_HIT will stop the projectile from hitting the mob. +/datum/martial_art/proc/on_projectile_hit(mob/living/A, obj/projectile/P, def_zone) + return BULLET_ACT_HIT diff --git a/code/datums/martial/boxing.dm b/code/datums/martial/boxing.dm index efa07687749ba..ccedec1bc37fd 100644 --- a/code/datums/martial/boxing.dm +++ b/code/datums/martial/boxing.dm @@ -1,24 +1,28 @@ /datum/martial_art/boxing name = "Boxing" id = MARTIALART_BOXING + pacifist_style = TRUE -/datum/martial_art/boxing/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/boxing/disarm_act(mob/living/A, mob/living/D) to_chat(A, span_warning("Can't disarm while boxing!")) - return 1 + return TRUE -/datum/martial_art/boxing/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/boxing/grab_act(mob/living/A, mob/living/D) to_chat(A, span_warning("Can't grab while boxing!")) - return 1 + return TRUE -/datum/martial_art/boxing/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/boxing/harm_act(mob/living/A, mob/living/D) + + var/mob/living/carbon/human/attacker_human = A + var/datum/species/species = attacker_human.dna.species A.do_attack_animation(D, ATTACK_EFFECT_PUNCH) var/atk_verb = pick("left hook","right hook","straight punch") - var/damage = 6 + A.dna.species.punchdamage + var/damage = 6 +species.punchdamage if(!damage) - playsound(D.loc, A.dna.species.miss_sound, 25, 1, -1) + playsound(D.loc, species.miss_sound, 25, TRUE, -1) D.visible_message(span_warning("[A]'s [atk_verb] misses [D]!"), \ span_userdanger("[A]'s [atk_verb] misses you!"), null, COMBAT_MESSAGE_RANGE) log_combat(A, D, "attempted to hit", atk_verb, important = FALSE) @@ -28,7 +32,7 @@ var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.get_combat_bodyzone(D))) var/armor_block = D.run_armor_check(affecting, MELEE) - playsound(D.loc, A.dna.species.attack_sound, 25, 1, -1) + playsound(D.loc, species.attack_sound, 25, TRUE, -1) D.visible_message(span_danger("[A] [atk_verb]ed [D]!"), \ span_userdanger("[A] [atk_verb]ed you!"), null, COMBAT_MESSAGE_RANGE) @@ -43,29 +47,31 @@ to_chat(A, span_danger("You knock [D] out with a haymaker!")) D.apply_effect(200,EFFECT_KNOCKDOWN,armor_block) D.SetSleeping(100) - D.force_say(A) log_combat(A, D, "knocked out (boxing) ", name) - else if(D.body_position == LYING_DOWN) - D.force_say(A) return TRUE +/datum/martial_art/boxing/can_use(mob/living/owner) + if (!ishuman(owner)) + return FALSE + return ..() + /obj/item/clothing/gloves/boxing var/datum/martial_art/boxing/style = new /obj/item/clothing/gloves/boxing/equipped(mob/user, slot) ..() + // boxing requires human if(!ishuman(user)) return if(slot == ITEM_SLOT_GLOVES) - var/mob/living/carbon/human/H = user - style.teach(H,1) + var/mob/living/student = user + style.teach(student, 1) return /obj/item/clothing/gloves/boxing/dropped(mob/user) ..() if(!ishuman(user)) return - var/mob/living/carbon/human/H = user - if(H.get_item_by_slot(ITEM_SLOT_GLOVES) == src) - style.remove(H) + var/mob/living/owner = user + style.remove(owner) return diff --git a/code/datums/martial/cqc.dm b/code/datums/martial/cqc.dm index bc776b57aef2e..2bfbbff2352b9 100644 --- a/code/datums/martial/cqc.dm +++ b/code/datums/martial/cqc.dm @@ -7,49 +7,39 @@ /datum/martial_art/cqc name = "CQC" id = MARTIALART_CQC - help_verb = /mob/living/carbon/human/proc/CQC_help + help_verb = /mob/living/proc/CQC_help block_chance = 75 - var/just_a_cook = FALSE smashes_tables = TRUE + display_combos = TRUE + var/old_grab_state = null + var/mob/restraining_mob -/datum/martial_art/cqc/under_siege - name = "Close Quarters Cooking" - just_a_cook = TRUE - -/datum/martial_art/cqc/proc/drop_restraining() - restraining = FALSE - -/datum/martial_art/cqc/can_use(mob/living/carbon/human/H) - var/area/A = get_area(H) - if(just_a_cook && !(istype(A, /area/crew_quarters/kitchen))) - return FALSE +/datum/martial_art/cqc/reset_streak(mob/living/new_target) + if(new_target && new_target != restraining_mob) + restraining_mob = null return ..() -/datum/martial_art/cqc/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/cqc/proc/check_streak(mob/living/A, mob/living/D) if(!can_use(A)) return FALSE if(findtext(streak,SLAM_COMBO)) - streak = "" - Slam(A,D) - return TRUE + reset_streak() + return Slam(A,D) if(findtext(streak,KICK_COMBO)) - streak = "" - Kick(A,D) - return TRUE + reset_streak() + return Kick(A,D) if(findtext(streak,RESTRAIN_COMBO)) - streak = "" - Restrain(A,D) - return TRUE + reset_streak() + return Restrain(A,D) if(findtext(streak,PRESSURE_COMBO)) - streak = "" - Pressure(A,D) - return TRUE + reset_streak() + return Pressure(A,D) if(findtext(streak,CONSECUTIVE_COMBO)) - streak = "" - Consecutive(A,D) + reset_streak() + return Consecutive(A,D) return FALSE -/datum/martial_art/cqc/proc/Slam(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/cqc/proc/Slam(mob/living/A, mob/living/D) var/def_check = D.getarmor(BODY_ZONE_CHEST, MELEE) if(!can_use(A)) return FALSE @@ -59,11 +49,11 @@ to_chat(A, span_danger("You slam [D] into the ground!")) playsound(get_turf(A), 'sound/weapons/slam.ogg', 50, 1, -1) D.apply_damage(10, BRUTE, blocked = def_check) - D.Paralyze(120) + D.Paralyze(12 SECONDS) log_combat(A, D, "slammed (CQC)", name) - return TRUE + return TRUE -/datum/martial_art/cqc/proc/Kick(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/cqc/proc/Kick(mob/living/A, mob/living/D) var/def_check = D.getarmor(BODY_ZONE_CHEST, MELEE) if(!can_use(A)) return FALSE @@ -74,8 +64,9 @@ playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1) var/atom/throw_target = get_edge_target_turf(D, A.dir) D.throw_at(throw_target, 1, 14, A) - D.apply_damage(10, A.dna.species.attack_type, blocked = def_check) + D.apply_damage(10, A.get_attack_type(), blocked = def_check) log_combat(A, D, "kicked (CQC)", name) + . = TRUE if(D.IsParalyzed() && !D.stat) log_combat(A, D, "knocked out (Head kick)(CQC)", name) D.visible_message(span_danger("[A] kicks [D]'s head, knocking [D.p_them()] out!"), \ @@ -84,9 +75,9 @@ playsound(get_turf(A), 'sound/weapons/genhit1.ogg', 50, 1, -1) D.SetSleeping(10 SECONDS) D.adjustOrganLoss(ORGAN_SLOT_BRAIN, 15, 150) - return TRUE + . = TRUE -/datum/martial_art/cqc/proc/Pressure(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/cqc/proc/Pressure(mob/living/A, mob/living/D) if(!can_use(A)) return FALSE log_combat(A, D, "pressured (CQC)", name) @@ -97,8 +88,8 @@ playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1) return TRUE -/datum/martial_art/cqc/proc/Restrain(mob/living/carbon/human/A, mob/living/carbon/human/D) - if(restraining) +/datum/martial_art/cqc/proc/Restrain(mob/living/A, mob/living/D) + if(restraining_mob) return if(!can_use(A)) return FALSE @@ -108,12 +99,12 @@ span_userdanger("You're locked into a restraining position by [A]!"), span_hear("You hear shuffling and a muffled groan!"), null, A) to_chat(A, span_danger("You lock [D] into a restraining position!")) D.adjustStaminaLoss(20) - D.Stun(100) - restraining = TRUE - addtimer(CALLBACK(src, PROC_REF(drop_restraining)), 50, TIMER_UNIQUE) - return TRUE + D.Stun(10 SECONDS) + restraining_mob = D + addtimer(VARSET_CALLBACK(src, restraining_mob, null), 50, TIMER_UNIQUE) + return TRUE -/datum/martial_art/cqc/proc/Consecutive(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/cqc/proc/Consecutive(mob/living/A, mob/living/D) var/def_check = D.getarmor(BODY_ZONE_CHEST, MELEE) if(!can_use(A)) return FALSE @@ -127,31 +118,28 @@ if(I && D.temporarilyRemoveItemFromInventory(I)) A.put_in_hands(I) D.adjustStaminaLoss(50) - D.apply_damage(25, A.dna.species.attack_type, blocked = def_check) - return TRUE + D.apply_damage(25, A.get_attack_type(), blocked = def_check) + return TRUE -/datum/martial_art/cqc/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D) - if(!can_use(A)) - return FALSE - if(A==D) - return FALSE //prevents grabbing yourself - if(A.a_intent == INTENT_GRAB) +/datum/martial_art/cqc/grab_act(mob/living/A, mob/living/D) + if(A.a_intent == INTENT_GRAB && A!=D && can_use(A)) // A!=D prevents grabbing yourself add_to_streak("G",D) - if(check_streak(A,D)) //doing combos is prioritized over upgrading grabs + if(check_streak(A,D)) //if a combo is made no grab upgrade is done return TRUE + old_grab_state = A.grab_state D.grabbedby(A, 1) - if(A.grab_state == GRAB_PASSIVE) + if(old_grab_state == GRAB_PASSIVE) D.drop_all_held_items() A.setGrabState(GRAB_AGGRESSIVE) //Instant aggressive grab if on grab intent log_combat(A, D, "grabbed", name, addition="aggressively") D.visible_message(span_warning("[A] violently grabs [D]!"), \ span_userdanger("You're grabbed violently by [A]!"), span_hear("You hear sounds of aggressive fondling!"), COMBAT_MESSAGE_RANGE, A) to_chat(A, span_danger("You violently grab [D]!")) + return TRUE else - D.grabbedby(A, 1) - return TRUE + return FALSE -/datum/martial_art/cqc/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/cqc/harm_act(mob/living/A, mob/living/D) var/def_check = D.getarmor(BODY_ZONE_CHEST, MELEE) if(!can_use(A)) return FALSE @@ -180,11 +168,11 @@ to_chat(A, span_danger("You leg sweep [D]!")) playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, 1, -1) D.apply_damage(10, BRUTE, blocked = def_check) - D.Paralyze(60) + D.Paralyze(6 SECONDS) log_combat(A, D, "sweeped (CQC)", name) return TRUE -/datum/martial_art/cqc/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/cqc/disarm_act(mob/living/A, mob/living/D) var/def_check = D.getarmor(BODY_ZONE_CHEST, MELEE) if(!can_use(A)) return FALSE @@ -192,8 +180,19 @@ var/obj/item/I = null if(check_streak(A,D)) return TRUE + log_combat(A, D, "disarmed (CQC)", "[I ? " grabbing \the [I]" : ""]") + if(restraining_mob && A.pulling == restraining_mob) + log_combat(A, D, "knocked out (Chokehold)(CQC)", name) + D.visible_message("[A] puts [D] into a chokehold!", \ + "You're put into a chokehold by [A]!", "You hear shuffling and a muffled groan!", null, A) + to_chat(A, "You put [D] into a chokehold!") + D.SetSleeping(40 SECONDS) + restraining_mob = null + if(A.grab_state < GRAB_NECK && !HAS_TRAIT(A, TRAIT_PACIFISM)) + A.setGrabState(GRAB_NECK) + return TRUE if(prob(65)) - if(!D.stat || !D.IsParalyzed() || !restraining) + if(!D.stat || !D.IsParalyzed() || !restraining_mob) I = D.get_active_held_item() D.visible_message(span_danger("[A] strikes [D]'s jaw with their hand!"), \ span_userdanger("Your jaw is struck by [A], you feel disoriented!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, A) @@ -202,28 +201,16 @@ if(I && D.temporarilyRemoveItemFromInventory(I)) A.put_in_hands(I) D.Jitter(2) - D.apply_damage(5, A.dna.species.attack_type, blocked = def_check) + D.apply_damage(5, A.get_attack_type(), blocked = def_check) else - D.visible_message(span_danger("[A] fails to disarm [D]!"), \ - span_userdanger("You're nearly disarmed by [A]!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, A) - to_chat(A, span_warning("You fail to disarm [D]!")) - playsound(D, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - log_combat(A, D, "disarmed (CQC)[I ? " grabbing \the [I]" : ""]", name) - if(restraining && A.pulling == D) - log_combat(A, D, "knocked out (Chokehold)(CQC)", name) - D.visible_message(span_danger("[A] puts [D] into a chokehold!"), \ - span_userdanger("You're put into a chokehold by [A]!"), span_hear("You hear shuffling and a muffled groan!"), null, A) - to_chat(A, span_danger("You put [D] into a chokehold!")) - D.SetSleeping(15 SECONDS) - restraining = FALSE - if(A.grab_state < GRAB_NECK) - A.setGrabState(GRAB_NECK) - else - restraining = FALSE - return FALSE - return TRUE + D.visible_message("[A] fails to disarm [D]!", \ + "You're nearly disarmed by [A]!", "You hear a swoosh!", COMBAT_MESSAGE_RANGE, A) + to_chat(A, "You fail to disarm [D]!") + playsound(D, 'sound/weapons/punchmiss.ogg', 25, TRUE, -1) + return FALSE + -/mob/living/carbon/human/proc/CQC_help() +/mob/living/proc/CQC_help() set name = "Remember The Basics" set desc = "You try to remember some of the basics of CQC." set category = "CQC" @@ -237,6 +224,17 @@ to_chat(usr, "In addition, by having your throw mode on when being attacked, you enter an active defense mode where you have a chance to block and sometimes even counter attacks done to you.") +///Subtype of CQC. Only used for the chef. +/datum/martial_art/cqc/under_siege + name = "Close Quarters Cooking" + var/list/valid_areas = list(/area/crew_quarters/kitchen) + +///Prevents use if the cook is not in the kitchen. +/datum/martial_art/cqc/under_siege/can_use(mob/living/owner) //this is used to make chef CQC only work in kitchen + if(!is_type_in_list(get_area(owner), valid_areas)) + return FALSE + return ..() + #undef SLAM_COMBO #undef KICK_COMBO #undef RESTRAIN_COMBO diff --git a/code/datums/martial/karate.dm b/code/datums/martial/karate.dm index 0094483b8549e..0339a7a782c75 100644 --- a/code/datums/martial/karate.dm +++ b/code/datums/martial/karate.dm @@ -11,19 +11,19 @@ /datum/martial_art/karate/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D) if(findtext(streak,JUMPING_KNEE_COMBO)) - streak = "" + reset_streak() jumpingKnee(A,D) return 1 if(findtext(streak,KARATE_CHOP_COMBO)) - streak = "" + reset_streak() karateChop(A,D) return 1 if(findtext(streak,FLOOR_KICK_COMBO)) - streak = "" + reset_streak() floorKick(A,D) return 1 if(findtext(streak,CALF_KICK_COMBO)) - streak = "" + reset_streak() calfKick(A,D) return 1 return 0 @@ -42,7 +42,7 @@ D.apply_damage(20, A.dna.species.attack_type, BODY_ZONE_HEAD, def_check) D.apply_damage(10, STAMINA, BODY_ZONE_HEAD, def_check) return 1 - return basic_hit(A,D) + return FALSE //Calf Kick - paralyse one leg with stamina damage /datum/martial_art/karate/proc/calfKick(mob/living/carbon/human/A, mob/living/carbon/human/D) @@ -57,7 +57,7 @@ A.do_attack_animation(D, ATTACK_EFFECT_KICK) D.apply_damage(50, STAMINA, pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG), def_check) return 1 - return basic_hit(A,D) + return FALSE //Jumping Knee - brief knockdown and decent stamina damage /datum/martial_art/karate/proc/jumpingKnee(mob/living/carbon/human/A, mob/living/carbon/human/D) @@ -74,7 +74,7 @@ D.apply_damage(30, STAMINA, BODY_ZONE_CHEST, def_check) D.Knockdown(10) return 1 - return basic_hit(A,D) + return FALSE // Karate Chop - short confusion and blurred eyes /datum/martial_art/karate/proc/karateChop(mob/living/carbon/human/A, mob/living/carbon/human/D) @@ -90,7 +90,7 @@ D.confused += 2 D.Jitter(20) return 1 - return basic_hit(A,D) + return FALSE /datum/martial_art/karate/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) add_to_streak("H",D) diff --git a/code/datums/martial/krav_maga.dm b/code/datums/martial/krav_maga.dm index d262d438776bd..c75c2345d0f46 100644 --- a/code/datums/martial/krav_maga.dm +++ b/code/datums/martial/krav_maga.dm @@ -14,13 +14,12 @@ if(owner.incapacitated()) to_chat(owner, span_warning("You can't use [name] while you're incapacitated.")) return - var/mob/living/carbon/human/H = owner - if (H.mind.martial_art.streak == "neck_chop") + if (owner.mind.martial_art.streak == "neck_chop") owner.visible_message(span_danger("[owner] assumes a neutral stance."), "Your next attack is cleared.") - H.mind.martial_art.streak = "" + owner.mind.martial_art.streak = "" else owner.visible_message(span_danger("[owner] assumes the Neck Chop stance!"), "Your next attack will be a Neck Chop.") - H.mind.martial_art.streak = "neck_chop" + owner.mind.martial_art.streak = "neck_chop" /datum/action/leg_sweep name = "Leg Sweep - Trips the victim, knocking them down for a brief moment." @@ -31,13 +30,12 @@ if(owner.incapacitated()) to_chat(owner, span_warning("You can't use [name] while you're incapacitated.")) return - var/mob/living/carbon/human/H = owner - if (H.mind.martial_art.streak == "leg_sweep") + if (owner.mind.martial_art.streak == "leg_sweep") owner.visible_message(span_danger("[owner] assumes a neutral stance."), "Your next attack is cleared.") - H.mind.martial_art.streak = "" + owner.mind.martial_art.streak = "" else owner.visible_message(span_danger("[owner] assumes the Leg Sweep stance!"), "Your next attack will be a Leg Sweep.") - H.mind.martial_art.streak = "leg_sweep" + owner.mind.martial_art.streak = "leg_sweep" /datum/action/lung_punch//referred to internally as 'quick choke' name = "Lung Punch - Delivers a strong punch just above the victim's abdomen, constraining the lungs. The victim will be unable to breathe for a short time." @@ -48,29 +46,28 @@ if(owner.incapacitated()) to_chat(owner, span_warning("You can't use [name] while you're incapacitated.")) return - var/mob/living/carbon/human/H = owner - if (H.mind.martial_art.streak == "quick_choke") + if (owner.mind.martial_art.streak == "quick_choke") owner.visible_message(span_danger("[owner] assumes a neutral stance."), "Your next attack is cleared.") - H.mind.martial_art.streak = "" + owner.mind.martial_art.streak = "" else owner.visible_message(span_danger("[owner] assumes the Lung Punch stance!"), "Your next attack will be a Lung Punch.") - H.mind.martial_art.streak = "quick_choke"//internal name for lung punch + owner.mind.martial_art.streak = "quick_choke"//internal name for lung punch -/datum/martial_art/krav_maga/teach(mob/living/carbon/human/H,make_temporary=0) +/datum/martial_art/krav_maga/teach(mob/living/owner, make_temporary=FALSE) if(..()) - to_chat(H, span_userdanger("You know the arts of [name]!")) - to_chat(H, span_danger("Place your cursor over a move at the top of the screen to see what it does.")) - neckchop.Grant(H) - legsweep.Grant(H) - lungpunch.Grant(H) - -/datum/martial_art/krav_maga/on_remove(mob/living/carbon/human/H) - to_chat(H, span_userdanger("You suddenly forget the arts of [name]...")) - neckchop.Remove(H) - legsweep.Remove(H) - lungpunch.Remove(H) - -/datum/martial_art/krav_maga/proc/check_streak(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D) + to_chat(owner, span_userdanger("You know the arts of [name]!")) + to_chat(owner, span_danger("Place your cursor over a move at the top of the screen to see what it does.")) + neckchop.Grant(owner) + legsweep.Grant(owner) + lungpunch.Grant(owner) + +/datum/martial_art/krav_maga/on_remove(mob/living/owner) + to_chat(owner, span_userdanger("You suddenly forget the arts of [name]...")) + neckchop.Remove(owner) + legsweep.Remove(owner) + lungpunch.Remove(owner) + +/datum/martial_art/krav_maga/proc/check_streak(mob/living/A, mob/living/D) switch(streak) if("neck_chop") streak = "" @@ -86,7 +83,7 @@ return 1 return 0 -/datum/martial_art/krav_maga/proc/leg_sweep(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D) +/datum/martial_art/krav_maga/proc/leg_sweep(mob/living/A, mob/living/D) if(D.stat || D.IsParalyzed()) return 0 var/obj/item/bodypart/affecting = D.get_bodypart(BODY_ZONE_CHEST) @@ -98,9 +95,9 @@ D.apply_damage(rand(20,30), STAMINA, affecting, armor_block) D.Knockdown(60) log_combat(A, D, "leg sweeped", name) - return 1 + return TRUE -/datum/martial_art/krav_maga/proc/quick_choke(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)//is actually lung punch +/datum/martial_art/krav_maga/proc/quick_choke(mob/living/A, mob/living/D)//is actually lung punch D.visible_message(span_warning("[A] pounds [D] on the chest!"), \ span_userdanger("Your chest is slammed by [A]! You can't breathe!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, A) to_chat(A, span_danger("You pound [D] on the chest!")) @@ -109,28 +106,30 @@ D.losebreath = clamp(D.losebreath + 5, 0, 10) D.adjustOxyLoss(10) log_combat(A, D, "quickchoked", name) - return 1 + return TRUE -/datum/martial_art/krav_maga/proc/neck_chop(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D) +/datum/martial_art/krav_maga/proc/neck_chop(mob/living/A, mob/living/D) D.visible_message(span_warning("[A] karate chops [D]'s neck!"), \ span_userdanger("Your neck is karate chopped by [A], rendering you unable to speak!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), COMBAT_MESSAGE_RANGE, A) to_chat(A, span_danger("You karate chop [D]'s neck, rendering [D.p_them()] unable to speak!")) playsound(get_turf(A), 'sound/effects/hit_punch.ogg', 50, 1, -1) - D.apply_damage(5, A.dna.species.attack_type) - if(D.silent <= 10) - D.silent = clamp(D.silent + 10, 0, 10) + D.apply_damage(5, A.get_attack_type()) + if (iscarbon(D)) + var/mob/living/carbon/carbon_defender = D + if(carbon_defender.silent <= 10) + carbon_defender.silent = clamp(carbon_defender.silent + 10, 0, 10) log_combat(A, D, "neck chopped", name) - return 1 + return TRUE -/datum/martial_art/krav_maga/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D) +/datum/martial_art/krav_maga/grab_act(mob/living/A, mob/living/D) if(check_streak(A,D)) - return 1 + return TRUE log_combat(A, D, "grabbed (Krav Maga)", name) ..() -/datum/martial_art/krav_maga/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D) +/datum/martial_art/krav_maga/harm_act(mob/living/A, mob/living/D) if(check_streak(A,D)) - return 1 + return TRUE var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.get_combat_bodyzone(D))) var/armor_block = D.run_armor_check(affecting, MELEE) var/picked_hit_type = pick("punch", "kick") @@ -138,7 +137,7 @@ if(D.body_position == LYING_DOWN) bonus_damage += 5 picked_hit_type = "stomp" - D.apply_damage(rand(5,10) + bonus_damage, A.dna.species.attack_type, affecting, armor_block) + D.apply_damage(rand(5,10) + bonus_damage, A.get_attack_type(), affecting, armor_block) if(picked_hit_type == "kick" || picked_hit_type == "stomp") A.do_attack_animation(D, ATTACK_EFFECT_KICK) playsound(get_turf(D), 'sound/effects/hit_kick.ogg', 50, 1, -1) @@ -151,7 +150,7 @@ log_combat(A, D, "[picked_hit_type] with [name]", name) return 1 -/datum/martial_art/krav_maga/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D) +/datum/martial_art/krav_maga/disarm_act(mob/living/A, mob/living/D) if(check_streak(A,D)) return 1 var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.get_combat_bodyzone(D))) @@ -194,19 +193,13 @@ /obj/item/clothing/gloves/krav_maga/equipped(mob/user, slot) . = ..() - if(!ishuman(user)) - return if(slot == ITEM_SLOT_GLOVES) - var/mob/living/carbon/human/H = user - style.teach(H,1) + style.teach(user, TRUE) /obj/item/clothing/gloves/krav_maga/dropped(mob/user) . = ..() - if(!ishuman(user)) - return - var/mob/living/carbon/human/H = user - if(H.get_item_by_slot(ITEM_SLOT_GLOVES) == src) - style.remove(H) + if(user.get_item_by_slot(ITEM_SLOT_GLOVES) == src) + style.remove(user) /obj/item/clothing/gloves/krav_maga/combatglovesplus name = "combat gloves plus" diff --git a/code/datums/martial/mushpunch.dm b/code/datums/martial/mushpunch.dm index 1f9f0d32d5b72..3cda46667dc15 100644 --- a/code/datums/martial/mushpunch.dm +++ b/code/datums/martial/mushpunch.dm @@ -2,7 +2,7 @@ name = "Mushroom Punch" id = MARTIALART_MUSHPUNCH -/datum/martial_art/mushpunch/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/mushpunch/harm_act(mob/living/A, mob/living/D) var/atk_verb to_chat(A, span_spider("You begin to wind up an attack...")) if(!do_after(A, 25, target = D)) @@ -13,7 +13,7 @@ D.visible_message(span_danger("[A] [atk_verb]ed [D] with such inhuman strength that it sends [D.p_them()] flying backwards!"), \ span_userdanger("You're [atk_verb]ed by [A] with such inhuman strength that it sends you flying backwards!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, A) to_chat(A, span_danger("You [atk_verb] [D] with such inhuman strength that it sends [D.p_them()] flying backwards!")) - D.apply_damage(rand(15,30), A.dna.species.attack_type) + D.apply_damage(rand(15,30), A.get_attack_type()) playsound(D, 'sound/effects/meteorimpact.ogg', 25, 1, -1) var/throwtarget = get_edge_target_turf(A, get_dir(A, get_step_away(D, A))) D.throw_at(throwtarget, 4, 2, A)//So stuff gets tossed around at the same time. @@ -28,7 +28,7 @@ icon = 'icons/obj/hydroponics/seeds.dmi' icon_state = "mycelium-angel" -/obj/item/mushpunch/attack_self(mob/living/carbon/human/user) +/obj/item/mushpunch/attack_self(mob/living/user) if(!istype(user) || !user) return var/message = span_spider("You devour [src], and a confluence of skill and power from the mushroom enhances your punches! You do need a short moment to charge these powerful punches.") diff --git a/code/datums/martial/plasma_fist.dm b/code/datums/martial/plasma_fist.dm index aeabb10ae5777..f5f7a8f190de3 100644 --- a/code/datums/martial/plasma_fist.dm +++ b/code/datums/martial/plasma_fist.dm @@ -5,23 +5,34 @@ /datum/martial_art/plasma_fist name = "Plasma Fist" id = MARTIALART_PLASMAFIST - help_verb = /mob/living/carbon/human/proc/plasma_fist_help + help_verb = /mob/living/proc/plasma_fist_help + var/nobomb = FALSE + var/plasma_power = 1 //starts at a 1, 2, 4 explosion. + var/plasma_increment = 1 //how much explosion power gets added per kill (1 = 1, 2, 4. 2 = 2, 4, 8 and so on) + var/plasma_cap = 12 //max size explosion level + display_combos = TRUE - -/datum/martial_art/plasma_fist/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/plasma_fist/proc/check_streak(mob/living/A, mob/living/D) if(findtext(streak,TORNADO_COMBO)) - streak = "" + if(A == D)//helps using apotheosis + return FALSE + reset_streak() Tornado(A,D) - return 1 + return TRUE if(findtext(streak,THROWBACK_COMBO)) - streak = "" + if(A == D)//helps using apotheosis + return FALSE + reset_streak() Throwback(A,D) - return 1 + return TRUE if(findtext(streak,PLASMA_COMBO)) - streak = "" - Plasma(A,D) - return 1 - return 0 + reset_streak() + if(A == D && !nobomb) + Apotheosis(A,D) + else + Plasma(A,D) + return TRUE + return FALSE /datum/martial_art/plasma_fist/proc/TornadoAnimate(mob/living/carbon/human/A) set waitfor = FALSE @@ -32,7 +43,7 @@ playsound(A.loc, 'sound/weapons/punch1.ogg', 15, 1, -1) sleep(1) -/datum/martial_art/plasma_fist/proc/Tornado(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/plasma_fist/proc/Tornado(mob/living/A, mob/living/D) A.say("TORNADO SWEEP!", forced="plasma fist") TornadoAnimate(A) var/obj/effect/proc_holder/spell/aoe_turf/repulse/R = new(null) @@ -40,7 +51,7 @@ log_combat(A, D, "tornado sweeped(Plasma Fist)", name) return -/datum/martial_art/plasma_fist/proc/Throwback(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/plasma_fist/proc/Throwback(mob/living/A, mob/living/D) D.visible_message(span_danger("[A] hits [D] with Plasma Punch!"), \ span_userdanger("You're hit with a Plasma Punch by [A]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, A) to_chat(A, span_danger("You hit [D] with Plasma Punch!")) @@ -51,47 +62,135 @@ log_combat(A, D, "threw back (Plasma Fist)", name) return -/datum/martial_art/plasma_fist/proc/Plasma(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/plasma_fist/proc/Plasma(mob/living/A, mob/living/D) + var/hasclient = D.client ? TRUE : FALSE + A.do_attack_animation(D, ATTACK_EFFECT_PUNCH) playsound(D.loc, 'sound/weapons/punch1.ogg', 50, 1, -1) A.say("PLASMA FIST!", forced="plasma fist") D.visible_message(span_danger("[A] hits [D] with THE PLASMA FIST TECHNIQUE!"), \ span_userdanger("You're suddenly hit with THE PLASMA FIST TECHNIQUE by [A]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, A) to_chat(A, span_danger("You hit [D] with THE PLASMA FIST TECHNIQUE!")) - D.gib() log_combat(A, D, "gibbed (Plasma Fist)", name) - return + var/turf/Dturf = get_turf(D) + D.gib() + if(nobomb) + return + if(!hasclient) + to_chat(A, "Taking this plasma energy for your Apotheosis would bring dishonor to the clan!") + new /obj/effect/temp_visual/plasma_soul(Dturf)//doesn't beam to you, so it just hangs around and poofs. + return + else if(plasma_power >= plasma_cap) + to_chat(A, "You cannot power up your Apotheosis any more!") + new /obj/effect/temp_visual/plasma_soul(Dturf)//doesn't beam to you, so it just hangs around and poofs. + else + plasma_power += plasma_increment + to_chat(A, "Power increasing! Your Apotheosis is now at power level [plasma_power]!") + new /obj/effect/temp_visual/plasma_soul(Dturf, A) + var/oldcolor = A.color + A.color = "#9C00FF" + flash_color(A, flash_color = "#9C00FF", flash_time = 3 SECONDS) + animate(A, color = oldcolor, time = 3 SECONDS) + + +/datum/martial_art/plasma_fist/proc/Apotheosis(mob/living/A, mob/living/D) + A.say("APOTHEOSIS!!", forced="plasma fist") + if (ishuman(A)) + var/mob/living/carbon/human/human_attacker = A + human_attacker.set_species(/datum/species/plasmaman) + human_attacker.dna.species.species_traits += TRAIT_BOMBIMMUNE + human_attacker.unequip_everything() + human_attacker.underwear = "Nude" + human_attacker.undershirt = "Nude" + human_attacker.socks = "Nude" + human_attacker.update_body() + var/turf/boomspot = get_turf(A) + + //before ghosting to prevent issues + log_combat(A, A, "triggered final plasma explosion with size [plasma_power], [plasma_power*2], [plasma_power*4] (Plasma Fist)") + message_admins("[key_name_admin(A)] triggered final plasma explosion with size [plasma_power], [plasma_power*2], [plasma_power*4].") + + to_chat(A, "The explosion knocks your soul out of your body!") + A.ghostize(FALSE) //prevents... horrible memes just believe me -/datum/martial_art/plasma_fist/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) + A.apply_damage(rand(50,70), BRUTE) + + addtimer(CALLBACK(src, PROC_REF(Apotheosis_end), A), 6 SECONDS) + playsound(boomspot, 'sound/weapons/punch1.ogg', 50, TRUE, -1) + explosion(boomspot,plasma_power,plasma_power*2,plasma_power*4,ignorecap = TRUE) + plasma_power = 1 //just in case there is any clever way to cause it to happen again + +/datum/martial_art/plasma_fist/proc/Apotheosis_end(mob/living/dying) + var/datum/dna/dna = dying.has_dna() + if (dna?.species) + dna.species.species_traits -= TRAIT_BOMBIMMUNE + if(dying.stat == DEAD) + return + dying.death() + +/datum/martial_art/plasma_fist/harm_act(mob/living/A, mob/living/D) add_to_streak("H",D) if(check_streak(A,D)) - return 1 - basic_hit(A,D) - return 1 + return TRUE + return FALSE -/datum/martial_art/plasma_fist/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/plasma_fist/disarm_act(mob/living/A, mob/living/D) add_to_streak("D",D) if(check_streak(A,D)) - return 1 - basic_hit(A,D) - return 1 + return TRUE + if(A == D)//there is no disarming yourself, so we need to let plasma fist user know + to_chat(A, "You have added a disarm to your streak.") + return FALSE -/datum/martial_art/plasma_fist/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/plasma_fist/grab_act(mob/living/A, mob/living/D) add_to_streak("G",D) if(check_streak(A,D)) - return 1 - basic_hit(A,D) - return 1 + return TRUE + return FALSE -/mob/living/carbon/human/proc/plasma_fist_help() +/mob/living/proc/plasma_fist_help() set name = "Recall Teachings" set desc = "Remember the martial techniques of the Plasma Fist." set category = "Plasma Fist" + var/datum/martial_art/plasma_fist/martial = usr.mind.martial_art to_chat(usr, "You clench your fists and have a flashback of knowledge...") to_chat(usr, "[span_notice("Tornado Sweep")]: Harm Harm Disarm. Repulses target and everyone back.") to_chat(usr, "[span_notice("Throwback")]: Disarm Harm Disarm. Throws the target and an item at them.") to_chat(usr, "[span_notice("The Plasma Fist")]: Harm Disarm Disarm Disarm Harm. Knocks the brain out of the opponent and gibs their body.") + if(!martial.nobomb) + to_chat(usr, "Apotheosis: Use The Plasma Fist on yourself. Sends you away in a glorious explosion.") + + +/obj/effect/temp_visual/plasma_soul + name = "plasma energy" + desc = "Leftover energy brought out from The Plasma Fist." + icon = 'icons/effects/effects.dmi' + icon_state = "explosion" + duration = 3 SECONDS + var/atom/movable/beam_target + +/obj/effect/temp_visual/plasma_soul/Initialize(mapload, _beam_target) + . = ..() + beam_target = _beam_target + if(beam_target) + var/datum/beam/beam = Beam(beam_target, "plasmabeam", time= 3 SECONDS, maxdistance=INFINITY, beam_type=/obj/effect/ebeam/plasma_fist) + animate(beam.visuals, alpha = 0, time = 3 SECONDS) + animate(src, alpha = 0, transform = matrix()*0.5, time = 3 SECONDS) + +/obj/effect/temp_visual/plasma_soul/Destroy() + if(!beam_target) + visible_message("[src] fades away...") + . = ..() + +/obj/effect/ebeam/plasma_fist + name = "plasma" + mouse_opacity = MOUSE_OPACITY_ICON + desc = "Flowing energy." + +/datum/martial_art/plasma_fist/nobomb + name = "Novice Plasma Fist" + nobomb = TRUE #undef TORNADO_COMBO #undef THROWBACK_COMBO diff --git a/code/datums/martial/psychotic_brawl.dm b/code/datums/martial/psychotic_brawl.dm index ad0af9ccb9561..829917680e23e 100644 --- a/code/datums/martial/psychotic_brawl.dm +++ b/code/datums/martial/psychotic_brawl.dm @@ -2,24 +2,26 @@ name = "Psychotic Brawling" id = MARTIALART_PSYCHOBRAWL -/datum/martial_art/psychotic_brawling/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/psychotic_brawling/disarm_act(mob/living/A, mob/living/D) if(HAS_TRAIT(A, TRAIT_PACIFISM)) return FALSE return psycho_attack(A,D) -/datum/martial_art/psychotic_brawling/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/psychotic_brawling/grab_act(mob/living/A, mob/living/D) if(HAS_TRAIT(A, TRAIT_PACIFISM)) return FALSE return psycho_attack(A,D) -/datum/martial_art/psychotic_brawling/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/psychotic_brawling/harm_act(mob/living/A, mob/living/D) return psycho_attack(A,D) -/datum/martial_art/psychotic_brawling/proc/psycho_attack(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/psychotic_brawling/proc/psycho_attack(mob/living/A, mob/living/D) var/atk_verb switch(rand(1,8)) if(1) - D.help_shake_act(A) + if (iscarbon(D) && iscarbon(A)) + var/mob/living/carbon/defender = D + defender.help_shake_act(A) atk_verb = "helped" if(2) A.emote("cry") @@ -49,10 +51,12 @@ span_userdanger("You're [atk_verb]ed by [A]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, A) to_chat(A, span_danger("You [atk_verb] [D]!")) playsound(get_turf(D), 'sound/weapons/punch1.ogg', 40, 1, -1) - D.apply_damage(rand(5,10), A.dna.species.attack_type, BODY_ZONE_HEAD) - A.apply_damage(rand(5,10), A.dna.species.attack_type, BODY_ZONE_HEAD) - if(!istype(D.head,/obj/item/clothing/head/helmet/) && !istype(D.head,/obj/item/clothing/head/utility/hardhat)) - D.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5) + D.apply_damage(rand(5,10), A.get_attack_type(), BODY_ZONE_HEAD) + A.apply_damage(rand(5,10), A.get_attack_type(), BODY_ZONE_HEAD) + if (iscarbon(D)) + var/mob/living/carbon/defender = D + if(!istype(defender.head,/obj/item/clothing/head/helmet/) && !istype(defender.head,/obj/item/clothing/head/utility/hardhat)) + defender.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5) A.Stun(rand(10,45)) D.Stun(rand(5,30)) if(5,6) @@ -61,14 +65,14 @@ D.visible_message(span_danger("[A] [atk_verb]s [D] with such inhuman strength that it sends [D.p_them()] flying backwards!"), \ span_userdanger("You're [atk_verb]ed by [A] with such inhuman strength that it sends you flying backwards!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, A) to_chat(A, span_danger("You [atk_verb] [D] with such inhuman strength that it sends [D.p_them()] flying backwards!")) - D.apply_damage(rand(15,30), A.dna.species.attack_type) + D.apply_damage(rand(15,30), A.get_attack_type()) playsound(get_turf(D), 'sound/effects/meteorimpact.ogg', 25, 1, -1) var/throwtarget = get_edge_target_turf(A, get_dir(A, get_step_away(D, A))) D.throw_at(throwtarget, 4, 2, A)//So stuff gets tossed around at the same time. D.Paralyze(60) if(7,8) - basic_hit(A,D) + return FALSE //Resume default behaviour if(atk_verb) log_combat(A, D, "[atk_verb] (Psychotic Brawling)", name) - return 1 + return TRUE diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index 30699fa6ec5e5..5020ca2270fec 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -7,37 +7,36 @@ /datum/martial_art/the_sleeping_carp name = "The Sleeping Carp" id = MARTIALART_SLEEPINGCARP - deflection_chance = 100 - reroute_deflection = TRUE - no_guns = TRUE allow_temp_override = FALSE - help_verb = /mob/living/carbon/human/proc/sleeping_carp_help + help_verb = /mob/living/proc/sleeping_carp_help smashes_tables = TRUE + display_combos = TRUE + var/old_grab_state = null -/datum/martial_art/the_sleeping_carp/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/the_sleeping_carp/proc/check_streak(mob/living/A, mob/living/D) if(findtext(streak,WRIST_WRENCH_COMBO)) - streak = "" + reset_streak() wristWrench(A,D) - return 1 + return TRUE if(findtext(streak,BACK_KICK_COMBO)) - streak = "" + reset_streak() backKick(A,D) - return 1 + return TRUE if(findtext(streak,STOMACH_KNEE_COMBO)) - streak = "" + reset_streak() kneeStomach(A,D) - return 1 + return TRUE if(findtext(streak,HEAD_KICK_COMBO)) - streak = "" + reset_streak() headKick(A,D) - return 1 + return TRUE if(findtext(streak,ELBOW_DROP_COMBO)) - streak = "" + reset_streak() elbowDrop(A,D) - return 1 - return 0 + return TRUE + return FALSE -/datum/martial_art/the_sleeping_carp/proc/wristWrench(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/the_sleeping_carp/proc/wristWrench(mob/living/A, mob/living/D) if(!D.stat && !D.IsStun() && !D.IsParalyzed()) log_combat(A, D, "wrist wrenched (Sleeping Carp)", name) A.do_attack_animation(D, ATTACK_EFFECT_PUNCH) @@ -51,28 +50,26 @@ D.Stun(60) return 1 - return basic_hit(A,D) + return FALSE -/datum/martial_art/the_sleeping_carp/proc/backKick(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/the_sleeping_carp/proc/backKick(mob/living/A, mob/living/D) if(!D.stat && !D.IsParalyzed()) - if(A.dir == D.dir) - log_combat(A, D, "back-kicked (Sleeping Carp)", name) - A.do_attack_animation(D, ATTACK_EFFECT_PUNCH) - D.visible_message(span_warning("[A] kicks [D] in the back!"), \ - span_danger("You're kicked in the back by [A]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, A) - to_chat(A, span_danger("You kick [D] in the back!")) - step_to(D,get_step(D,D.dir),1) - D.Paralyze(80) - playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1) - return 1 - else + if(A.dir != D.dir) log_combat(A, D, "missed a back-kick (Sleeping Carp) on", name) - D.visible_message(span_warning("[A] tries to kick [D] in the back, but misses!"), \ - span_danger("You avoid a kick in the back by [A]!"), span_hear("You hear a swoosh!"), null, A) - to_chat(A, span_warning("Your kick to [D]'s back misses!")) - return basic_hit(A,D) + D.visible_message("[A] tries to kick [D] in the back, but misses!", \ + "[A] tries to kick you in the back, but misses!") + return TRUE + log_combat(A, D, "back-kicked (Sleeping Carp)", name) + A.do_attack_animation(D, ATTACK_EFFECT_PUNCH) + D.visible_message("[A] kicks [D] in the back!", \ + "[A] kicks you in the back, making you stumble and fall!") + step_to(D,get_step(D,D.dir),1) + D.Paralyze(80) + playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, TRUE, -1) + return TRUE + return FALSE -/datum/martial_art/the_sleeping_carp/proc/kneeStomach(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/the_sleeping_carp/proc/kneeStomach(mob/living/A, mob/living/D) if(!D.stat && !D.IsParalyzed()) log_combat(A, D, "stomach kneed (Sleeping Carp)", name) A.do_attack_animation(D, ATTACK_EFFECT_KICK) @@ -84,24 +81,24 @@ D.Stun(40) playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1) return 1 - return basic_hit(A,D) + return FALSE -/datum/martial_art/the_sleeping_carp/proc/headKick(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/the_sleeping_carp/proc/headKick(mob/living/A, mob/living/D) var/def_check = D.getarmor(BODY_ZONE_HEAD, MELEE) if(!D.stat && !D.IsParalyzed()) log_combat(A, D, "head kicked (Sleeping Carp)", name) A.do_attack_animation(D, ATTACK_EFFECT_KICK) - D.visible_message(span_warning("[A] kicks [D] in the head!"), \ - span_userdanger("Your jaw is kicked by [A]!"), span_hear("You hear a sickening sound of flesh hitting flesh!"), null, A) - to_chat(A, span_danger("You kick [D] in the jaw!")) - D.apply_damage(20, A.dna.species.attack_type, BODY_ZONE_HEAD, blocked = def_check) + D.visible_message("[A] kicks [D] in the head!", \ + "Your jaw is kicked by [A]!", "You hear a sickening sound of flesh hitting flesh!", null, A) + to_chat(A, "You kick [D] in the jaw!") + D.apply_damage(20, A.get_attack_type(), BODY_ZONE_HEAD, blocked = def_check) D.drop_all_held_items() playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1) D.Stun(80) return 1 - return basic_hit(A,D) + return FALSE -/datum/martial_art/the_sleeping_carp/proc/elbowDrop(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/the_sleeping_carp/proc/elbowDrop(mob/living/A, mob/living/D) var/def_check = D.getarmor(BODY_ZONE_CHEST, MELEE) if(D.body_position == LYING_DOWN) log_combat(A, D, "elbow dropped (Sleeping Carp)", name) @@ -111,31 +108,29 @@ to_chat(A, span_danger("You piledrive [D] with your elbow!")) if(D.stat) D.death() //FINISH HIM! - D.apply_damage(50, A.dna.species.attack_type, BODY_ZONE_CHEST, blocked = def_check) + D.apply_damage(50, A.get_attack_type(), BODY_ZONE_CHEST, blocked = def_check) playsound(get_turf(D), 'sound/weapons/punch1.ogg', 75, 1, -1) return 1 - return basic_hit(A,D) + return FALSE -/datum/martial_art/the_sleeping_carp/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D) - if(A==D) - return 0 //prevents grabbing yourself - if(A.a_intent == INTENT_GRAB) +/datum/martial_art/the_sleeping_carp/grab_act(mob/living/A, mob/living/D) + if(A.a_intent == INTENT_GRAB && A!=D) // A!=D prevents grabbing yourself add_to_streak("G",D) - if(check_streak(A,D)) //doing combos is prioritized over upgrading grabs - return 1 + if(check_streak(A,D)) //if a combo is made no grab upgrade is done + return TRUE + old_grab_state = A.grab_state D.grabbedby(A, 1) - if(A.grab_state == GRAB_PASSIVE) + if(old_grab_state == GRAB_PASSIVE) D.drop_all_held_items() A.setGrabState(GRAB_AGGRESSIVE) //Instant aggressive grab if on grab intent log_combat(A, D, "grabbed", name, addition="aggressively") - D.visible_message(span_warning("[A] violently grabs [D]!"), \ - span_userdanger("You're violently grabbed by [A]!"), span_hear("You hear aggressive shuffling!"), null, A) - to_chat(A, span_danger("You violently grab [D]!")) - else - D.grabbedby(A, 1) - return 1 + D.visible_message("[A] violently grabs [D]!", \ + "You're violently grabbed by [A]!", "You hear aggressive shuffling!", null, A) + to_chat(A, "You violently grab [D]!") + return TRUE + return FALSE -/datum/martial_art/the_sleeping_carp/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/the_sleeping_carp/harm_act(mob/living/A, mob/living/D) var/def_check = D.getarmor(BODY_ZONE_CHEST, MELEE) add_to_streak("H",D) if(check_streak(A,D)) @@ -151,13 +146,42 @@ return TRUE -/datum/martial_art/the_sleeping_carp/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/the_sleeping_carp/disarm_act(mob/living/A, mob/living/D) add_to_streak("D",D) if(check_streak(A,D)) return TRUE return ..() -/mob/living/carbon/human/proc/sleeping_carp_help() +/datum/martial_art/the_sleeping_carp/on_projectile_hit(mob/living/A, obj/projectile/P, def_zone) + . = ..() + if(A.incapacitated(FALSE, TRUE)) //NO STUN + return BULLET_ACT_HIT + if(!(A.mobility_flags & MOBILITY_USE)) //NO UNABLE TO USE + return BULLET_ACT_HIT + var/datum/dna/dna = A.has_dna() + if(dna?.check_mutation(HULK)) //NO HULK + return BULLET_ACT_HIT + if(!P.martial_arts_no_deflect) + return BULLET_ACT_HIT + if(!isturf(A.loc)) //NO MOTHERFLIPPIN MECHS! + return BULLET_ACT_HIT + A.visible_message("[A] deflects the projectile; [A.p_they()] can't be hit with ranged weapons!", "You deflect the projectile!") + playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1) + P.firer = A + P.set_angle(rand(0, 360))//SHING + return BULLET_ACT_FORCE_PIERCE + +/datum/martial_art/the_sleeping_carp/teach(mob/living/carbon/human/H, make_temporary = FALSE) + . = ..() + if(!.) + return + ADD_TRAIT(H, TRAIT_NOGUNS, SLEEPING_CARP_TRAIT) + +/datum/martial_art/the_sleeping_carp/on_remove(mob/living/carbon/human/H) + . = ..() + REMOVE_TRAIT(H, TRAIT_NOGUNS, SLEEPING_CARP_TRAIT) + +/mob/living/proc/sleeping_carp_help() set name = "Recall Teachings" set desc = "Remember the martial techniques of the Sleeping Carp clan." set category = "Sleeping Carp" diff --git a/code/datums/martial/tribal_claw.dm b/code/datums/martial/tribal_claw.dm index f6768b45cc803..b15dfb9a438ea 100644 --- a/code/datums/martial/tribal_claw.dm +++ b/code/datums/martial/tribal_claw.dm @@ -66,7 +66,7 @@ Deals 15 brute to head(reduced by armor) and causes a rapid bleeding effect simi A.do_attack_animation(D, ATTACK_EFFECT_CLAW) playsound(get_turf(D), 'sound/weapons/slash.ogg', 50, 1, -1) else - return basic_hit(A,D) + return FALSE //Tail Grab, instantly puts your target in a T3 grab and makes them unable to talk for a short time. /datum/martial_art/tribal_claw/proc/tailGrab(mob/living/carbon/human/A, mob/living/carbon/human/D) diff --git a/code/datums/martial/wrestling.dm b/code/datums/martial/wrestling.dm index 85073cb867315..078dac2aa267b 100644 --- a/code/datums/martial/wrestling.dm +++ b/code/datums/martial/wrestling.dm @@ -1,4 +1,4 @@ -/mob/living/carbon/human/proc/wrestling_help() +/mob/living/proc/wrestling_help() set name = "Recall Teachings" set desc = "Remember how to wrestle." set category = "Wrestling" @@ -17,7 +17,7 @@ var/datum/action/strike/strike = new/datum/action/strike() var/datum/action/drop/drop = new/datum/action/drop() -/datum/martial_art/wrestling/proc/check_streak(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D) +/datum/martial_art/wrestling/proc/check_streak(mob/living/A, mob/living/D) switch(streak) if("drop") streak = "" @@ -50,8 +50,7 @@ to_chat(owner, span_warning("You can't WRESTLE while you're OUT FOR THE COUNT.")) return owner.visible_message(span_danger("[owner] prepares to BODY SLAM!"), "Your next attack will be a BODY SLAM.") - var/mob/living/carbon/human/H = owner - H.mind.martial_art.streak = "slam" + owner.mind.martial_art.streak = "slam" /datum/action/throw_wrassle name = "Throw (Cinch) - Spin a cinched opponent around and throw them." @@ -62,8 +61,7 @@ to_chat(owner, span_warning("You can't WRESTLE while you're OUT FOR THE COUNT.")) return owner.visible_message(span_danger("[owner] prepares to THROW!"), "Your next attack will be a THROW.") - var/mob/living/carbon/human/H = owner - H.mind.martial_art.streak = "throw" + owner.mind.martial_art.streak = "throw" /datum/action/kick name = "Kick - A powerful kick, sends people flying away from you. Also useful for escaping from bad situations." @@ -74,8 +72,7 @@ to_chat(owner, span_warning("You can't WRESTLE while you're OUT FOR THE COUNT.")) return owner.visible_message(span_danger("[owner] prepares to KICK!"), "Your next attack will be a KICK.") - var/mob/living/carbon/human/H = owner - H.mind.martial_art.streak = "kick" + owner.mind.martial_art.streak = "kick" /datum/action/strike name = "Strike - Hit a neaby opponent with a quick attack." @@ -86,8 +83,7 @@ to_chat(owner, span_warning("You can't WRESTLE while you're OUT FOR THE COUNT.")) return owner.visible_message(span_danger("[owner] prepares to STRIKE!"), "Your next attack will be a STRIKE.") - var/mob/living/carbon/human/H = owner - H.mind.martial_art.streak = "strike" + owner.mind.martial_art.streak = "strike" /datum/action/drop name = "Drop - Smash down onto an opponent." @@ -98,34 +94,33 @@ to_chat(owner, span_warning("You can't WRESTLE while you're OUT FOR THE COUNT.")) return owner.visible_message(span_danger("[owner] prepares to LEG DROP!"), "Your next attack will be a LEG DROP.") - var/mob/living/carbon/human/H = owner - H.mind.martial_art.streak = "drop" + owner.mind.martial_art.streak = "drop" -/datum/martial_art/wrestling/teach(mob/living/carbon/human/H,make_temporary=0) +/datum/martial_art/wrestling/teach(mob/living/owner, make_temporary=FALSE) if(..()) - to_chat(H, span_userdanger("SNAP INTO A THIN TIM!")) - to_chat(H, span_danger("Place your cursor over a move at the top of the screen to see what it does.")) - drop.Grant(H) - kick.Grant(H) - slam.Grant(H) - throw_wrassle.Grant(H) - strike.Grant(H) - -/datum/martial_art/wrestling/on_remove(mob/living/carbon/human/H) - to_chat(H, span_userdanger("You no longer feel that the tower of power is too sweet to be sour...")) - drop.Remove(H) - kick.Remove(H) - slam.Remove(H) - throw_wrassle.Remove(H) - strike.Remove(H) - -/datum/martial_art/wrestling/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) + to_chat(owner, span_userdanger("SNAP INTO A THIN TIM!")) + to_chat(owner, span_danger("Place your cursor over a move at the top of the screen to see what it does.")) + drop.Grant(owner) + kick.Grant(owner) + slam.Grant(owner) + throw_wrassle.Grant(owner) + strike.Grant(owner) + +/datum/martial_art/wrestling/on_remove(mob/living/owner) + to_chat(owner, span_userdanger("You no longer feel that the tower of power is too sweet to be sour...")) + drop.Remove(owner) + kick.Remove(owner) + slam.Remove(owner) + throw_wrassle.Remove(owner) + strike.Remove(owner) + +/datum/martial_art/wrestling/harm_act(mob/living/A, mob/living/D) if(check_streak(A,D)) return 1 log_combat(A, D, "punched with wrestling", name) ..() -/datum/martial_art/wrestling/proc/throw_wrassle(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/wrestling/proc/throw_wrassle(mob/living/A, mob/living/D) if(!D) return if(!A.pulling || A.pulling != D) @@ -197,11 +192,11 @@ if (T && isturf(T)) if (!D.stat) D.emote("scream") - D.throw_at(T, 10, 4, A, TRUE, TRUE, callback = CALLBACK(D, TYPE_PROC_REF(/mob/living/carbon/human, Paralyze), 20)) + D.throw_at(T, 10, 4, A, TRUE, TRUE, callback = CALLBACK(D, TYPE_PROC_REF(/mob/living, Paralyze), 20)) log_combat(A, D, "has thrown with wrestling", name) return 0 -/datum/martial_art/wrestling/proc/FlipAnimation(mob/living/carbon/human/D) +/datum/martial_art/wrestling/proc/FlipAnimation(mob/living/D) set waitfor = FALSE if (D) animate(D, transform = matrix(180, MATRIX_ROTATE), time = 1, loop = 0) @@ -209,7 +204,7 @@ if (D) animate(D, transform = null, time = 1, loop = 0) -/datum/martial_art/wrestling/proc/slam(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/wrestling/proc/slam(mob/living/A, mob/living/D) if(!D) return if(!A.pulling || A.pulling != D) @@ -321,11 +316,11 @@ log_combat(A, D, "body-slammed", name) return 0 -/datum/martial_art/wrestling/proc/CheckStrikeTurf(mob/living/carbon/human/A, turf/T) +/datum/martial_art/wrestling/proc/CheckStrikeTurf(mob/living/A, turf/T) if (A && (T && isturf(T) && get_dist(A, T) <= 1)) A.forceMove(T) -/datum/martial_art/wrestling/proc/strike(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/wrestling/proc/strike(mob/living/A, mob/living/D) if(!D) return var/turf/T = get_turf(A) @@ -344,7 +339,7 @@ D.Unconscious(20) log_combat(A, D, "headbutted", name) -/datum/martial_art/wrestling/proc/kick(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/wrestling/proc/kick(mob/living/A, mob/living/D) if(!D) return A.emote("scream") @@ -363,7 +358,7 @@ D.throw_at(T, 3, 2) log_combat(A, D, "roundhouse-kicked", name) -/datum/martial_art/wrestling/proc/drop(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/wrestling/proc/drop(mob/living/A, mob/living/D) if(!D) return var/obj/surface = null @@ -439,13 +434,13 @@ log_combat(A, D, "leg-dropped", name) return -/datum/martial_art/wrestling/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/wrestling/disarm_act(mob/living/A, mob/living/D) if(check_streak(A,D)) return 1 log_combat(A, D, "wrestling-disarmed", name) ..() -/datum/martial_art/wrestling/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D) +/datum/martial_art/wrestling/grab_act(mob/living/A, mob/living/D) if(check_streak(A,D)) return 1 if(A.pulling == D) @@ -464,17 +459,11 @@ /obj/item/storage/belt/champion/wrestling/equipped(mob/user, slot) . = ..() - if(!ishuman(user)) - return if(slot == ITEM_SLOT_BELT) - var/mob/living/carbon/human/H = user - style.teach(H,1) + style.teach(user, TRUE) return /obj/item/storage/belt/champion/wrestling/dropped(mob/user) . = ..() - if(!ishuman(user)) - return - var/mob/living/carbon/human/H = user - if(H.get_item_by_slot(ITEM_SLOT_BELT) == src) - style.remove(H) + if(user.get_item_by_slot(ITEM_SLOT_BELT) == src) + style.remove(user) diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm index 25c3d1fd36da7..e07173b721ad4 100644 --- a/code/datums/mutations/hulk.dm +++ b/code/datums/mutations/hulk.dm @@ -25,6 +25,7 @@ return SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "hulk", /datum/mood_event/hulk) RegisterSignal(owner, COMSIG_MOB_SAY, PROC_REF(handle_speech)) + ADD_TRAIT(owner, TRAIT_CHUNKYFINGERS, TRAIT_HULK) owner.update_body_parts() /datum/mutation/hulk/on_attack_hand(atom/target, proximity) @@ -40,6 +41,7 @@ if(..()) return SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "hulk") + REMOVE_TRAIT(owner, TRAIT_CHUNKYFINGERS, TRAIT_HULK) owner.update_body_parts() UnregisterSignal(owner, COMSIG_MOB_SAY) diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index 37c0003425ea4..17f102430ffd3 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -78,17 +78,11 @@ if (!user.IsAdvancedToolUser()) to_chat(user, span_warning("You don't have the dexterity to do this!")) return - if(HAS_TRAIT(user, TRAIT_NOGUNS)) - to_chat(user, span_warning("Your fingers can't press the button!")) + if(HAS_TRAIT(user, TRAIT_CHUNKYFINGERS)) + to_chat(user, "Your fingers can't press the button!") return - if(user.has_dna()) - var/mob/living/carbon/C = user - if(C.dna.check_mutation(HULK)) - to_chat(user, span_warning("Your fingers can't press the button!")) - return - add_fingerprint(user) - + //nothing happens if the battery is drained if(recharge_locked) to_chat(user, span_notice("You point [src] at [target], but it's still charging.")) diff --git a/code/game/objects/items/granters.dm b/code/game/objects/items/granters.dm index 845fa09cc2932..18ff72fdcdf3f 100644 --- a/code/game/objects/items/granters.dm +++ b/code/game/objects/items/granters.dm @@ -439,6 +439,9 @@ name = "empty scroll" icon_state = "blankscroll" +/obj/item/book/granter/martial/plasma_fist/nobomb + martial = /datum/martial_art/plasma_fist/nobomb + // I did not include mushpunch's grant, it is not a book and the item does it just fine. //Crafting Recipe books diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 4b49d3d1d4e3a..70577fcc7912b 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -168,7 +168,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/table) /obj/structure/table/proc/tableheadsmash(mob/living/user, mob/living/pushed_mob) pushed_mob.Knockdown(30) - pushed_mob.apply_damage(40, BRUTE, BODY_ZONE_HEAD) + pushed_mob?.apply_damage(40, BRUTE, BODY_ZONE_HEAD) pushed_mob.apply_damage(60, STAMINA) take_damage(50) if(user.mind?.martial_art?.smashes_tables) diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 44344b0681a6f..9d2f7e37e8d51 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -1210,7 +1210,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/item/shared_storage/blue) to_chat(user, span_warning("[name] is too far from the source of its power!")) else power = 15 - if(user.mind.martial_art.no_guns) + if(HAS_TRAIT_FROM(user, TRAIT_NOGUNS, SLEEPING_CARP_TRAIT)) to_chat(user, span_warning("To use this weapon would bring dishonor to the clan.")) return var/turf/T = get_turf(target) diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm index ecb61a4f1db70..120123492f701 100644 --- a/code/modules/mob/living/carbon/alien/alien_defense.dm +++ b/code/modules/mob/living/carbon/alien/alien_defense.dm @@ -12,14 +12,18 @@ As such, they can either help or harm other aliens. Help works like the human help command while harm is a simple nibble. In all, this is a lot like the monkey code. /N */ -/mob/living/carbon/alien/attack_alien(mob/living/carbon/alien/M) +/mob/living/carbon/alien/attack_alien(mob/living/carbon/alien/user, list/modifiers) if(isturf(loc) && istype(loc.loc, /area/start)) - to_chat(M, "No attacking people at spawn, you jackass.") + to_chat(user, "No attacking people at spawn, you jackass.") return - switch(M.a_intent) + var/martial_result = user.apply_martial_art(src, modifiers) + if (martial_result != MARTIAL_ATTACK_INVALID) + return martial_result + + switch(user.a_intent) if("help") - if(M == src && check_self_for_injuries()) + if(user == src && check_self_for_injuries()) return set_resting(FALSE) AdjustStun(-60) @@ -28,23 +32,23 @@ In all, this is a lot like the monkey code. /N AdjustParalyzed(-60) AdjustUnconscious(-60) AdjustSleeping(-100) - visible_message(span_notice("[M.name] nuzzles [src] trying to wake [p_them()] up!")) + visible_message(span_notice("[user.name] nuzzles [src] trying to wake [p_them()] up!")) if("grab") - grabbedby(M) + grabbedby(user) else if(health > 1) - M.do_attack_animation(src, ATTACK_EFFECT_BITE) + user.do_attack_animation(src, ATTACK_EFFECT_BITE) playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) - visible_message(span_danger("[M.name] playfully bites [src]!"), \ - span_userdanger("[M.name] playfully bites you!"), null, COMBAT_MESSAGE_RANGE) - to_chat(M, span_danger("You playfully bite [src]!")) + visible_message(span_danger("[user.name] playfully bites [src]!"), \ + span_userdanger("[user.name] playfully bites you!"), null, COMBAT_MESSAGE_RANGE) + to_chat(user, span_danger("You playfully bite [src]!")) adjustBruteLoss(1) - log_combat(M, src, "attacked", M) + log_combat(user, src, "attacked", user) updatehealth() else - to_chat(M, span_warning("[name] is too injured for that.")) + to_chat(user, span_warning("[name] is too injured for that.")) /mob/living/carbon/alien/attack_larva(mob/living/carbon/alien/larva/L) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index ac113bf93469b..d411fcf648e5c 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1236,3 +1236,26 @@ CREATION_TEST_IGNORE_SELF(/mob/living/carbon) set_lying_angle(pick(90, 270)) else set_lying_angle(new_lying_angle) + + +/mob/living/carbon/vv_edit_var(var_name, var_value) + switch(var_name) + if(NAMEOF(src, disgust)) + set_disgust(var_value) + . = TRUE + if(NAMEOF(src, handcuffed)) + set_handcuffed(var_value) + . = TRUE + + if(!isnull(.)) + datum_flags |= DF_VAR_EDITED + return + + return ..() + + +/mob/living/carbon/get_attack_type() + var/datum/species/species = dna?.species + if (species) + return species.attack_type + return ..() diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 0bd8dcad70dda..ddbbdc53185ae 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -71,25 +71,12 @@ if(spec_return) return spec_return + //MARTIAL ART STUFF if(mind) - if(mind.martial_art && !incapacitated(FALSE, TRUE) && mind.martial_art.can_use(src) && mind.martial_art.deflection_chance) //Some martial arts users can deflect projectiles! - if(prob(mind.martial_art.deflection_chance)) - if((mobility_flags & MOBILITY_USE) && dna && !dna.check_mutation(HULK) && !P.martial_arts_no_deflect) //But only if they're otherwise able to use items, and hulks can't do it. Also damageless weapons are not deflected. - if(!isturf(loc)) //if we're inside something and still got hit - P.force_hit = TRUE //The thing we're in passed the bullet to us. Pass it back, and tell it to take the damage. - loc.bullet_act(P) - return BULLET_ACT_HIT - if(mind.martial_art.deflection_chance >= 100) //if they can NEVER be hit, lets clue sec in ;) - visible_message(span_danger("[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!"), span_userdanger("You deflect the projectile!")) - else - visible_message(span_danger("[src] deflects the projectile!"), span_userdanger("You deflect the projectile!")) - playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1) - if(!mind.martial_art.reroute_deflection) - return BULLET_ACT_BLOCK - else - P.firer = src - P.set_angle(rand(0, 360))//SHING - return BULLET_ACT_FORCE_PIERCE + if(mind.martial_art && mind.martial_art.can_use(src)) //Some martial arts users can deflect projectiles! + var/martial_art_result = mind.martial_art.on_projectile_hit(src, P, def_zone) + if(!(martial_art_result == BULLET_ACT_HIT)) + return martial_art_result if(!(P.original == src && P.firer == src)) //can't block or reflect when shooting yourself if(P.reflectable & REFLECT_NORMAL) @@ -232,28 +219,33 @@ var/mob/living/carbon/human/H = user H.dna.species.spec_attack_hand(H, src) -/mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/M) - if(check_shields(M, 0, "the [M.name]", UNARMED_ATTACK)) - visible_message(span_danger("[M] attempts to touch [src]!"), \ - span_danger("[M] attempts to touch you!"), span_hear("You hear a swoosh!"), null, M) - to_chat(M, span_warning("You attempt to touch [src]!")) +/mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/user, list/modifiers) + if(check_shields(user, 0, "the [user.name]", UNARMED_ATTACK)) + visible_message(span_danger("[user] attempts to touch [src]!"), \ + span_danger("[user] attempts to touch you!"), span_hear("You hear a swoosh!"), null, user) + to_chat(user, span_warning("You attempt to touch [src]!")) return 0 var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) if(!affecting) affecting = get_bodypart(BODY_ZONE_CHEST) - if(M.a_intent == INTENT_HELP) + + var/martial_result = user.apply_martial_art(src, modifiers) + if (martial_result != MARTIAL_ATTACK_INVALID) + return martial_result + + if(user.a_intent == INTENT_HELP) ..() //shaking return 0 - if(M.a_intent == INTENT_DISARM) //the fact that this fucking works is hilarious to me - dna.species.disarm(M, src) + if(user.a_intent == INTENT_DISARM) //the fact that this fucking works is hilarious to me + dna.species.disarm(user, src) return 1 - if(M.limb_destroyer) - dismembering_strike(M, affecting.body_zone) + if(user.limb_destroyer) + dismembering_strike(user, affecting.body_zone) - if(can_inject(M, 1, affecting))//Thick suits can stop monkey bites. + if(can_inject(user, 1, affecting))//Thick suits can stop monkey bites. if(..()) //successful monkey bite, this handles disease contraction. var/damage = rand(1, 3) if(stat != DEAD) @@ -336,7 +328,7 @@ apply_damage(damage, BRUTE, affecting, armor_block) /mob/living/carbon/human/ex_act(severity, target, origin) - if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src)) + if(TRAIT_BOMBIMMUNE in dna.species.species_traits) return ..() if (!severity || QDELETED(src)) diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 069ec26960884..a514bf9e75e15 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -237,17 +237,12 @@ . = ..() if(G.trigger_guard == TRIGGER_GUARD_NORMAL) - if(src.dna.check_mutation(HULK)) - to_chat(src, span_warning("Your meaty finger is much too large for the trigger guard!")) + if(HAS_TRAIT(src, TRAIT_CHUNKYFINGERS)) + to_chat(src, "Your meaty finger is much too large for the trigger guard!") return FALSE if(HAS_TRAIT(src, TRAIT_NOGUNS)) - to_chat(src, span_warning("Your fingers don't fit in the trigger guard!")) + to_chat(src, "You can't bring yourself to use a ranged weapon!") return FALSE - if(mind) - if(mind.martial_art && mind.martial_art.no_guns) //great dishonor to famiry - to_chat(src, span_warning("Use of ranged weaponry would bring dishonor to the clan.")) - return FALSE - return . /mob/living/carbon/human/proc/get_bank_account() diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index cf1b3f57e4779..4378d14f8647d 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1636,7 +1636,7 @@ GLOBAL_LIST_EMPTY(features_by_species) span_userdanger("You block [user]'s grab!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, user) to_chat(user, span_warning("Your grab at [target] was blocked!")) return FALSE - if(attacker_style && attacker_style.grab_act(user,target)) + if(attacker_style?.grab_act(user,target) == MARTIAL_ATTACK_SUCCESS) return TRUE else //Steal them shoes @@ -1658,7 +1658,7 @@ GLOBAL_LIST_EMPTY(features_by_species) return TRUE /datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) - if(HAS_TRAIT(user, TRAIT_PACIFISM)) + if(HAS_TRAIT(user, TRAIT_PACIFISM) && !attacker_style?.pacifist_style) to_chat(user, span_warning("You don't want to harm [target]!")) return FALSE if(target.check_block()) @@ -1666,7 +1666,7 @@ GLOBAL_LIST_EMPTY(features_by_species) span_userdanger("You block [user]'s attack!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, user) to_chat(user, span_warning("Your attack at [target] was blocked!")) return FALSE - if(attacker_style && attacker_style.harm_act(user,target)) + if(attacker_style?.harm_act(user,target) == MARTIAL_ATTACK_SUCCESS) return TRUE else @@ -1732,7 +1732,7 @@ GLOBAL_LIST_EMPTY(features_by_species) span_danger("You block [user]'s shove!"), span_hear("You hear a swoosh!"), COMBAT_MESSAGE_RANGE, user) to_chat(user, span_warning("Your shove at [target] was blocked!")) return FALSE - if(attacker_style && attacker_style.disarm_act(user,target)) + if(attacker_style?.disarm_act(user,target) == MARTIAL_ATTACK_SUCCESS) return TRUE if(user.resting || user.IsKnockdown()) return FALSE diff --git a/code/modules/mob/living/carbon/human/species_types/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductors.dm index 7191c9bb0aa33..7b14c81f2bf2f 100644 --- a/code/modules/mob/living/carbon/human/species_types/abductors.dm +++ b/code/modules/mob/living/carbon/human/species_types/abductors.dm @@ -3,7 +3,12 @@ id = SPECIES_ABDUCTOR sexes = FALSE species_traits = list(NOBLOOD,NOEYESPRITES,NOMOUTH) - inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NOGUNS,TRAIT_NOHUNGER,TRAIT_NOBREATH) + inherent_traits = list( + TRAIT_VIRUSIMMUNE, + TRAIT_CHUNKYFINGERS, + TRAIT_NOHUNGER, + TRAIT_NOBREATH + ) mutanttongue = /obj/item/organ/tongue/abductor changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 2a25bc7897f02..eaae301e1dd1c 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -3,7 +3,19 @@ name = "\improper Golem" id = SPECIES_GOLEM_IRON species_traits = list(NOBLOOD,MUTCOLORS,NO_UNDERWEAR,NOTRANSSTING) - inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER, TRAIT_NONECRODISEASE) + inherent_traits = list( + TRAIT_RESISTHEAT, + TRAIT_NOBREATH, + TRAIT_RESISTCOLD, + TRAIT_RESISTHIGHPRESSURE, + TRAIT_RESISTLOWPRESSURE, + TRAIT_NOFIRE, + TRAIT_CHUNKYFINGERS, + TRAIT_RADIMMUNE, + TRAIT_PIERCEIMMUNE, + TRAIT_NODISMEMBER, + TRAIT_NONECRODISEASE + ) inherent_biotypes = list(MOB_INORGANIC, MOB_HUMANOID) mutant_organs = list(/obj/item/organ/adamantine_resonator) mutanttongue = /obj/item/organ/tongue/golem @@ -110,7 +122,16 @@ fixed_mut_color = "a3d" meat = /obj/item/stack/ore/plasma //Can burn and takes damage from heat - inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER) //no RESISTHEAT, NOFIRE + inherent_traits = list( + TRAIT_NOBREATH, + TRAIT_RESISTCOLD, + TRAIT_RESISTHIGHPRESSURE, + TRAIT_RESISTLOWPRESSURE, + TRAIT_CHUNKYFINGERS, + TRAIT_RADIMMUNE, + TRAIT_PIERCEIMMUNE, + TRAIT_NODISMEMBER + ) //no RESISTHEAT, NOFIRE info_text = "As a " + span_danger("Plasma Golem") + ", you burn easily. Be careful, if you get hot enough while burning, you'll blow up!" heatmod = 0 //fine until they blow up prefix = "Plasma" @@ -215,7 +236,19 @@ armor = 30 meat = /obj/item/stack/ore/copper siemens_coeff = 1 //set as conductive, next line sets shock immunity - inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER, TRAIT_SHOCKIMMUNE) + inherent_traits = list( + TRAIT_RESISTHEAT, + TRAIT_NOBREATH, + TRAIT_RESISTCOLD, + TRAIT_RESISTHIGHPRESSURE, + TRAIT_RESISTLOWPRESSURE, + TRAIT_NOFIRE, + TRAIT_CHUNKYFINGERS, + TRAIT_RADIMMUNE, + TRAIT_PIERCEIMMUNE, + TRAIT_NODISMEMBER, + TRAIT_SHOCKIMMUNE + ) info_text = "As a " + span_danger("Copper Golem") + ", you are faster but less resistant than the average golem. You also act as a conduit for electricity, while not being affected by it." prefix = "Copper" special_names = list("Wire") @@ -320,7 +353,16 @@ fixed_mut_color = "9E704B" meat = /obj/item/stack/sheet/wood //Can burn and take damage from heat - inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER) + inherent_traits = list( + TRAIT_NOBREATH, + TRAIT_RESISTCOLD, + TRAIT_RESISTHIGHPRESSURE, + TRAIT_RESISTLOWPRESSURE, + TRAIT_CHUNKYFINGERS, + TRAIT_RADIMMUNE, + TRAIT_PIERCEIMMUNE, + TRAIT_NODISMEMBER + ) armor = 30 burnmod = 1.25 heatmod = 1.5 @@ -758,7 +800,16 @@ info_text = "As a " + span_danger("Cloth Golem") + ", you are able to reform yourself after death, provided your remains aren't burned or destroyed. You are, of course, very flammable. \ Being made of cloth, your body is magic resistant and faster than that of other golems, but weaker and less resilient." species_traits = list(NOBLOOD,NO_UNDERWEAR,NOTRANSSTING) //no mutcolors, and can burn - inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOGUNS) + inherent_traits = list( + TRAIT_RESISTCOLD, + TRAIT_NOBREATH, + TRAIT_RESISTHIGHPRESSURE, + TRAIT_RESISTLOWPRESSURE, + TRAIT_RADIMMUNE, + TRAIT_PIERCEIMMUNE, + TRAIT_NODISMEMBER, + TRAIT_CHUNKYFINGERS + ) inherent_biotypes = list(MOB_UNDEAD, MOB_HUMANOID) armor = 15 //feels no pain, but not too resistant burnmod = 2 // don't get burned @@ -1018,7 +1069,16 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/cloth_pile) special_names = list("Box") info_text = "As a " + span_danger("Cardboard Golem") + ", you aren't very strong, but you are a bit quicker and can easily create more brethren by using cardboard on yourself." species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYESPRITES,NOFLASH,NOTRANSSTING) - inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER) + inherent_traits = list( + TRAIT_NOBREATH, + TRAIT_RESISTCOLD, + TRAIT_RESISTHIGHPRESSURE, + TRAIT_RESISTLOWPRESSURE, + TRAIT_CHUNKYFINGERS, + TRAIT_RADIMMUNE, + TRAIT_PIERCEIMMUNE, + TRAIT_NODISMEMBER + ) attack_verb = "whips" attack_sound = 'sound/weapons/whip.ogg' miss_sound = 'sound/weapons/etherealmiss.ogg' @@ -1067,7 +1127,17 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/cloth_pile) name = "Leather Golem" id = SPECIES_GOLEM_LEATHER special_names = list("Face", "Man", "Belt") //Ah dude 4 strength 4 stam leather belt AHHH - inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER, TRAIT_STRONG_GRABBER) + inherent_traits = list( + TRAIT_NOBREATH, + TRAIT_RESISTCOLD, + TRAIT_RESISTHIGHPRESSURE, + TRAIT_RESISTLOWPRESSURE, + TRAIT_CHUNKYFINGERS, + TRAIT_RADIMMUNE, + TRAIT_PIERCEIMMUNE, + TRAIT_NODISMEMBER, + TRAIT_STRONG_GRABBER + ) prefix = "Leather" fixed_mut_color = "624a2e" info_text = "As a " + span_danger("Leather Golem") + ", you are flammable, but you can grab things with incredible ease, allowing all your grabs to start at a strong level." @@ -1081,7 +1151,16 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/cloth_pile) special_names = list("Boll","Weave") species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYESPRITES,NOFLASH,NOTRANSSTING) fixed_mut_color = null - inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER) + inherent_traits = list( + TRAIT_NOBREATH, + TRAIT_RESISTCOLD, + TRAIT_RESISTHIGHPRESSURE, + TRAIT_RESISTLOWPRESSURE, + TRAIT_CHUNKYFINGERS, + TRAIT_RADIMMUNE, + TRAIT_PIERCEIMMUNE, + TRAIT_NODISMEMBER + ) info_text = "As a " + span_danger("Durathread Golem") + ", your strikes will cause those your targets to start choking, but your woven body won't withstand fire as well." species_chest = /obj/item/bodypart/chest/golem/durathread @@ -1105,7 +1184,19 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/cloth_pile) mutanttongue = /obj/item/organ/tongue/bone sexes = FALSE fixed_mut_color = null - inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_FAKEDEATH) + inherent_traits = list( + TRAIT_RESISTHEAT, + TRAIT_NOBREATH, + TRAIT_RESISTCOLD, + TRAIT_RESISTHIGHPRESSURE, + TRAIT_RESISTLOWPRESSURE, + TRAIT_NOFIRE, + TRAIT_CHUNKYFINGERS, + TRAIT_RADIMMUNE, + TRAIT_PIERCEIMMUNE, + TRAIT_NODISMEMBER, + TRAIT_FAKEDEATH + ) species_language_holder = /datum/language_holder/golem/bone info_text = "As a " + span_danger("Bone Golem") + ", You have a powerful spell that lets you chill your enemies with fear, and milk heals you! Just make sure to watch our for bone-hurting juice." var/datum/action/innate/bonechill/bonechill @@ -1188,7 +1279,16 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/cloth_pile) prefix = "Snow" special_names = list("Flake", "Blizzard", "Storm") species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYESPRITES,NOTRANSSTING) //no mutcolors, no eye sprites - inherent_traits = list(TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER) + inherent_traits = list( + TRAIT_NOBREATH, + TRAIT_RESISTCOLD, + TRAIT_RESISTHIGHPRESSURE, + TRAIT_RESISTLOWPRESSURE, + TRAIT_CHUNKYFINGERS, + TRAIT_RADIMMUNE, + TRAIT_PIERCEIMMUNE, + TRAIT_NODISMEMBER + ) var/obj/effect/proc_holder/spell/targeted/conjure_item/snowball/ball var/obj/effect/proc_holder/spell/aimed/cryo/cryo diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 7b32986dea02a..1589554c80709 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -96,7 +96,7 @@ id = SPECIES_ASHWALKER examine_limb_id = SPECIES_LIZARD species_traits = list(MUTCOLORS,EYECOLOR,LIPS, NO_UNDERWEAR) - inherent_traits = list(TRAIT_NOGUNS) + inherent_traits = list(TRAIT_CHUNKYFINGERS) species_language_holder = /datum/language_holder/lizard/ash mutantlungs = /obj/item/organ/lungs/ashwalker digitigrade_customization = DIGITIGRADE_FORCED diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index a89f88441b5f3..778455cbd4046 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -93,7 +93,18 @@ burnmod = 1.5 no_equip = list(ITEM_SLOT_OCLOTHING, ITEM_SLOT_GLOVES, ITEM_SLOT_FEET, ITEM_SLOT_ICLOTHING, ITEM_SLOT_SUITSTORE) species_traits = list(NOBLOOD,NO_UNDERWEAR,NO_DNA_COPY,NOTRANSSTING,NOEYESPRITES,NOFLASH) - inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_VIRUSIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER) + inherent_traits = list( + TRAIT_RESISTCOLD, + TRAIT_NOBREATH, + TRAIT_RESISTHIGHPRESSURE, + TRAIT_RESISTLOWPRESSURE, + TRAIT_CHUNKYFINGERS, + TRAIT_RADIMMUNE, + TRAIT_VIRUSIMMUNE, + TRAIT_PIERCEIMMUNE, + TRAIT_NODISMEMBER, + TRAIT_NOHUNGER + ) mutanteyes = /obj/item/organ/eyes/night_vision/nightmare mutantheart = /obj/item/organ/heart/nightmare mutantbrain = /obj/item/organ/brain/nightmare diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index 4b383961a5a3b..de3d287d65923 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -258,7 +258,13 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/living/carbon/monkey) name = "Teratoma" id = "teratoma" species_traits = list(NOTRANSSTING, NO_DNA_COPY, EYECOLOR, HAIR, FACEHAIR, LIPS) - inherent_traits = list(TRAIT_NOHUNGER, TRAIT_RADIMMUNE, TRAIT_BADDNA, TRAIT_NOGUNS, TRAIT_NONECRODISEASE) //Made of mutated cells + inherent_traits = list( + TRAIT_NOHUNGER, + TRAIT_RADIMMUNE, + TRAIT_BADDNA, + TRAIT_CHUNKYFINGERS, + TRAIT_NONECRODISEASE + ) //Made of mutated cells use_skintones = FALSE skinned_type = /obj/item/stack/sheet/animalhide/monkey changesource_flags = MIRROR_BADMIN diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 3bc43dc883409..e463938d51941 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -640,8 +640,43 @@ update_stat() med_hud_set_health() med_hud_set_status() + update_health_hud() SEND_SIGNAL(src, COMSIG_LIVING_UPDATE_HEALTH) +/mob/living/update_health_hud() + var/severity = 0 + var/healthpercent = (health/maxHealth) * 100 + if(hud_used?.healthdoll) //to really put you in the boots of a simplemob + var/atom/movable/screen/healthdoll/living/livingdoll = hud_used.healthdoll + switch(healthpercent) + if(100 to INFINITY) + severity = 0 + if(80 to 100) + severity = 1 + if(60 to 80) + severity = 2 + if(40 to 60) + severity = 3 + if(20 to 40) + severity = 4 + if(1 to 20) + severity = 5 + else + severity = 6 + livingdoll.icon_state = "living[severity]" + if(!livingdoll.filtered) + livingdoll.filtered = TRUE + var/icon/mob_mask = icon(icon, icon_state) + if(mob_mask.Height() > world.icon_size || mob_mask.Width() > world.icon_size) + var/health_doll_icon_state = health_doll_icon ? health_doll_icon : "megasprite" + mob_mask = icon('icons/hud/screen_gen.dmi', health_doll_icon_state) //swap to something generic if they have no special doll + livingdoll.add_filter("mob_shape_mask", 1, alpha_mask_filter(icon = mob_mask)) + livingdoll.add_filter("inset_drop_shadow", 2, drop_shadow_filter(size = -1)) + if(severity > 0) + overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity) + else + clear_fullscreen("brute") + //proc used to ressuscitate a mob /mob/living/proc/revive(full_heal = FALSE, admin_revive = FALSE) SEND_SIGNAL(src, COMSIG_LIVING_REVIVE, src, full_heal, admin_revive) @@ -1713,3 +1748,34 @@ /mob/living/proc/on_handsblocked_end() REMOVE_TRAIT(src, TRAIT_UI_BLOCKED, TRAIT_HANDS_BLOCKED) REMOVE_TRAIT(src, TRAIT_PULL_BLOCKED, TRAIT_HANDS_BLOCKED) + +/// Returns the attack damage type of a living mob such as [BRUTE]. +/mob/living/proc/get_attack_type() + return BRUTE + + +/** + * Apply a martial art move from src to target. + * + * This is used to process martial art attacks against nonhumans. + * It is also used to process martial art attacks by nonhumans, even against humans + * Human vs human attacks are handled in species code right now. + */ +/mob/living/proc/apply_martial_art(mob/living/target, modifiers) + if(HAS_TRAIT(target, TRAIT_MARTIAL_ARTS_IMMUNE)) + return MARTIAL_ATTACK_INVALID + var/datum/martial_art/style = mind?.martial_art + if (!style) + return MARTIAL_ATTACK_INVALID + // will return boolean below since it's not invalid + switch (a_intent) + if (INTENT_GRAB) + return style.grab_act(src, target) + if (INTENT_HARM) + if (HAS_TRAIT(src, TRAIT_PACIFISM)) + return FALSE + return style.harm_act(src, target) + if (INTENT_DISARM) + return style.disarm_act(src, target) + if (INTENT_HELP) + return style.help_act(src, target) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index bb39743aa1bd3..45fece17a2761 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -273,27 +273,44 @@ log_combat(M, src, "attacked") return TRUE +/mob/living/attack_hand(mob/living/carbon/human/user, list/modifiers) + . = ..() + var/martial_result = user.apply_martial_art(src, modifiers) + if (martial_result != MARTIAL_ATTACK_INVALID) + return martial_result -/mob/living/attack_paw(mob/living/carbon/monkey/M) +/mob/living/attack_paw(mob/living/carbon/monkey/user, list/modifiers) if(isturf(loc) && istype(loc.loc, /area/start)) - to_chat(M, "No attacking people at spawn, you jackass.") + to_chat(user, "No attacking people at spawn, you jackass.") return FALSE - if (M.a_intent == INTENT_HARM) - if(HAS_TRAIT(M, TRAIT_PACIFISM)) - to_chat(M, span_notice("You don't want to hurt anyone!")) - return FALSE + var/martial_result = user.apply_martial_art(src, modifiers) + if (martial_result != MARTIAL_ATTACK_INVALID) + return martial_result - if(M.is_muzzled() || M.is_mouth_covered(FALSE, TRUE)) - to_chat(M, span_warning("You can't bite with your mouth covered!")) + switch (user.a_intent) + if (INTENT_HARM) + if(HAS_TRAIT(user, TRAIT_PACIFISM)) + to_chat(user, "You don't want to hurt anyone!") + return FALSE + + if(user.is_muzzled() || user.is_mouth_covered(FALSE, TRUE)) + to_chat(user, "You can't bite with your mouth covered!") + return FALSE + user.do_attack_animation(src, ATTACK_EFFECT_BITE) + log_combat(user, src, "attacked") + playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) + visible_message("[user.name] bites [src]!", \ + "[user.name] bites you!", "You hear a chomp!", COMBAT_MESSAGE_RANGE, user) + to_chat(user, "You bite [src]!") + return TRUE + if (INTENT_GRAB) + grabbedby(user) return FALSE - M.do_attack_animation(src, ATTACK_EFFECT_BITE) - log_combat(M, src, "attacked") - playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1) - visible_message(span_danger("[M.name] bites [src]!"), \ - span_userdanger("[M.name] bites you!"), span_hear("You hear a chomp!"), COMBAT_MESSAGE_RANGE, M) - to_chat(M, span_danger("You bite [src]!")) - return TRUE + if (INTENT_DISARM) + if (user != src) + user.disarm(src) + return TRUE return FALSE /mob/living/attack_larva(mob/living/carbon/alien/larva/L) diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index c7b849c0c4b69..98ed5a506bb9f 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -6,6 +6,7 @@ pressure_resistance = 10 chat_color = "#CCCCCC" //The say color of the mob, for when ID say isn't available (simplemobs that are not /mob/living/carbon/human) + hud_type = /datum/hud/living var/resize = 1 //Badminnery resize var/lastattacker = null @@ -91,6 +92,8 @@ var/smoke_delay = 0 //used to prevent spam with smoke reagent reaction on mob. var/bubble_icon = "default" //what icon the mob uses for speechbubbles + ///if this exists AND the normal sprite is bigger than 32x32, this is the replacement icon state (because health doll size limitations). the icon will always be screen_gen.dmi + var/health_doll_icon var/last_bumped = 0 var/unique_name = 0 //if a mob's name should be appended with an id when created e.g. Mob (666) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 62fdbaaf3c4eb..dc2560425b34a 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -68,6 +68,7 @@ diag_hud_set_health() create_access_card(default_access_list) default_access_list = null + ADD_TRAIT(src, TRAIT_MARTIAL_ARTS_IMMUNE, ROUNDSTART_TRAIT) /mob/living/silicon/Destroy() QDEL_NULL(radio) diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm index 2f973fc39852a..cea1a292eac26 100644 --- a/code/modules/mob/living/simple_animal/animal_defense.dm +++ b/code/modules/mob/living/simple_animal/animal_defense.dm @@ -1,7 +1,9 @@ /mob/living/simple_animal/attack_hand(mob/living/carbon/human/M) - ..() + // so that martial arts don't double dip + if (..()) + return TRUE switch(M.a_intent) if("help") if (health > 0) diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 42e63aa5eaa3a..234bcd1b616e6 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -36,7 +36,6 @@ del_on_death = TRUE initial_language_holder = /datum/language_holder/construct deathmessage = "collapses in a shattered heap." - hud_type = /datum/hud/constructs hardattacks = TRUE var/list/construct_spells = list() var/playstyle_string = span_bigbold("You are a generic construct!") + " Your job is to not exist, and you should probably adminhelp this." @@ -128,11 +127,6 @@ /mob/living/simple_animal/hostile/construct/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE) return 0 -/mob/living/simple_animal/hostile/construct/adjustHealth(amount, updating_health = TRUE, forced = FALSE) - . = ..() - if(updating_health) - update_health_hud() - /////////////////Juggernaut/////////////// /mob/living/simple_animal/hostile/construct/juggernaut name = "Juggernaut" @@ -531,21 +525,3 @@ desc = "Activate to track Nar'Sie!" button_icon_state = "sintouch" the_construct.seeking = TRUE - - -/////////////////////////////ui stuff///////////////////////////// - -/mob/living/simple_animal/hostile/construct/update_health_hud() - if(hud_used) - if(health >= maxHealth) - hud_used.healths.icon_state = "[icon_state]_health0" - else if(health > maxHealth*0.8) - hud_used.healths.icon_state = "[icon_state]_health2" - else if(health > maxHealth*0.6) - hud_used.healths.icon_state = "[icon_state]_health3" - else if(health > maxHealth*0.4) - hud_used.healths.icon_state = "[icon_state]_health4" - else if(health > maxHealth*0.2) - hud_used.healths.icon_state = "[icon_state]_health5" - else - hud_used.healths.icon_state = "[icon_state]_health6" diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index e5f19e5daa38c..11274c170d4f9 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -176,7 +176,7 @@ Difficulty: Very Hard if(ishuman(L)) var/mob/living/carbon/human/H = L if(H.mind) - if(H.mind.martial_art && prob(H.mind.martial_art.deflection_chance)) + if(istype(H.mind.martial_art, /datum/martial_art/the_sleeping_carp)) . = TRUE /mob/living/simple_animal/hostile/megafauna/colossus/proc/alternating_dir_shots() diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm index dadbc5835d15a..71c9bf4c4fd3d 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm @@ -52,6 +52,7 @@ if(gps_name && true_spawn) AddComponent(/datum/component/gps, gps_name) ADD_TRAIT(src, TRAIT_NO_TELEPORT, MEGAFAUNA_TRAIT) + ADD_TRAIT(src, TRAIT_MARTIAL_ARTS_IMMUNE, MEGAFAUNA_TRAIT) for(var/action_type in attack_action_types) var/datum/action/innate/megafauna_attack/attack_action = new action_type() attack_action.Grant(src) diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm index acddf727e9b7f..cb096d9a79de1 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm @@ -18,7 +18,6 @@ stat_attack = HARD_CRIT layer = LARGE_MOB_LAYER sentience_type = SENTIENCE_BOSS - hud_type = /datum/hud/lavaland_elite var/chosen_attack = 1 var/list/attack_action_types = list() var/can_talk = FALSE @@ -82,33 +81,6 @@ While using this makes the system rely on OnFire, it still gives options for tim elite_owner.chosen_attack = chosen_attack_num to_chat(elite_owner, chosen_message) -/mob/living/simple_animal/hostile/asteroid/elite/update_health_hud() - if(hud_used) - var/severity = 0 - var/healthpercent = (health/maxHealth) * 100 - switch(healthpercent) - if(100 to INFINITY) - hud_used.healths.icon_state = "elite_health0" - if(80 to 100) - severity = 1 - if(60 to 80) - severity = 2 - if(40 to 60) - severity = 3 - if(20 to 40) - severity = 4 - if(10 to 20) - severity = 5 - if(1 to 20) - severity = 6 - else - severity = 7 - hud_used.healths.icon_state = "elite_health[severity]" - if(severity > 0) - overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity) - else - clear_fullscreen("brute") - //The Pulsing Tumor, the actual "spawn-point" of elites, handles the spawning, arena, and procs for dealing with basic scenarios. /obj/structure/elite_tumor diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 2eb087aa46f87..9c24e2b3a0f0e 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -191,16 +191,6 @@ /mob/living/simple_animal/updatehealth() . = ..() health = clamp(health, 0, maxHealth) - update_health_hud() - -/mob/living/simple_animal/update_health_hud() - if(!hud_used) - return - var/severity = 5 - clamp(FLOOR((health / maxHealth) * 5, 1), 0, 5) - if(severity > 0) - overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity) - else - clear_fullscreen("brute") /mob/living/simple_animal/update_stat() if(status_flags & GODMODE) diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index 6855314a38879..abf7ce49e01e8 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -45,7 +45,6 @@ footstep_type = FOOTSTEP_MOB_SLIME - hud_type = /datum/hud/slime hardattacks = TRUE //A sharp blade wont cut a slime from a mere parry discovery_points = 1000 @@ -179,36 +178,6 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/living/simple_animal/slime) mod += 2 add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/slime_healthmod, multiplicative_slowdown = mod) -/mob/living/simple_animal/slime/update_health_hud() - if(hud_used) - var/severity = 0 - var/healthpercent = (health/maxHealth) * 100 - switch(healthpercent) - if(100 to INFINITY) - hud_used.healths.icon_state = "slime_health0" - if(80 to 100) - hud_used.healths.icon_state = "slime_health1" - severity = 1 - if(60 to 80) - hud_used.healths.icon_state = "slime_health2" - severity = 2 - if(40 to 60) - hud_used.healths.icon_state = "slime_health3" - severity = 3 - if(20 to 40) - hud_used.healths.icon_state = "slime_health4" - severity = 4 - if(1 to 20) - hud_used.healths.icon_state = "slime_health5" - severity = 5 - else - hud_used.healths.icon_state = "slime_health7" - severity = 6 - if(severity > 0) - overlay_fullscreen("brute", /atom/movable/screen/fullscreen/brute, severity) - else - clear_fullscreen("brute") - /mob/living/simple_animal/slime/adjust_bodytemperature() . = ..() var/mod = 0 diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi index af297187cac97..6489055798643 100644 Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ diff --git a/icons/hud/screen_gen.dmi b/icons/hud/screen_gen.dmi index 1e34ba1144290..68afde5159219 100644 Binary files a/icons/hud/screen_gen.dmi and b/icons/hud/screen_gen.dmi differ diff --git a/icons/ui/screen_gen.dmi b/icons/ui/screen_gen.dmi deleted file mode 100644 index a94f53eb96274..0000000000000 Binary files a/icons/ui/screen_gen.dmi and /dev/null differ