diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 8de2255c79..93a4e1507d 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -449,3 +449,11 @@ var/list/default_xeno_onmob_icons = list( #define MOBILITY_FLAGS_CARBON_DEFAULT (MOBILITY_MOVE | MOBILITY_STAND | MOBILITY_REST | MOBILITY_LIEDOWN) #define MOBILITY_FLAGS_REST_CAPABLE_DEFAULT (MOBILITY_MOVE | MOBILITY_STAND | MOBILITY_REST | MOBILITY_LIEDOWN) +/// Sleeps for X and will perform return if A is qdeleted or a dead mob. +#define SLEEP_CHECK_DEATH(X, A) \ + sleep(X); \ + if(QDELETED(A)) return; \ + if(ismob(A)) { \ + var/mob/sleep_check_death_mob = A; \ + if(sleep_check_death_mob.stat == DEAD) return; \ + } diff --git a/code/__DEFINES/xeno.dm b/code/__DEFINES/xeno.dm index 878a591357..0f2454105c 100644 --- a/code/__DEFINES/xeno.dm +++ b/code/__DEFINES/xeno.dm @@ -239,6 +239,7 @@ #define XENO_HEALTH_TIER_14 950 * XENO_UNIVERSAL_HPMULT #define XENO_HEALTH_QUEEN 1000 * XENO_UNIVERSAL_HPMULT #define XENO_HEALTH_IMMORTAL 1200 * XENO_UNIVERSAL_HPMULT +#define XENO_HEALTH_KING 1500 * XENO_UNIVERSAL_HPMULT // Plasma bands #define XENO_NO_PLASMA 0 @@ -381,6 +382,7 @@ // Armor mods. Use the above defines for some guidance // In general, +20 armor should be a little more than +20% effective HP, however, // the higher the Xeno's base armor, the greater the effect. +#define XENO_ARMOR_MOD_TINY 2.5 #define XENO_ARMOR_MOD_VERY_SMALL 5 #define XENO_ARMOR_MOD_SMALL 10 #define XENO_ARMOR_MOD_MED 15 @@ -614,6 +616,7 @@ #define XENO_SHIELD_SOURCE_GARDENER 8 #define XENO_SHIELD_SOURCE_SHIELD_PILLAR 9 #define XENO_SHIELD_SOURCE_CUMULATIVE_GENERIC 10 +#define XENO_SHIELD_SOURCE_KING_BULWARKSPELL 11 //XENO CASTES #define XENO_CASTE_LARVA "Bloody Larva" @@ -643,12 +646,13 @@ #define XENO_CASTE_RAVAGER "Ravager" #define XENO_T3_CASTES list(XENO_CASTE_BOILER, XENO_CASTE_PRAETORIAN, XENO_CASTE_CRUSHER, XENO_CASTE_RAVAGER) //special +#define XENO_CASTE_KING "King" #define XENO_CASTE_QUEEN "Queen" #define XENO_CASTE_PREDALIEN "Predalien" #define XENO_CASTE_HELLHOUND "Hellhound" #define XENO_SPECIAL_CASTES list(XENO_CASTE_QUEEN, XENO_CASTE_PREDALIEN, XENO_CASTE_HELLHOUND) -#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_PRAETORIAN, XENO_CASTE_CRUSHER, XENO_CASTE_RAVAGER, XENO_CASTE_QUEEN, XENO_CASTE_PREDALIEN, XENO_CASTE_HELLHOUND) +#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_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/_globalvars/misc.dm b/code/_globalvars/misc.dm index 74f3149610..7cd20cb9e7 100644 --- a/code/_globalvars/misc.dm +++ b/code/_globalvars/misc.dm @@ -55,3 +55,5 @@ GLOBAL_VAR(obfs_x) GLOBAL_VAR(obfs_y) GLOBAL_VAR_INIT(ai_xeno_weeding, TRUE) + +GLOBAL_LIST_INIT(alldirs, list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST)) diff --git a/code/datums/langchat/langchat.dm b/code/datums/langchat/langchat.dm index a447861231..4348cb32b7 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/king/langchat_height = 64 #define LANGCHAT_LONGEST_TEXT 64 #define LANGCHAT_WIDTH 96 diff --git a/code/datums/xeno_shields/shield_types/king_shield.dm b/code/datums/xeno_shields/shield_types/king_shield.dm new file mode 100644 index 0000000000..c8a54bf2c5 --- /dev/null +++ b/code/datums/xeno_shields/shield_types/king_shield.dm @@ -0,0 +1,20 @@ +/// Shield can be equal to a maximum of percent_maxhealth_damagecap of the receiver's max hp +/datum/xeno_shield/king_shield + duration = 10 SECONDS + decay_amount_per_second = 100 + /// The maximum damage multiplier of max health to apply in a hit + var/percent_maxhealth_damagecap = 0.1 + +/datum/xeno_shield/king_shield/on_hit(damage) + var/relative_damage_cap = linked_xeno.maxHealth * percent_maxhealth_damagecap + + if(damage > relative_damage_cap) + damage = relative_damage_cap + return ..(damage) + + +/datum/xeno_shield/king_shield/on_removal() + . = ..() + if(linked_xeno) + // Remove the shield overlay early + linked_xeno.remove_suit_layer() diff --git a/code/datums/xeno_shields/xeno_shield.dm b/code/datums/xeno_shields/xeno_shield.dm index 49f04f19e6..659884d669 100644 --- a/code/datums/xeno_shields/xeno_shield.dm +++ b/code/datums/xeno_shields/xeno_shield.dm @@ -79,11 +79,14 @@ xeno_shields += new_shield new_shield.last_damage_taken = world.time // So we don't insta-delete our shield. - new_shield.decay_amount_per_second = decay_amount_per_second + if(decay_amount_per_second) + new_shield.decay_amount_per_second = decay_amount_per_second + if(duration) + new_shield.duration = duration new_shield.linked_xeno = src - if(duration > -1) - addtimer(CALLBACK(new_shield, TYPE_PROC_REF(/datum/xeno_shield, begin_decay)), duration) + if(new_shield.duration > -1) + addtimer(CALLBACK(new_shield, TYPE_PROC_REF(/datum/xeno_shield, begin_decay)), new_shield.duration) overlay_shields() return new_shield diff --git a/code/game/jobs/role_authority.dm b/code/game/jobs/role_authority.dm index 42ffc22570..f46f0dac21 100644 --- a/code/game/jobs/role_authority.dm +++ b/code/game/jobs/role_authority.dm @@ -773,6 +773,8 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou M = /mob/living/carbon/xenomorph/predalien if(XENO_CASTE_HELLHOUND) M = /mob/living/carbon/xenomorph/hellhound + if(XENO_CASTE_KING) + M = /mob/living/carbon/xenomorph/king return M diff --git a/code/game/objects/effects/effect_system/smoke.dm b/code/game/objects/effects/effect_system/smoke.dm index 4cd3c4a37d..9e472ec5d7 100644 --- a/code/game/objects/effects/effect_system/smoke.dm +++ b/code/game/objects/effects/effect_system/smoke.dm @@ -681,6 +681,22 @@ // XENO SMOKES +/obj/effect/particle_effect/smoke/king + opacity = FALSE + color = "#000000" + icon = 'icons/effects/effects.dmi' + icon_state = "sparks" + anchored = TRUE + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + layer = BELOW_OBJ_LAYER + time_to_live = 5 + spread_speed = 1 + pixel_x = 0 + pixel_y = 0 + +/datum/effect_system/smoke_spread/king_doom + smoke_type = /obj/effect/particle_effect/smoke/king + /datum/effect_system/smoke_spread/xeno_acid smoke_type = /obj/effect/particle_effect/smoke/xeno_burn diff --git a/code/game/objects/effects/temporary_visuals.dm b/code/game/objects/effects/temporary_visuals.dm index 1f3800fa01..97612a3a8f 100644 --- a/code/game/objects/effects/temporary_visuals.dm +++ b/code/game/objects/effects/temporary_visuals.dm @@ -21,6 +21,19 @@ . = ..() deltimer(timerid) +//----------------------------------------- +//HEAVY IMPACT +//----------------------------------------- + +/obj/effect/temp_visual/heavy_impact + icon = 'icons/effects/heavyimpact.dmi' + icon_state = "heavyimpact" + duration = 1.3 SECONDS + +/obj/effect/temp_visual/heavyimpact/Initialize(mapload) + . = ..() + flick("heavyimpact", src) + /obj/effect/temp_visual/dir_setting randomdir = FALSE diff --git a/code/modules/admin/game_master/game_master.dm b/code/modules/admin/game_master/game_master.dm index 874bc14ecf..784f69113c 100644 --- a/code/modules/admin/game_master/game_master.dm +++ b/code/modules/admin/game_master/game_master.dm @@ -29,7 +29,7 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100) // Spawn stuff #define DEFAULT_SPAWN_XENO_STRING XENO_CASTE_DRONE -#define GAME_MASTER_AI_XENOS list(XENO_CASTE_DRONE, XENO_CASTE_RUNNER, XENO_CASTE_LURKER, XENO_CASTE_CRUSHER, XENO_CASTE_FACEHUGGER) +#define GAME_MASTER_AI_XENOS list(XENO_CASTE_DRONE, XENO_CASTE_RUNNER, XENO_CASTE_LURKER, XENO_CASTE_CRUSHER, XENO_CASTE_FACEHUGGER, XENO_CASTE_KING) #define DEFAULT_SPAWN_HIVE_STRING XENO_HIVE_NORMAL #define DEFAULT_XENO_AMOUNT_TO_SPAWN 1 diff --git a/code/modules/admin/player_panel/actions/transform.dm b/code/modules/admin/player_panel/actions/transform.dm index df2eb87f5c..ca20829357 100644 --- a/code/modules/admin/player_panel/actions/transform.dm +++ b/code/modules/admin/player_panel/actions/transform.dm @@ -140,6 +140,11 @@ GLOBAL_LIST_INIT(pp_transformables, list( name = XENO_CASTE_PREDALIEN, key = /mob/living/carbon/xenomorph/predalien, color = "purple" + ), + list( + name = XENO_CASTE_KING, + key = /mob/living/carbon/xenomorph/king, + color="purple" ) ), diff --git a/code/modules/cm_aliens/XenoStructures.dm b/code/modules/cm_aliens/XenoStructures.dm index 3cbac124b3..d2ccd0cdea 100644 --- a/code/modules/cm_aliens/XenoStructures.dm +++ b/code/modules/cm_aliens/XenoStructures.dm @@ -919,6 +919,16 @@ E.source = initial(name) qdel(src) +/obj/effect/alien/resin/king_cocoon + name = "alien cocoon" + desc = "A large pulsating cocoon." + icon = 'icons/obj/structures/alien/xenoKingHatchery.dmi' + icon_state = "growing" // I wanna to set hatching/hatched state on MMB game panel soon + health = 4000 + pixel_x = -48 + pixel_y = -64 + density = TRUE + plane = FLOOR_PLANE /datum/automata_cell/acid neighbor_type = NEIGHBORS_NONE diff --git a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm index 8d3367ee68..768445995a 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm @@ -688,8 +688,10 @@ return "Moderate" if(3 to 3.9) return "Strong" - if(4 to INFINITY) + if(4 to 4.9) return "Very Strong" + if(4.9 to INFINITY) + return "Overwhelming" /mob/living/carbon/xenomorph/proc/start_tracking_resin_mark(obj/effect/alien/resin/marker/target) if(!target) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/king/king_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/king/king_abilities.dm new file mode 100644 index 0000000000..68d9c21e00 --- /dev/null +++ b/code/modules/mob/living/carbon/xenomorph/abilities/king/king_abilities.dm @@ -0,0 +1,153 @@ +/// 3 x 3 damage centred on the xenomorph +/datum/action/xeno_action/onclick/rend + name = "Rend" + action_icon_state = "rav_eviscerate" + ability_name = "rend" + macro_path = /datum/action_xeno_action/verb/verb_rend + xeno_cooldown = 2.5 SECONDS + plasma_cost = 25 + ability_primacy = XENO_PRIMARY_ACTION_1 + + var/damage = 25 + var/list/humans_near = list() + + default_ai_action = TRUE + ai_prob_chance = 100 + + var/slash_sounds = list('sound/weapons/alien_claw_flesh1.ogg', 'sound/weapons/alien_claw_flesh2.ogg', 'sound/weapons/alien_claw_flesh3.ogg', 'sound/weapons/alien_claw_flesh4.ogg', 'sound/weapons/alien_claw_flesh5.ogg', 'sound/weapons/alien_claw_flesh6.ogg') + +/datum/action/xeno_action/onclick/rend/process_ai(mob/living/carbon/xenomorph/X, delta_time) + for(var/mob/living/carbon/human/inrange in view(X)) + var/distance_check = get_dist(X, inrange) + + if(distance_check < 3) + humans_near |= inrange + continue + + if(!DT_PROB(ai_prob_chance, delta_time) || length(humans_near) < 2 || get_dist(X, X.current_target) < 3 || X.action_busy) + humans_near.RemoveAll() + return + + use_ability_async() + humans_near.RemoveAll() + + +/// Screech which puts out lights in a 7 tile radius, slows and dazes. +/datum/action/xeno_action/onclick/doom + name = "Doom" + action_icon_state = "screech" + ability_name = "doom" + macro_path = /datum/action_xeno_action/verb/verb_doom + xeno_cooldown = 45 SECONDS + plasma_cost = 50 + ability_primacy = XENO_PRIMARY_ACTION_2 + + var/daze_length_seconds = 1 + var/slow_length_seconds = 4 + var/list/humans_near = list() + + default_ai_action = TRUE + ai_prob_chance = 80 + +/datum/action/xeno_action/onclick/doom/process_ai(mob/living/carbon/xenomorph/X, delta_time) + for(var/mob/living/carbon/human/inrange in view(X)) + var/distance_check = get_dist(X, inrange) + + if(distance_check < 5) + humans_near |= inrange + continue + + if(!DT_PROB(ai_prob_chance, delta_time) || length(humans_near) < 3 || get_dist(X, X.current_target) > 3 || X.action_busy) + humans_near.RemoveAll() + return + + use_ability_async() + humans_near.RemoveAll() + +/// Leap ability, crashing down dealing major damage to mobs and structures in the area. +/datum/action/xeno_action/onclick/destroy + name = "Destroy" + action_icon_state = "charge" + ability_name = "destroy" + macro_path = /datum/action/xeno_action/verb/verb_destroy + action_type = XENO_ACTION_ACTIVATE + xeno_cooldown = 15 SECONDS + plasma_cost = 0 + ability_primacy = XENO_PRIMARY_ACTION_3 + + var/range = 7 + var/leaping = FALSE + + default_ai_action = TRUE + ai_prob_chance = 60 + +/datum/action/xeno_action/onclick/destroy/process_ai(mob/living/carbon/xenomorph/X, delta_time) + var/distance_check = get_dist(X, X.current_target) + + if(distance_check > 7) + return + + if(!DT_PROB(ai_prob_chance, delta_time) || get_dist(X, X.current_target) < 2 || X.action_busy) + return + + use_ability_async() + +/// Shield ability, limits the amount of damage from a single instance of damage to 10% of the xenomorph's max health. +/datum/action/xeno_action/onclick/king_shield + name = "Bulwark of the Hive" + action_icon_state = "soak" + ability_name = "legion_shield" + macro_path = /datum/action_xeno_action/verb/king_shield + action_type = XENO_ACTION_ACTIVATE + xeno_cooldown = 60 SECONDS + plasma_cost = 0 + ability_primacy = XENO_PRIMARY_ACTION_4 + + default_ai_action = TRUE + ai_prob_chance = 80 + + var/shield_duration = 10 SECONDS + var/area_of_effect = 6 + var/shield_amount = 100 + var/list/xenos_near = list() + +/datum/action/xeno_action/onclick/king_shield/process_ai(mob/living/carbon/xenomorph/X, delta_time) + for(var/mob/living/carbon/xenomorph/inrange in view(X)) + var/distance_check = get_dist(X, inrange) + + if(distance_check < 5) + xenos_near |= inrange + continue + + if(!DT_PROB(ai_prob_chance, delta_time) || length(xenos_near) < 4 || X.action_busy) + xenos_near.RemoveAll() + return + + use_ability_async() + xenos_near.RemoveAll() + +/datum/action/xeno_action/onclick/king_frenzy + name = "King_frenzy" + action_icon_state = "charge_spit" + ability_name = "King Frenzy" + macro_path = /datum/action/xeno_action/verb/verb_charge_spit + ability_primacy = XENO_PRIMARY_ACTION_5 + action_type = XENO_ACTION_ACTIVATE + plasma_cost = 50 + xeno_cooldown = 6 SECONDS + + // Config + var/duration = 40 + var/speed_buff_amount = 1.2 // Go from shit slow to kindafast + + var/buffs_active = FALSE + + default_ai_action = TRUE + ai_prob_chance = 80 + +/datum/action/xeno_action/onclick/king_frenzy/process_ai(mob/living/carbon/xenomorph/X, delta_time) + + if(!DT_PROB(ai_prob_chance, delta_time) || get_dist(X, X.current_target) < 2 || X.action_busy) + return + + use_ability_async() diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/king/king_macros.dm b/code/modules/mob/living/carbon/xenomorph/abilities/king/king_macros.dm new file mode 100644 index 0000000000..2df965861e --- /dev/null +++ b/code/modules/mob/living/carbon/xenomorph/abilities/king/king_macros.dm @@ -0,0 +1,27 @@ +/datum/action_xeno_action/verb/verb_rend() + set category = "Alien" + set name = "Rend" + set hidden = TRUE + var/action_name = "Rend" + handle_xeno_macro(src, action_name) + +/datum/action/xeno_action/verb/verb_destroy() + set category = "Alien" + set name = "Destroy" + set hidden = TRUE + var/action_name = "Destroy" + handle_xeno_macro(src, action_name) + +/datum/action_xeno_action/verb/verb_doom() + set category = "Alien" + set name = "Doom" + set hidden = TRUE + var/action_name = "Doom" + handle_xeno_macro(src, action_name) + +/datum/action_xeno_action/verb/king_shield() + set category = "Alien" + set name = "Bulwark" + set hidden = TRUE + var/action_name = "Bulwark" + handle_xeno_macro(src, action_name) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/king/king_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/king/king_powers.dm new file mode 100644 index 0000000000..738d49aba4 --- /dev/null +++ b/code/modules/mob/living/carbon/xenomorph/abilities/king/king_powers.dm @@ -0,0 +1,383 @@ +/* + REND ABILITY + 3x3 aoe damage centred on the King. Basic ability, spammable, low damage. +*/ + +/datum/action/xeno_action/onclick/rend/use_ability() + var/mob/living/carbon/xenomorph/xeno = owner + XENO_ACTION_CHECK_USE_PLASMA(xeno) + + xeno.spin_circle() + xeno.emote("hiss") + for(var/mob/living/carbon/carbon in orange(2, xeno) - xeno) + + if(carbon.stat == DEAD) + continue + if(xeno.can_not_harm(carbon)) + continue + carbon.apply_armoured_damage(damage) + carbon.last_damage_data = create_cause_data(initial(xeno.name), xeno) + xeno.flick_attack_overlay(carbon, "tail") + to_chat(carbon, SPAN_DANGER("[xeno] cuts you with its razor sharp tail.")) + log_attack("[key_name(xeno)] hit [key_name(carbon)] with [name]") + playsound(carbon, pick(slash_sounds), 30, TRUE) + + xeno.visible_message(SPAN_DANGER("[xeno] slices around itself!"), SPAN_NOTICE("We slice around ourself!")) + apply_cooldown() + ..() + + + +/* + DOOM ABILITY + King channels for a while shrieks which turns off all lights in the vicinity and applies a mild daze + Medium cooldown soft CC +*/ + +/datum/action/xeno_action/onclick/doom/use_ability(atom/target) + var/mob/living/carbon/xenomorph/xeno = owner + XENO_ACTION_CHECK_USE_PLASMA(xeno) + + playsound(xeno, 'sound/voice/deep_alien_screech2.ogg', 75, 0, status = 0) + xeno.visible_message(SPAN_XENOHIGHDANGER("[xeno] emits an raspy guttural roar!")) + xeno.create_shriekwave() + + var/datum/effect_system/smoke_spread/king_doom/smoke_gas = new /datum/effect_system/smoke_spread/king_doom + smoke_gas.set_up(7, 0, get_turf(xeno), null, 6) + smoke_gas.start() + + for(var/atom/current_atom as anything in view(owner)) + if(istype(current_atom, /obj/item/device)) + var/obj/item/device/potential_lightsource = current_atom + + var/time_to_extinguish = get_dist(owner, potential_lightsource) DECISECONDS + + //Flares + if(istype(potential_lightsource, /obj/item/device/flashlight/flare)) + var/obj/item/device/flashlight/flare/flare = potential_lightsource + addtimer(CALLBACK(flare, TYPE_PROC_REF(/obj/item/device/flashlight/flare/, burn_out)), time_to_extinguish) + + //Flashlights + if(istype(potential_lightsource, /obj/item/device/flashlight)) + var/obj/item/device/flashlight/flashlight = potential_lightsource + addtimer(CALLBACK(flashlight, TYPE_PROC_REF(/obj/item/device/flashlight, turn_off_light)), time_to_extinguish) + + else if(ishuman(current_atom)) + // "Confuse" and slow humans in the area and turn off their armour lights. + var/mob/living/carbon/human/human = current_atom + + human.EyeBlur(daze_length_seconds) + human.Daze(daze_length_seconds) + human.Superslow(slow_length_seconds) + human.add_client_color_matrix("doom", 99, color_matrix_multiply(color_matrix_saturation(0), color_matrix_from_string("#eeeeee"))) + human.overlay_fullscreen("doom", /atom/movable/screen/fullscreen/flash/noise/nvg) + addtimer(CALLBACK(human, TYPE_PROC_REF(/mob, remove_client_color_matrix), "doom", 1 SECONDS), 5 SECONDS) + addtimer(CALLBACK(human, TYPE_PROC_REF(/mob, clear_fullscreen), "doom", 0.5 SECONDS), 5 SECONDS) + + to_chat(human, SPAN_HIGHDANGER("[xeno]'s roar overwhelms your entire being!")) + shake_camera(human, 6, 1) + + var/time_to_extinguish = get_dist(owner, human) SECONDS + var/obj/item/clothing/suit/suit = human.get_item_by_slot(WEAR_JACKET) + if(istype(suit, /obj/item/clothing/suit/storage/marine)) + var/obj/item/clothing/suit/storage/marine/armour = suit + addtimer(CALLBACK(armour, TYPE_PROC_REF(/atom, turn_light), null, FALSE), time_to_extinguish) + + if(!istype(current_atom, /mob/dead)) + var/power = current_atom.light_power + var/range = current_atom.light_range + if(power > 0 && range > 0) + if(current_atom.light_system != MOVABLE_LIGHT) + current_atom.set_light(l_range=0) + addtimer(CALLBACK(current_atom, TYPE_PROC_REF(/atom, set_light), range, power), 10 SECONDS) + else + current_atom.set_light_range(0) + addtimer(CALLBACK(current_atom, TYPE_PROC_REF(/atom, set_light_range), range), 10 SECONDS) + + + apply_cooldown() + ..() + +/* + BULWARK ABILITY - AoE shield + Long cooldown defensive ability, provides a shield which caps damage taken to 10% of the xeno's max health per individual source of damage. +*/ + +/datum/action/xeno_action/onclick/king_shield/use_ability() + var/mob/living/carbon/xenomorph/xeno = owner + + XENO_ACTION_CHECK_USE_PLASMA(xeno) + + + playsound(xeno.loc, 'sound/voice/deep_alien_screech.ogg', 50, 0, status = 0) + // Add our shield + start_shield(xeno) + + // Add other xeno's shields in AoE range + for(var/mob/living/carbon/xenomorph/xeno_in_aoe in range(area_of_effect, xeno)) + if(xeno_in_aoe == xeno) + continue + if(xeno_in_aoe.stat == DEAD) + continue + if(xeno_in_aoe.hivenumber != xeno.hivenumber) + continue + start_shield(xeno_in_aoe) + xeno.beam(xeno_in_aoe, "purple_lightning", time = 4 SECONDS) + + apply_cooldown() + return ..() + +/datum/action/xeno_action/onclick/king_shield/proc/start_shield(mob/living/carbon/xenomorph/xeno) + var/datum/xeno_shield/shield = xeno.add_xeno_shield(shield_amount, XENO_SHIELD_SOURCE_KING_BULWARKSPELL, /datum/xeno_shield/king_shield) + if(shield) + xeno.create_shield(shield_duration, "purple_animated_shield_full") + + +/* + DESTROY ABILITY + King leaps into the air and crashes down damaging cades and mobs in a 3x3 area centred on him. + Long cooldown high damage ability, massive damage against cades, highly telegraphed. +*/ + +#define LEAP_HEIGHT 210 //how high up leaps go, in pixels +#define LEAP_DIRECTION_CHANGE_RANGE 5 //the range our x has to be within to not change the direction we slam from + +/datum/action/xeno_action/onclick/destroy/use_ability(mob/living/target) + var/mob/living/carbon/xenomorph/xeno = owner + target = xeno.current_target + XENO_ACTION_CHECK(xeno) + + if(get_dist(owner, target) > range) + to_chat(xeno, SPAN_XENONOTICE("Sorry bud, you can't use this ability!")) + return + + var/turf/target_turf = get_turf(target) + + if(!target_turf || target_turf.density) + return + + if(istype(target_turf, /turf/open/space)) + return + + if(istype(target, /obj/vehicle/multitile)) + return + + var/list/leap_line = get_line(xeno, target) + for(var/turf/jump_turf in leap_line) + if(jump_turf.density) + return + + for(var/obj/structure/possible_blocker in jump_turf) + if(possible_blocker.density && !possible_blocker.throwpass) + return + + if(!check_and_use_plasma_owner()) + to_chat(xeno, SPAN_XENONOTICE("We don't have enough plasma to use [name].")) + return + + var/turf/template_turf = get_step(target_turf, SOUTHWEST) + + to_chat(xeno, SPAN_XENONOTICE("Our muscles tense as we prepare ourself for a giant leap.")) + ADD_TRAIT(owner, TRAIT_IMMOBILIZED, "WaitBeforeMove") // idk, that probably works + xeno.make_jittery(1 SECONDS) + if(!do_after(xeno, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE)) + to_chat(xeno, SPAN_XENONOTICE("We relax our muslces and end our leap.")) + return + if(leaping || !target) + return + // stop target movement + leaping = TRUE + ADD_TRAIT(owner, TRAIT_UNDENSE, "Destroy") + ADD_TRAIT(owner, TRAIT_IMMOBILIZED, "Destroy") + owner.visible_message(SPAN_WARNING("[owner] takes a giant leap into the air!")) + + var/negative + var/initial_x = owner.x + if(target.x < initial_x) //if the target's x is lower than ours, go to the left + negative = TRUE + else if(target.x > initial_x) + negative = FALSE + else if(target.x == initial_x) //if their x is the same, pick a direction + negative = prob(50) + + owner.face_atom(target) + owner.emote("roar") + + //Initial visual + var/obj/effect/temp_visual/king_leap/leap_visual = new(owner.loc, negative, owner.dir) + new /obj/effect/xenomorph/xeno_telegraph/king_attack_template(template_turf, 20) + + negative = !negative //invert it for the descent later + + var/oldtransform = owner.transform + owner.alpha = 255 + animate(owner, alpha = 0, transform = matrix()*0.9, time = 3, easing = BOUNCE_EASING) + for(var/i in 1 to 3) + sleep(1 DECISECONDS) + if(QDELETED(owner) || owner.stat == DEAD) //we got hit and died, rip us + + //Initial effect + qdel(leap_visual) + + if(owner.stat == DEAD) + leaping = FALSE + animate(owner, alpha = 255, transform = oldtransform, time = 0, flags = ANIMATION_END_NOW) //reset immediately + return + + owner.mouse_opacity = MOUSE_OPACITY_TRANSPARENT + SLEEP_CHECK_DEATH(7, owner) + + while(target_turf && owner.loc != target_turf) + owner.forceMove(get_step(owner, get_dir(owner, target_turf))) + SLEEP_CHECK_DEATH(0.5, owner) + + animate(owner, alpha = 100, transform = matrix()*0.7, time = 7) + var/descentTime = 3 + + if(negative) + if(ISINRANGE(owner.x, initial_x + 1, initial_x + LEAP_DIRECTION_CHANGE_RANGE)) + negative = FALSE + else + if(ISINRANGE(owner.x, initial_x - LEAP_DIRECTION_CHANGE_RANGE, initial_x - 1)) + negative = TRUE + + new /obj/effect/temp_visual/king_leap/end(owner.loc, negative, owner.dir) + + SLEEP_CHECK_DEATH(descentTime, owner) + animate(owner, alpha = 255, transform = oldtransform, descentTime) + owner.mouse_opacity = initial(owner.mouse_opacity) + playsound(owner.loc, 'sound/effects/meteorimpact.ogg', 200, TRUE) + + /// Effects for landing + new /obj/effect/temp_visual/heavy_impact(owner.loc) + for(var/step in CARDINAL_ALL_DIRS) + new /obj/effect/temp_visual/heavy_impact(get_step(owner.loc, step)) + + // Actual Damaging Effects - Add stuff for cades - NEED TELEGRAPHS NEED EFFECTS + + // Mobs first high damage and knockback away from centre + for(var/mob/living/carbon/carbon in orange(2, owner) - owner) + if(xeno.can_not_harm(carbon)) + continue + carbon.adjustBruteLoss(75) + if(!QDELETED(carbon)) // Some mobs are deleted on death + log_attack("[key_name(xeno)] hit [key_name(carbon)] with [name]") + carbon.last_damage_data = create_cause_data(initial(xeno.name), xeno) + var/throw_dir = get_dir(owner, carbon) + if(carbon.loc == owner.loc) + throw_dir = pick(GLOB.alldirs) + var/throwtarget = get_edge_target_turf(owner, throw_dir) + carbon.throw_atom(throwtarget, 2, SPEED_REALLY_FAST, owner, TRUE) + carbon.KnockDown(0.5) + xeno.visible_message(SPAN_WARNING("[carbon] is thrown clear of [owner]!")) + + // Any items get thrown away + for(var/obj/item/item in orange(2, owner)) + if(!QDELETED(item)) + var/throw_dir = get_dir(owner, item) + if(item.loc == owner.loc) + throw_dir = pick(GLOB.alldirs) + var/throwtarget = get_edge_target_turf(owner, throw_dir) + item.throw_atom(throwtarget, 2, SPEED_REALLY_FAST, owner, TRUE) + + for(var/obj/structure/structure in orange(2, owner)) + structure.ex_act(300, get_dir(owner, structure)) + + for(var/mob/living in range(7, owner)) + shake_camera(living, 15, 1) + + REMOVE_TRAIT(owner, TRAIT_UNDENSE, "Destroy") + REMOVE_TRAIT(owner, TRAIT_IMMOBILIZED, "Destroy") + REMOVE_TRAIT(owner, TRAIT_IMMOBILIZED, "WaitBeforeMove") + + SLEEP_CHECK_DEATH(1, owner) + leaping = FALSE + apply_cooldown() + ..() + +/datum/action/xeno_action/onclick/destroy/proc/second_template(turf/template_turf) + new /obj/effect/xenomorph/xeno_telegraph/king_attack_template(template_turf, 10) + +/obj/effect/temp_visual/king_leap + icon = 'icons/mob/xenos/king.dmi' + icon_state = "Normal King Charging" + layer = 4.7 + plane = -4 + pixel_x = -32 + duration = 2 + randomdir = FALSE + +/obj/effect/temp_visual/king_leap/Initialize(mapload, negative, dir) + . = ..() + setDir(dir) + INVOKE_ASYNC(src, PROC_REF(flight), negative) + +/obj/effect/temp_visual/king_leap/proc/flight(negative) + if(negative) + animate(src, pixel_x = -LEAP_HEIGHT*0.1, pixel_z = LEAP_HEIGHT*0.15, time = 3, easing = BOUNCE_EASING) + else + animate(src, pixel_x = LEAP_HEIGHT*0.1, pixel_z = LEAP_HEIGHT*0.15, time = 3, easing = BOUNCE_EASING) + sleep(0.3 SECONDS) + icon_state = "Normal King Charging" + if(negative) + animate(src, pixel_x = -LEAP_HEIGHT, pixel_z = LEAP_HEIGHT, time = 7) + else + animate(src, pixel_x = LEAP_HEIGHT, pixel_z = LEAP_HEIGHT, time = 7) + +/obj/effect/temp_visual/king_leap/end + pixel_x = LEAP_HEIGHT + pixel_z = LEAP_HEIGHT + duration = 2 + +/obj/effect/temp_visual/king_leap/end/flight(negative) + if(negative) + pixel_x = -LEAP_HEIGHT + animate(src, pixel_x = -16, pixel_z = 0, time = 5) + else + animate(src, pixel_x = -16, pixel_z = 0, time = 5) + +/obj/effect/xenomorph/xeno_telegraph/king_attack_template + icon = 'icons/effects/96x96.dmi' + icon_state = "xenolanding" + layer = BELOW_MOB_LAYER + +/obj/effect/xenomorph/xeno_telegraph/king_attack_template/yellow + icon_state = "xenolandingyellow" + +/datum/action/xeno_action/onclick/king_frenzy/use_ability(atom/A) + var/mob/living/carbon/xenomorph/king = owner + + if (!action_cooldown_check()) + return + + if (!istype(king) || !king.check_state()) + return + + if (buffs_active) + return + + if (!check_and_use_plasma_owner()) + return + + king.create_custom_empower(icolor = "#ec7878", ialpha = 200, small_xeno = FALSE) + buffs_active = TRUE + owner.add_filter("Enrage", 1, list("type" = "outline", "color" = "#7c3e3e", "size" = 1)) + king.speed_modifier -= speed_buff_amount + king.recalculate_speed() + owner.visible_message(SPAN_WARNING("[owner] enrages!")) + + addtimer(CALLBACK(src, PROC_REF(remove_effects)), duration) + + apply_cooldown() + return ..() + +/datum/action/xeno_action/onclick/king_frenzy/proc/remove_effects() + var/mob/living/carbon/xenomorph/king = owner + + if (!istype(king)) + return + + owner.remove_filter("Enrage") + king.speed_modifier += speed_buff_amount + king.recalculate_speed() + buffs_active = FALSE diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/ravager/ravager_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/ravager/ravager_powers.dm index e876d97c4d..11054e86ce 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/ravager/ravager_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/ravager/ravager_powers.dm @@ -462,7 +462,7 @@ shield.shrapnel_amount = shield_shrapnel_amount xeno.overlay_shields() - xeno.create_shield(shield_duration) + xeno.create_shield(shield_duration, "shield2") shield_active = TRUE button.icon_state = "template_active" addtimer(CALLBACK(src, PROC_REF(remove_shield)), shield_duration) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm b/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm index 59c9bf9d9e..d54b964b14 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm @@ -486,3 +486,6 @@ track_xeno_ability_stats() if(action_start_message) to_chat(owner, SPAN_NOTICE(action_start_message)) + +#define XENO_ACTION_CHECK(X) if(!X.check_state() || !action_cooldown_check() || !check_plasma_owner(src.plasma_cost)) return +#define XENO_ACTION_CHECK_USE_PLASMA(X) if(!X.check_state() || !action_cooldown_check() || !check_and_use_plasma_owner(src.plasma_cost)) return diff --git a/code/modules/mob/living/carbon/xenomorph/castes/king.dm b/code/modules/mob/living/carbon/xenomorph/castes/king.dm new file mode 100644 index 0000000000..56f4001720 --- /dev/null +++ b/code/modules/mob/living/carbon/xenomorph/castes/king.dm @@ -0,0 +1,113 @@ +/datum/caste_datum/king + caste_type = XENO_CASTE_KING + caste_desc = "The end of the line." + tier = 4 + + melee_damage_lower = XENO_DAMAGE_TIER_6 + melee_damage_upper = XENO_DAMAGE_TIER_8 + melee_vehicle_damage = XENO_DAMAGE_TIER_5 + max_health = XENO_HEALTH_KING * 4 // PVE X4 boss edition + plasma_gain = XENO_PLASMA_GAIN_TIER_3 + plasma_max = XENO_PLASMA_TIER_10 * 3 // PVE X3 boss edition + xeno_explosion_resistance = XENO_EXPLOSIVE_ARMOR_TIER_7 + armor_deflection = XENO_ARMOR_FACTOR_TIER_5 + speed = XENO_SPEED_TIER_1 + + evolves_to = null + deevolves_to = null + evolution_allowed = FALSE + can_vent_crawl = FALSE + + behavior_delegate_type = /datum/behavior_delegate/king_base + + tackle_min = 6 + tackle_max = 10 + + minimap_icon = "xenoqueen" + + fire_immunity = FIRE_IMMUNITY_NO_DAMAGE + +/mob/living/carbon/xenomorph/king + caste_type = XENO_CASTE_KING + name = XENO_CASTE_KING + desc = "A massive alien covered in spines and armoured plates." + icon = 'icons/mob/xenos/king.dmi' + icon_size = 64 + icon_state = "King Walking" + plasma_types = list(PLASMA_CHITIN) + pixel_x = -16 + old_x = -16 + mob_size = MOB_SIZE_IMMOBILE + tier = 4 + small_explosives_stun = FALSE + counts_for_slots = FALSE + + claw_type = CLAW_TYPE_VERY_SHARP + age = -1 + aura_strength = 6 + + base_actions = list( + /datum/action/xeno_action/onclick/xeno_resting, + /datum/action/xeno_action/onclick/regurgitate, + /datum/action/xeno_action/watch_xeno, + /datum/action/xeno_action/activable/tail_stab, + /datum/action/xeno_action/onclick/rend, + /datum/action/xeno_action/onclick/doom, + /datum/action/xeno_action/onclick/destroy, + /datum/action/xeno_action/onclick/king_shield, + /datum/action/xeno_action/onclick/king_frenzy, + /datum/action/xeno_action/onclick/emit_pheromones, + ) + + icon_xeno = 'icons/mob/xenos/king.dmi' + + bubble_icon = "alienroyal" + +/mob/living/carbon/xenomorph/king/Destroy() + UnregisterSignal(src, COMSIG_MOVABLE_PRE_MOVE) + + return ..() + +/mob/living/carbon/xenomorph/king/Initialize() + . = ..() + AddComponent(/datum/component/footstep, 2 , 35, 11, 4, "alien_footstep_large") + RegisterSignal(src, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(check_block)) + + playsound(src, 'sound/voice/alien_death_unused.ogg', 100, TRUE, 30, falloff = 5) + playsound(src, 'sound/voice/king_background.ogg', 100, TRUE, 30, falloff = 5) + for(var/mob/current_mob as anything in get_mobs_in_z_level_range(get_turf(src), 30) - src) + var/relative_dir = get_dir(current_mob, src) + var/final_dir = dir2text(relative_dir) + to_chat(current_mob, SPAN_HIGHDANGER("You hear a terrible roar from [final_dir ? "the [final_dir]" : "nearby"] as the VIOLENTLY ground shakes!")) + +/mob/living/carbon/xenomorph/king/proc/check_block(mob/king, turf/new_loc) + SIGNAL_HANDLER + for(var/mob/living/carbon/carbon in new_loc.contents) + if(isxeno(carbon)) + var/mob/living/carbon/xenomorph/xeno = carbon + if(xeno.hivenumber == src.hivenumber) + xeno.KnockDown((5 DECISECONDS) / GLOBAL_STATUS_MULTIPLIER) + else + xeno.KnockDown((1 SECONDS) / GLOBAL_STATUS_MULTIPLIER) + else + if(carbon.stat != DEAD) + carbon.apply_armoured_damage(20) + carbon.KnockDown((1 SECONDS) / GLOBAL_STATUS_MULTIPLIER) + + playsound(src, 'sound/weapons/alien_knockdown.ogg', 25, 1) + +/datum/behavior_delegate/king_base + name = "Base King Behavior Delegate" + +/mob/living/carbon/xenomorph/king/rogue + icon_xeno = 'icons/mob/xenos/rogueking.dmi' + icon = 'icons/mob/xenos/rogueking.dmi' + +/atom/movable/vis_obj/xeno_wounds/rogue + icon = 'icons/mob/xenos/roguedamage.dmi' + +/mob/living/carbon/xenomorph/king/rogue/Initialize(mapload, mob/living/carbon/xenomorph/old_xeno, hivenumber) + . = ..() + vis_contents -= wound_icon_holder + wound_icon_holder = new /atom/movable/vis_obj/xeno_wounds/rogue(null, src) + vis_contents += wound_icon_holder diff --git a/code/modules/mob/living/carbon/xenomorph/update_icons.dm b/code/modules/mob/living/carbon/xenomorph/update_icons.dm index 504cfa6685..0369bf2136 100644 --- a/code/modules/mob/living/carbon/xenomorph/update_icons.dm +++ b/code/modules/mob/living/carbon/xenomorph/update_icons.dm @@ -272,10 +272,10 @@ apply_overlay(X_SUIT_LAYER) addtimer(CALLBACK(src, PROC_REF(remove_overlay), X_SUIT_LAYER), 2 SECONDS) -/mob/living/carbon/xenomorph/proc/create_shield(duration = 10) +/mob/living/carbon/xenomorph/proc/create_shield(duration = 10, icon_state) remove_suit_layer() - overlays_standing[X_SUIT_LAYER] = image("icon"='icons/mob/xenos/overlay_effects64x64.dmi', "icon_state" = "shield2") + overlays_standing[X_SUIT_LAYER] = image("icon"='icons/mob/xenos/overlay_effects64x64.dmi', "icon_state" = icon_state) apply_overlay(X_SUIT_LAYER) addtimer(CALLBACK(src, PROC_REF(remove_overlay), X_SUIT_LAYER), duration) diff --git a/colonialmarines.dme b/colonialmarines.dme index d5e035d6d2..b482c5bb36 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -689,6 +689,7 @@ #include "code\datums\xeno_shields\xeno_shield.dm" #include "code\datums\xeno_shields\shield_types\crusher_shield.dm" #include "code\datums\xeno_shields\shield_types\hedgehog_shield.dm" +#include "code\datums\xeno_shields\shield_types\king_shield.dm" #include "code\datums\xeno_shields\shield_types\vanguard_shield.dm" #include "code\defines\procs\admin.dm" #include "code\defines\procs\announcement.dm" @@ -2011,6 +2012,9 @@ #include "code\modules\mob\living\carbon\xenomorph\abilities\facehugger\facehugger_powers.dm" #include "code\modules\mob\living\carbon\xenomorph\abilities\hivelord\hivelord_abilities.dm" #include "code\modules\mob\living\carbon\xenomorph\abilities\hivelord\hivelord_powers.dm" +#include "code\modules\mob\living\carbon\xenomorph\abilities\king\king_abilities.dm" +#include "code\modules\mob\living\carbon\xenomorph\abilities\king\king_macros.dm" +#include "code\modules\mob\living\carbon\xenomorph\abilities\king\king_powers.dm" #include "code\modules\mob\living\carbon\xenomorph\abilities\lesser_drone\lesser_drone_abilities.dm" #include "code\modules\mob\living\carbon\xenomorph\abilities\lesser_drone\lesser_drone_macros.dm" #include "code\modules\mob\living\carbon\xenomorph\abilities\lesser_drone\lesser_drone_powers.dm" @@ -2056,6 +2060,7 @@ #include "code\modules\mob\living\carbon\xenomorph\castes\Facehugger.dm" #include "code\modules\mob\living\carbon\xenomorph\castes\Hellhound.dm" #include "code\modules\mob\living\carbon\xenomorph\castes\Hivelord.dm" +#include "code\modules\mob\living\carbon\xenomorph\castes\king.dm" #include "code\modules\mob\living\carbon\xenomorph\castes\Larva.dm" #include "code\modules\mob\living\carbon\xenomorph\castes\lesser_drone.dm" #include "code\modules\mob\living\carbon\xenomorph\castes\Lurker.dm" diff --git a/icons/effects/96x96.dmi b/icons/effects/96x96.dmi index 521aea66d4..011bacb760 100644 Binary files a/icons/effects/96x96.dmi and b/icons/effects/96x96.dmi differ diff --git a/icons/effects/heavyimpact.dmi b/icons/effects/heavyimpact.dmi new file mode 100644 index 0000000000..e7af5cf49b Binary files /dev/null and b/icons/effects/heavyimpact.dmi differ diff --git a/icons/mob/xenos/king.dmi b/icons/mob/xenos/king.dmi new file mode 100644 index 0000000000..cee599ba7f Binary files /dev/null and b/icons/mob/xenos/king.dmi differ diff --git a/icons/mob/xenos/overlay_effects64x64.dmi b/icons/mob/xenos/overlay_effects64x64.dmi index 360aa4c54f..0be09311a7 100644 Binary files a/icons/mob/xenos/overlay_effects64x64.dmi and b/icons/mob/xenos/overlay_effects64x64.dmi differ diff --git a/icons/mob/xenos/roguedamage.dmi b/icons/mob/xenos/roguedamage.dmi new file mode 100644 index 0000000000..92ca12ed9d Binary files /dev/null and b/icons/mob/xenos/roguedamage.dmi differ diff --git a/icons/mob/xenos/rogueking.dmi b/icons/mob/xenos/rogueking.dmi new file mode 100644 index 0000000000..10ea568069 Binary files /dev/null and b/icons/mob/xenos/rogueking.dmi differ diff --git a/icons/mob/xenos/structures64x64.dmi b/icons/mob/xenos/structures64x64.dmi index 92ffdccf3b..410f1a6f49 100644 Binary files a/icons/mob/xenos/structures64x64.dmi and b/icons/mob/xenos/structures64x64.dmi differ diff --git a/icons/obj/structures/alien/xenoKingHatchery.dmi b/icons/obj/structures/alien/xenoKingHatchery.dmi new file mode 100644 index 0000000000..e7911658b3 Binary files /dev/null and b/icons/obj/structures/alien/xenoKingHatchery.dmi differ diff --git a/sound/voice/deep_alien_screech.ogg b/sound/voice/deep_alien_screech.ogg new file mode 100644 index 0000000000..994ac0abee Binary files /dev/null and b/sound/voice/deep_alien_screech.ogg differ diff --git a/sound/voice/deep_alien_screech2.ogg b/sound/voice/deep_alien_screech2.ogg new file mode 100644 index 0000000000..1f13e8859d Binary files /dev/null and b/sound/voice/deep_alien_screech2.ogg differ diff --git a/sound/voice/king_background.ogg b/sound/voice/king_background.ogg new file mode 100644 index 0000000000..4f37369868 Binary files /dev/null and b/sound/voice/king_background.ogg differ