diff --git a/code/modules/emotes/definitions/audible.dm b/code/modules/emotes/definitions/audible.dm
index 29031da5c3..1a5a4e3084 100644
--- a/code/modules/emotes/definitions/audible.dm
+++ b/code/modules/emotes/definitions/audible.dm
@@ -228,13 +228,10 @@
emote_message_3p_target = "trills at TARGET."
emote_sound = 'sound/voice/teshtrill.ogg' // Copyright CC BY-NC 3.0 Arnaud Coutancier (freesound.org) for the source audio.
-//CHOMPEdit Add Start
/decl/emote/audible/prbt
key = "prbt"
emote_message_1p = "You prbt."
emote_message_3p = "prbts."
emote_message_1p_target = "You prbt at TARGET."
emote_message_3p_target = "prbts at TARGET."
- emote_sound = 'sound/voice/prbt.ogg'
-
-//CHOMPEdit Add End
\ No newline at end of file
+ emote_sound = 'sound/voice/prbt.ogg'
\ No newline at end of file
diff --git a/modular_chomp/code/modules/emotes/definitions/audiable.dm b/modular_chomp/code/modules/emotes/definitions/audiable.dm
new file mode 100644
index 0000000000..c845d1ae39
--- /dev/null
+++ b/modular_chomp/code/modules/emotes/definitions/audiable.dm
@@ -0,0 +1,4 @@
+/decl/emote/audible/wheeze
+ ..()
+ emote_sound = 'modular_chomp/sound/voice/wheeze.ogg'
+
diff --git a/modular_chomp/code/modules/mob/living/emote.dm b/modular_chomp/code/modules/mob/living/emote.dm
new file mode 100644
index 0000000000..c5f36f01c8
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/emote.dm
@@ -0,0 +1,9 @@
+world/New()
+ . = ..()
+ //add stuff to default emote vars specifically for chomp.
+
+ //human default emotes
+ _human_default_emotes += /decl/emote/audible/wheeze
+
+ //simple_mob default emotes
+ _simple_mob_default_emotes += /decl/emote/audible/wheeze
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_mob/simple_mob_ch.dm b/modular_chomp/code/modules/mob/living/simple_mob/simple_mob.dm
similarity index 73%
rename from code/modules/mob/living/simple_mob/simple_mob_ch.dm
rename to modular_chomp/code/modules/mob/living/simple_mob/simple_mob.dm
index cf89e7c625..75bbf9ab2a 100644
--- a/code/modules/mob/living/simple_mob/simple_mob_ch.dm
+++ b/modular_chomp/code/modules/mob/living/simple_mob/simple_mob.dm
@@ -1,7 +1,19 @@
/mob/living/simple_mob
+ //speech sounds
+ var/list/speech_sounds = list()
+ var/speech_chance = 75 //mobs can be a bit more emotive than carbon/humans
+
//vars for vore_icons toggle control
- var/vore_icons_toggle = 1 // on by default, as is legacy
- var/vore_icons_cache = 0 // 0 by default. Going from ON to OFF should store vore_icons val here.
+ var/vore_icons_cache = null // null by default. Going from ON to OFF should store vore_icons val here, OFF to ON reset as null
+
+ //spitting projectiles
+ var/spitting = 0
+ var/spit_projectile = null // what our spit projectile is. Can be anything
+
+/mob/living/simple_mob/RangedAttack(var/atom/A)
+ if(!isnull(spit_projectile) && spitting)
+ Spit(A)
+ . = ..()
mob/living/simple_mob/verb/toggle_vore_icons()
@@ -11,18 +23,24 @@ mob/living/simple_mob/verb/toggle_vore_icons()
if(!vore_icons && !vore_icons_cache)
to_chat(src,"This simplemob has no vore sprite.")
- else if(vore_icons_toggle)
+ else if(isnull(vore_icons_cache))
vore_icons_cache = vore_icons
vore_icons = 0
- vore_icons_toggle = 0
to_chat(src,"Vore sprite disabled.")
else
vore_icons = vore_icons_cache
- vore_icons_toggle = 1
+ vore_icons_cache = null
to_chat(src,"Vore sprite enabled.")
update_icon()
+mob/living/simple_mob/handle_speech_sound()
+ if(speech_sounds && speech_sounds.len && prob(speech_chance))
+ var/list/returns[2]
+ returns[1] = sound(pick(speech_sounds))
+ returns[2] = 50
+ return returns
+ . = ..()
// a unique named update_transforms override to allow simplemobs going horizontal on lay/stun.
// This will not make the mob horizontal if the mob has a icon_rest != null
@@ -65,3 +83,5 @@ mob/living/simple_mob/verb/toggle_vore_icons()
// This from original living.dm update_transforms too
handle_status_indicators()
+
+
diff --git a/modular_chomp/code/modules/mob/living/simple_mob/simple_mob_abilities.dm b/modular_chomp/code/modules/mob/living/simple_mob/simple_mob_abilities.dm
new file mode 100644
index 0000000000..97e8fc607f
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/simple_mob/simple_mob_abilities.dm
@@ -0,0 +1,349 @@
+//Place for abilities that any /mob/living/simple_mob can use. Chomp-modular located file.
+/mob/living/simple_mob
+ // pounce proc specific
+ var/pouncing = 0 // if the user has toggled 'pounce mode' on
+ var/pounce_last = 0 // time of previous pounce
+ var/pounce_delay = 0 // pounce delay in game ticks
+ var/pounce_speed = 1 // pounce speed in idk?? 2 kinda fast tho
+
+ // icon handling for pounce. Has to handle a possible file change
+ var/icon_state_prepounce = null //icon state for 'preparing to pounce'. Null to not use any icon.
+
+ var/icon_pounce_cache = null // cache. If pounce icons are in different files, the procs will cache the original icon filepath here for resetting
+ var/icon_pounce = null // icon filepath for pouncing (Flying through air). Null if same as original icon path.
+ var/icon_state_pounce = null // icon state for pouncing (Flying through air). Null to not use any icon.
+ var/icon_pounce_x = 0 // icon pixelshift x
+ var/icon_pounce_y = 0 // icon pixelshift y
+ var/icon_pounce_x_old = null // icon pixelshift x cache to preserve original value
+ var/icon_pounce_y_old = null // icon pixelshift y cache to preserve original value
+
+ //spitting
+ var/spit_delay = 20 // maximum spit fire rate
+ var/spit_last = 0
+ var/icon_overlay_spit = null // spit iconstate
+ var/icon_overlay_spit_pounce = null // spit while pouncing
+
+ //speen
+ var/speen_last = 0
+ var/speen_delay = 80 // maximum spin spam
+
+
+
+/mob/living/simple_mob/update_icon()
+ . = ..()
+ //use prepounce or pounce sprites, if any
+ if(pouncing && (status_flags & LEAPING)) //pouncing, flying through the air
+ if(!isnull(icon_state_pounce)) // if state is set
+ icon_state = icon_state_pounce
+ if(!isnull(icon_pounce)) // if icon filepath is set and not equal to pounce cache
+ if(icon != icon_pounce) // prevent accidently writing the pounce icon into the icon cache
+ icon_pounce_cache = icon
+ icon = icon_pounce
+
+ else if(pouncing) //pre-pouncing
+ if(!isnull(icon_state_prepounce)) // if state is set
+ icon_state = icon_state_prepounce
+ if(!isnull(icon_pounce_cache)) // if cache is set
+ icon = icon_pounce_cache
+ icon_pounce_cache = null
+ else if(!isnull(icon_pounce_cache)) // not pouncing at all but cache is still set
+ icon = icon_pounce_cache
+ icon_pounce_cache = null
+
+ //handle pounce variant pixelshifting
+ // X first
+ if(icon_pounce_x) // if an offset is even assigned
+ if(pouncing)
+ if(status_flags & LEAPING) //Flying through air - set
+ if(isnull(icon_pounce_x_old)) // only set once
+ icon_pounce_x_old = pixel_x
+ pixel_x = icon_pounce_x
+ else //Prepouncing - reset
+ if(!isnull(icon_pounce_x_old)) //only act if not already cleared
+ pixel_x = icon_pounce_x_old
+ icon_pounce_x_old = null
+
+ else //Not pouncing or prepouncing - reset
+ if(!isnull(icon_pounce_x_old)) //only act if not already cleared
+ pixel_x = icon_pounce_x_old
+ icon_pounce_x_old = null
+ // Then Y
+ if(icon_pounce_y) // if an offset is even assigned
+ if(pouncing)
+ if(status_flags & LEAPING) //Flying through air - set
+ if(isnull(icon_pounce_y_old)) // only set once
+ icon_pounce_y_old = pixel_y
+ pixel_y = icon_pounce_y
+ else //Prepouncing - reset
+ if(!isnull(icon_pounce_y_old)) //only act if not already cleared
+ pixel_y = icon_pounce_y_old
+ icon_pounce_y_old = null
+
+ else //Not pouncing or prepouncing - reset
+ if(!isnull(icon_pounce_y_old)) //only act if not already cleared
+ pixel_y = icon_pounce_y_old
+ icon_pounce_y_old = null
+
+ // show spitting warning overlay, if any
+ if(spitting)
+ var/spiticon = null
+ if(!isnull(icon_overlay_spit) && (icon_state == icon_living))
+ spiticon = icon_overlay_spit
+ else if(!isnull(icon_overlay_spit_pounce) && (icon_state == icon_state_prepounce))
+ spiticon = icon_overlay_spit_pounce
+
+ if(spiticon)
+ var/image/I = image(icon, spiticon)
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
+ I.plane = MOB_PLANE
+ I.layer = MOB_LAYER
+ add_overlay(I)
+
+// Pouncing procs.
+// Pouncing consists of a series of functions:
+// > A user-toggleable enable or disable to 'pounce' or not pounce; "pouncing" toggled by a verb
+// > When enabled, just click somewhere not adjacent to pounce there.
+// > If you bump a person, stop on them and knock them over.
+// > If you bump a solid object, stun yourself and fall over
+/mob/living/simple_mob/proc/pounce_toggle()
+ set name = "Toggle Pouncing"
+ set desc = "Toggle pouncing. Doubleclick to pounce."
+ set category = "Abilities"
+
+ if(pouncing)
+ to_chat(src, "Pouncing toggled off.")
+ pouncing = 0
+ else
+ to_chat(src, "Pouncing toggled on! DoubleClick somewhere to pounce there.")
+ pouncing = 1
+ update_icon()
+
+// This is the on-double-click action.
+// We should alter them for the space of this specific proc, and then return them to what they were.
+/mob/living/simple_mob/DblClickOn(atom/A, P)
+ //trying/permitted to pounce
+ if(pouncing)
+ //able to pounce (not dead or stunned or on CD)
+ if(isliving(src) && !src.weakened && (world.time > pounce_last) && !(status_flags & LEAPING))
+ //can see pounce target
+ if((A in view(src, world.view)))
+ //make sure we're targetting a turf!
+ var/turf/T = get_turf(A)
+ //handle delay spam
+ pounce_last = world.time + pounce_delay
+ status_flags |= LEAPING
+
+ //deal with passflag - give flags if don't have, mark for removal. Prevent removal if already has flags.
+ var/foundpt = 0
+ var/foundpm = 0
+ if(pass_flags & PASSTABLE)
+ foundpt = 1
+ else
+ pass_flags |= PASSTABLE
+ if(pass_flags & PASSMOB)
+ foundpm = 1
+ else
+ pass_flags |= PASSMOB
+
+ // Do the pounce action
+
+ //flying = 1 //So we can thunk into things
+ hovering = 1 // So we don't hurt ourselves running off cliffs
+ playsound(src, "sound/weapons/punchmiss.ogg", 50, 1)
+
+ // throw_at returns FALSE if it will not call it's callback - useful to prevent state jamming
+ if(!throw_at(T, 10, pounce_speed, callback = CALLBACK(src, .proc/pouncefinish, foundpt, foundpm, T)))
+ if(status_flags & LEAPING)
+ status_flags &= ~LEAPING
+ flying = 0
+ hovering = 0
+ if(!foundpt)
+ pass_flags &= ~PASSTABLE
+ if(!foundpm)
+ pass_flags &= ~PASSMOB
+ else
+ to_chat(src, "Pouncing blind isn't wise!")
+ else
+ to_chat(src, "You can't do that right now!")
+ // some sanity incase the callback didn't fire for some reason
+ if(status_flags & LEAPING)
+ status_flags &= ~LEAPING
+ flying = 0
+ hovering = 0
+ pouncing = 0
+ update_icon()
+ else
+ . = ..()
+
+// callback to terminate leap mode. Reset passflag if passflag = 0 (Mob doesn't already have it)
+/mob/living/simple_mob/proc/pouncefinish(var/pt, var/pm, var/atom/T)
+ if(status_flags & LEAPING)
+ status_flags &= ~LEAPING
+ flying = 0
+ hovering = 0
+
+ if(!pt)
+ pass_flags &= ~PASSTABLE
+ if(!pm)
+ pass_flags &= ~PASSMOB
+
+ //PASSMOB is broken so we have to perform jank
+ //if we're adjacent to our target turf (but not ontop of it) and we are not blocked from moving there
+ if(Adjacent(T) && get_dist(src, T) && !LinkBlocked(src, T))
+ //if a mob is on our target (This should be the only reason we didn't arrive)
+ for(var/mob/living/M in T)
+ if(isliving(M) && M != src)
+ var/mob/living/LM = M
+
+ if(M.buckled) // make sure they fall when weakened
+ M.buckled.unbuckle_mob()
+
+ LM.Weaken(5)
+ playsound(src, get_sfx("punch"), 50, 1)
+ pouncing = 0
+ src.Move(T)
+
+ //did we fail to arrive at our destination?
+ if(get_dist(src, T))
+ pouncing = 0
+ update_icon()
+ src.Weaken(5)
+ playsound(src, get_sfx("punch"), 50, 1)
+ else
+ //if we arrived, and weren't blocked, and are STILL pouncing, see if we landed on any living things that didn't block us that ISN't ourselves lmfao.
+ if(pouncing)
+ for(var/mob/living/M in T)
+ if(isliving(M) && M != src)
+ var/mob/living/LM = M
+ LM.Weaken(5)
+ playsound(src, get_sfx("punch"), 50, 1)
+ pouncing = 0
+ update_icon()
+
+
+// ported from mob/living/carbon/human/species/xenomorph/alien_powers
+/mob/living/simple_mob/proc/Spit(var/atom/A)
+ if(isnull(spit_projectile))
+ return
+
+ if((spit_last + spit_delay) > world.time) //To prevent YATATATATATAT spitting.
+ to_chat(src, "You have not yet prepared your chemical glands. You must wait before spitting again.")
+ return
+ else
+ spit_last = world.time
+
+ if(spitting && incapacitated(INCAPACITATION_DISABLED))
+ to_chat(src, "You cannot spit in your current state.")
+ spitting = 0
+ update_icon()
+ return
+ else if(spitting)
+ //visible_message("[src] spits [spit_name] at \the [A]!", "You spit [spit_name] at \the [A].")
+ var/obj/item/projectile/P = new spit_projectile(get_turf(src))
+ P.firer = src
+ P.old_style_target(A)
+ P.fire()
+ playsound(src, 'sound/weapons/alien_spitacid.ogg', 25, 0)
+
+/mob/living/simple_mob/proc/neurotoxin()
+ set name = "Toggle Neurotoxic Spit"
+ set desc = "Readies a neurotoxic spit, which paralyzes the target for a short time if they are not wearing protective gear."
+ set category = "Abilities"
+
+ if(spitting)
+ to_chat(src, "You stop preparing to spit.")
+ spitting = 0
+ else
+ spitting = 1
+ spit_projectile = /obj/item/projectile/energy/neurotoxin
+ to_chat(src, "You prepare to spit neurotoxin.")
+ update_icon()
+
+/mob/living/simple_mob/proc/acidspit()
+ set name = "Toggle Acid Spit"
+ set desc = "Readies an acidic spit, which burns the target if they are not wearing protective gear."
+ set category = "Abilities"
+
+ if(spitting)
+ to_chat(src, "You stop preparing to spit.")
+ spitting = 0
+ else
+ spitting = 1
+ spit_projectile = /obj/item/projectile/energy/acid
+ to_chat(src, "You prepare to spit acid.")
+ update_icon()
+
+/mob/living/simple_mob/proc/corrosive_acid(O as obj|turf in oview(1)) //If they right click to corrode, an error will flash if its an invalid target./N
+ set name = "Corrosive Acid"
+ set desc = "Drench an object in acid, destroying it over time."
+ set category = "Abilities"
+
+ if(!(O in oview(1)))
+ to_chat(src, "[O] is too far away.")
+ return
+
+ // OBJ CHECK
+ var/cannot_melt
+ if(isobj(O))
+ var/obj/I = O //Gurgs : Melts pretty much any object that isn't considered unacidable = TRUE
+ if(I.unacidable)
+ cannot_melt = 1
+ else
+ if(istype(O, /turf/simulated/wall))
+ var/turf/simulated/wall/W = O //Gurgs : Walls are deconstructed into girders.
+ if(W.material.flags & MATERIAL_UNMELTABLE)
+ cannot_melt = 1
+ else if(istype(O, /turf/simulated/floor))
+ var/turf/simulated/floor/F = O //Gurgs : Floors are destroyed with ex_act(1), turning them into whatever tile it would be if empty. Z-Level Friendly, does not destroy pipes.
+ if(F.flooring && (F.flooring.flags & TURF_ACID_IMMUNE))
+ cannot_melt = 1
+ else
+ cannot_melt = 1 //Gurgs : Everything that isn't a object, simulated wall, or simulated floor is assumed to be acid immune. Includes weird things like unsimulated floors and space.
+
+ if(cannot_melt)
+ to_chat(src, "You cannot dissolve this object.")
+ return
+
+ new /obj/effect/alien/acid(get_turf(O), O)
+ visible_message("[src] vomits globs of vile stuff all over [O]. It begins to sizzle and melt under the bubbling mess of acid!")
+
+ return
+
+// spin blatantly stolen from BlackMajor's bigdragon
+/mob/living/simple_mob/proc/speen(var/range = 2)
+ set name = "Spin Attack"
+ set desc = "Spins to strike enemies away from you."
+ set category = "Abilities"
+
+ if(world.time < speen_last)
+ to_chat(src, "You cannot spin again so soon.")
+ return
+
+ speen_last = world.time + speen_delay
+ var/list/thrownatoms = list()
+ for(var/mob/living/victim in oview(range, src))
+ thrownatoms += victim
+ src.spin(12,1)
+ for(var/am in thrownatoms)
+ var/atom/movable/AM = am
+ if(AM == src || AM.anchored)
+ continue
+ addtimer(CALLBACK(src, .proc/speen_throw, am), 1)
+ playsound(src, "sound/weapons/punchmiss.ogg", 50, 1)
+
+/mob/living/simple_mob/proc/speen_throw(var/atom/movable/AM, var/gentle = 0, var/damage = 10)
+ var/maxthrow = 7
+ var/atom/throwtarget
+ throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(AM, src)))
+
+ if (!throwtarget) // default case is north if unset
+ throwtarget = locate(src.x, world.maxy, src.z)
+
+ if(isliving(AM))
+ var/mob/living/M = AM
+ M.Weaken(1.5)
+ if(!gentle)
+ M.adjustBruteLoss(damage)
+ to_chat(M, "You're thrown back by [src]!")
+ playsound(src, get_sfx("punch"), 50, 1)
+ AM.throw_at(throwtarget, maxthrow, 3, src)
\ No newline at end of file
diff --git a/modular_chomp/code/modules/mob/living/simple_mob/subtypes/xenomorph.dm b/modular_chomp/code/modules/mob/living/simple_mob/subtypes/xenomorph.dm
new file mode 100644
index 0000000000..c3e8b129c1
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/simple_mob/subtypes/xenomorph.dm
@@ -0,0 +1,203 @@
+// Chomp version of a xeno. Uses the thicc sprites for the queen - has a couple little custom abilities too.
+// Thanks to BlackMajor for much guidance / stealing stuff from his bigdragon mob
+
+// Base type (Mostly initialises as an ability-less xeno hunter
+/mob/living/simple_mob/xeno_ch
+ name = "badly spawned xenomorph"
+ desc = "A chitin-covered bipedal creature with an eerie skittery nature. this one was spawned in wrong."
+
+ icon = 'modular_chomp/icons/mob/xenos_32.dmi'
+ vis_height = 32
+
+ faction = "xeno"
+ maxHealth = 200
+ health = 200
+ see_in_dark = 10
+
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+
+ melee_damage_lower = 8
+ melee_damage_upper = 16
+ grab_resist = 50
+
+ vore_active = 1
+ vore_capacity = 2
+ vore_pounce_chance = 50
+ vore_icons = null
+
+ response_help = "pats"
+ response_disarm = "tries to shove"
+ response_harm = "hits"
+ attacktext = list("slashed")
+ friendly = list("nuzzles", "caresses", "headbumps against", "leans against", "nibbles affectionately on")
+ speech_sounds = list( 'sound/voice/hiss1.ogg',
+ 'sound/voice/hiss2.ogg',
+ 'sound/voice/hiss3.ogg',
+ 'sound/voice/hiss4.ogg',
+ 'sound/voice/hiss5.ogg')
+ has_hands = TRUE
+
+ can_enter_vent_with = list( /obj/item/weapon/implant,
+ /obj/item/device/radio/borg,
+ /obj/item/weapon/holder,
+ /obj/machinery/camera,
+ /obj/belly,
+ /obj/screen,
+ /atom/movable/emissive_blocker,
+ /obj/item/weapon/material,
+ /obj/item/weapon/melee,
+ /obj/item/stack/,
+ /obj/item/weapon/tool,
+ /obj/item/weapon/reagent_containers/food,
+ /obj/item/weapon/coin,
+ /obj/item/weapon/aliencoin,
+ /obj/item/weapon/ore,
+ /obj/item/weapon/disk/nuclear,
+ /obj/item/toy,
+ /obj/item/weapon/card,
+ /obj/item/device/radio,
+ /obj/item/device/perfect_tele_beacon,
+ /obj/item/weapon/clipboard,
+ /obj/item/weapon/paper,
+ /obj/item/weapon/pen,
+ /obj/item/canvas,
+ /obj/item/paint_palette,
+ /obj/item/paint_brush,
+ /obj/item/device/camera,
+ /obj/item/weapon/photo,
+ /obj/item/device/camera_film,
+ /obj/item/device/taperecorder,
+ /obj/item/device/tape)
+
+ var/xeno_build_time = 5 //time to build a structure
+
+ //HUD
+ var/datum/action/innate/xeno_ch/xeno_build/build_action = new
+ var/datum/action/innate/xeno_ch/xeno_neuro/neurotox_action = new
+ var/datum/action/innate/xeno_ch/xeno_acidspit/acidspit_action = new
+ var/datum/action/innate/xeno_ch/xeno_corrode/corrode_action = new
+ var/datum/action/innate/xeno_ch/xeno_pounce/pounce_action = new
+ var/datum/action/innate/xeno_ch/xeno_spin/spin_action = new
+
+/mob/living/simple_mob/xeno_ch/Initialize()
+ ..()
+ src.adjust_nutrition(src.max_nutrition)
+ sight |= SEE_MOBS
+
+/mob/living/simple_mob/xeno_ch/Login()
+ . = ..()
+ faction = "neutral"
+ verbs |= /mob/living/simple_mob/xeno_ch/proc/xeno_build
+ build_action.Grant(src)
+
+
+// Xenomorph hunter subtype
+/mob/living/simple_mob/xeno_ch/hunter
+ name = "xenomorph hunter"
+ desc = "A chitin-covered bipedal creature with an eerie skittery nature."
+
+ movement_cooldown = 1
+
+ icon_dead = "alienh_dead"
+ icon_living = "alienh"
+ icon_rest = "alienh_sleep"
+ icon_state = "alienh"
+
+ icon_state_prepounce = "alienh_pounce"
+ icon_pounce = 'modular_chomp/icons/mob/xenoleap_96.dmi'
+ icon_state_pounce = "alienh_leap"
+ icon_overlay_spit = "alienspit"
+ icon_overlay_spit_pounce = "alienspit_leap"
+ icon_pounce_x = -32
+ icon_pounce_y = -32
+
+/mob/living/simple_mob/xeno_ch/hunter/Login()
+ . = ..()
+ verbs |= /mob/living/simple_mob/proc/pounce_toggle
+ verbs |= /mob/living/proc/ventcrawl
+ verbs |= /mob/living/proc/hide
+ pounce_action.Grant(src)
+
+//Xenomorph Sentinel subtype
+/mob/living/simple_mob/xeno_ch/sentinel
+ name = "xenomorph sentinel"
+ desc = "A chitin-covered bipedal creature with an acrid scent about it."
+
+ movement_cooldown = 1.5
+
+ icon_dead = "aliens_dead"
+ icon_living = "aliens"
+ icon_rest = "aliens_sleep"
+ icon_state = "aliens"
+
+ icon_state_prepounce = "aliens_pounce"
+ icon_pounce = 'modular_chomp/icons/mob/xenoleap_96.dmi'
+ icon_state_pounce = "aliens_leap"
+ icon_overlay_spit = "alienspit"
+ icon_overlay_spit_pounce = "alienspit_leap"
+ icon_pounce_x = -32
+ icon_pounce_y = -32
+
+
+/mob/living/simple_mob/xeno_ch/sentinel/Login()
+ . = ..()
+ verbs |= /mob/living/simple_mob/proc/pounce_toggle
+ verbs |= /mob/living/proc/hide
+ verbs |= /mob/living/simple_mob/proc/neurotoxin
+ verbs |= /mob/living/simple_mob/proc/acidspit
+ verbs |= /mob/living/simple_mob/proc/corrosive_acid
+ pounce_action.Grant(src)
+ neurotox_action.Grant(src)
+ acidspit_action.Grant(src)
+ corrode_action.Grant(src)
+
+
+//Xenomorph queen subtype
+/mob/living/simple_mob/xeno_ch/queen
+ name = "xenomorph queen"
+ desc = "A towering chitin-covered bipedal creature with a rather intimidating aura about them."
+
+ icon_dead = "alienq_dead"
+ icon_living = "alienq"
+ icon_rest = "alienq_sleep"
+ icon_state = "alienq"
+ icon = 'modular_chomp/icons/mob/xenoqueen_64.dmi'
+ vis_height = 64
+ pixel_x = -16
+ default_pixel_x = -16
+ pixel_y = 0
+ default_pixel_y = 0
+
+ maxHealth = 600
+ health = 600
+
+ movement_cooldown = 2
+
+/mob/living/simple_mob/xeno_ch/queen/Login()
+ . = ..()
+ verbs |= /mob/living/simple_mob/proc/neurotoxin
+ verbs |= /mob/living/simple_mob/proc/acidspit
+ verbs |= /mob/living/simple_mob/proc/corrosive_acid
+ verbs |= /mob/living/simple_mob/proc/speen
+ neurotox_action.Grant(src)
+ acidspit_action.Grant(src)
+ corrode_action.Grant(src)
+ spin_action.Grant(src)
+
+/mob/living/simple_mob/xeno_ch/queen/maid
+ name = "xenomorph maid queen"
+ desc = "A towering chitin-covered bipedal creature with a rather intimidating aura about them... though, they seem to be wearing an interesting outfit."
+
+ icon_dead = "alienqmaid_dead"
+ icon_living = "alienqmaid"
+ icon_rest = "alienqmaid_sleep"
+ icon_state = "alienqmaid"
diff --git a/modular_chomp/code/modules/mob/living/simple_mob/subtypes/xenomorph_abilities.dm b/modular_chomp/code/modules/mob/living/simple_mob/subtypes/xenomorph_abilities.dm
new file mode 100644
index 0000000000..f7153d2eee
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/simple_mob/subtypes/xenomorph_abilities.dm
@@ -0,0 +1,117 @@
+/mob/living/simple_mob/xeno_ch/proc/xeno_build()
+ set name = "Build Resin Structure"
+ set desc = "Build a xenomorph resin structure."
+ set category = "Abilities"
+
+ var/list/options = list("Resin Door","Resin Membrane","Nest","Resin Wall","Weed Node")
+ for(var/option in options)
+ LAZYSET(options, option, image('modular_chomp/icons/mob/xeno_screen.dmi', option))
+ var/choice = show_radial_menu(src, src, options, radius = 60)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return FALSE
+ . = TRUE
+
+ var/targetLoc = get_step(src, dir)
+
+ if(iswall(targetLoc))
+ targetLoc = get_turf(src)
+
+ var/obj/O
+
+ if(do_after(src, xeno_build_time))
+ switch(choice)
+ if("Resin Door")
+ O = new /obj/structure/simple_door/resin(targetLoc)
+
+ if("Resin Membrane")
+ O = new /obj/structure/alien/membrane(targetLoc)
+
+ if("Nest")
+ O = new /obj/structure/bed/nest(targetLoc)
+
+ if("Resin Wall")
+ O = new /obj/structure/alien/wall(targetLoc)
+
+ if("Weed Node")
+ O = new /obj/effect/alien/weeds/node(targetLoc)
+
+ if(O)
+ visible_message("[src] vomits up a thick purple substance and begins to shape it!", "You shape a [choice].")
+ O.color = "#321D37"
+ playsound(src, 'sound/effects/blobattack.ogg', 40, 1)
+
+
+
+/////
+/////
+// DATUM actions for xeno buttons
+/////
+/////
+
+
+
+/datum/action/innate/xeno_ch
+ check_flags = AB_CHECK_RESTRAINED | AB_CHECK_STUNNED | AB_CHECK_ALIVE
+ button_icon = 'modular_chomp/icons/mob/xeno_screen.dmi'
+ var/mob/living/simple_mob/xeno_ch/parent_xeno
+
+
+/datum/action/innate/xeno_ch/Grant(mob/living/L)
+ if(L)
+ parent_xeno = L
+ ..()
+
+/datum/action/innate/xeno_ch/xeno_build
+ name = "Build resin structures"
+ button_icon_state = "Nest"
+
+/datum/action/innate/xeno_ch/xeno_build/Activate()
+ parent_xeno.xeno_build()
+
+
+/datum/action/innate/xeno_ch/xeno_neuro
+ name = "Spit neurotoxin"
+ button_icon_state = "Neuro Spit"
+
+/datum/action/innate/xeno_ch/xeno_neuro/Activate()
+ parent_xeno.neurotoxin()
+
+
+/datum/action/innate/xeno_ch/xeno_acidspit
+ name = "Spit acid"
+ button_icon_state = "Acid Spit"
+
+/datum/action/innate/xeno_ch/xeno_acidspit/Activate()
+ parent_xeno.acidspit()
+
+
+/datum/action/innate/xeno_ch/xeno_corrode
+ name = "Corrode Object"
+ button_icon_state = "Acid"
+
+/datum/action/innate/xeno_ch/xeno_corrode/Activate()
+ parent_xeno.corrosive_acid()
+
+
+/datum/action/innate/xeno_ch/xeno_pounce
+ name = "Pounce"
+ button_icon_state = "Pounce"
+
+/datum/action/innate/xeno_ch/xeno_pounce/Activate()
+ parent_xeno.pounce_toggle()
+
+/datum/action/innate/xeno_ch/xeno_spin
+ name = "Spin"
+ button_icon_state = "Spin"
+
+/datum/action/innate/xeno_ch/xeno_spin/Activate()
+ parent_xeno.speen()
+
+
+/mob/living/simple_mob/xeno_ch/proc/grantallactions()
+ build_action.Grant(src)
+ neurotox_action.Grant(src)
+ acidspit_action.Grant(src)
+ corrode_action.Grant(src)
+ pounce_action.Grant(src)
+ spin_action.Grant(src)
\ No newline at end of file
diff --git a/modular_chomp/icons/mob/xeno_screen.dmi b/modular_chomp/icons/mob/xeno_screen.dmi
new file mode 100644
index 0000000000..6d8aa9e997
Binary files /dev/null and b/modular_chomp/icons/mob/xeno_screen.dmi differ
diff --git a/modular_chomp/icons/mob/xenoleap_96.dmi b/modular_chomp/icons/mob/xenoleap_96.dmi
new file mode 100644
index 0000000000..7e10b8a5c5
Binary files /dev/null and b/modular_chomp/icons/mob/xenoleap_96.dmi differ
diff --git a/modular_chomp/icons/mob/xenoqueen_64.dmi b/modular_chomp/icons/mob/xenoqueen_64.dmi
new file mode 100644
index 0000000000..863aeb84ad
Binary files /dev/null and b/modular_chomp/icons/mob/xenoqueen_64.dmi differ
diff --git a/modular_chomp/icons/mob/xenos_32.dmi b/modular_chomp/icons/mob/xenos_32.dmi
new file mode 100644
index 0000000000..b4397da603
Binary files /dev/null and b/modular_chomp/icons/mob/xenos_32.dmi differ
diff --git a/modular_chomp/sound/voice/wheeze.ogg b/modular_chomp/sound/voice/wheeze.ogg
new file mode 100644
index 0000000000..873bbbd2c7
Binary files /dev/null and b/modular_chomp/sound/voice/wheeze.ogg differ
diff --git a/vorestation.dme b/vorestation.dme
index 1e5d7944e5..14791bba3a 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -3158,7 +3158,6 @@
#include "code\modules\mob\living\simple_mob\sd_pets.dm"
#include "code\modules\mob\living\simple_mob\simple_hud.dm"
#include "code\modules\mob\living\simple_mob\simple_mob.dm"
-#include "code\modules\mob\living\simple_mob\simple_mob_ch.dm"
#include "code\modules\mob\living\simple_mob\simple_mob_vr.dm"
#include "code\modules\mob\living\simple_mob\taming.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\animal.dm"
@@ -4481,7 +4480,9 @@
#include "maps\~map_system\maps.dm"
#include "modular_chomp\code\modules\admin\functions\modify_traits.dm"
#include "modular_chomp\code\modules\clothing\spacesuits\rig\rig.dm"
+#include "modular_chomp\code\modules\emotes\definitions\audiable.dm"
#include "modular_chomp\code\modules\mob\holder.dm"
+#include "modular_chomp\code\modules\mob\living\emote.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\species\species.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\species\station\protean\_protean_defines.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\species\station\protean\protean_blob.dm"
@@ -4489,5 +4490,9 @@
#include "modular_chomp\code\modules\mob\living\carbon\human\species\station\protean\protean_powers.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\species\station\protean\protean_rig.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\species\station\protean\protean_species.dm"
+#include "modular_chomp\code\modules\mob\living\simple_mob\simple_mob.dm"
+#include "modular_chomp\code\modules\mob\living\simple_mob\simple_mob_abilities.dm"
+#include "modular_chomp\code\modules\mob\living\simple_mob\subtypes\xenomorph.dm"
+#include "modular_chomp\code\modules\mob\living\simple_mob\subtypes\xenomorph_abilities.dm"
#include "modular_chomp\code\modules\mob\living\simple_mob\subtypes\vore\bigdragon.dm"
// END_INCLUDE