diff --git a/code/__DEFINES/xeno.dm b/code/__DEFINES/xeno.dm index ee8962ace73d..fd0e890f0063 100644 --- a/code/__DEFINES/xeno.dm +++ b/code/__DEFINES/xeno.dm @@ -682,8 +682,9 @@ #define XENO_CASTE_HIVELORD "Hivelord" #define XENO_CASTE_LURKER "Lurker" #define XENO_CASTE_WARRIOR "Warrior" +#define XENO_CASTE_BOXER "Yuji Itadori" #define XENO_CASTE_SPITTER "Spitter" -#define XENO_T2_CASTES list(XENO_CASTE_BURROWER, XENO_CASTE_CARRIER, XENO_CASTE_HIVELORD, XENO_CASTE_LURKER, XENO_CASTE_WARRIOR, XENO_CASTE_SPITTER) +#define XENO_T2_CASTES list(XENO_CASTE_BURROWER, XENO_CASTE_CARRIER, XENO_CASTE_HIVELORD, XENO_CASTE_LURKER, XENO_CASTE_WARRIOR, XENO_CASTE_BOXER, XENO_CASTE_SPITTER) //t3 #define XENO_CASTE_BOILER "Boiler" #define XENO_CASTE_PRAETORIAN "Praetorian" @@ -704,7 +705,7 @@ //caste list #define XENO_CONSTRUCT_NODE_BOOST list(XENO_CASTE_HIVELORD, XENO_CASTE_BURROWER, XENO_CASTE_CARRIER, XENO_CASTE_QUEEN) -#define ALL_XENO_CASTES list(XENO_CASTE_LARVA, XENO_CASTE_PREDALIEN_LARVA, XENO_CASTE_FACEHUGGER, XENO_CASTE_LESSER_DRONE, XENO_CASTE_DRONE, XENO_CASTE_RUNNER, XENO_CASTE_SENTINEL, XENO_CASTE_DEFENDER, XENO_CASTE_BURROWER, XENO_CASTE_CARRIER, XENO_CASTE_HIVELORD, XENO_CASTE_LURKER, XENO_CASTE_WARRIOR, XENO_CASTE_SPITTER, XENO_CASTE_BOILER, XENO_CASTE_DESPOILER, XENO_CASTE_PRAETORIAN, XENO_CASTE_CRUSHER, XENO_CASTE_RAVAGER, XENO_CASTE_QUEEN, XENO_CASTE_PREDALIEN, XENO_CASTE_HELLHOUND, XENO_CASTE_KING) +#define ALL_XENO_CASTES list(XENO_CASTE_LARVA, XENO_CASTE_PREDALIEN_LARVA, XENO_CASTE_FACEHUGGER, XENO_CASTE_LESSER_DRONE, XENO_CASTE_DRONE, XENO_CASTE_RUNNER, XENO_CASTE_SENTINEL, XENO_CASTE_DEFENDER, XENO_CASTE_BURROWER, XENO_CASTE_CARRIER, XENO_CASTE_HIVELORD, XENO_CASTE_LURKER, XENO_CASTE_WARRIOR, XENO_CASTE_BOXER, XENO_CASTE_SPITTER, XENO_CASTE_BOILER, XENO_CASTE_DESPOILER, XENO_CASTE_PRAETORIAN, XENO_CASTE_CRUSHER, XENO_CASTE_RAVAGER, XENO_CASTE_QUEEN, XENO_CASTE_PREDALIEN, XENO_CASTE_HELLHOUND, XENO_CASTE_KING) // Checks if two hives are allied to each other. // PARAMETERS: diff --git a/code/datums/langchat/langchat.dm b/code/datums/langchat/langchat.dm index fe87903a8d69..89d1c67b0ac1 100644 --- a/code/datums/langchat/langchat.dm +++ b/code/datums/langchat/langchat.dm @@ -10,6 +10,7 @@ /mob/living/carbon/xenomorph/hivelord/langchat_height = 64 /mob/living/carbon/xenomorph/defender/langchat_height = 48 /mob/living/carbon/xenomorph/warrior/langchat_height = 48 +/mob/living/carbon/xenomorph/boxer/langchat_height = 48 /mob/living/carbon/xenomorph/king/langchat_height = 64 /mob/living/carbon/xenomorph/despoiler/langchat_height = 64 diff --git a/code/game/jobs/role_authority.dm b/code/game/jobs/role_authority.dm index 208decb04520..7ac333b2d264 100644 --- a/code/game/jobs/role_authority.dm +++ b/code/game/jobs/role_authority.dm @@ -636,6 +636,8 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou M = /mob/living/carbon/xenomorph/lurker if(XENO_CASTE_WARRIOR) M = /mob/living/carbon/xenomorph/warrior + if(XENO_CASTE_BOXER) + M = /mob/living/carbon/xenomorph/boxer if(XENO_CASTE_DEFENDER) M = /mob/living/carbon/xenomorph/defender if(XENO_CASTE_QUEEN) diff --git a/code/game/sound.dm b/code/game/sound.dm index 5d6858f8273b..625ed22b7d19 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -386,6 +386,8 @@ sound = pick('sound/voice/alien_roar_larva1.ogg','sound/voice/alien_roar_larva2.ogg') if("queen") sound = pick('sound/voice/alien_queen_command.ogg','sound/voice/alien_queen_command2.ogg','sound/voice/alien_queen_command3.ogg') + if("yuji_talk") + sound = pick ('sound/voice/yuji_talk.ogg', 'sound/voice/yuji_talk2.ogg', 'sound/voice/yuji_talk3.ogg',) // Human if("male_scream") sound = pick('sound/voice/human_male_scream_1.ogg','sound/voice/human_male_scream_2.ogg','sound/voice/human_male_scream_3.ogg','sound/voice/human_male_scream_4.ogg',5;'sound/voice/human_male_scream_5.ogg',5;'sound/voice/human_jackson_scream.ogg',5;'sound/voice/human_ack_scream.ogg','sound/voice/human_male_scream_6.ogg') diff --git a/code/modules/admin/player_panel/actions/transform.dm b/code/modules/admin/player_panel/actions/transform.dm index bcd77ff1a37b..d6f091ccfc68 100644 --- a/code/modules/admin/player_panel/actions/transform.dm +++ b/code/modules/admin/player_panel/actions/transform.dm @@ -81,6 +81,11 @@ GLOBAL_LIST_INIT(pp_transformables, list( color = "purple" ), list( + name = XENO_CASTE_BOXER, + key = /mob/living/carbon/xenomorph/boxer, + color = "purple" + ), + list( name = XENO_CASTE_SPITTER, key = /mob/living/carbon/xenomorph/spitter, color = "purple" diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Boxer.dm b/code/modules/mob/living/carbon/xenomorph/castes/Boxer.dm new file mode 100644 index 000000000000..b1473567e743 --- /dev/null +++ b/code/modules/mob/living/carbon/xenomorph/castes/Boxer.dm @@ -0,0 +1,547 @@ +/datum/caste_datum/boxer + caste_type = XENO_CASTE_BOXER + tier = 2 + + melee_damage_lower = XENO_DAMAGE_TIER_3 + melee_damage_upper = XENO_DAMAGE_TIER_5 + melee_vehicle_damage = XENO_DAMAGE_TIER_5 + max_health = XENO_HEALTH_TIER_8 + plasma_gain = XENO_PLASMA_GAIN_TIER_9 + plasma_max = XENO_NO_PLASMA + xeno_explosion_resistance = XENO_EXPLOSIVE_ARMOR_TIER_4 + armor_deflection = XENO_ARMOR_TIER_3 + evasion = XENO_EVASION_NONE + speed = XENO_SPEED_TIER_7 + + behavior_delegate_type = /datum/behavior_delegate/boxer_base + + evolves_to = list(XENO_CASTE_PRAETORIAN, XENO_CASTE_CRUSHER) + deevolves_to = list(XENO_CASTE_DEFENDER) + caste_desc = "A powerful front line combatant." + can_vent_crawl = 0 + + tackle_min = 2 + tackle_max = 4 + + agility_speed_increase = -0.9 + + heal_resting = 1.4 + + minimum_evolve_time = 9 MINUTES + + minimap_icon = "boxer" + + +/mob/living/carbon/xenomorph/boxer + caste_type = XENO_CASTE_BOXER + name = XENO_CASTE_BOXER + desc = "Thats just a guy with pink hair." + icon = 'icons/mob/xenos/castes/tier_2/boxer.dmi' + icon_size = 64 + icon_state = "Yuji Itadori Walking" + plasma_types = list(PLASMA_CHITIN) + pixel_x = -16 + old_x = -16 + tier = 2 + pull_speed = 2 // about what it was before, slightly faster + organ_value = 2000 + base_actions = list( + /datum/action/xeno_action/onclick/xeno_resting, + /datum/action/xeno_action/onclick/release_haul, + /datum/action/xeno_action/watch_xeno, + /datum/action/xeno_action/activable/boxer_punch, + /datum/action/xeno_action/activable/jab, + /datum/action/xeno_action/activable/uppercut, + ) + + claw_type = CLAW_TYPE_SHARP + + icon_xeno = 'icons/mob/xenos/castes/tier_2/boxer.dmi' + icon_xenonid = 'icons/mob/xenonids/castes/tier_2/warrior.dmi' + + weed_food_icon = 'icons/mob/xenos/weeds_64x64.dmi' + weed_food_states = list("Warrior_1","Warrior_2","Warrior_3") + weed_food_states_flipped = list("Warrior_1","Warrior_2","Warrior_3") + + skull = /obj/item/skull/warrior + pelt = /obj/item/pelt/warrior + + slash_sound = 'sound/weapons/punch1.ogg' + slash_verb = "punch" + slashes_verb = "punches" + speaking_noise = "yuji_talk" + +/datum/behavior_delegate/boxer_base + + name = "Base Boxer Behavior Delegate" + + var/ko_delay = 5 SECONDS + var/max_clear_head = 3 + var/clear_head_delay = 15 SECONDS + var/clear_head = 3 + var/next_clear_head_regen + var/clear_head_tickcancel + + var/mob/punching_bag + var/ko_counter = 0 + var/ko_reset_timer + var/max_ko_counter = 15 + + var/image/ko_icon + var/image/big_ko_icon + +/datum/behavior_delegate/boxer_base/New() + . = ..() + if(SSticker.mode && (SSticker.mode.flags_round_type & MODE_XVX)) + clear_head = 0 + max_clear_head = 0 + + +/datum/behavior_delegate/boxer_base/append_to_stat() + . = list() + if(punching_bag) + . += "Beating [punching_bag] - [ko_counter] hits" + + . += "Clarity [clear_head] hits" + +/datum/behavior_delegate/boxer_base/on_life() + var/world_time = world.time + if(world_time > next_clear_head_regen && clear_head < max_clear_head) + clear_head++ + next_clear_head_regen = world_time+ clear_head_delay + +/datum/behavior_delegate/boxer_base/melee_attack_additional_effects_target(mob/living/carbon/carbon_target, ko_boost = 0.5) + + if(!ismob(carbon_target)) + return + + if(punching_bag != carbon_target) + remove_ko() + punching_bag = carbon_target + ko_icon = image(null, carbon_target) + ko_icon.alpha = 196 + ko_icon.color = "#ee0808" + ko_icon.maptext_width = 16 + ko_icon.maptext_x = -16 + ko_icon.maptext_y = 16 + ko_icon.layer = 20 + bound_xeno.client.images += ko_icon + + ko_counter += ko_boost + if(ko_counter > max_ko_counter) + ko_counter = max_ko_counter + var/to_display = round(ko_counter) + ko_icon.maptext = "[to_display]" + + ko_reset_timer = addtimer(CALLBACK(src, PROC_REF(remove_ko)), ko_delay, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_NO_HASH_WAIT | TIMER_STOPPABLE) + + +/datum/behavior_delegate/boxer_base/proc/remove_ko() + punching_bag = null + ko_counter = 0 + if(bound_xeno.client && ko_icon) + bound_xeno.client.images -= ko_icon + ko_icon = null + +/datum/behavior_delegate/boxer_base/proc/display_ko_message(mob/carbon_target) + + big_ko_icon = image(null, carbon_target) + big_ko_icon.alpha = 196 + big_ko_icon.maptext_y = carbon_target.langchat_height + big_ko_icon.maptext_width = LANGCHAT_WIDTH + big_ko_icon.maptext_height = 16 + big_ko_icon.color = "#FF0000" + big_ko_icon.maptext_x = -32 + big_ko_icon.maptext = "KOKUSEN!" + bound_xeno.client.images += big_ko_icon + addtimer(CALLBACK(src, PROC_REF(remove_big_ko)), 2 SECONDS) + +/datum/behavior_delegate/boxer_base/proc/remove_big_ko() + if(bound_xeno.client && big_ko_icon) + bound_xeno.client.images -= big_ko_icon + big_ko_icon = null + + + ///BOXER CLARITY STUFF GOES HERE + +/mob/living/carbon/xenomorph/boxer/Daze(amount) + var/datum/behavior_delegate/boxer_base/boxer_delegate = behavior_delegate + if(istype(behavior_delegate, boxer_delegate)) + if(boxer_delegate.clear_head <= 0) + ..(amount) + return + if(boxer_delegate.clear_head_tickcancel == world.time) + return + boxer_delegate.clear_head_tickcancel = world.time + boxer_delegate.clear_head-- + if(boxer_delegate.clear_head <= 0) + boxer_delegate.clear_head = 0 + + +/mob/living/carbon/xenomorph/boxer/SetDaze(amount) + var/datum/behavior_delegate/boxer_base/boxer_delegate = behavior_delegate + if(istype(behavior_delegate, boxer_delegate)) + if(boxer_delegate.clear_head <= 0) + ..(amount) + return + if(boxer_delegate.clear_head_tickcancel == world.time) + return + + boxer_delegate.clear_head_tickcancel = world.time + boxer_delegate.clear_head-- + if(boxer_delegate.clear_head <= 0) + boxer_delegate.clear_head = 0 + + +/mob/living/carbon/xenomorph/boxer/AdjustDaze(amount) + var/datum/behavior_delegate/boxer_base/boxer_delegate = behavior_delegate + if(istype(behavior_delegate, boxer_delegate)) + if(boxer_delegate.clear_head <= 0) + ..(amount) + return + if(boxer_delegate.clear_head_tickcancel == world.time) + return + + boxer_delegate.clear_head_tickcancel = world.time + boxer_delegate.clear_head-- + if(boxer_delegate.clear_head <= 0) + boxer_delegate.clear_head = 0 + + +/mob/living/carbon/xenomorph/boxer/KnockDown(amount, forced) + var/datum/behavior_delegate/boxer_base/boxer_delegate = behavior_delegate + if(istype(behavior_delegate, boxer_delegate)) + if(boxer_delegate.clear_head <= 0) + ..(amount) + return + if(boxer_delegate.clear_head_tickcancel == world.time) + return + + boxer_delegate.clear_head_tickcancel = world.time + boxer_delegate.clear_head-- + if(boxer_delegate.clear_head <= 0) + boxer_delegate.clear_head = 0 + + +/mob/living/carbon/xenomorph/boxer/SetKnockDown(amount) + var/datum/behavior_delegate/boxer_base/boxer_delegate = behavior_delegate + if(istype(behavior_delegate, boxer_delegate)) + if(boxer_delegate.clear_head <= 0) + ..(amount) + return + if(boxer_delegate.clear_head_tickcancel == world.time) + return + + boxer_delegate.clear_head_tickcancel = world.time + boxer_delegate.clear_head-- + if(boxer_delegate.clear_head <= 0) + boxer_delegate.clear_head = 0 + + + +/mob/living/carbon/xenomorph/boxer/AdjustKnockDown(amount) + var/datum/behavior_delegate/boxer_base/boxer_delegate = behavior_delegate + if(istype(behavior_delegate, boxer_delegate)) + if(boxer_delegate.clear_head <= 0) + ..(amount) + return + if(boxer_delegate.clear_head_tickcancel == world.time) + return + + boxer_delegate.clear_head_tickcancel = world.time + boxer_delegate.clear_head-- + if(boxer_delegate.clear_head <= 0) + boxer_delegate.clear_head = 0 + + +/mob/living/carbon/xenomorph/boxer/Stun(amount) + var/datum/behavior_delegate/boxer_base/boxer_delegate = behavior_delegate + if(istype(behavior_delegate, boxer_delegate)) + if(boxer_delegate.clear_head <= 0) + ..(amount) + return + if(boxer_delegate.clear_head_tickcancel == world.time) + return + + boxer_delegate.clear_head_tickcancel = world.time + boxer_delegate.clear_head-- + if(boxer_delegate.clear_head <= 0) + boxer_delegate.clear_head = 0 + + +/mob/living/carbon/xenomorph/boxer/SetStun(amount) + var/datum/behavior_delegate/boxer_base/boxer_delegate = behavior_delegate + if(istype(behavior_delegate, boxer_delegate)) + if(boxer_delegate.clear_head <= 0) + ..(amount) + return + if(boxer_delegate.clear_head_tickcancel == world.time) + return + + boxer_delegate.clear_head_tickcancel = world.time + boxer_delegate.clear_head-- + if(boxer_delegate.clear_head <= 0) + boxer_delegate.clear_head = 0 + + + +/mob/living/carbon/xenomorph/boxer/AdjustStun(amount) + var/datum/behavior_delegate/boxer_base/boxer_delegate = behavior_delegate + if(istype(behavior_delegate, boxer_delegate)) + if(boxer_delegate.clear_head <= 0) + ..(amount) + return + if(boxer_delegate.clear_head_tickcancel == world.time) + return + + boxer_delegate.clear_head_tickcancel = world.time + boxer_delegate.clear_head-- + if(boxer_delegate.clear_head <= 0) + boxer_delegate.clear_head = 0 + + +///boxer clarity end + + +/datum/action/xeno_action/activable/boxer_punch + + name = "Punch" + action_icon_state = "punch" + action_type = XENO_ACTION_CLICK + ability_primacy = XENO_PRIMARY_ACTION_1 + xeno_cooldown = 4.5 SECONDS + + var/boxer_punch_damage = 20 + var/boxer_punch_damage_synth = 30 + var/boxer_punch_damage_pred = 25 + var/base_damage = 25 + var/damage_variance = 5 + +/datum/action/xeno_action/activable/uppercut + name = "Uppercut" + action_icon_state = "rav_clothesline" + action_type = XENO_ACTION_CLICK + ability_primacy = XENO_PRIMARY_ACTION_3 + xeno_cooldown = 25 SECONDS + var/base_damage = 15 + var/base_knockback = 40 + var/base_knockdown = 0.25 + var/knockout_power = 11 // 11 seconds + var/base_healthgain = 5 // in percents of health per ko point + +/datum/action/xeno_action/activable/jab + name = "Jab" + action_icon_state = "pounce" + action_type = XENO_ACTION_CLICK + ability_primacy = XENO_PRIMARY_ACTION_2 + xeno_cooldown = 4 SECONDS + +/datum/action/xeno_action/activable/boxer_punch/use_ability(atom/affected_atom) + var/mob/living/carbon/xenomorph/boxer_punch = owner + var/mob/living/carbon/carbon = affected_atom + + if (!action_cooldown_check()) + return + + if (!isxeno_human(carbon) || boxer_punch.can_not_harm(carbon)) + return + + if (!boxer_punch.check_state() || boxer_punch.agility) + return + + if (!boxer_punch.Adjacent(carbon)) + return + + if (!boxer_punch.Adjacent(carbon)) + return + + if(carbon.stat == DEAD) + return + + if(HAS_TRAIT(carbon, TRAIT_NESTED)) + return + + var/obj/limb/target_limb = carbon.get_limb(check_zone(boxer_punch.zone_selected)) + + if (ishuman(carbon) && (!target_limb || (target_limb.status & LIMB_DESTROYED))) + target_limb = carbon.get_limb("chest") + + if (!check_and_use_plasma_owner()) + return + + carbon.last_damage_data = create_cause_data(initial(boxer_punch.caste_type), boxer_punch) + + boxer_punch.visible_message(SPAN_XENOWARNING("[boxer_punch] hits [carbon] in the [target_limb ? target_limb.display_name : "chest"] with a devastatingly powerful punch!"), + SPAN_XENOWARNING("We hit [carbon] in the [target_limb ? target_limb.display_name : "chest"] with a devastatingly powerful punch!")) + var/sound = pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg') + boxer_punch.flick_attack_overlay(carbon, "slam") + playsound(carbon, sound, 50, 1) + do_boxer_punch(carbon, target_limb) + apply_cooldown() + return ..() + + +/datum/action/xeno_action/activable/boxer_punch/proc/do_boxer_punch(mob/living/carbon/carbon, obj/limb/target_limb) + var/mob/living/carbon/xenomorph/boxer = owner + + var/damage = rand(boxer_punch_damage, boxer_punch_damage + damage_variance) + + if(ishuman(carbon)) + if(isyautja(carbon)) + damage = rand(boxer_punch_damage_pred, boxer_punch_damage_pred + damage_variance) + else if(target_limb.status & (LIMB_ROBOT | LIMB_SYNTHSKIN)) + damage = rand(boxer_punch_damage_synth, boxer_punch_damage_synth + damage_variance) + + + carbon.apply_armoured_damage(get_xeno_damage_slash(carbon, damage), ARMOR_MELEE, BRUTE, target_limb? target_limb.name : "chest") + + step_away(carbon, boxer) + if(prob(25)) // 25% chance to fly 2 tiles + step_away(carbon, boxer) + var/datum/behavior_delegate/boxer_base/boxer_delegate = boxer.behavior_delegate + if(istype(boxer_delegate)) + boxer_delegate.melee_attack_additional_effects_target(carbon, 1) + + var/datum/action/xeno_action/activable/jab/jab_action = get_action(boxer, /datum/action/xeno_action/activable/jab) + if(istype(jab_action) && !jab_action.action_cooldown_check()) + if(isxeno(carbon)) + jab_action.reduce_cooldown(jab_action.xeno_cooldown / 2) + else + jab_action.end_cooldown() + +/datum/action/xeno_action/activable/jab/use_ability(atom/A) + var/mob/living/carbon/xenomorph/boxer_jab = owner + var/mob/living/carbon/carbon_target = A + + if(!action_cooldown_check()) + return + + if(boxer_jab.can_not_harm(carbon_target)) + return + + if (!isxeno_human(carbon_target)) + return + + var/distance = get_dist(boxer_jab, carbon_target) + + if(distance > 3) + return + + if(carbon_target.stat == DEAD) + return + + if(HAS_TRAIT(carbon_target, TRAIT_NESTED)) + return + + if(!check_and_use_plasma_owner()) + return + + if(distance > 1 & 2) + step_towards(boxer_jab, carbon_target, 1) + + if(!boxer_jab.Adjacent(carbon_target)) + return + + carbon_target.last_damage_data = create_cause_data(initial(boxer_jab.caste_type), boxer_jab) + boxer_jab.visible_message(SPAN_XENOWARNING("[boxer_jab] hits [carbon_target] with a powerful jab!"), + SPAN_XENOWARNING("You hit [carbon_target] with a powerful jab!")) + var/sound_pick = pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg') + playsound(carbon_target, sound_pick, 45, 1) + boxer_jab.flick_attack_overlay(carbon_target, "slam") + + var/datum/action/xeno_action/activable/boxer_punch/punch_action = get_action(boxer_jab, /datum/action/xeno_action/activable/boxer_punch) + if(punch_action && !punch_action.action_cooldown_check()) + if(isxeno(carbon_target)) + punch_action.reduce_cooldown(punch_action.xeno_cooldown / 2) + else + punch_action.end_cooldown() + + carbon_target.Daze(3) + carbon_target.Slow(5) + + var/datum/behavior_delegate/boxer_base/behavior_delegate = boxer_jab.behavior_delegate + if(istype(behavior_delegate)) + behavior_delegate.melee_attack_additional_effects_target(carbon_target, 1) + apply_cooldown() + ..() + + +/datum/action/xeno_action/activable/uppercut/use_ability(atom/A) + var/mob/living/carbon/xenomorph/upper_cut = owner + + if(upper_cut.can_not_harm(A)) + return + + if(!upper_cut.check_state()) + return + + var/datum/behavior_delegate/boxer_base/behavior_delegate = upper_cut.behavior_delegate + + if(!istype(behavior_delegate)) + return + + if(!behavior_delegate.punching_bag) + return + + var/mob/living/carbon/carbon_target = behavior_delegate.punching_bag + if(carbon_target.stat == DEAD) + return + + if(HAS_TRAIT(carbon_target, TRAIT_NESTED)) + return + + if(!check_and_use_plasma_owner()) + return + + if(!upper_cut.Adjacent(carbon_target)) + return + + if(carbon_target.mob_size >= MOB_SIZE_BIG) + to_chat(upper_cut, SPAN_XENOWARNING("[carbon_target] is too big for you to uppercut!")) + return + + carbon_target.last_damage_data = create_cause_data(initial(upper_cut.caste_type), upper_cut) + + var/ko_counter = behavior_delegate.ko_counter + + var/damage = ko_counter >= 1 + var/knockback = ko_counter >= 3 + var/knockdown = ko_counter >= 6 + var/knockout = ko_counter >= 9 + + var/message = (!damage) ? "weak" : (!knockback) ? "good" : (!knockdown) ? "powerful" : (!knockout) ? "gigantic" : "titanic" + + upper_cut.visible_message(SPAN_XENOWARNING("[upper_cut] hits [carbon_target] with a [message] uppercut!"), + SPAN_XENOWARNING("We hit [carbon_target] with a [message] uppercut!")) + var/sound_pick = pick('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg') + playsound(carbon_target, sound_pick, 50, 1) + + if(behavior_delegate.ko_reset_timer != TIMER_ID_NULL) + deltimer(behavior_delegate.ko_reset_timer) + behavior_delegate.remove_ko() + + var/obj/limb/target_limb = carbon_target.get_limb(check_zone(upper_cut.zone_selected)) + + if(damage) + carbon_target.apply_armoured_damage(get_xeno_damage_slash(carbon_target, base_damage * ko_counter), ARMOR_MELEE, BRUTE, target_limb? target_limb.name : "chest") + + if(knockout) + carbon_target.KnockOut(knockout_power) + behavior_delegate.display_ko_message(carbon_target) + playsound(carbon_target, 'sound/effects/blackflash.ogg', 75, 1) + + if(knockback) + carbon_target.explosion_throw(base_knockback * ko_counter, get_dir(upper_cut, carbon_target)) + + if(knockdown) + carbon_target.KnockDown(base_knockdown** ko_counter) + + var/mob_multiplier = 1 + if(isxeno(carbon_target)) + mob_multiplier = XVX_WARRIOR_HEALMULT + + if(ko_counter > 0) + upper_cut.gain_health(mob_multiplier * ko_counter * base_healthgain * upper_cut.maxHealth / 100) + + apply_cooldown() + ..() diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm index e4b135b5773f..8d8cebd577c9 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm @@ -24,7 +24,7 @@ tackle_chance = 25 evolution_allowed = FALSE - deevolves_to = list(XENO_CASTE_WARRIOR) + deevolves_to = list(XENO_CASTE_WARRIOR, XENO_CASTE_BOXER) caste_desc = "A huge tanky xenomorph." minimap_icon = "crusher" diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm b/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm index 17d51bd063bf..7967f4a984e2 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm @@ -14,7 +14,7 @@ evasion = XENO_EVASION_NONE speed = XENO_SPEED_TIER_6 - evolves_to = list(XENO_CASTE_WARRIOR) + evolves_to = list(XENO_CASTE_WARRIOR, XENO_CASTE_BOXER) deevolves_to = list(XENO_CASTE_LARVA) can_vent_crawl = 0 diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm b/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm index 621903578c1c..513fd9bcede4 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm @@ -14,7 +14,7 @@ speed = XENO_SPEED_TIER_6 evolution_allowed = FALSE - deevolves_to = list(XENO_CASTE_WARRIOR, XENO_CASTE_SPITTER) + deevolves_to = list(XENO_CASTE_WARRIOR, XENO_CASTE_SPITTER, XENO_CASTE_BOXER) caste_desc = "The warleader of the hive." spit_types = list(/datum/ammo/xeno/acid/praetorian) acid_level = 2 diff --git a/code/modules/mob/living/carbon/xenomorph/emote.dm b/code/modules/mob/living/carbon/xenomorph/emote.dm index 0b5057749603..0c60bd4a08fe 100644 --- a/code/modules/mob/living/carbon/xenomorph/emote.dm +++ b/code/modules/mob/living/carbon/xenomorph/emote.dm @@ -15,7 +15,7 @@ . = larva_sound /datum/emote/living/carbon/xeno/growl - mob_type_blacklist_typecache = list(/mob/living/carbon/xenomorph/hellhound) + mob_type_blacklist_typecache = list(/mob/living/carbon/xenomorph/hellhound, /mob/living/carbon/xenomorph/boxer) key = "growl" message = "growls." @@ -24,7 +24,7 @@ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE /datum/emote/living/carbon/xeno/hiss - mob_type_blacklist_typecache = list(/mob/living/carbon/xenomorph/hellhound) + mob_type_blacklist_typecache = list(/mob/living/carbon/xenomorph/hellhound, /mob/living/carbon/xenomorph/boxer) key = "hiss" message = "hisses." @@ -33,7 +33,7 @@ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE /datum/emote/living/carbon/xeno/needshelp - mob_type_blacklist_typecache = list(/mob/living/carbon/xenomorph/hellhound) + mob_type_blacklist_typecache = list(/mob/living/carbon/xenomorph/hellhound, /mob/living/carbon/xenomorph/boxer) key = "needshelp" message = "needs help!" @@ -41,7 +41,7 @@ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE /datum/emote/living/carbon/xeno/roar - mob_type_blacklist_typecache = list(/mob/living/carbon/xenomorph/hellhound) + mob_type_blacklist_typecache = list(/mob/living/carbon/xenomorph/hellhound, /mob/living/carbon/xenomorph/boxer) key = "roar" message = "roars!" @@ -51,10 +51,33 @@ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE /datum/emote/living/carbon/xeno/tail + mob_type_blacklist_typecache = list(/mob/living/carbon/xenomorph/boxer) key = "tail" message = "swipes its tail." sound = "alien_tail_swipe" +/datum/emote/living/carbon/xeno/boxer ///yuji + mob_type_allowed_typecache = list(/mob/living/carbon/xenomorph/boxer) + keybind = FALSE + +/datum/emote/living/carbon/xeno/boxer/roar + key = "roar" + message = "ヘイ!オー・ピー・ピー!" + sound = 'sound/voice/opp.ogg' + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/xeno/boxer/iamyou + key = "iamyou" + message = "受け入れるよ、真人、私はお前だ。." + sound = 'sound/voice/iamyou.ogg' + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/xeno/boxer/whatareyou + key = "whatareyou" + message = "お前は一体何者だ、真人!" + sound = 'sound/voice/whatareyou.ogg' + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + /datum/emote/living/carbon/xeno/hellhound mob_type_allowed_typecache = list(/mob/living/carbon/xenomorph/hellhound) keybind = FALSE diff --git a/code/modules/mob/living/carbon/xenomorph/hive_status.dm b/code/modules/mob/living/carbon/xenomorph/hive_status.dm index c2edfe1fdf22..330d485ad0ba 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_status.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_status.dm @@ -501,7 +501,7 @@ // Yes, Queen is technically considered to be tier 0 list(XENO_CASTE_LARVA = 0, XENO_CASTE_QUEEN = 0), list(XENO_CASTE_DRONE = 0, XENO_CASTE_RUNNER = 0, XENO_CASTE_SENTINEL = 0, XENO_CASTE_DEFENDER = 0), - list(XENO_CASTE_HIVELORD = 0, XENO_CASTE_BURROWER = 0, XENO_CASTE_CARRIER = 0, XENO_CASTE_LURKER = 0, XENO_CASTE_SPITTER = 0, XENO_CASTE_WARRIOR = 0), + list(XENO_CASTE_HIVELORD = 0, XENO_CASTE_BURROWER = 0, XENO_CASTE_CARRIER = 0, XENO_CASTE_LURKER = 0, XENO_CASTE_SPITTER = 0, XENO_CASTE_WARRIOR = 0, XENO_CASTE_BOXER = 0), list(XENO_CASTE_BOILER = 0, XENO_CASTE_CRUSHER = 0, XENO_CASTE_PRAETORIAN = 0, XENO_CASTE_RAVAGER = 0, XENO_CASTE_DESPOILER = 0) ) @@ -523,7 +523,7 @@ var/list/xeno_icons = list( list(XENO_CASTE_LARVA = "", XENO_CASTE_QUEEN = "", XENO_CASTE_PREDALIEN_LARVA = "", XENO_CASTE_HELLHOUND = ""), list(XENO_CASTE_DRONE = "", XENO_CASTE_RUNNER = "", XENO_CASTE_SENTINEL = "", XENO_CASTE_DEFENDER = "", XENO_CASTE_PREDALIEN = ""), - list(XENO_CASTE_HIVELORD = "", XENO_CASTE_BURROWER = "", XENO_CASTE_CARRIER = "", XENO_CASTE_LURKER = "", XENO_CASTE_SPITTER = "", XENO_CASTE_WARRIOR = ""), + list(XENO_CASTE_HIVELORD = "", XENO_CASTE_BURROWER = "", XENO_CASTE_CARRIER = "", XENO_CASTE_LURKER = "", XENO_CASTE_SPITTER = "", XENO_CASTE_WARRIOR = "", XENO_CASTE_BOXER = ""), list(XENO_CASTE_BOILER = "", XENO_CASTE_CRUSHER = "", XENO_CASTE_PRAETORIAN = "", XENO_CASTE_RAVAGER = "", XENO_CASTE_DESPOILER = "") ) diff --git a/colonialmarines.dme b/colonialmarines.dme index dd70a2945f13..3f65ed803c04 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -2253,6 +2253,7 @@ #include "code\modules\mob\living\carbon\xenomorph\abilities\warrior\warrior_abilities.dm" #include "code\modules\mob\living\carbon\xenomorph\abilities\warrior\warrior_macros.dm" #include "code\modules\mob\living\carbon\xenomorph\castes\Boiler.dm" +#include "code\modules\mob\living\carbon\xenomorph\castes\Boxer.dm" #include "code\modules\mob\living\carbon\xenomorph\castes\Burrower.dm" #include "code\modules\mob\living\carbon\xenomorph\castes\Carrier.dm" #include "code\modules\mob\living\carbon\xenomorph\castes\caste_datum.dm" diff --git a/icons/mob/xenos/castes/tier_2/boxer.dmi b/icons/mob/xenos/castes/tier_2/boxer.dmi new file mode 100644 index 000000000000..ee959f5673fb Binary files /dev/null and b/icons/mob/xenos/castes/tier_2/boxer.dmi differ diff --git a/icons/mob/xenos/castes/tier_2/warrior.dmi b/icons/mob/xenos/castes/tier_2/warrior.dmi index af3000a3dd5a..706f251e62cc 100644 Binary files a/icons/mob/xenos/castes/tier_2/warrior.dmi and b/icons/mob/xenos/castes/tier_2/warrior.dmi differ diff --git a/icons/mob/xenos/onmob/warrior.dmi b/icons/mob/xenos/onmob/warrior.dmi index 4351ad78339e..706f251e62cc 100644 Binary files a/icons/mob/xenos/onmob/warrior.dmi and b/icons/mob/xenos/onmob/warrior.dmi differ diff --git a/sound/effects/blackflash.ogg b/sound/effects/blackflash.ogg new file mode 100644 index 000000000000..2e7c30e5d461 Binary files /dev/null and b/sound/effects/blackflash.ogg differ diff --git a/sound/voice/iamyou.ogg b/sound/voice/iamyou.ogg new file mode 100644 index 000000000000..4d282bddcc78 Binary files /dev/null and b/sound/voice/iamyou.ogg differ diff --git a/sound/voice/opp.ogg b/sound/voice/opp.ogg new file mode 100644 index 000000000000..b9ce7591b367 Binary files /dev/null and b/sound/voice/opp.ogg differ diff --git a/sound/voice/whatareyou.ogg b/sound/voice/whatareyou.ogg new file mode 100644 index 000000000000..9003e41c1cbe Binary files /dev/null and b/sound/voice/whatareyou.ogg differ diff --git a/sound/voice/yuji_talk.ogg b/sound/voice/yuji_talk.ogg new file mode 100644 index 000000000000..c22f04aa5515 Binary files /dev/null and b/sound/voice/yuji_talk.ogg differ diff --git a/sound/voice/yuji_talk2.ogg b/sound/voice/yuji_talk2.ogg new file mode 100644 index 000000000000..a4b37b67dba9 Binary files /dev/null and b/sound/voice/yuji_talk2.ogg differ diff --git a/sound/voice/yuji_talk3.ogg b/sound/voice/yuji_talk3.ogg new file mode 100644 index 000000000000..d12a2c21609b Binary files /dev/null and b/sound/voice/yuji_talk3.ogg differ