diff --git a/code/__defines/_fruits.dm b/code/__defines/_fruits.dm
index 827d64b471..4247fb2301 100644
--- a/code/__defines/_fruits.dm
+++ b/code/__defines/_fruits.dm
@@ -92,6 +92,9 @@
#define PLANT_WURMWOAD "wurmwoad"
#define PLANT_MICROM "microm"
#define PLANT_MEGAM "megam"
+#define PLANT_TEA "tea"
+#define PLANT_PITCHERPLANT "pitcher plant"
+#define PLANT_NULLHARDLIGHT "Type NULL Hardlight Generator"
GLOBAL_LIST_INIT(acceptable_fruit_types, list(
PLANT_AMBROSIA,
diff --git a/code/__defines/_reagents.dm b/code/__defines/_reagents.dm
index 985cb1d447..837fc895fb 100644
--- a/code/__defines/_reagents.dm
+++ b/code/__defines/_reagents.dm
@@ -27,6 +27,8 @@
#define REAGENT_ID_FLUORINE "fluorine"
#define REAGENT_CHLORINE "Chlorine"
#define REAGENT_ID_CHLORINE "chlorine"
+#define REAGENT_MIASMA "Miasma"
+#define REAGENT_ID_MIASMA "miasma"
// Fluid Reagents
@@ -147,6 +149,8 @@
#define REAGENT_ID_PAROXETINE "paroxetine"
#define REAGENT_QERRQUEM "Qerr-quem"
#define REAGENT_ID_QERRQUEM "qerr_quem"
+#define REAGENT_APHRODISIAC "Aphrodisiac"
+#define REAGENT_ID_APHRODISIAC "aphrodisiac"
// Modifiers
@@ -433,6 +437,8 @@
#define REAGENT_ID_LIQUIDCARPETO "liquidcarpeto"
#define REAGENT_ESSENTIALOIL "Essential Oils"
#define REAGENT_ID_ESSENTIALOIL "essential_oil"
+#define REAGENT_PITCHERNECTAR "Pitcher Nectar"
+#define REAGENT_ID_PITCHERNECTAR "pitcher_nectar"
// Admin chems
@@ -1033,6 +1039,8 @@
#define REAGENT_ID_CHAMPAGNE "champagne"
#define REAGENT_CIDER "Cider"
#define REAGENT_ID_CIDER "cider"
+#define REAGENT_TEAMUSH "Tea mush"
+#define REAGENT_ID_TEAMUSH "teamush"
// Cocktails
#define REAGENT_ACIDSPIT "Acid Spit"
@@ -1369,6 +1377,11 @@
#define REAGENT_ID_METAMORPHIC "metamorphic"
#define REAGENT_BINDING "Binding Metal"
#define REAGENT_ID_BINDING "binding"
+#define REAGENT_NUMBING_FLUID "Numbing Fluid"
+#define REAGENT_ID_NUMBING_FLUID "succubi_numbing"
+#define REAGENT_PARALYZE_FLUID "Paralyzing Fluid"
+#define REAGENT_ID_PARALYZE_FLUID "succubi_paralize"
+#define REAGENT_ID_APHRODIAC_FLUID "succubi_aphrodisiac"
// Xenoslimes
diff --git a/code/__defines/faction.dm b/code/__defines/faction.dm
index 363a786f54..974f649595 100644
--- a/code/__defines/faction.dm
+++ b/code/__defines/faction.dm
@@ -60,6 +60,7 @@
#define FACTION_GOLEM "golem"
#define FACTION_GRAFADREKA "grafadreka"
#define FACTION_GRUBS "grubs"
+#define FACTION_GRYPHON "gryphon"
#define FACTION_HORSE "horse"
#define FACTION_INSECTS "insects"
#define FACTION_JELLYFISH "jellyfish"
@@ -113,6 +114,7 @@
#define FACTION_WORM "worm"
#define FACTION_XENO "xeno"
#define FACTION_CORGI "corgi"
+#define FACTION_ZORGOIA "zorgoia"
#define FACTION_PLANTS "plants"
diff --git a/code/datums/components/crafting/recipes/weapons.dm b/code/datums/components/crafting/recipes/weapons.dm
index 84ba37b69b..fbdd5a0622 100644
--- a/code/datums/components/crafting/recipes/weapons.dm
+++ b/code/datums/components/crafting/recipes/weapons.dm
@@ -65,3 +65,16 @@
time = 180
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
+
+/datum/crafting_recipe/ziplaser
+ name = "Ziplaser"
+ result = /obj/item/gun/energy/zip/craftable
+ reqs = list(list(/obj/item/cell/high = 1),
+ list(/obj/item/stack/rods = 2),
+ list(/obj/item/stack/material/steel = 8),
+ list(/obj/item/stack/material/plastic = 5),
+ list(/obj/item/cell/device = 2)
+ )
+ time = 120
+ category = CAT_WEAPONRY
+ subcategory = CAT_WEAPON
diff --git a/code/datums/elements/lootable/mecha.dm b/code/datums/elements/lootable/mecha.dm
index 781d59ac7f..92cd419256 100644
--- a/code/datums/elements/lootable/mecha.dm
+++ b/code/datums/elements/lootable/mecha.dm
@@ -243,3 +243,57 @@
/obj/item/mecha_parts/mecha_equipment/repair_droid,
/obj/item/mecha_parts/mecha_equipment/teleporter
)
+
+// Stuff you may find attached to a mouse tank.
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/datum/element/lootable/mecha/mouse_tank
+ loot_left= 5
+
+ common_loot = list(
+ /obj/random/tool,
+ /obj/random/tool,
+ /obj/item/stack/cable_coil/random,
+ /obj/random/tank,
+ /obj/random/tech_supply/component,
+ /obj/random/tech_supply/component,
+ /obj/effect/decal/remains/mouse,
+ /obj/item/stack/material/steel{amount = 20}
+ )
+
+ uncommon_loot = list(
+ /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg/rigged,
+ /obj/item/mecha_parts/mecha_equipment/generator
+ )
+
+ rare_loot = list(
+ /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg,
+ /obj/item/mecha_parts/mecha_equipment/generator/nuclear
+ )
+
+// Stuff you may find attached to a livewire mouse tank.
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/datum/element/lootable/mecha/mouse_tank/livewire
+
+ uncommon_loot = list(
+ /obj/item/mecha_parts/mecha_equipment/weapon/energy/flamer/rigged,
+ /obj/item/mecha_parts/mecha_equipment/tool/extinguisher
+ )
+
+ rare_loot = list(
+ /obj/item/mecha_parts/mecha_equipment/weapon/energy/flamer,
+ /obj/item/mecha_parts/mecha_equipment/generator
+ )
+
+// Stuff you may find attached to a eraticator mouse tank.
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/datum/element/lootable/mecha/mouse_tank/eraticator
+
+ uncommon_loot = list(
+ /obj/item/ammo_magazine/m75,
+ /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/mortar
+ )
+
+ rare_loot = list(
+ /obj/item/gun/projectile/gyropistol,
+ /obj/item/mecha_parts/mecha_equipment/generator/nuclear
+ )
diff --git a/code/datums/elements/sellable.dm b/code/datums/elements/sellable.dm
index 1630072f9e..8232154b91 100644
--- a/code/datums/elements/sellable.dm
+++ b/code/datums/elements/sellable.dm
@@ -172,3 +172,22 @@
else
GLOB.refined_chems_sold[R.industrial_use]["units"] += FLOOR(R.volume, 1)
GLOB.refined_chems_sold[R.industrial_use]["value"] += reagent_value
+
+/datum/element/sellable/salvage //For selling /obj/item/salvage
+
+/datum/element/sellable/salvage/calculate_sell_value(obj/source)
+ var/obj/item/salvage/salvagedStuff = source
+ return salvagedStuff.worth
+
+/datum/element/sellable/organ //For selling /obj/item/organ/internal
+/datum/element/sellable/organ/calculate_sell_value(obj/source)
+ var/obj/item/organ/internal/organ_stuff = source
+ return organ_stuff.supply_conversion_value
+
+/datum/element/sellable/organ/sell_error(obj/source)
+ if(!istype(source.loc, /obj/structure/closet/crate/freezer))
+ return "Error: Product was improperly packaged. Send contents in freezer crate to preserve contents for transport."
+ var/obj/item/organ/internal/organ_stuff = source
+ if(organ_stuff.health != initial(organ_stuff.health) )
+ return "Error: Product was damaged on arrival."
+ return null
diff --git a/code/game/gamemodes/cult/construct_spells.dm b/code/game/gamemodes/cult/construct_spells.dm
index c2ebdaee50..0c907ccb71 100644
--- a/code/game/gamemodes/cult/construct_spells.dm
+++ b/code/game/gamemodes/cult/construct_spells.dm
@@ -578,6 +578,17 @@
tracer_type = /obj/effect/projectile/tracer/inversion
impact_type = /obj/effect/projectile/impact/inversion
+/obj/item/projectile/energy/inversion
+ name = "inversion blast"
+ icon = 'icons/obj/projectiles_impact.dmi'
+ icon_state = "impact_invert"
+ damage = 30
+ armor_penetration = 60
+ damage_type = BURN
+ check_armour = "laser"
+ color = "#ffffff"
+ fire_sound = 'sound/weapons/spiderlunge.ogg'
+
//Harvester Pain Orb
/obj/item/spell/construct/spawner/agonizing_sphere
@@ -672,3 +683,343 @@
user.visible_message(span_bold("\The [user]") + " lowers its fist.")
return
qdel(src)
+
+
+////////////////////////////
+// Purity Construct - Bishop - Spells
+////////////////////////////
+
+/spell/targeted/construct_advanced/crippling_beam
+ name = "Crippling Beam"
+ desc = "Fire a crippling beam to hold down your enemies or prey."
+
+ hud_state = "const_beam"
+ spell_obj = /obj/item/spell/construct/projectile/crippling_beam
+
+/obj/item/spell/construct/projectile/crippling_beam
+ name = "Crippling Beam"
+ icon_state = "generic"
+ desc = "Your manipulators fire crippling beam of dense light."
+ cast_methods = CAST_RANGED
+ spell_projectile = /obj/item/projectile/beam/crippling_beam
+ pre_shot_delay = 0
+ cooldown = 50
+ fire_sound = 'sound/weapons/spiderlunge.ogg'
+
+/obj/item/projectile/beam/crippling_beam
+ name = "Crippling Beam"
+ icon_state = "invert"
+ fire_sound = 'sound/weapons/spiderlunge.ogg'
+ damage = 20
+ damage_type = BURN
+ check_armour = "laser"
+ armor_penetration = 60
+ light_range = 2
+ light_power = -2
+ light_color = "#64B4E6"
+
+ muzzle_type = /obj/effect/projectile/muzzle/laser_omni
+ tracer_type = /obj/effect/projectile/tracer/laser_omni
+ impact_type = /obj/effect/projectile/impact/laser_omni
+
+/obj/item/projectile/beam/crippling_beam/proc/bang(var/mob/living/carbon/M)
+ to_chat(M, span_danger("You hear a loud roar."))
+ playsound(src, 'sound/effects/bang.ogg', 50, 1)
+ var/ear_safety = 0
+ ear_safety = M.get_ear_protection()
+ if(ear_safety == 1)
+ M.Confuse(150)
+ else if (ear_safety > 1)
+ M.Confuse(30)
+ else if (!ear_safety)
+ M.Stun(10)
+ M.Weaken(2)
+ M.ear_damage += rand(1, 10)
+ M.ear_deaf = max(M.ear_deaf,15)
+ // M.deaf_loop.start() // used Downstream
+ if (M.ear_damage >= 15)
+ to_chat(M, span_danger("Your ears start to ring badly!"))
+ if (prob(M.ear_damage - 5))
+ to_chat(M, span_danger("You can't hear anything!"))
+ M.sdisabilities |= DEAF
+ // M.deaf_loop.start() // used Downstream
+ else
+ if (M.ear_damage >= 5)
+ to_chat(M, span_danger("Your ears start to ring!"))
+ M.update_icons()
+
+/obj/item/projectile/beam/crippling_beam/on_hit(var/atom/target)
+ bang(target)
+ . = ..()
+
+/spell/targeted/construct_advanced/banishment
+ name = "banishment"
+ desc = "Fire a searing beam of light, banishing unholy foes."
+
+ hud_state = "const_beam"
+ spell_obj = /obj/item/spell/construct/projectile/banishment
+
+/obj/item/spell/construct/projectile/banishment
+ name = "banishment"
+ icon_state = "generic"
+ desc = "Your manipulators fire searing beams of light."
+ cast_methods = CAST_RANGED
+ spell_projectile = /obj/item/projectile/beam/banishment
+ pre_shot_delay = 0
+ cooldown = 10
+ fire_sound = 'sound/weapons/spiderlunge.ogg'
+
+/obj/item/projectile/beam/banishment
+ name = "banishment"
+ icon_state = "invert"
+ fire_sound = 'sound/weapons/spiderlunge.ogg'
+ damage = 15
+ damage_type = BURN
+ mob_bonus_damage = 45
+ check_armour = "laser"
+ armor_penetration = 60
+ light_range = 2
+ light_power = -2
+ light_color = "#64B4E6"
+
+ muzzle_type = /obj/effect/projectile/muzzle/lightning
+ tracer_type = /obj/effect/projectile/tracer/lightning
+ impact_type = /obj/effect/projectile/impact/lightning
+
+/obj/item/projectile/beam/banishment/proc/banish(var/mob/living/simple_mob/construct)
+ if(construct)
+ construct.Stun(10)
+ construct.Weaken(2)
+ else
+ return
+
+/obj/item/projectile/beam/banishment/on_hit(var/atom/target)
+ banish(target)
+ . = ..()
+
+////////////////////////////
+// Purity Construct - Deacon - Spells
+////////////////////////////
+
+///Deacon Laser
+/spell/targeted/construct_advanced/force_beam
+ name = "Force Beam"
+ desc = "Fire a beam of kinetic energy to force back troublemakers."
+
+ hud_state = "const_beam"
+ spell_obj = /obj/item/spell/construct/projectile/force_beam
+
+/obj/item/spell/construct/projectile/force_beam
+ name = "force_beam"
+ icon_state = "generic"
+ desc = "Your manipulators fire a condensed beam of kinetic energy."
+ cast_methods = CAST_RANGED
+ spell_projectile = /obj/item/projectile/beam/force_beam
+ pre_shot_delay = 0
+ cooldown = 5
+ fire_sound = 'sound/weapons/spiderlunge.ogg'
+
+/obj/item/projectile/beam/force_beam
+ name = "force beam"
+ icon_state = "invert"
+ fire_sound = 'sound/weapons/spiderlunge.ogg'
+ damage = 5
+ damage_type = BRUTE
+ check_armour = "melee"
+ armor_penetration = 60
+ light_range = 2
+ light_power = -2
+ light_color = "#64B4E6"
+
+ muzzle_type = /obj/effect/projectile/muzzle/tungsten
+ tracer_type = /obj/effect/projectile/tracer/tungsten
+ impact_type = /obj/effect/projectile/impact/tungsten
+
+/obj/item/projectile/beam/force_beam/on_hit(var/atom/movable/target, var/blocked = 0)
+ if(isliving(target))
+ var/mob/living/L = target
+ if(prob(40) && !blocked)
+ L.Stun(1)
+ L.Confuse(1)
+
+
+///Deacon Healing Sphere
+/spell/targeted/construct_advanced/soothing_sphere
+ name = "Sphere of soothing"
+ desc = "Rend a portal into a plane of sothing energy at the target location."
+
+ charge_max = 100
+
+ hud_state = "const_harvest"
+ spell_obj = /obj/item/spell/construct/spawner/soothing_sphere
+
+/obj/item/spell/construct/spawner/soothing_sphere
+ name = "sphere of soothing"
+ desc = "Call forth a portal to a dimension of soothing energies at your target."
+
+ spawner_type = /obj/effect/temporary_effect/pulse/soothing_sphere
+
+/obj/item/spell/construct/spawner/soothing_sphere/on_ranged_cast(atom/hit_atom, mob/user)
+ if(within_range(hit_atom) && pay_energy(10))
+ ..()
+
+/obj/item/spell/construct/spawner/soothing_sphere/on_throw_cast(atom/hit_atom, mob/user)
+ pay_energy(5)
+ if(isliving(hit_atom))
+ var/mob/living/L = hit_atom
+ L.add_modifier(/datum/modifier/soothe, 10 SECONDS)
+
+/obj/effect/temporary_effect/pulse/soothing_sphere
+ name = "soothing sphere"
+ desc = "A portal to some hellish place. Its screams wrack your body with pain."
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "blue_static_sphere"
+ time_to_die = null
+ light_range = 4
+ light_power = 5
+ light_color = "#64B4E6"
+ light_on = TRUE
+ pulses_remaining = 10
+ pulse_delay = 1 SECOND
+
+/obj/effect/temporary_effect/pulse/soothing_sphere/on_pulse()
+ for(var/mob/living/L in view(4,src))
+ if(!iscultist(L) && !istype(L, /mob/living/simple_mob/construct))
+ L.add_modifier(/datum/modifier/soothe, 2 SECONDS)
+ L.adjustBruteLoss(rand(-5,-10))
+ L.adjustFireLoss(rand(-5,-10))
+
+/datum/modifier/soothe
+ name = "soothe"
+ desc = "Your body is soothed of pain."
+
+ on_created_text = span_notice("A blue lightning quickly covers your body. Pain quickly fading.")
+ on_expired_text = span_notice("The lightning fades, and so too does the ongoing soothing of pain.")
+
+ stacks = MODIFIER_STACK_EXTEND
+
+ mob_overlay_state = "blue_electricity_constant"
+
+/datum/modifier/soothe/tick()
+ spawn()
+ if(ishuman(holder))
+ var/mob/living/carbon/human/H = holder
+ H.apply_effect(-20, AGONY)
+ if(prob(10))
+ to_chat(H, span_warning("It feels so comforting!"))
+
+////////////////////////////
+// Purity Construct - Priest - Spells
+////////////////////////////
+
+/spell/targeted/construct_advanced/mend_purity
+ name = "Mend Purity"
+ desc = "Mend a target living being or construct over time."
+
+ charge_max = 100
+
+ hud_state = "const_mend"
+ spell_obj = /obj/item/spell/construct/mend_purity
+
+/obj/item/spell/construct/mend_purity
+ name = "Mend Purity"
+ desc = "Mend the wounds of constructs or living beings overtime."
+ icon_state = "mend_wounds"
+ cast_methods = CAST_MELEE
+ aspect = ASPECT_UNHOLY
+ light_color = "#64B4E6"
+ light_power = -2
+ light_on = TRUE
+
+/obj/item/spell/construct/mend_purity/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
+ if(isliving(hit_atom))
+ var/mob/living/L = hit_atom
+ L.add_modifier(/datum/modifier/mend_purity, 150)
+ qdel(src)
+
+/datum/modifier/mend_purity
+ name = "holy mending"
+ desc = "Your body is mending, rejoice!"
+
+ on_created_text = span_notice("A holy light envelops your body as it begins to mend.")
+ on_expired_text = span_notice("The cloak of unease dissipates.")
+
+ stacks = MODIFIER_STACK_EXTEND
+
+ mob_overlay_state = "blue_electricity_constant"
+
+/datum/modifier/mend_purity/tick()
+ spawn()
+ if(isliving(holder))
+ var/mob/living/L = holder
+ if(istype(L, /mob/living/simple_mob/construct))
+ L.adjustBruteLoss(rand(-5,-10))
+ L.adjustFireLoss(rand(-5,-10))
+ else
+ L.adjustBruteLoss(-2)
+ L.adjustFireLoss(-2)
+
+ if(ishuman(holder))
+ var/mob/living/carbon/human/H = holder
+
+ for(var/obj/item/organ/O in H.internal_organs)
+ if(O.damage > 0)
+ O.damage = max(O.damage - 2, 0)
+ if(O.damage <= 5 && O.organ_tag == O_EYES)
+ H.sdisabilities &= ~BLIND
+
+ for(var/obj/item/organ/external/O in H.organs)
+ O.heal_damage(rand(1,3), rand(1,3), internal = 1, robo_repair = 1)
+
+ for(var/obj/item/organ/E in H.bad_external_organs)
+ var/obj/item/organ/external/affected = E
+ if((affected.damage < affected.min_broken_damage * CONFIG_GET(number/organ_health_multiplier)) && (affected.status & ORGAN_BROKEN))
+ affected.status &= ~ORGAN_BROKEN
+
+ for(var/datum/wound/W in affected.wounds)
+ if(istype(W, /datum/wound/internal_bleeding))
+ affected.wounds -= W
+ affected.update_damages()
+
+ H.restore_blood()
+ if(iscultist(H))
+ H.apply_effect(100, AGONY)//it will heal cultists but purity really doesn't like them so causes much pain
+ if(prob(10))
+ to_chat(H, span_danger("It feels as though your body is being torn apart!"))
+ L.updatehealth()
+
+/spell/targeted/purity_repair_aura
+ name = "Repair Aura"
+ desc = "Emit a field of energy around your shell to repair nearby constructs at range."
+
+ range = -1
+ school = "evocation"
+ charge_type = Sp_RECHARGE
+ invocation_type = SpI_NONE
+
+ spell_flags = CONSTRUCT_CHECK | INCLUDEUSER
+
+ hud_state = "const_repairaura"
+ smoke_amt = 0
+
+ charge_max = 600
+
+/spell/targeted/purity_repair_aura/cast(list/targets, mob/living/user)
+ if(findNullRod(user) || user.has_modifier_of_type(/datum/modifier/repair_aura))
+ charge_counter = 300
+ return
+ user.add_modifier(/datum/modifier/repair_aura_purity, 30 SECONDS)
+
+/datum/modifier/repair_aura_purity
+ name = "aura of repair (purity)"
+ desc = "You are emitting a field of strange energy, capable of repairing constructs."
+
+ on_created_text = span_notice("You begin emitting an purity repair aura.")
+ on_expired_text = span_notice("The purity repair aura fades.")
+ stacks = MODIFIER_STACK_EXTEND
+
+/datum/modifier/repair_aura_purity/tick()
+ spawn()
+ for(var/mob/living/simple_mob/construct/T in view(4,holder))
+ T.adjustBruteLoss(rand(-10,-15))
+ T.adjustFireLoss(rand(-10,-15))
diff --git a/code/game/machinery/pointdefense.dm b/code/game/machinery/pointdefense.dm
index cf3634a939..8ac509b3de 100644
--- a/code/game/machinery/pointdefense.dm
+++ b/code/game/machinery/pointdefense.dm
@@ -133,7 +133,7 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/pointdefense)
var/rotation_speed = 4.5 SECONDS //How quickly we turn to face threats
var/datum/weakref/engaging = null // The meteor we're shooting at
var/id_tag = null
- var/fire_sounds = list('sound/weapons/frigate_turret/frigate_turret_fire1.ogg', 'sound/weapons/frigate_turret/frigate_turret_fire2.ogg', 'sound/weapons/frigate_turret/frigate_turret_fire3.ogg', 'sound/weapons/frigate_turret/frigate_turret_fire4.ogg') // CHOMPEdit: Pew
+ var/fire_sounds = list('sound/weapons/frigate_turret/frigate_turret_fire1.ogg', 'sound/weapons/frigate_turret/frigate_turret_fire2.ogg', 'sound/weapons/frigate_turret/frigate_turret_fire3.ogg', 'sound/weapons/frigate_turret/frigate_turret_fire4.ogg')
/obj/machinery/pointdefense/Initialize(mapload)
. = ..()
diff --git a/code/game/objects/effects/decals/Cleanable/vore.dm b/code/game/objects/effects/decals/Cleanable/vore.dm
index 6378cfb4b5..936adec6d9 100644
--- a/code/game/objects/effects/decals/Cleanable/vore.dm
+++ b/code/game/objects/effects/decals/Cleanable/vore.dm
@@ -1,5 +1,3 @@
-////////////CHOMP CLEANABLE REAGENT PUDDLES/////////////////////
-
/obj/effect/decal/cleanable/blood/reagent //Yes, we are using the blood system for this
name = "liquid"
dryname = "dried liquid"
diff --git a/code/game/objects/items/devices/vacpack.dm b/code/game/objects/items/devices/vacpack.dm
new file mode 100644
index 0000000000..f8413332c9
--- /dev/null
+++ b/code/game/objects/items/devices/vacpack.dm
@@ -0,0 +1,295 @@
+//Vac attachment
+/obj/item/vac_attachment
+ name = "\improper Vac-Pack attachment"
+ desc = "Useful for slurping mess off the floors. Even things and stuff depending on settings. Can be connected to a trash bag or vore belly. On-mob sprites can be toggled via verb in Objects tab."
+ icon = 'icons/mob/vacpack.dmi'
+ icon_override = 'icons/mob/vacpack.dmi'
+ icon_state = "sucker_drop"
+ item_state = "sucker"
+ slot_flags = SLOT_BELT | SLOT_BACK
+ var/vac_power = 0
+ var/output_dest = null
+ var/list/vac_settings = list(
+ "power off" = 0,
+ "dust and grime" = 1,
+ "tiny objects" = 2,
+ "pests and small objects" = 3,
+ "medium objects" = 4,
+ "large objects" = 5,
+ "large pests" = 6,
+ "auto-level" = 7,
+ "output destination" = 8
+ )
+ var/vac_owner = null
+ flags = NOBLUDGEON
+
+/obj/item/vac_attachment/attack_self(mob/living/user)
+ var/set_input = null
+ if(!output_dest)
+ set_input = "output destination"
+ if(!set_input)
+ set_input = tgui_input_list(user, "Set your vacuum attachment's power level or output mode.", "Vac Settings", vac_settings)
+ if(set_input)
+ if(set_input == "output destination")
+ if(vac_owner && user != vac_owner)
+ to_chat(user, span_warning("Only designated owner can change this setting."))
+ return
+ var/vac_options = list("Vore Belly", "Trash Bag") //Dont show option for borg belly if the user isnt even a borg. QOL!
+ if(isrobot(user))
+ vac_options = list("Vore Belly", "Borg Belly", "Trash Bag")
+ var/set_output = tgui_input_list(user, "Set your vacuum attachment's connection port", "Vac Settings", vac_options)
+ switch(set_output)
+ if("Borg Belly")
+ if(isrobot(user))
+ var/mob/living/silicon/robot/R = user
+ var/obj/item/robot_module/M = R.module
+ for(var/obj/item/dogborg/sleeper/S in M.modules)
+ if(istype(S))
+ output_dest = S
+ return
+ to_chat(user, span_warning("Borg belly not found."))
+ if("Trash Bag")
+ if(isrobot(user))
+ var/mob/living/silicon/robot/R = user
+ var/obj/item/robot_module/M = R.module
+ for(var/obj/item/storage/bag/trash/T in M.modules)
+ if(istype(T))
+ output_dest = T
+ return
+ for(var/obj/item/storage/bag/trash/T in user.contents)
+ if(istype(T))
+ output_dest = T
+ return
+ to_chat(user, span_warning("Trash bag not found."))
+ if("Vore Belly")
+ if(user.vore_selected)
+ output_dest = user.vore_selected
+ return
+ else
+ vac_power = vac_settings[set_input]
+ icon_state = "sucker-[vac_power]"
+
+/obj/item/vac_attachment/afterattack(atom/target, mob/living/user, proximity)
+ if(vac_power < 1)
+ return
+ if(!proximity)
+ return
+ if(!output_dest)
+ return
+ if(istype(target,/obj/structure/window) || istype(target,/obj/structure/grille))
+ target = get_turf(target) // Windows can be clicked to clean their turf
+ if(istype(output_dest,/obj/item/storage/bag/trash))
+ if(get_turf(output_dest) != get_turf(user))
+ vac_power = 0
+ icon_state = "sucker-0"
+ output_dest = null
+ to_chat(user, span_warning("Trash bag not found. Shutting down."))
+ return
+ var/obj/item/storage/bag/trash/B = output_dest
+ if(LAZYLEN(B.contents) >= B.max_storage_space) //A bit more lenient than the w_class system to avoid complicated spaghetti.
+ to_chat(user, span_warning("Trash bag full. Empty trash bag contents to continue."))
+ return
+ if(istype(output_dest,/obj/item/dogborg/sleeper))
+ var/obj/item/dogborg/sleeper/B = output_dest
+ if(LAZYLEN(B.contents) >= B.max_item_count)
+ to_chat(user, span_warning("[B.name] full. Empty or process contents to continue."))
+ return
+ if(B.ore_storage)
+ if(B.current_capacity >= B.max_ore_storage)
+ to_chat(user, span_warning("Ore storage full. Deposit ore contents to a box continue."))
+ return
+ if(isbelly(output_dest))
+ var/turf/T = get_turf(output_dest)
+ if(!T.Adjacent(user)) //Can still be used as a feeding tube by another adjacent player.
+ if(vac_owner && user != vac_owner)
+ return
+ vac_power = 0
+ icon_state = "sucker-0"
+ output_dest = null
+ to_chat(user, span_warning("Target destination not found. Shutting down."))
+ return
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ var/auto_setting = 1
+ if(isturf(target))
+ user.visible_message(span_filter_notice("[user] begins vacuuming the mess off \the [target.name]..."), span_notice("You begin vacuuming the mess off \the [target.name]..."))
+ var/list/suckables = list()
+ if(vac_power >= 1)
+ for(var/obj/effect/decal/cleanable/C in target)
+ suckables |= C
+ if(vac_power >= 2)
+ for(var/obj/item/I in target)
+ if(I.anchored || I.w_class > 1)
+ continue
+ else
+ suckables |= I
+ if(vac_power >= 3)
+ for(var/obj/item/I in target)
+ if(I.anchored || I.w_class > 2)
+ continue
+ else
+ suckables |= I
+ for(var/mob/living/L in target)
+ if(L.anchored || !L.devourable || L == user || L.buckled || !L.can_be_drop_prey)
+ continue
+ if(L.size_multiplier < 0.5)
+ suckables |= L
+ if(istype(L,/mob/living/simple_mob/animal/passive/mouse) || istype(L,/mob/living/simple_mob/animal/passive/lizard) || istype(L,/mob/living/simple_mob/animal/passive/cockroach))
+ suckables |= L
+ if(vac_power >= 4)
+ for(var/obj/item/I in target)
+ if(I.anchored || I.w_class > 3)
+ continue
+ else
+ suckables |= I
+ if(vac_power >= 5)
+ for(var/obj/item/I in target)
+ if(I.anchored)
+ continue
+ else
+ suckables |= I
+ if(vac_power >= 6)
+ for(var/mob/living/L in target)
+ if(L.anchored || !L.devourable || L == user || L.buckled || !L.can_be_drop_prey)
+ continue
+ suckables |= L
+ if(LAZYLEN(suckables))
+ if(vac_power == 7)
+ for(var/atom/movable/F in suckables)
+ if(isitem(F))
+ auto_setting = max(2, auto_setting)
+ var/obj/item/I = F
+ if(I.w_class > auto_setting)
+ auto_setting = min(I.w_class, 5)
+ if(isliving(F))
+ var/mob/living/L = F
+ if(L.size_multiplier < 0.5 || istype(L,/mob/living/simple_mob/animal/passive/mouse) || istype(L,/mob/living/simple_mob/animal/passive/lizard) || istype(L,/mob/living/simple_mob/animal/passive/cockroach))
+ if(auto_setting < 3)
+ auto_setting = 3
+ else
+ auto_setting = 6
+ else
+ auto_setting = vac_power
+ playsound(src, 'sound/machines/kitchen/candymaker/candymaker-mid1.ogg', auto_setting * 20, 1, -1)
+ var/vac_conga = 0
+ for(var/atom/movable/F in suckables)
+ if(is_type_in_list(F, GLOB.item_vore_blacklist) || F.loc != target)
+ continue
+ if(istype(F,/obj/effect/decal/cleanable))
+ if(isbelly(output_dest))
+ var/obj/belly/B = output_dest
+ B.owner_adjust_nutrition(1)
+ qdel(F)
+ continue
+ if(istype(output_dest,/obj/item/storage/bag/trash))
+ var/obj/item/storage/bag/trash/B = output_dest
+ if(LAZYLEN(B.contents) >= B.max_storage_space)
+ to_chat(user, span_warning("Trash bag full. Empty trash bag contents to continue."))
+ return
+ if(vac_conga < 100)
+ vac_conga += 3
+ spawn(3 + vac_conga)
+ if(!F.Adjacent(user) || src.loc != user || vac_power < 2) //Cancel if moved/unpowered/dropped
+ break
+ F.SpinAnimation(5,1)
+ spawn(5)
+ if(F.loc == target)
+ if(isitem(F))
+ var/obj/item/I = F
+ if(I.drop_sound)
+ playsound(src, I.drop_sound, auto_setting * 5, 1, -1)
+ playsound(src, 'sound/rakshasa/corrosion3.ogg', auto_setting * 15, 1, -1)
+ F.forceMove(output_dest)
+ if(istype(target, /turf/simulated))
+ var/turf/simulated/T = target
+ if(isbelly(output_dest) && T.dirt > 50)
+ var/obj/belly/B = output_dest
+ B.owner_adjust_nutrition((T.dirt - 50) / 10) //Max tile dirt is 101. so about 5 nutrition from a disgusting floor, I think that's okay.
+ T.dirt = 0
+ T.wash(CLEAN_WASH)
+ return
+ if(!isturf(target.loc))
+ return
+ if(istype(target,/obj/item))
+ var/obj/item/I = target
+ if(is_type_in_list(I, GLOB.item_vore_blacklist) || I.w_class >= ITEMSIZE_HUGE)
+ return
+ if(vac_power > I.w_class)
+ if(vac_power == 7)
+ auto_setting = min(I.w_class, 5)
+ else
+ auto_setting = vac_power
+ playsound(src, 'sound/machines/kitchen/candymaker/candymaker-mid1.ogg', auto_setting * 20, 1, -1)
+ user.visible_message(span_filter_notice("[user] vacuums up \the [target.name]."), span_notice("You vacuum up \the [target.name]..."))
+ I.SpinAnimation(5,1)
+ spawn(5)
+ if(!I.Adjacent(user) || src.loc != user || vac_power < 2) //Cancel if moved/unpowered/dropped
+ return
+ if(I.drop_sound)
+ playsound(src, I.drop_sound, vac_power * 5, 1, -1)
+ playsound(src, 'sound/rakshasa/corrosion3.ogg', auto_setting * 15, 1, -1)
+ I.forceMove(output_dest)
+ else if(istype(target,/obj/effect/decal/cleanable))
+ playsound(src, 'sound/machines/kitchen/candymaker/candymaker-mid1.ogg', auto_setting * 20, 1, -1)
+ user.visible_message(span_filter_notice("[user] vacuums up \the [target.name]."), span_notice("You vacuum up \the [target.name]..."))
+ qdel(target)
+ else if(isliving(target))
+ var/mob/living/L = target
+ var/valid_to_suck = FALSE
+ if(L.anchored || !L.devourable || L == user || L.buckled || !L.can_be_drop_prey)
+ return
+ if(vac_power >= 3)
+ if(L.size_multiplier > 0.5 || istype(L,/mob/living/simple_mob/animal/passive/mouse) || istype(L,/mob/living/simple_mob/animal/passive/lizard))
+ valid_to_suck = TRUE
+ auto_setting = 3
+ if(vac_power >= 6)
+ valid_to_suck = TRUE
+ auto_setting = 6
+ if(valid_to_suck)
+ playsound(src, 'sound/machines/kitchen/candymaker/candymaker-mid1.ogg', auto_setting * 20, 1, -1)
+ user.visible_message(span_filter_notice("[user] vacuums up \the [target.name]."), span_notice("You vacuum up \the [target.name]..."))
+ L.SpinAnimation(5,1)
+ spawn(5)
+ if(!L.Adjacent(user) || src.loc != user || vac_power < 2) //Cancel if moved/unpowered/dropped
+ return
+ playsound(src, 'sound/rakshasa/corrosion3.ogg', auto_setting * 15, 1, -1)
+ L.forceMove(output_dest)
+ return
+
+/obj/item/vac_attachment/resolve_attackby(atom/A, mob/user, var/attack_modifier = 1, var/click_parameters)
+ if(istype(A,/obj/structure) && vac_power > 0)
+ afterattack(A.loc, user, click_parameters)
+ return TRUE
+ return ..()
+
+/obj/item/vac_attachment/pickup(mob/user)
+ .=..()
+ icon_state = "sucker-[vac_power]"
+
+/obj/item/vac_attachment/equipped()
+ .=..()
+ icon_state = "sucker-[vac_power]"
+
+/obj/item/vac_attachment/dropped(mob/user as mob)
+ .=..()
+ icon_state = "sucker_drop"
+
+/obj/item/vac_attachment/verb/hide_pack()
+ set name = "Toggle Vac-Pack Sprites"
+ set desc = "Toggle Vac-Pack sprite visibility"
+ set category = "Object"
+ var/choice = tgui_input_list(usr, "Vac-Pack Visibility Options", "Vac-Pack Visibility Options", list("Show Pack", "Show Tube", "Hidden"))
+ if(choice == "Show Pack")
+ item_state = "sucker"
+ if(choice == "Show Tube")
+ item_state = "sucker_nobag"
+ if(choice == "Hidden")
+ item_state = null
+ usr.update_inv_r_hand()
+ usr.update_inv_l_hand()
+
+/obj/item/storage/Entered(atom/movable/thing, atom/OldLoc) //Holder the mob so they don't get stuck in trashbags etc.
+ . = ..()
+ if(isliving(thing))
+ var/mob/living/L = thing
+ var/mob_holder_type = L.holder_type || /obj/item/holder
+ new mob_holder_type(src, L)
diff --git a/code/game/objects/mob_spawner_vr.dm b/code/game/objects/mob_spawner_vr.dm
index 4919ae4c3b..6b5ff39ca5 100644
--- a/code/game/objects/mob_spawner_vr.dm
+++ b/code/game/objects/mob_spawner_vr.dm
@@ -197,6 +197,65 @@ It also makes it so a ghost wont know where all the goodies/mobs are.
/mob/living/simple_mob/animal/space/alien/queen = 5,
)
+/obj/structure/mob_spawner/scanner/mining_animals
+ name = "Mining Lazy Spawner"
+ spawn_delay = 10 MINUTES
+ range = 10
+ simultaneous_spawns = 1
+ mob_faction = "wild animal"
+ total_spawns = 2
+ destructible = 0
+ anchored = 1
+ invisibility = INVISIBILITY_ABSTRACT
+ spawn_types = list(
+ /mob/living/simple_mob/vore/bat = 70,
+ /mob/living/simple_mob/animal/passive/cockroach = 60,
+ /obj/effect/spider/spiderling/non_growing = 50,
+ /mob/living/simple_mob/animal/giant_spider/tunneler/cave = 50,
+ /mob/living/simple_mob/vore/jelly = 40,
+ /mob/living/simple_mob/vore/aggressive/rat = 30,
+ /mob/living/simple_mob/animal/passive/mouse = 30,
+ /mob/living/simple_mob/animal/passive/mouse/rat = 25,
+ // /mob/living/simple_mob/metroid/mine = 25, // Downstream
+ /mob/living/simple_mob/vore/oregrub = 25,
+ /mob/living/simple_mob/vore/aggressive/dino = 20,
+ /mob/living/simple_mob/animal/space/carp = 20,
+ /mob/living/simple_mob/vore/oregrub/lava = 15,
+ /mob/living/simple_mob/vore/stalker = 10,
+ /mob/living/simple_mob/vore/lamia/copper/cave = 10,
+ /mob/living/simple_mob/vore/lamia/albino/cave = 5,
+ /mob/living/simple_mob/vore/aggressive/lizardman = 5,
+ /mob/living/simple_mob/vore/otie = 5,
+ /mob/living/simple_mob/animal/passive/pillbug = 5, // These aren't dangerous, but are made rare just because few people are going to bother killing them.
+ /obj/structure/closet/crate/mimic/cointoss = 1,
+ /obj/structure/closet/crate/mimic/closet/cointoss = 1,
+ /mob/living/simple_mob/vore/otie/feral = 1,
+ // /mob/living/simple_mob/vore/sonadile = 1, // Removed until sprite issues fixed.
+ /mob/living/simple_mob/animal/space/bear/brown = 1,
+ /mob/living/simple_mob/vore/aggressive/deathclaw = 1,
+ /mob/living/simple_mob/vore/gryphon = 1,
+ /mob/living/simple_mob/vore/demon = 0.5 // VERY rare!
+ )
+
+/obj/structure/mob_spawner/proc/get_used_report(var/obj/structure/closet/crate/mimic/O)
+ if(O in spawned_mobs)
+ spawned_mobs.Remove(O)
+
+/obj/structure/mob_spawner/mouse_nest/mousehole
+ name = "small hole"
+ desc = "A small hole, critters seem to move in and out from here."
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "tunnel_hole"
+ spawn_types = list(
+ /mob/living/simple_mob/animal/passive/mouse = 100,
+ /mob/living/simple_mob/animal/passive/cockroach = 25,
+ /mob/living/simple_mob/animal/passive/mouse/rat/strong = 10, // Because I'm a horrible person. <3
+ /obj/effect/spider/spiderling/non_growing = 5)
+
+/obj/structure/mob_spawner/mouse_nest/mousehole/Initialize(mapload)
+ . = ..()
+ icon_state = "tunnel_hole"
+
/obj/structure/mob_spawner/recycler
desc = "A bizarre mess of robotic limbs, glowing microrefineries, and nanoassemblers gradually converting the pile of raw materials into active hivebots."
destructible = 1
@@ -206,3 +265,4 @@ It also makes it so a ghost wont know where all the goodies/mobs are.
simultaneous_spawns = 6
spawn_delay = 300
spawn_types = list(/mob/living/simple_mob/mechanical/hivebot/swarm = 200, /mob/living/simple_mob/mechanical/hivebot/ranged_damage/basic = 50, /mob/living/simple_mob/mechanical/hivebot/ranged_damage/laser = 25, /mob/living/simple_mob/mechanical/hivebot/ranged_damage/ion = 10, /mob/living/simple_mob/mechanical/hivebot/tank/meatshield = 10)
+
diff --git a/code/game/objects/structures/ghost_pods/event_vr.dm b/code/game/objects/structures/ghost_pods/event_vr.dm
index 8b9709fb9e..6d30fc7895 100644
--- a/code/game/objects/structures/ghost_pods/event_vr.dm
+++ b/code/game/objects/structures/ghost_pods/event_vr.dm
@@ -49,6 +49,7 @@
qdel(newPred.ai_holder)
newPred.ai_holder = null
//newPred.movement_cooldown = 0 // The "needless artificial speed cap" exists for a reason
+ // R.has_hands = TRUE // Downstream
if(M.mind)
M.mind.transfer_to(newPred)
to_chat(M, span_notice("You are " + span_bold("[newPred]") + ", somehow having gotten aboard the station in search of food. \
diff --git a/code/game/objects/structures/ghost_pods/mysterious.dm b/code/game/objects/structures/ghost_pods/mysterious.dm
index d25d2a752c..5a96adb311 100644
--- a/code/game/objects/structures/ghost_pods/mysterious.dm
+++ b/code/game/objects/structures/ghost_pods/mysterious.dm
@@ -16,6 +16,7 @@
lightning_strike(get_turf(src), cosmetic = TRUE)
density = FALSE
var/mob/living/simple_mob/animal/passive/dog/corgi/R = new(get_turf(src))
+ // R.has_hands = TRUE // Downstream
if(M.mind)
M.mind.transfer_to(R)
to_chat(M, span_notice("You are a Corgi! Woof!"))
diff --git a/code/game/objects/structures/loot_piles.dm b/code/game/objects/structures/loot_piles.dm
index 031796653f..87b4da65c9 100644
--- a/code/game/objects/structures/loot_piles.dm
+++ b/code/game/objects/structures/loot_piles.dm
@@ -213,3 +213,42 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
icon_state = "medicine_cabinet"
density = FALSE
loot_element_path = /datum/element/lootable/fresh_medicine
+
+//Micro mecha loot.
+/obj/structure/loot_pile/mecha/mouse_tank
+ name = "\improper Whisker wreckage"
+ desc = "The ruins of a small tank. Perhaps some child's toy?"
+ icon = 'icons/mob/mouse_army.dmi'
+ icon_state = "whisker-broken"
+ density = TRUE
+ anchored = FALSE // In case a dead mecha-mob dies in a bad spot.
+
+ loot_element_path = /datum/element/lootable/mecha/mouse_tank
+
+/obj/structure/loot_pile/mecha/mouse_tank/livewire
+ name = "\improper Livewire wreckage"
+ desc = "The smoldering ruins of a small tank. Perhaps some child's toy?"
+ icon_state = "livewire-broken"
+ density = TRUE
+ anchored = FALSE // In case a dead mecha-mob dies in a bad spot.
+
+ loot_element_path = /datum/element/lootable/mecha/mouse_tank/livewire
+
+/obj/structure/loot_pile/mecha/mouse_tank/eraticator
+ name = "\improper Eraticator wreckage"
+ desc = "The blasted ruins of a small tank. Perhaps some child's toy?"
+ icon_state = "eraticator-broken"
+ density = TRUE
+ anchored = FALSE // In case a dead mecha-mob dies in a b
+
+ loot_element_path = /datum/element/lootable/mecha/mouse_tank/eraticator
+
+/obj/structure/loot_pile/mecha/ripley/pirate
+ icon = 'icons/mob/pirates.dmi'
+ icon_state = "pirate-broken"
+
+/obj/structure/loot_pile/maint/technical
+ density = FALSE
+
+/obj/structure/loot_pile/maint/boxfort
+ density = FALSE
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 781a414d6e..db86fdabb6 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -227,11 +227,9 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_HOLDER, "Show Player Panel", m
if(!f) body += " | "
else f = 0
if(L in player.languages)
- k = span_green(k)
- body += "[k]"
+ body += "[span_green(k)]"
else
- k = span_red(k)
- body += "[k]"
+ body += "[span_red(k)]"
body += {"
"}
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 8298b96a32..5e4d6cb9c7 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1868,7 +1868,7 @@
to_chat(usr, span_filter_adminlog("Failed to remove language '[lang2toggle]' from \the [M]!"))
else
if(!M.add_language(lang2toggle))
- to_chat(usr, span_filter_adminlog("Failed to add language '[lang2toggle]' from \the [M]!"))
+ to_chat(usr, span_filter_adminlog("Failed to add language '[lang2toggle]' to \the [M]!"))
SSadmin_verbs.dynamic_invoke_verb(usr.client, /datum/admin_verb/show_player_panel, M)
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 8db00ad4ed..eb6bd566ff 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -142,7 +142,7 @@ ADMIN_VERB(drop_everything, R_ADMIN, "Drop Everything", ADMIN_VERB_NO_DESCRIPTIO
if(!M)
return
- var/msg = tgui_input_text(usr, "Message:", text("Enter the text you wish to appear to your target:"))
+ var/msg = tgui_input_text(usr, "Message:", text("Enter the text you wish to appear to your target:"), encode = FALSE)
if(msg && !(msg[1] == "<" && msg[length(msg)] == ">")) //You can use HTML but only if the whole thing is HTML. Tries to prevent admin 'accidents'.
msg = sanitize(msg)
diff --git a/code/modules/ai/ai_holder_subtypes/simple_mob_ai.dm b/code/modules/ai/ai_holder_subtypes/simple_mob_ai.dm
index ce5f17ae98..18b7c7d806 100644
--- a/code/modules/ai/ai_holder_subtypes/simple_mob_ai.dm
+++ b/code/modules/ai/ai_holder_subtypes/simple_mob_ai.dm
@@ -226,3 +226,17 @@
// For setting up possible stealth missions
/datum/ai_holder/simple_mob/humanoid/hostile/guard_limit
guard_limit = TRUE
+
+/datum/ai_holder/simple_mob/melee/pack_mob
+ cooperative = TRUE
+ call_distance = 28 // pack mobs should be able to communicate quite a ways - we can assume by howls/etc
+ can_flee = TRUE
+ mauling = TRUE // Kill/finish off unconscious people.
+ vision_range = 12 // This is a bit cheaty - normal vision range is 7 tiles, one screen, setting that to 10 allows us to track targets offscreen by up to 5 tiles, and make for an easier time keeping chase of targets.
+ flee_when_dying = TRUE // animals know to run when wounded/overmatched
+ flee_when_outmatched = TRUE // animals know to run when wounded/overmatched
+
+/datum/ai_holder/simple_mob/melee/pack_mob/post_melee_attack(atom/A)
+ if(holder.Adjacent(A))
+ holder.IMove(get_step(holder, pick(GLOB.alldirs)))
+ holder.face_atom(A)
diff --git a/code/modules/ai/say_list.dm b/code/modules/ai/say_list.dm
index a944bce0f9..9bda39e216 100644
--- a/code/modules/ai/say_list.dm
+++ b/code/modules/ai/say_list.dm
@@ -137,3 +137,105 @@
/datum/say_list/crab
emote_hear = list("hisses")
+
+/datum/say_list/possessed
+ speak = list("Where am I?",
+ "Why am I here?",
+ "Where did everyone go?")
+
+ emote_hear = list("lets out a mournful cry.", "can be heard sobbing.", "groans out in pain.")
+ emote_see = list("kneels down for a moment, picking something up before casting it away.","stands as still as a statue.", "looks to be doing some kind of work.")
+
+ say_maybe_target = list("Is there someone there?", "Who's there?")
+ say_got_target = list("You! You help people!", "Can you help me?", "I'm lost!")
+ say_threaten = list("Help me!", "Please help!", "Hey, who turned out the lights?", "Allonsy!", "Geronimo!")
+ say_stand_down = list("Please. Anyone. Help!", "Where is everyone?", "Where am I?")
+ say_escalate = list("Help!", "I'm sorry!", "I can't stop!", "I don't want to do this!", "I don't want to go!")
+
+//Vox Pirate Saylist
+/datum/say_list/merc/voxpirate
+ speak = list("Lookings for scrap, yaya.",
+ "Tank is lookings low.",
+ "Knowings should haves stayed on the Ark.",
+ "Quills itchings...",
+ "Cravings Teshari on stick.",
+ "Plates locking up. Not good.")
+ emote_see = list("sniffs", "coughs", "taps his foot", "looks around", "checks his equipment")
+
+ say_understood = list("Yayaya!")
+ say_cannot = list("Skreking negatives!", "Can't do that.")
+ say_maybe_target = list("Who's theres?", "Is hearing things?")
+ say_got_target = list("Dust!", "Easy loot!")
+ say_threaten = list("Gets out of heres!")
+ say_stand_down = list("Yaya, runs!", "Kikikiki!")
+ say_escalate = list("Skrek!", "Bringings it!", "Takings shot", "Lock claws!")
+
+
+ //Synth Horror Saylist
+
+/datum/say_list/cyber_horror
+ speak = list("H@!#$$P M@!$#",
+ "GHAA!@@#",
+ "KR@!!N",
+ "K!@@##L!@@ %!@#E",
+ "G@#!$ H@!#%",
+ "H!@%%@ @!E")
+ emote_hear = list("emits", "groans", "wails", "pleads")
+ emote_see = list ("stares unblinkingly.", "jitters and twitches.", "emits a synthetic scream.", "rapidly twitches.", "convulses.", "twitches uncontrollably.", "goes stock still.")
+ say_threaten = list ("FR@#DOM","EN@ T#I$-$","N0$ M^> B@!#")
+ say_got_target = list("I *#@ Y@%","!E@#$P","F#RR @I","D0@#$ ##OK %","IT $##TS")
+
+//Roach Saylists Woo Hoo
+/datum/say_list/roach
+ speak = list("Chitter!","Chk chk!","Tchk?")
+ emote_hear = list("chitters","chirps","shuffles")
+ emote_see = list("rubs its antennae", "skitters", "clacks across the floor")
+
+/datum/say_list/merc/elite // colder. also, actually just assholes.
+ speak = list("I got better pay on my last job.",
+ "So, y'think we'll get to shoot anyone today?",
+ "Fuck, I hate those guys.",
+ "Would be nice for something to happen, for once.",
+ "Think those NT shits'll rear their heads?",
+ "Any of you see anything recently?")
+ emote_see = list("taps his foot", "looks around coldly", "checks his equipment", "rummages in his webbing")
+ say_understood = list("Aff.", "Affirmative.", "Copy.", "Understood.")
+ say_cannot = list("Neg.", "Negative.")
+ say_maybe_target = list("I heard something.")
+ say_got_target = list("Oh, good, I needed more range fodder.", "I'm going to enjoy this.", "I see you.", "Not quiet enough.")
+ say_threaten = list("Hoy, private property, fuck off.", "You're acting mighty bold for a bullet sponge.", "First and last warning; find somewhere else to be.", "I wouldn't do that if I were you.", "Back off or your field medic's getting a bonus.")
+ say_stand_down = list("Damn it, I was hoping you'd push your luck.", "What, that's it? Pussy.", "And don't come back.", "Good call. Don't do it again.", "Harrumph.", "That'll teach 'ya.")
+ say_escalate = list("Oh, I'm gonna enjoy this.", "I'm going to enjoy making you regret that.", "Last mistake you'll make.")
+
+
+//Synth Horror Saylist
+
+/datum/say_list/cyber_horror
+ speak = list("H@!#$$P M@!$#",
+ "GHAA!@@#",
+ "KR@!!N",
+ "K!@@##L!@@ %!@#E",
+ "G@#!$ H@!#%",
+ "H!@%%@ @!E")
+ emote_hear = list("emits", "groans", "wails", "pleads")
+ emote_see = list ("stares unblinkingly.", "jitters and twitches.", "emits a synthetic scream.", "rapidly twitches.", "convulses.", "twitches uncontrollably.", "goes stock still.")
+ say_threaten = list ("FR@#DOM","EN@ T#I$-$","N0$ M^> B@!#")
+ say_got_target = list("I *#@ Y@%","!E@#$P","F#RR @I","D0@#$ ##OK %","IT $##TS")
+
+
+// This one's pretty dumb, but pirates are dumb anyways.
+/datum/say_list/pirate
+ speak = list("Yarr!",
+ "Yohoho and a bottle of rum...",
+ "Getting tried of hardtack.",
+ "What do you do with a drunken sailor...",
+ "One day We'll get that big score.",
+ "They ain't catching this pirate no-sir-ree")
+
+ say_understood = list("Alright, matey.")
+ say_cannot = list("No, matey.")
+ say_maybe_target = list("Eh?", "Who goes there?")
+ say_got_target = list("Yarrrr!", "Just drop your loot and run")
+ say_threaten = list("You best leave, this booty is mine.", "No plank to walk on, just walk away.")
+ say_stand_down = list("Good.", "That's right run you lilly livers.")
+ say_escalate = list("Yarr! The booty is mine!", "Going to gut you landlubber.")
diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm
index ca6165beaf..0f1a21cae1 100644
--- a/code/modules/hydroponics/seed.dm
+++ b/code/modules/hydroponics/seed.dm
@@ -33,6 +33,8 @@
var/list/mutagenic_reagents // Reagents considered uniquely 'mutagenic' by a plant.
var/list/toxic_reagents // Reagents considered uniquely 'toxic' by a plant.
+ var/ai_mob_product = 0 //This variable determines whether or not a mob product is meant to be ai-controlled. If set to 0, mob products die without a player to control them.
+
/datum/seed/New()
set_trait(TRAIT_IMMUTABLE, 0) // If set, plant will never mutate. If -1, plant is highly mutable.
diff --git a/code/modules/hydroponics/seed_datums_vr.dm b/code/modules/hydroponics/seed_datums_vr.dm
index a6b50a0308..b493915c66 100644
--- a/code/modules/hydroponics/seed_datums_vr.dm
+++ b/code/modules/hydroponics/seed_datums_vr.dm
@@ -42,3 +42,76 @@
/datum/seed/gnomes
harvest_sound = 'sound/items/hooh.ogg'
+
+/datum/seed/pitcher_plant //Pitcher plant
+ name = PLANT_PITCHERPLANT
+ seed_name = PLANT_PITCHERPLANT
+ seed_noun = "pits"
+ display_name = "pitcher shoots"
+ can_self_harvest = 1
+ apply_color_to_mob = FALSE
+ has_mob_product = /mob/living/simple_mob/vore/pitcher_plant
+ ai_mob_product = 1
+
+/datum/seed/pitcher_plant/New() //No custom icons yet. No spread trait yet even though pitcher fruit can be planted outside of a tray as I've not tied that to hydroponics code.
+ ..()
+ set_trait(TRAIT_IMMUTABLE,1)
+ set_trait(TRAIT_CARNIVOROUS,1)
+ set_trait(TRAIT_MATURATION,8)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_WATER_CONSUMPTION,6)
+ set_trait(TRAIT_YIELD,1)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"corn")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#a839a2")
+ set_trait(TRAIT_PLANT_COLOUR,"#5b6f43")
+ set_trait(TRAIT_PLANT_ICON,"ambrosia")
+
+// Tea plants/variants.
+/datum/seed/tea
+ name = PLANT_TEA
+ seed_name = PLANT_TEA
+ display_name = "tea plant"
+ chems = list(REAGENT_ID_TEAMUSH = list(3,10))
+ mutants = null
+ kitchen_tag = PLANT_TEA
+
+/datum/seed/tea/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,5)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,6)
+ set_trait(TRAIT_POTENCY,20)
+ set_trait(TRAIT_PRODUCT_ICON,"tea")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#b7e496")
+ set_trait(TRAIT_PLANT_COLOUR,"#b7e496")
+ set_trait(TRAIT_PLANT_ICON,"bush4")
+ set_trait(TRAIT_IDEAL_HEAT, 298)
+ set_trait(TRAIT_IDEAL_LIGHT, 7)
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25)
+
+/datum/seed/hardlightseed //WIP: havent ported the mob and such yet, best someone more keen on these mobs does it - Jack
+ name = PLANT_NULLHARDLIGHT
+ seed_name = "Biomechanical Hardlight generator seed"
+ display_name = "Biomechanical Hardlight stem"
+ mutants = null
+ can_self_harvest = 1
+ has_mob_product = /mob/living/simple_mob/animal/synx/ai/pet/holo
+ ai_mob_product = 1
+
+/datum/seed/hardlightseed/New()
+ ..()
+ set_trait(TRAIT_IMMUTABLE,1) //Normal genetics wont be able to do much with the mechanical parts, its more a machine than a real plant
+ set_trait(TRAIT_MATURATION,1)
+ set_trait(TRAIT_PRODUCTION,1)
+ set_trait(TRAIT_YIELD,1)
+ set_trait(TRAIT_POTENCY,1)
+ set_trait(TRAIT_PRODUCT_ICON,"alien4")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#00FFFF")
+ set_trait(TRAIT_PLANT_COLOUR,"#00FFFF")
+ set_trait(TRAIT_PLANT_ICON,"alien4") //spooky pods
+ set_trait(TRAIT_IDEAL_HEAT, 283)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0)
+ set_trait(TRAIT_WATER_CONSUMPTION, 0)
diff --git a/code/modules/hydroponics/seed_mobs.dm b/code/modules/hydroponics/seed_mobs.dm
index 83bcf938d8..63c9f096ba 100644
--- a/code/modules/hydroponics/seed_mobs.dm
+++ b/code/modules/hydroponics/seed_mobs.dm
@@ -1,7 +1,7 @@
// The following procs are used to grab players for mobs produced by a seed (mostly for dionaea).
/datum/seed/proc/handle_living_product(var/mob/living/host)
- if(!host || !istype(host)) return
+ if(!host || !istype(host) || ai_mob_product) return
if(apply_color_to_mob)
host.color = traits[TRAIT_PRODUCT_COLOUR]
diff --git a/code/modules/hydroponics/seed_packets.dm b/code/modules/hydroponics/seed_packets.dm
index f16fb1db03..9a9525b67c 100644
--- a/code/modules/hydroponics/seed_packets.dm
+++ b/code/modules/hydroponics/seed_packets.dm
@@ -363,3 +363,9 @@ GLOBAL_LIST_BOILERPLATE(all_seed_packs, /obj/item/seeds)
/obj/item/seeds/megashroom
seed_type = PLANT_MEGAM
+
+/obj/item/seeds/teaseed
+ seed_type = PLANT_TEA
+
+/obj/item/seeds/pitcherseed
+ seed_type = PLANT_PITCHERPLANT
diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm
index d87e8afb01..94c56865ee 100644
--- a/code/modules/hydroponics/trays/tray.dm
+++ b/code/modules/hydroponics/trays/tray.dm
@@ -1,3 +1,5 @@
+#define AGE_MOD_MAX 10 // Define for age_mod sanity check as a define to allow for easy tweaking.
+
/obj/machinery/portable_atmospherics/hydroponics
name = "hydroponics tray"
desc = "A tray usually full of fluid for growing plants."
@@ -30,6 +32,7 @@
var/toxins = 0 // Toxicity in the tray?
var/mutation_level = 0 // When it hits 100, the plant mutates.
var/tray_light = 1 // Supplied lighting.
+ var/age_mod = 0 // Variable for chems which speed up plant growth. On average, every 3 age mod reduces growing time by 2.5 minutes.
// Mechanical concerns.
var/health = 0 // Plant health.
@@ -133,6 +136,10 @@
REAGENT_ID_MUTAGEN = 15
)
+ var/static/list/age_reagents = list(
+ REAGENT_ID_PITCHERNECTAR = 1
+ )
+
/obj/machinery/portable_atmospherics/hydroponics/AltClick(var/mob/living/user)
if(!istype(user))
return
@@ -308,6 +315,9 @@
else if(toxic_reagents[R.id])
toxins += toxic_reagents[R.id] * reagent_total
+ if(age_reagents[R.id])
+ age_mod += age_reagents[R.id] * reagent_total
+
//Handle some general level adjustments. These values are independent of plants existing.
if(weedkiller_reagents[R.id])
weedlevel -= weedkiller_reagents[R.id] * reagent_total
@@ -359,6 +369,7 @@
age = 0
sampled = 0
mutation_mod = 0
+ age_mod = 0
check_health()
return
@@ -377,6 +388,7 @@
age = 0
yield_mod = 0
mutation_mod = 0
+ age_mod = 0
to_chat(user, span_filter_notice("You remove the dead plant."))
lastproduce = 0
@@ -396,6 +408,7 @@
dead = 0
age = 0
+ age_mod = 0
health = seed.get_trait(TRAIT_ENDURANCE)
lastcycle = world.time
harvest = 0
@@ -472,6 +485,7 @@
pestlevel = max(0,min(pestlevel,10))
weedlevel = max(0,min(weedlevel,10))
toxins = max(0,min(toxins,10))
+ age_mod = max(0,min(age_mod,AGE_MOD_MAX)) // age_mod sanity check
/obj/machinery/portable_atmospherics/hydroponics/proc/mutate_species()
@@ -707,3 +721,5 @@
closed_system = !closed_system
to_chat(user, span_filter_notice("You [closed_system ? "close" : "open"] the tray's lid."))
update_icon()
+
+#undef AGE_MOD_MAX
diff --git a/code/modules/hydroponics/trays/tray_process.dm b/code/modules/hydroponics/trays/tray_process.dm
index edc54a30a2..4ea0582e79 100644
--- a/code/modules/hydroponics/trays/tray_process.dm
+++ b/code/modules/hydroponics/trays/tray_process.dm
@@ -38,7 +38,11 @@
return
// Advance plant age.
- if(prob(30)) age += 1 * HYDRO_SPEED_MULTIPLIER
+ if(prob(30))
+ age += 1 * HYDRO_SPEED_MULTIPLIER
+ if(age_mod >= 1) //Age reagents double the speed of plant growth in sufficient quantities
+ age += 1 * HYDRO_SPEED_MULTIPLIER
+ age_mod -= 1
//Highly mutable plants have a chance of mutating every tick.
if(seed.get_trait(TRAIT_IMMUTABLE) == -1)
diff --git a/code/modules/mob/dead/corpse.dm b/code/modules/mob/dead/corpse.dm
index 2440b43af7..9084719d97 100644
--- a/code/modules/mob/dead/corpse.dm
+++ b/code/modules/mob/dead/corpse.dm
@@ -35,13 +35,15 @@
/// Color is optional, each position after the name is a color channel from 1 to n.
var/list/ear_secondary_type
var/list/wing_type = null
+ var/hair = null
var/corpsesynthtype = 0 // 0 for organic, 1 for drone, 2 for posibrain
var/corpsesynthbrand = "Unbranded"
+ var/corpsesensormode = 0
delete_me = TRUE
/obj/effect/landmark/mobcorpse/Initialize(mapload)
- . = ..()
createCorpse()
+ . = ..()
/obj/effect/landmark/mobcorpse/proc/createCorpse() //Creates a mob and checks for gear in each slot before attempting to equip it.
var/mob/living/carbon/human/M = new /mob/living/carbon/human (src.loc)
@@ -90,6 +92,9 @@
M.g_ears3 = color_rgb_list[2]
M.b_ears3 = color_rgb_list[3]
M.update_hair()
+ if(hair)
+ M.h_style = hair
+ M.update_hair()
// handle secondary ears
if(length(ear_secondary_type) && (ear_secondary_type[1] in GLOB.ear_styles_list))
M.ear_secondary_style = GLOB.ear_styles_list[ear_secondary_type[1]]
@@ -117,6 +122,8 @@
M.update_wing_showing()
M.real_name = generateCorpseName()
M.set_stat(DEAD) //Kills the new mob
+ M.digest_leave_remains = TRUE
+ M.can_be_drop_prey = TRUE
if(corpsesynthtype > 0)
if(!corpsesynthbrand)
corpsesynthbrand = "Unbranded"
@@ -128,6 +135,10 @@
O.robotize(corpsesynthbrand)
if(src.corpseuniform)
M.equip_to_slot_or_del(new src.corpseuniform(M), slot_w_uniform)
+ if(M.w_uniform)
+ M.w_uniform?:sensor_mode = corpsesensormode
+ if(src.corpsesuit)
+ M.equip_to_slot_or_del(new src.corpsesuit(M), slot_wear_suit)
if(src.corpseshoes)
M.equip_to_slot_or_del(new src.corpseshoes(M), slot_shoes)
if(src.corpsegloves)
diff --git a/code/modules/mob/dead/corpse_vox.dm b/code/modules/mob/dead/corpse_vox.dm
new file mode 100644
index 0000000000..c68aecdb99
--- /dev/null
+++ b/code/modules/mob/dead/corpse_vox.dm
@@ -0,0 +1,57 @@
+//////////////////////////
+// Vox Bodies
+//////////////////////////
+
+/obj/effect/landmark/mobcorpse/vox
+ name = "vox"
+ hair = "Short Vox Quills"
+ species = SPECIES_VOX
+
+//Types of Vox corpses:
+
+/obj/effect/landmark/mobcorpse/vox/pirate
+ name = "vox pirate"
+ corpseuniform = /obj/item/clothing/under/color/black
+ corpsesuit = /obj/item/clothing/suit/armor/vox_scrap
+ corpseshoes = /obj/item/clothing/shoes/boots/workboots
+ corpsegloves = /obj/item/clothing/gloves/light_brown
+ corpsemask = /obj/item/clothing/mask/breath
+
+/obj/effect/landmark/mobcorpse/vox/boarder_m
+ name = "vox melee boarder"
+ corpseuniform = /obj/item/clothing/under/vox/vox_casual
+ corpsesuit = /obj/item/clothing/suit/armor/vox_scrap
+ corpseshoes = /obj/item/clothing/shoes/boots/workboots
+ corpsegloves = /obj/item/clothing/gloves/light_brown
+ corpsemask = /obj/item/clothing/mask/breath
+
+/obj/effect/landmark/mobcorpse/vox/boarder_r
+ name = "vox ranged boarder"
+ corpseuniform = /obj/item/clothing/under/rank/bartender
+ corpsesuit = /obj/item/clothing/suit/armor/bulletproof
+ corpseshoes = /obj/item/clothing/shoes/boots/workboots
+ corpsemask = /obj/item/clothing/mask/breath
+
+/obj/effect/landmark/mobcorpse/vox/boarder_t
+ name = "vox salvage technician"
+ corpseuniform = /obj/item/clothing/under/rank/bartender
+ corpsesuit = /obj/item/clothing/suit/armor/bulletproof
+ corpseshoes = /obj/item/clothing/shoes/boots/workboots
+ corpsemask = /obj/item/clothing/mask/breath
+
+/obj/effect/landmark/mobcorpse/vox/suppressor
+ name = "vox suppressor"
+ corpseuniform = /obj/item/clothing/under/color/red
+ corpsesuit = /obj/item/clothing/suit/storage/toggle/fr_jacket
+ corpseshoes = /obj/item/clothing/shoes/orange
+ corpsegloves = /obj/item/clothing/gloves/red
+ corpsemask = /obj/item/clothing/mask/gas/half
+
+/obj/effect/landmark/mobcorpse/vox/captain
+ name = "vox captain"
+ corpseuniform = /obj/item/clothing/under/color/black
+ corpsesuit = /obj/item/clothing/suit/space/vox/carapace
+ corpseshoes = /obj/item/clothing/shoes/magboots/vox
+ corpsegloves = /obj/item/clothing/gloves/light_brown
+ corpsemask = /obj/item/clothing/mask/breath
+ corpsehelmet = /obj/item/clothing/head/helmet/riot
diff --git a/code/modules/mob/living/carbon/human/species/station/protean/protean_powers.dm b/code/modules/mob/living/carbon/human/species/station/protean/protean_powers.dm
index 5e34d9ae96..1ccede6549 100644
--- a/code/modules/mob/living/carbon/human/species/station/protean/protean_powers.dm
+++ b/code/modules/mob/living/carbon/human/species/station/protean/protean_powers.dm
@@ -404,7 +404,7 @@
"rat" = image(icon = 'icons/mob/species/protean/protean64x32.dmi', icon_state = "rat", pixel_x = -16),
"lizard" = image(icon = 'icons/mob/species/protean/protean64x32.dmi', icon_state = "lizard", pixel_x = -16),
"wolf" = image(icon = 'icons/mob/species/protean/protean64x32.dmi', icon_state = "wolf", pixel_x = -16),
- //"drake" = image(icon = 'modular_chomp/icons/mob/species/protean/protean64x64.dmi', icon_state = "drake", pixel_x = -16),
+ //"drake" = image(icon = 'icons/mob/species/protean/protean64x64.dmi', icon_state = "drake", pixel_x = -16),
"teppi" = image(icon = 'icons/mob/species/protean/protean64x64.dmi', icon_state = "teppi", pixel_x = -16),
"panther" = image(icon = 'icons/mob/species/protean/protean64x64.dmi', icon_state = "panther", pixel_x = -16),
"robodrgn" = image(icon = 'icons/mob/species/protean/protean128x64.dmi', icon_state = "robodrgn", pixel_x = -48),
diff --git a/code/modules/mob/living/carbon/human/species/station/station_special_abilities.dm b/code/modules/mob/living/carbon/human/species/station/station_special_abilities.dm
index 7760b4441c..7c63db9516 100644
--- a/code/modules/mob/living/carbon/human/species/station/station_special_abilities.dm
+++ b/code/modules/mob/living/carbon/human/species/station/station_special_abilities.dm
@@ -1183,3 +1183,184 @@
if("eyes")
ourmsg += "on the eyes!"
visible_message(span_warning(ourmsg))
+
+//succuby bite is back baby
+/mob/living/proc/succubus_bite()
+ set name = "Inject Prey"
+ set desc = "Bite prey and inject them with various toxins."
+ set category = "Abilities.Succubus"
+
+ if(last_special > world.time)
+ return
+
+ if(!ishuman(src))
+ return //If you're not a human you don't have permission to do this.
+
+ var/mob/living/carbon/human/C = src
+
+ var/obj/item/grab/G = src.get_active_hand()
+
+ if(!istype(G))
+ to_chat(C, span_warning("You must be grabbing a creature in your active hand to bite them."))
+ return
+
+ var/mob/living/carbon/human/T = G.affecting
+
+ if(!istype(T) || T.isSynthetic())
+ to_chat(src, span_warning("\The [T] is not able to be bitten."))
+ return
+
+ if(G.state != GRAB_NECK)
+ to_chat(C, span_warning("You must have a tighter grip to bite this creature."))
+ return
+
+ var/choice = tgui_input_list(src, "What do you wish to inject?", "Reagent", list(REAGENT_APHRODISIAC, "Numbing", "Paralyzing"))
+
+ last_special = world.time + 600
+
+ if(!choice)
+ return
+
+ src.visible_message(span_bolddanger("[src] moves their head next to [T]'s neck, seemingly looking for something!"))
+
+ if(do_after(src, 300, T)) //Thrirty seconds.
+ if(choice == REAGENT_APHRODISIAC)
+ src.show_message(span_warning("You sink your fangs into [T] and inject your aphrodisiac!"))
+ src.visible_message(span_red("[src] sinks their fangs into [T]!"))
+ T.bloodstr.add_reagent(REAGENT_ID_APHRODIAC_FLUID,100)
+ return 0
+ else if(choice == "Numbing")
+ src.show_message(span_warning("You sink your fangs into [T] and inject your poison!"))
+ src.visible_message(span_red("[src] sinks their fangs into [T]!"))
+ T.bloodstr.add_reagent(REAGENT_ID_NUMBING_FLUID,20) //Poisons should work when more units are injected
+ else if(choice == "Paralyzing")
+ src.show_message(span_warning("You sink your fangs into [T] and inject your poison!"))
+ src.visible_message(span_red("[src] sinks their fangs into [T]!"))
+ T.bloodstr.add_reagent(REAGENT_ID_PARALYZE_FLUID,20) //Poisons should work when more units are injected
+ else
+ return //Should never happen
+
+/datum/reagent/succubi_aphrodisiac
+ name = REAGENT_APHRODISIAC
+ id = REAGENT_ID_APHRODIAC_FLUID
+ description = "A unknown liquid, it smells sweet"
+ metabolism = REM * 0.8
+ color = "#8A0829"
+ scannable = 0
+ wiki_flag = WIKI_SPOILER
+ supply_conversion_value = REFINERYEXPORT_VALUE_PROCESSED
+ industrial_use = REFINERYEXPORT_REASON_MATSCI
+
+/datum/reagent/succubi_aphrodisiac/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
+ if(prob(3))
+ M.show_message(span_warning("You feel funny, and fall in love with the person in front of you"))
+ M.say(pick("!blushes", "!moans", "!giggles", "!turns visibly red")) //using mob say so we dont have to define this dumb one time use emote that equates to just blushing -shark
+ //M.charmed() //TODO
+ return
+
+/datum/reagent/succubi_numbing //Using numbing_enzyme instead.
+ name = REAGENT_NUMBING_FLUID
+ id = REAGENT_ID_NUMBING_FLUID
+ description = "A unknown liquid, it doesn't smell"
+ metabolism = REM * 0.5
+ color = "#41029B"
+ scannable = 0
+ supply_conversion_value = REFINERYEXPORT_VALUE_PROCESSED
+ industrial_use = REFINERYEXPORT_REASON_MATSCI
+
+/datum/reagent/succubi_numbing/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
+
+
+ M.eye_blurry = max(M.eye_blurry, 10)
+ M.Weaken(2)
+ M.drowsyness = max(M.drowsyness, 20)
+ if(prob(7))
+ M.show_message(span_warning("You start to feel weakened, your body seems heavy."))
+ return
+
+/datum/reagent/succubi_paralize
+ name = REAGENT_PARALYZE_FLUID
+ id = REAGENT_ID_PARALYZE_FLUID
+ description = "A unknown liquid, it doesn't smell"
+ metabolism= REM * 0.5
+ color = "#41029B"
+ scannable = 0
+ supply_conversion_value = REFINERYEXPORT_VALUE_PROCESSED
+ industrial_use = REFINERYEXPORT_REASON_MATSCI
+
+/datum/reagent/succubi_paralize/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) //will first keep it like that. lets see what it changes. if nothing, than I will rework the effect again
+
+ M.Weaken(20)
+ M.eye_blurry = max(M.eye_blurry, 10)
+ if(prob(10))
+ M.show_message(span_warning("You lose sensation of your body."))
+ return
+
+
+//egglaying
+var/eggs = 0
+
+
+/mob/living/proc/mobegglaying()
+ set name = "Egg laying"
+ set desc = "you can lay Eggs"
+ set category = "Abilities.General"
+
+ var/mob/living/carbon/human/C = src
+
+ if(last_special > world.time)
+ return
+
+ var/choice = tgui_input_list(src, "What do you want to do?", "Egg Option", list("Make a Egg", "lay your Eggs"))
+ last_special = world.time + 600
+
+ if(!choice)
+ return
+
+ if(do_after(src, 300)) //Thrirty seconds.
+ if(choice == "Make a Egg")
+ src.show_message(span_warning("You feel your belly bulging a bit, you made an egg!"))
+ C.nutrition -=150
+ eggs += 1
+ return 0
+ else if(choice == "Make a Egg" && eggs > 5)
+ src.show_message(span_warning("Your Belly is full of Eggs you cant have more!!"))
+ return 0
+ else if(choice == "lay your Eggs" && eggs > 0)
+ src.visible_message(span_infoplain(span_white("[src] freezes and vissibly tries to squat down")))
+
+ while(eggs > 0)
+ src.show_message(span_warning("You lay a egg!"))
+ eggs--
+ var/obj/item/reagent_containers/food/snacks/egg/E = new(get_turf(src))
+ E.pixel_x = rand(-6,6)
+ E.pixel_y = rand(-6,6)
+ return
+ else
+ src.visible_message(span_warning("you dont have any eggs!"))
+ return //Should never happen
+
+/mob/living/proc/insect_sting()
+ set name = "Insect Sting"
+ set desc = "Sting a target and inject a small amount of toxin"
+ set category = "Abilities.General"
+
+ if(last_special > world.time)
+ return
+
+ var/list/victims = list()
+ for(var/mob/living/carbon/C in oview(1))
+ victims += C
+ var/mob/living/carbon/T = tgui_input_list(src, "Who will we sting?", "Target", victims)
+
+ if(!T)
+ return
+ if(T.isSynthetic())
+ to_chat(src, span_notice("We are unable to pierce the outer shell of [T]."))
+ return
+
+ to_chat(src, span_notice("You jab your stinger into [T]."))
+ to_chat(T, span_danger("You feel a stabbing pain as you are stung!"))
+ src.visible_message(span_infoplain(span_red("[src] sinks their stinger into [T]!")))
+ T.bloodstr.add_reagent(REAGENT_ID_CONDENSEDCAPSAICINV,3)
+ last_special = world.time + 50 // Many little jabs instead of one big one
diff --git a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper.dm b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper.dm
index 0388c64734..10501233a9 100644
--- a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper.dm
+++ b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper.dm
@@ -36,12 +36,16 @@
var/datum/matter_synth/glass = null
var/datum/matter_synth/wood = null
var/datum/matter_synth/plastic = null
+ var/datum/matter_synth/water = null
var/digest_brute = 2
var/digest_burn = 3
var/digest_multiplier = 1
var/recycles = FALSE
var/medsensor = TRUE //Does belly sprite come with patient ok/dead light?
var/obj/item/healthanalyzer/med_analyzer = null
+ var/ore_storage = FALSE
+ var/max_ore_storage = 500
+ var/current_capacity = 0
flags = NOBLUDGEON
/obj/item/dogborg/sleeper/Initialize(mapload)
@@ -124,7 +128,7 @@
trashman.reset_view(src)
START_PROCESSING(SSobj, src)
user.visible_message(span_warning("[hound.name]'s [src.name] groans lightly as [trashman] slips inside."), span_notice("Your [src.name] groans lightly as [trashman] slips inside."))
- log_admin("[key_name(hound)] has eaten [key_name(patient)] with a cyborg belly. ([hound ? "JMP" : "null"])")
+ log_attack("[key_name(hound)] has eaten [key_name(patient)] with a cyborg belly. ([hound ? "JMP" : "null"])")
playsound(src, gulpsound, vol = 100, vary = 1, falloff = 0.1, preference = /datum/preference/toggle/eating_noises)
if(delivery)
if(islist(deliverylists[delivery_tag]))
@@ -273,6 +277,9 @@
dat += span_red(span_bold("Current load:") + " [length(contents)] / [max_item_count] objects.") + "
"
dat += span_gray("([contents.Join(", ")])") + "
"
+ if(ore_storage)
+ dat += "Current ore capacity: [current_capacity] / [max_ore_storage].
"
+
if(delivery && length(contents))
dat += span_red(span_bold("Current load:") + " [length(contents)] / [max_item_count] objects.") + "
"
dat += span_gray("Cargo compartment slot: Cargo 1.") + "
"
@@ -552,6 +559,7 @@
if(SSair.current_cycle%3==1 && length(touchable_items))
//Burn all the mobs or add them to the exclusion list
+ var/volume = 0
for(var/mob/living/T in (touchable_items))
touchable_items -= T //Exclude mobs from loose item picking.
if(SEND_SIGNAL(T, COMSIG_CHECK_FOR_GODMODE) & COMSIG_GODMODE_CANCEL)
@@ -567,6 +575,8 @@
var/actual_burn = T.getFireLoss() - old_burn
var/damage_gain = actual_brute + actual_burn
hound.adjust_nutrition(2.5 * damage_gain) //drain(-25 * damage_gain) //25*total loss as with voreorgan stats.
+ if(water)
+ water.add_charge(damage_gain)
if(T.stat == DEAD)
if(ishuman(T))
log_admin("[key_name(hound)] has digested [key_name(T)] with a cyborg belly. ([hound ? "JMP" : "null"])")
@@ -600,6 +610,15 @@
items_preserved |= brain
else
T.drop_from_inventory(I, src)
+ if(ishuman(T))
+ var/mob/living/carbon/human/Prey = T
+ volume = (Prey.bloodstr.total_volume + Prey.ingested.total_volume + Prey.touching.total_volume + Prey.weight) * Prey.size_multiplier
+ if(water)
+ water.add_charge(volume)
+ if(T.reagents)
+ volume = T.reagents.total_volume
+ if(water)
+ water.add_charge(volume)
if(T.ckey)
GLOB.prey_digested_roundstat++
if(patient == T)
@@ -615,11 +634,15 @@
//Handle the target being anything but a /mob/living
var/obj/item/T = target
if(istype(T))
+ if(T.reagents)
+ volume = T.reagents.total_volume
var/is_trash = istype(T, /obj/item/trash)
var/digested = T.digest_act(item_storage = src)
if(!digested)
items_preserved |= T
else
+ if(volume && water)
+ water.add_charge(volume)
if(recycles && T.matter)
for(var/material in T.matter)
var/total_material = T.matter[material]
diff --git a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_types.dm b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_types.dm
index 93892f247f..d5cd8c1319 100644
--- a/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_types.dm
+++ b/code/modules/mob/living/silicon/robot/dogborg/dog_sleeper_types.dm
@@ -42,16 +42,58 @@
delivery = TRUE
recycles = FALSE
*/
+
/obj/item/dogborg/sleeper/compactor/supply //Miner borg belly
name = "Supply Storage"
desc = "A mounted survival unit with fuel processor, helpful with both deliveries and assisting injured miners."
icon_state = "sleeperc"
injection_chems = list(REAGENT_ID_GLUCOSE,REAGENT_ID_INAPROVALINE,REAGENT_ID_TRICORDRAZINE)
- max_item_count = 10
- recycles = FALSE
- stabilizer = TRUE
+ max_item_count = 20
+ ore_storage = TRUE
+ var/list/stored_ore = list(
+ ORE_SAND = 0,
+ ORE_HEMATITE = 0,
+ ORE_CARBON = 0,
+ ORE_COPPER = 0,
+ ORE_TIN = 0,
+ ORE_VOPAL = 0,
+ ORE_PAINITE = 0,
+ ORE_QUARTZ = 0,
+ ORE_BAUXITE = 0,
+ ORE_PHORON = 0,
+ ORE_SILVER = 0,
+ ORE_GOLD = 0,
+ ORE_MARBLE = 0,
+ ORE_URANIUM = 0,
+ ORE_DIAMOND = 0,
+ ORE_PLATINUM = 0,
+ ORE_LEAD = 0,
+ ORE_MHYDROGEN = 0,
+ ORE_VERDANTIUM = 0,
+ ORE_RUTILE = 0)
medsensor = FALSE
+/obj/item/dogborg/sleeper/compactor/supply/Entered(atom/movable/thing, atom/OldLoc)
+ . = ..()
+ if(istype(thing, /obj/item/ore))
+ var/obj/item/ore/ore = thing
+ stored_ore[ore.material]++
+ current_capacity++
+ qdel(ore)
+
+/obj/structure/ore_box/attackby(obj/item/W as obj, mob/user as mob)
+ if(istype(W, /obj/item/dogborg/sleeper/compactor/supply))
+ var/obj/item/dogborg/sleeper/compactor/supply/S = W
+ for(var/ore in S.stored_ore)
+ if(S.stored_ore[ore] > 0)
+ var/ore_amount = S.stored_ore[ore] // How many ores does the satchel have?
+ stored_ore[ore] += ore_amount // Add the ore to the machine.
+ S.stored_ore[ore] = 0 // Set the value of the ore in the satchel to 0.
+ S.current_capacity = 0 // Set the amount of ore in the satchel to 0.
+ to_chat(user, span_notice("You empty the satchel into the box."))
+ return
+ ..()
+
/obj/item/dogborg/sleeper/compactor/brewer
name = "Brew Belly"
desc = "A mounted drunk tank unit with fuel processor, for putting away particularly rowdy patrons."
@@ -69,6 +111,20 @@
max_item_count = 10
recycles = FALSE
+/obj/item/dogborg/sleeper/compactor/brewer/inject_chem(mob/user, chem)
+ if(patient && patient.reagents)
+ if((chem in injection_chems) + REAGENT_ID_INAPROVALINE)
+ if(hound.cell.charge < 200) //This is so borgs don't kill themselves with it.
+ to_chat(hound, span_notice("You don't have enough power to synthesize fluids."))
+ return
+ else if(patient.reagents.get_reagent_amount(chem) + 10 >= 50) //Preventing people from accidentally killing themselves by trying to inject too many chemicals!
+ to_chat(hound, span_notice("Your stomach is currently too full of fluids to secrete more fluids of this kind."))
+ else if(patient.reagents.get_reagent_amount(chem) + 10 <= 50) //No overdoses for you
+ patient.reagents.add_reagent(chem, inject_amount)
+ drain(100) //-100 charge per injection
+ var/units = round(patient.reagents.get_reagent_amount(chem))
+ to_chat(hound, span_notice("Injecting [units] unit\s into occupant.")) //If they were immersed, the reagents wouldn't leave with them.
+
/obj/item/dogborg/sleeper/K9/ert
name = "Emergency Storage"
desc = "A mounted 'emergency containment cell'."
diff --git a/code/modules/mob/living/simple_mob/combat.dm b/code/modules/mob/living/simple_mob/combat.dm
index 727efefcd2..f981b235e3 100644
--- a/code/modules/mob/living/simple_mob/combat.dm
+++ b/code/modules/mob/living/simple_mob/combat.dm
@@ -113,6 +113,15 @@
try_reload()
return FALSE
+ if(ranged_cooldown_time) //If you have a non-zero number in a mob's variables, this pattern begins.
+ if(ranged_cooldown <= world.time) //Further down, a timer keeps adding to the ranged_cooldown variable automatically.
+ visible_message(span_danger(span_bold("\The [src]") + " fires at \the [A]!")) //Leave notice of shooting.
+ shoot(A) //Perform the shoot action
+ if(casingtype) //If the mob is designated to leave casings...
+ new casingtype(loc) //... leave the casing.
+ ranged_cooldown = world.time + ranged_cooldown_time + ((injury_level / 2) SECONDS) //Special addition here. This is a timer. Keeping updating the time after shooting. Add that ranged cooldown time specified in the mob to the world time.
+ return TRUE
+
visible_message(span_danger(span_bold("\The [src]") + " fires at \the [A]!"))
shoot(A)
if(casingtype)
@@ -123,7 +132,6 @@
return TRUE
-
// Shoot a bullet at something.
/mob/living/simple_mob/proc/shoot(atom/A)
if(A == get_turf(src))
@@ -254,7 +262,6 @@
set_AI_busy(FALSE)
-
// Override these four for special custom animations (like the GOLEM).
/mob/living/simple_mob/proc/melee_pre_animation(atom/A)
do_windup_animation(A, melee_attack_delay)
diff --git a/code/modules/mob/living/simple_mob/defense.dm b/code/modules/mob/living/simple_mob/defense.dm
index 48d845d23e..d5d6bc8d1a 100644
--- a/code/modules/mob/living/simple_mob/defense.dm
+++ b/code/modules/mob/living/simple_mob/defense.dm
@@ -14,6 +14,9 @@
switch(L.a_intent)
if(I_HELP)
if(health > 0)
+ if(L.zone_sel.selecting == BP_GROIN)
+ if(L.vore_bellyrub(src))
+ return
L.visible_message(span_notice("\The [L] [response_help] \the [src]."))
if(I_DISARM)
@@ -199,7 +202,8 @@
// Electricity
/mob/living/simple_mob/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, var/def_zone = null)
- shock_damage *= siemens_coeff
+ var/zap = min((1-get_shock_protection()), siemens_coeff)
+ shock_damage *= zap
if(shock_damage < 1)
return 0
diff --git a/code/modules/mob/living/simple_mob/harvesting.dm b/code/modules/mob/living/simple_mob/harvesting.dm
index 9d2d497cce..6cbdc2cb7c 100644
--- a/code/modules/mob/living/simple_mob/harvesting.dm
+++ b/code/modules/mob/living/simple_mob/harvesting.dm
@@ -18,10 +18,10 @@
/mob/living/simple_mob/examine(mob/user)
. = ..()
if(stat != DEAD && user && harvest_tool && (get_dist(user, src) <= 3))
- . += span_notice("\The [src] can be [harvest_verb] with a [initial(harvest_tool.name)] every [round(harvest_cooldown, 0.1)] minutes.")
+ . += span_notice("\The [src] can be [harvest_verb] with a [initial(harvest_tool.name)] every [harvest_cooldown / 600] minutes.")
var/time_to_harvest = (harvest_recent + harvest_cooldown) - world.time
if(time_to_harvest > 0)
- . += span_notice("It can be [harvest_verb] in [time_to_harvest / (1 MINUTE)] second(s).")
+ . += span_notice("It can be [harvest_verb] in [(time_to_harvest)] second(s).")
else
. += span_notice("It can be [harvest_verb] now.")
diff --git a/code/modules/mob/living/simple_mob/life.dm b/code/modules/mob/living/simple_mob/life.dm
index 0046f723f3..36e7ea8274 100644
--- a/code/modules/mob/living/simple_mob/life.dm
+++ b/code/modules/mob/living/simple_mob/life.dm
@@ -61,7 +61,7 @@
healths.icon_state = "health7"
//Updates the nutrition while we're here
- var/food_per = (nutrition / 500) * 100 //VOREStation Edit: Bandaid hardcode number to avoid misleading percentage based hunger alerts with our 6k cap.
+ var/food_per = (nutrition / max_nutrition) * 100
switch(food_per)
if(90 to INFINITY)
clear_alert("nutrition")
@@ -187,6 +187,9 @@
if(purge)
purge -= 1
+/mob/living/simple_mob/
+ var/update_icon_timer
+
/mob/living/simple_mob/death(gibbed, deathmessage = "dies!")
density = FALSE //We don't block even if we did before
@@ -198,7 +201,14 @@
if(prob(loot_list[path]))
new path(get_turf(src))
- spawn(3) //We'll update our icon in a sec
- update_icon()
+ update_icon_timer = addtimer(CALLBACK(src, PROC_REF(callback_update_icon)), 3, TIMER_STOPPABLE)
return ..(gibbed,deathmessage)
+
+/mob/living/simple_mob/proc/callback_update_icon()
+ update_icon()
+
+/mob/living/simple_mob/Destroy()
+ deltimer(update_icon_timer)
+ update_icon_timer = null
+ . = ..()
diff --git a/code/modules/mob/living/simple_mob/on_click.dm b/code/modules/mob/living/simple_mob/on_click.dm
index ea0aeba2a6..69e18211f2 100644
--- a/code/modules/mob/living/simple_mob/on_click.dm
+++ b/code/modules/mob/living/simple_mob/on_click.dm
@@ -13,9 +13,13 @@
switch(a_intent)
if(I_HELP)
+
if(isliving(A))
var/mob/living/L = A
if(istype(L) && (!has_hands || !L.attempt_to_scoop(src)))
+ if(src.zone_sel.selecting == BP_GROIN)
+ if(src.vore_bellyrub(A))
+ return
automatic_custom_emote(VISIBLE_MESSAGE,"[pick(friendly)] \the [A]!", check_stat = TRUE)
if(istype(A,/obj/structure/micro_tunnel)) //Allows simplemobs to click on mouse holes, mice should be allowed to go in mouse holes, and other mobs
var/obj/structure/micro_tunnel/t = A //should be allowed to drag the mice out of the mouse holes!
diff --git a/code/modules/mob/living/simple_mob/simple_mob.dm b/code/modules/mob/living/simple_mob/simple_mob.dm
index 9f0aa2b866..33319e0f1b 100644
--- a/code/modules/mob/living/simple_mob/simple_mob.dm
+++ b/code/modules/mob/living/simple_mob/simple_mob.dm
@@ -111,6 +111,10 @@
var/melee_attack_delay = 2 // If set, the mob will do a windup animation and can miss if the target moves out of the way.
var/ranged_attack_delay = null
var/special_attack_delay = null
+ var/ranged_cooldown = 0
+ var/ranged_cooldown_time = 0
+ var/picked_color = FALSE
+ var/picked_size = FALSE
//Special attacks
// var/special_attack_prob = 0 // The chance to ATTEMPT a special_attack_target(). If it fails, it will do a regular attack instead.
@@ -168,10 +172,10 @@
var/list/myid_access = list() //VOREStation Edit
var/ID_provided = FALSE //VOREStation Edit
// VOREStation Add: Move/Shoot/Attack delays based on damage
- var/damage_fatigue_mult = 0 // Our multiplier for how heavily mobs are affected by injury. [UPDATE THIS IF THE FORMULA CHANGES]: Formula = injury_level = round(rand(1,3) * damage_fatigue_mult * clamp(((rand(2,5) * (h / getMaxHealth())) - rand(0,2)), 1, 5))
+ var/damage_fatigue_mult = 1 // Our multiplier for how heavily mobs are affected by injury. [UPDATE THIS IF THE FORMULA CHANGES]: Formula = injury_level = round(rand(1,3) * damage_fatigue_mult * clamp(((rand(2,5) * (h / getMaxHealth())) - rand(0,2)), 1, 5))
var/injury_level = 0 // What our injury level is. Rather than being the flat damage, this is the amount added to various delays to simulate injuries in a manner as lightweight as possible.
var/threshold = 0.6 // When we start slowing down. Configure this setting per-mob. Default is 60%
- var/injury_enrages = FALSE // Do injuries enrage (aka strengthen) our mob? If yes, we'll interpret how hurt we are differently.
+ var/injury_enrages = FALSE // Do injuries enrage (aka strengthen) our mob? If yes, we'll interpret how hurt we are differently.
// VOREStation Add End
var/has_recoloured = FALSE
@@ -203,6 +207,11 @@
if(has_eye_glow)
add_eyes()
+ if(vore_active) // Moved here so the verb is useable before initialising vorgans.
+ add_verb(src,/mob/living/simple_mob/proc/animal_nom)
+ add_verb(src,/mob/living/proc/shred_limb)
+ add_verb(src,/mob/living/simple_mob/proc/nutrition_heal)
+
if(organ_names)
organ_names = GET_DECL(organ_names)
@@ -234,12 +243,48 @@
//Client attached
/mob/living/simple_mob/Login()
. = ..()
+ add_verb(src,/mob/living/simple_mob/proc/pick_size)
+ add_verb(src,/mob/living/simple_mob/proc/pick_color)
to_chat(src,span_boldnotice("You are \the [src].") + " [player_msg]")
if(vore_active && !voremob_loaded)
init_vore(TRUE)
if(hasthermals)
add_verb(src, /mob/living/simple_mob/proc/hunting_vision) //So that maint preds can see prey through walls, to make it easier to find them.
+
+/mob/living/simple_mob/proc/pick_size()
+ set name = "Pick Size"
+ set category = "Abilities.Settings"
+
+ if(picked_size)
+ to_chat(src, span_notice("You have already picked a size! If you picked the wrong size, ask an admin to change your picked_size variable to 0."))
+ return
+ if(!resizable)
+ to_chat(src, span_warning("You are immune to resizing!"))
+ return
+
+ var/nagmessage = "Pick a size between [RESIZE_MINIMUM * 100] to [RESIZE_MAXIMUM * 100]%. (Only usable once!)"
+ var/new_size = tgui_input_number(src, nagmessage, "Pick a Size", size_multiplier*100, RESIZE_MAXIMUM * 100, RESIZE_MINIMUM * 100)
+ if(size_range_check(new_size))
+ resize(new_size/100, uncapped = has_large_resize_bounds(), ignore_prefs = TRUE)
+ picked_size = TRUE
+ if(temporary_form) //resizing both our forms
+ var/mob/living/L = temporary_form
+ L.resize(new_size/100, uncapped = has_large_resize_bounds(), ignore_prefs = TRUE)
+
+/mob/living/simple_mob/proc/pick_color()
+ set name = "Pick Color"
+ set category = "Abilities.Settings"
+ set desc = "You can set your color!"
+ if(picked_color)
+ to_chat(src, span_notice("You have already picked a color! If you picked the wrong color, ask an admin to change your picked_color variable to 0."))
+ return
+ var/newcolor = tgui_color_picker(usr, "Choose a color.", "", color)
+ if(newcolor)
+ color = newcolor
+ picked_color = TRUE
+ update_icon()
+
/mob/living/simple_mob/SelfMove(turf/n, direct, movetime)
var/turf/old_turf = get_turf(src)
var/old_dir = dir
@@ -352,7 +397,7 @@
//Makes it so that simplemobs can understand galcomm without being able to speak it.
/mob/living/simple_mob/say_understands(var/mob/other, var/datum/language/speaking = null)
- if(understands_common && speaking?.name == LANGUAGE_GALCOM)
+ if(understands_common && (speaking?.name == LANGUAGE_GALCOM || !speaking))
return TRUE
return ..()
@@ -369,6 +414,8 @@
if((h / getMaxHealth()) <= threshold) // Essentially, did our health go down? We don't modify want to modify our total slowdown if we didn't actually take damage, and aren't below our threshold %
var/totaldelay = round(rand(1,3) * damage_fatigue_mult * clamp(((rand(2,5) * (h / getMaxHealth())) - rand(0,2)), 1, 5)) // totaldelay is how much delay we're going to feed into attacks and movement. Do NOT change this formula unless you know how to math.
injury_level = totaldelay // Adds our returned slowdown to the mob's injury level
+ else if((h / getMaxHealth()) >= threshold) // If our health has gone up somehow, and we're over our threshold percentage now, reset it to full
+ injury_level = 0 // Reset to no slowdown
/mob/living/simple_mob/proc/ColorMate()
set name = "Recolour"
diff --git a/code/modules/mob/living/simple_mob/simple_mob_vr.dm b/code/modules/mob/living/simple_mob/simple_mob_vr.dm
index 1414de091e..628765fc30 100644
--- a/code/modules/mob/living/simple_mob/simple_mob_vr.dm
+++ b/code/modules/mob/living/simple_mob/simple_mob_vr.dm
@@ -43,9 +43,10 @@
var/mount_offset_x = 5 // Horizontal riding offset.
var/mount_offset_y = 8 // Vertical riding offset
- var/obj/item/radio/headset/mob_headset/mob_radio //Adminbus headset for simplemob shenanigans.
+ var/obj/item/radio/headset/mob_radio //Adminbus headset for simplemob shenanigans.
does_spin = FALSE
can_be_drop_pred = TRUE // Mobs are pred by default.
+ can_be_drop_prey = TRUE
var/damage_threshold = 0 //For some mobs, they have a damage threshold required to deal damage to them.
var/nom_mob = FALSE //If a mob is meant to be hostile for vore purposes but is otherwise not hostile, if true makes certain AI ignore the mob
@@ -62,6 +63,11 @@
//For all those ID-having mobs
/mob/living/simple_mob/GetIdCard()
+ if(get_active_hand())
+ var/obj/item/I = get_active_hand()
+ var/id = I.GetID()
+ if(id)
+ return id
if(myid)
return myid
@@ -138,7 +144,7 @@
return PounceTarget(L, pouncechance)
// We're not attempting a pounce, if they're down or we can eat standing, do it as long as they're edible. Otherwise, hit normally.
- if(will_eat(L) && (!L.canmove || vore_standing_too))
+ if(will_eat(L) && (L.lying || vore_standing_too))
return EatTarget(L)
else
return ..()
@@ -223,6 +229,8 @@
add_verb(src, /mob/living/simple_mob/proc/animal_nom)
add_verb(src, /mob/living/proc/shred_limb)
add_verb(src, /mob/living/simple_mob/proc/nutrition_heal)
+ add_verb(src, /mob/living/proc/eat_trash)
+ add_verb(src, /mob/living/proc/toggle_trash_catching)
if(LAZYLEN(vore_organs))
return
@@ -272,7 +280,10 @@
"The juices pooling beneath you sizzle against your sore skin.",
"The churning walls slowly pulverize you into meaty nutrients.",
"The stomach glorps and gurgles as it tries to work you into slop.")
- B.belly_fullscreen = "yet_another_tumby"
+ can_be_drop_pred = TRUE // Mobs will eat anyone that decides to drop/slip into them by default.
+ B.belly_fullscreen = "a_tumby"
+ B.belly_fullscreen_color = "#823232"
+ B.belly_fullscreen_color2 = "#823232"
/mob/living/simple_mob/Bumped(var/atom/movable/AM, yes)
if(tryBumpNom(AM))
@@ -390,21 +401,20 @@
visible_message(span_notice("[M] starts riding [name]!"))
/mob/living/simple_mob/handle_message_mode(message_mode, message, verb, used_radios, speaking, alt_name)
- if(mob_radio)
- switch(message_mode)
- if("intercom")
- for(var/obj/item/radio/intercom/I in view(1, null))
- I.talk_into(src, message, verb, speaking)
- used_radios += I
- if("headset")
- if(mob_radio && istype(mob_radio,/obj/item/radio/headset/mob_headset))
- mob_radio.talk_into(src,message,null,verb,speaking)
+ if(message_mode)
+ if(message_mode == "intercom")
+ for(var/obj/item/radio/intercom/I in view(1, null))
+ I.talk_into(src,message,message_mode,verb,speaking)
+ used_radios += I
+ if(message_mode == "headset")
+ if(mob_radio && istype(mob_radio,/obj/item/radio/headset))
+ mob_radio.talk_into(src,message,message_mode,verb,speaking)
+ used_radios += mob_radio
+ else
+ if(mob_radio && istype(mob_radio,/obj/item/radio/headset))
+ if(mob_radio.channels[message_mode])
+ mob_radio.talk_into(src,message,message_mode,verb,speaking)
used_radios += mob_radio
- else
- if(message_mode)
- if(mob_radio && istype(mob_radio,/obj/item/radio/headset/mob_headset))
- mob_radio.talk_into(src,message, message_mode, verb, speaking)
- used_radios += mob_radio
else
..()
@@ -464,5 +474,5 @@
var/armor_block = run_armor_check(T, "melee")
var/armor_soak = get_armor_soak(T, "melee")
T.apply_damage(20, HALLOSS,, armor_block, armor_soak)
- if(prob(33))
+ if(prob(75))
T.apply_effect(3, WEAKEN, armor_block)
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/catslug.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/catslug.dm
index 46f9ff6298..009d8b8b99 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/catslug.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/catslug.dm
@@ -60,7 +60,6 @@
allow_mind_transfer = TRUE
- var/picked_color = FALSE //This needs to be moved to simple_mob. Out of scope for this PR.
can_enter_vent_with = list(
/obj/item/implant,
@@ -121,7 +120,6 @@
B.name = "stomach"
B.desc = "The hot slick gut of a catslug!! Copious slime smears over you as you’re packed away into the gloom and oppressive humidity of this churning gastric sac. The pressure around you is intense, the squashy flesh bends and forms to your figure, clinging to you insistently! There’s basically no free space at all as your ears are filled with the slick slide of flesh against flesh and the burbling of gastric juices glooping all around you. The thumping of a heart booms from somewhere nearby, making everything pulse in against you in time with it! This is it! You’ve been devoured by a catslug!!!"
B.mode_flags = 40
- B.belly_fullscreen = "yet_another_tumby"
B.digest_brute = 0.5
B.digest_burn = 0.5
B.digestchance = 10
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/jellyfish.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/jellyfish.dm
index fb4563ec90..fe7187fe32 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/jellyfish.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/jellyfish.dm
@@ -78,6 +78,7 @@ GLOBAL_VAR_INIT(jellyfish_count, 0)
vore_default_contamination_flavor = "Wet"
vore_default_contamination_color = "grey"
vore_default_item_mode = IM_DIGEST
+ can_be_drop_prey = FALSE
var/reproduction_cooldown = 0
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/skeleton.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/skeleton.dm
index 7014211c85..49ba3cfb66 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/skeleton.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/skeleton.dm
@@ -75,6 +75,7 @@
vore_default_contamination_flavor = "Wet"
vore_default_contamination_color = "grey"
vore_default_item_mode = IM_DIGEST
+ can_be_drop_prey = FALSE
/mob/living/simple_mob/vore/alienanimals/skeleton/alt
icon_state = "altskeleton"
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/space_mouse.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/space_mouse.dm
index 129999c3f0..d0cc3deff0 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/space_mouse.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/space_mouse.dm
@@ -28,6 +28,9 @@
response_disarm = "pushes"
response_harm = "punches"
+ has_langs = list(LANGUAGE_MOUSE)
+ universal_understand = 1
+
melee_damage_lower = 1
melee_damage_upper = 2
attack_sharp = FALSE
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/spacewhale.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/spacewhale.dm
index 4ae6362b1f..8887631913 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/spacewhale.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/spacewhale.dm
@@ -47,6 +47,7 @@
vore_default_contamination_flavor = "Wet"
vore_default_contamination_color = "grey"
vore_default_item_mode = IM_DIGEST
+ can_be_drop_prey = FALSE
/datum/say_list/spacewhale
emote_see = list("ripples and flows", "flashes rhythmically","glows faintly","investigates something")
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/spookyghost.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/spookyghost.dm
index 486c860fc9..1518d58066 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/spookyghost.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/spookyghost.dm
@@ -87,6 +87,8 @@
reload_count = 0
reload_time = 7 SECONDS
+ can_be_drop_prey = FALSE
+
/datum/ai_holder/simple_mob/ranged/kiting/space_ghost
hostile = TRUE
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm
index 8574603a60..4a4b845f8b 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/stardog.dm
@@ -381,7 +381,6 @@
edge_blending_priority = 4
initial_flooring = /decl/flooring/fur
can_dig = FALSE
- turf_layers = list()
var/tree_chance = 25
var/tree_color = null
var/tree_type = /obj/structure/flora/tree/fur
@@ -1530,16 +1529,14 @@
linked_mob.adjust_nutrition(how_much)
H.mind?.vore_death = TRUE
GLOB.prey_digested_roundstat++
- spawn(0)
qdel(H) //glorp
return
+ H.burn_skin(damage)
if(linked_mob)
- H.burn_skin(damage)
- if(linked_mob)
- var/how_much = (damage * H.size_multiplier) * H.get_digestion_nutrition_modifier() * linked_mob.get_digestion_efficiency_modifier()
- if(!H.ckey)
- how_much = how_much / 10 //Braindead mobs are worth less
- linked_mob.adjust_nutrition(how_much)
+ var/how_much = (damage * H.size_multiplier) * H.get_digestion_nutrition_modifier() * linked_mob.get_digestion_efficiency_modifier()
+ if(!H.ckey)
+ how_much = how_much / 10 //Braindead mobs are worth less
+ linked_mob.adjust_nutrition(how_much)
else if (isliving(thing))
var/mob/living/L = thing
if(!L)
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/startreader.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/startreader.dm
index b2563b1b80..6b1f47d51f 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/startreader.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/startreader.dm
@@ -86,6 +86,8 @@
var/flipped = FALSE
var/flip_cooldown = 0
+ can_be_drop_prey = FALSE
+
/datum/say_list/startreader
emote_see = list("bobs", "digs around","gnashes at something","yawns","snaps at something")
emote_hear = list("thrumms","clicks","rattles","groans","burbles")
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/succlet.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/succlet.dm
index 771d2078b1..7be6409b1b 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/succlet.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/succlet.dm
@@ -78,7 +78,6 @@
B.name = "stummy"
B.desc = "It's a star shaped stomach. A stummy, if you will. It's warm and soft, not unlike plush, but it's tight!"
B.mode_flags = DM_FLAG_THICKBELLY | DM_FLAG_NUMBING
- B.belly_fullscreen = "yet_another_tumby"
B.digest_brute = 0
B.digest_burn = 0
B.digest_oxy = 12
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/synx.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/synx.dm
new file mode 100644
index 0000000000..b4caacc493
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/synx.dm
@@ -0,0 +1,1024 @@
+#define SYNX_LOWER_DAMAGE 2 //Using defines to make damage easier to tweak for hacky burn attack code.
+#define SYNX_UPPER_DAMAGE 6
+
+
+/mob/living/simple_mob/animal/synx //Player controlled variant
+ //on inteligence https://synx.fandom.com/wiki/Behavior/Intelligence //keeping this here for player controlled synxes.
+ name = "Synx"
+ desc = "A cold blooded, genderless, parasitic eel from the more distant and stranger areas of the cosmos. Plain, white, perpetually grinning and possessing a hunger as enthusiastic and endless as humanity's sense of exploration."
+ tt_desc = "synxus pergulus"
+
+ //Synx species belongs to ChimeraSynx , Base sprites made by: SpitefulCrow
+ icon = 'icons/mob/synx_modular.dmi'//giving synxes their own DMI file!
+ icon_state = "synx_living"
+ icon_living = "synx_living"
+ icon_dead = "synx_dead"
+ mob_bump_flag = SIMPLE_ANIMAL //This not existing was breaking vore bump for some reason.
+ parasitic = TRUE //Digestion immunity var
+
+ var/list/speak = list()
+ var/speak_chance = 0 //MAy have forgotten to readd that.
+ //Synx speech code overrides normal speech code but is still a x in 200 chance of triggereing, as all mobs do.
+ //VAR$ SETUP
+ //annoying for player controlled synxes.
+ var/realname = null
+ var/poison_per_bite = 1 //Even with 2 this was OP with a 99% injection chance
+ var/poison_chance = 99.666
+ var/poison_type = "synxchem"//inaprovalin, but evil
+ var/transformed_state = "synx_t"
+ var/stomach_distended_state = "synx_s"
+ var/transformed = FALSE
+ var/memorysize = 50 //Var for how many messages synxes remember if they know speechcode
+ var/list/voices = list()
+ var/acid_damage_lower = SYNX_LOWER_DAMAGE - 1 //Variables for a hacky way to change to burn damage when they vomit up their stomachs. Set to 1 less than melee damage because it takes a minimum of 1 brute damage for this to activate.
+ var/acid_damage_upper = SYNX_UPPER_DAMAGE - 1
+ var/stomach_distended = 0 //Check for whether or not the synx has vomitted up its stomach.
+ var/forcefeedchance = 20 //This needs to be defined in the parent because code.
+ // Recycling bigdragon code for modular system. Hope this works! -Azel
+ //Sprites are layered ontop of one-another in order of this list
+ var/list/overlay_colors = list(
+ "Body" = "#FFFFFF",
+ "Horns" = "#FFFFFF",
+ "Marks" = "#FFFFFF",
+ "Eyes" = "#FFFFFF"
+ )
+ //If you add any more, it's as easy as adding the icons to these lists
+ var/list/body_styles = list(
+ "Normal"
+ )
+ var/body
+ var/list/horn_styles = list(
+ "None",
+ "Curved",
+ "Straight",
+ "Nub",
+ "Capra",
+ )
+ var/horns
+ var/list/marking_styles = list(
+ "None",
+ "Basic",
+ "Star",
+ "Short",
+ "Long",
+ )
+ var/markings
+ var/list/eye_styles = list(
+ "Normal"
+ )
+ var/eyes
+//TODO: Add more customization options, these are pretty scarce
+ faction = "Synx"
+
+ //intelligence_level = SA_ANIMAL
+ ai_holder_type = null //added for player controlled variant only.
+
+ maxHealth = 75 //Lowered from 150. 150 is wayyy too high for a noodly stealth predator. - Lo
+ health = 75
+ movement_cooldown = 6
+ see_in_dark = 6
+ grab_resist = 2 //slippery. % grabwill not work. Should be 10-20%. -Lo
+ armor = list( // will be determined
+ "melee" = 0, //Changed from 20.They don't have scales or armor. -LO
+ "bullet" = 0,
+ "laser" = 0,
+ "energy" = 0,
+ "bomb" = 0, //Same as above. -LO
+ "bio" = 50, //Nerfed from 100. They should have some protection against these things, but 100 is pushing it. -Lo
+ "rad" = 100) //Keeping 100 rad armor as mobs cannot easily get radiation storm announcements. If this is reduced it'd be a good idea to make it 100 for the ai types.
+ has_hands = 1
+ pass_flags = PASSTABLE
+
+ /*
+ response_help = "pokes the synx, shifting the fur-like bristles on its body."
+ response_disarm = "gently pushes aside the synx, dislodging a clump of bristly hair in your hand. The substance quickly melts upon contact with your sweat."
+ response_harm = "tries to hit the synx. This tears out an area of fur which firmly melts upon contact, covering you in something sticky."
+ */
+ // I dont think the person who wrote the above descriptions realized what they were used for, because they dont work at all. Leaving these commented incase someone wants to reimplement this properly someday.
+ response_help = "pokes"
+ response_disarm = "awkwardly shoves"
+ //Leaving response_harm the same as default; "hits".
+
+ melee_damage_lower = SYNX_LOWER_DAMAGE //Massive damage reduction, will be balanced with toxin injection/ //LO- Made up for in skills. Toxin injection does not technically cause damage with these guys. Stomach acid does when they disegage their stomach from their mouths does, but that could be done differently.
+ melee_damage_upper = SYNX_UPPER_DAMAGE
+ attacktext = list("clawed") // "You are [attacktext] by the mob!"
+ var/distend_attacktext = list("smacked")
+ var/initial_attacktext = list("clawed") //I hate needing to do it this way.
+ friendly = list("prods") // "The mob [friendly] the person."
+ attack_armor_pen = 0 // How much armor pen this attack has. //Changed from 40. -Lo
+ attack_sharp = 1
+ attack_edge = 1
+ attack_armor_type = "melee" //Default is melee but I'm stating this explicitly to make it more obvious to anybody reading this
+
+//Vore stuff//leaving most of this here even though its no going to be an AI controlled variant.
+ vore_active = 1
+ vore_capacity = 2
+ vore_pounce_chance = 50
+ vore_bump_chance = 10
+ vore_bump_emote = "Slowly wraps its tongue around, and slides its drooling maw over the head of"
+ vore_standing_too = 1 //I believe this lets it vore standing people, rather than only resting.
+ vore_ignores_undigestable = 0 //Synx don't care if you digest or not, you squirm fine either way.
+ vore_default_mode = DM_HOLD
+ vore_digest_chance = 45 // Chance to switch to digest mode if resisted
+ vore_absorb_chance = 0
+ vore_escape_chance = 10
+ vore_icons = SA_ICON_LIVING //no vore icons //TODO: Implement these, I have the sprites done but they're unnecessary for core function rn and I'd rather get this into a working state first -Azel
+ swallowTime = 6 SECONDS //Enter the eel you nerd
+
+//Shouldn't be affected by lack of atmos, it's a space eel. //nah lets give him some temperature
+
+ minbodytemp = 223 //Below -50 Degrees Celcius
+ maxbodytemp = 323 //Above 50 Degrees Celcius
+ min_oxy = 0
+ max_oxy = 0 //Maybe add a max
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0 //Maybe add a max
+ min_n2 = 0
+ max_n2 = 0 //Maybe add a max
+ // TODO: Set a max temperature of about 20-30 above room temperatures. Synx don't like the heat.
+
+
+/mob/living/simple_mob/animal/synx/Initialize(mapload)
+ . = ..()
+ src.adjust_nutrition(src.max_nutrition)
+ build_icons(1)
+ if(!voremob_loaded)
+ voremob_loaded = TRUE
+ init_vore()
+ mob_radio = new /obj/item/radio/headset/mob_headset(src) //We always give radios to spawned mobs anyway
+
+/mob/living/simple_mob/animal/synx/get_available_emotes()
+ . = ..()
+ . |= _human_default_emotes //Synx are great at mimicking
+
+/mob/living/simple_mob/animal/synx/ai //AI controlled variant
+
+ ai_holder_type = /datum/ai_holder/simple_mob/retaliate
+
+/mob/living/simple_mob/animal/synx/load_default_bellies()
+ . = ..()
+ var/obj/belly/B = vore_selected
+ //B.human_prey_swallow_time = 6 SECONDS //doesnt work
+ //B.nonhuman_prey_swallow_time = 3 SECONDS //doesnt work
+ B.vore_verb = "swallow"
+ B.name = "stomach"
+ B.desc = "You're pulled into the snug stomach of the synx. The walls knead weakly around you, coating you in thick, viscous fluids that cling to your body, that soon starts to tingle and burn..."
+ B.digest_burn = 1
+ B.digest_brute = 0
+ B.emote_lists[DM_HOLD] = list(
+ "The walls churn around you, soaking you in thick, smelling fluid as you're kneaded and rolled about in the surprisingly roomy, but still snug, space.",
+ "The unusually cool stomach rolls around you slowly and lazily, trying to almost knead you to sleep gently as the synx pulses around you.",
+ "The thick, viscous fluids cling to your body soaking in deep, giving you a full bath with the kneading of the walls helping to make sure you'll be smelling like synx stomach for days."
+ )
+ B.emote_lists[DM_DIGEST] = list(
+ "The stomach kneads roughly around you, squishing and molding to your shape, with the thick fluids clinging to your body and tingling, making it hard to breathe.",
+ "Firm churns of the stomach roll and knead you around, your body tingling as fur sizzles all around you, your body getting nice and tenderized for the stomach.",
+ "Your body tingles and the air smells strongly of acid, as the stomach churns around you firmly and slowly, eager to break you down.",
+ "You're jostled in the stomach as the synx lets out what can only described as an alien belch, the space around you getting even more snug as the thick acids rise further up your body."
+ )
+ B.digest_messages_prey = list(
+ "Your eyes grow heavy as the air grows thin in the stomach, the burning of the acids slowly putting you into a final slumber, adding you to the synx's hips and tail.",
+ "Slowly, the stinging and burning of the acids, and the constant churning is just too much, and with a few final clenches, your body is broken down into fuel for the synx.",
+ "The acids and fluids rise up above your head, quickly putting an end to your squirming and conciousness.. the stomach eager to break you down completely.",
+ "The synx lets out an audible belch, the last of your air going with it, and with a few audible crunches from the outside, the stomach claims you as food for the parasite."
+ )
+ B.mode_flags = DM_FLAG_NUMBING //Prey are more docile when it doesn't hurt.
+
+/* //OC-insert mob removals. Commenting out instead of full removal as there's some good detail here.
+/mob/living/simple_mob/animal/synx/ai/pet/asteri/load_default_bellies()
+ . = ..()
+ var/obj/belly/B = vore_selected
+ B.desc = "The synx eagerly swallows you, taking you from its gullet into its long, serpentine stomach. The internals around you greedily press into your from all sides, keeping you coated in a slick coat of numbing fluids..."
+ B.digest_burn = 2
+ B.digest_brute = 0 //no brute should be done. ramping up burn as a result. this is acid. -Lo
+ B.emote_lists[DM_HOLD] = list(
+ "Your taut prison presses and pads into your body, the synx squeezing around you almost constrictingly tight while the rolling pulses of muscle around you keep your squirms well-contained.",
+ "You can feel parts of you sink and press into the squishy stomach walls as the synx's gut seems to relax, the wet ambience of its stomach muffling the parasite's various heartbeats.",
+ "You can hear the synx teasingly mimic the sounds you've made while it's eaten you, the stomach walls practically massaging more of numbing fluid into you as its innards do their best to tire you out.",
+ )
+ B.emote_lists[DM_DIGEST] = list(
+ "The stomach gives a crushing squeeze around your frame, its body restraining your movements and pressing digestive fluids deeper into you with overwhelming pressure from all sides..",
+ "The synx's insides greedily press into you all over, kneading around your body and softening you up for the slurry of numbing acid that's pooled around your melting frame.",
+ "You can hear a cacophony of wet churns and gurgles from the synx's body as it works on breaking you down, the parasite eagerly awaiting your final moments.",
+ "The tight, fleshy tunnel constricts around you, making it even harder to breathe the already thin air as the digestive cocktail around you wears you out.",
+ )
+ B.digest_messages_prey = list(
+ "You finally give in to the constricting pressure, softened up enough for the acids around you to turn your entire being into a gooey slop to be pumped through its body.",
+ "Slipping past the point of saving, your body gives out on you as the stomach walls grind your goopy remains into a chunky sludge, leaving behind only a few acid-soaked bones for it to stash in the vents.",
+ "The constant fatal massage pulls you under, your conciousness fading away as you're drawn into a numb, permanent sleep. The body you leave behind is put to good use as a few extra pounds on the synx's frame, its now-wider hips making it just a little harder to squeeze through the vents it's so fond of.",
+ "The synx's body gleefully takes what's left of your life, Asteri's usually-repressed sadism overwhelmed with a sinister satisfaction in snuffing you out as your liquefied remains gush into a bit more heft on the parasite's emaciated frame.",
+ )
+*/
+
+/mob/living/simple_mob/animal/synx/Initialize(mapload, is_pet) //this is really cool. Should be able to ventcrawl canonicaly, contort, and make random speech.
+//some things should be here that arent tho.
+ . = ..()
+ if(is_pet)
+ return
+ add_verb(src,/mob/living/proc/ventcrawl)
+ add_verb(src,/mob/living/simple_mob/animal/synx/proc/distend_stomach)
+ add_verb(src,/mob/living/simple_mob/proc/contort)
+ add_verb(src,/mob/living/simple_mob/animal/synx/proc/sonar_ping)
+ add_verb(src,/mob/living/proc/shred_limb)
+ add_verb(src,/mob/living/simple_mob/animal/synx/proc/disguise)
+ add_verb(src,/mob/living/simple_mob/animal/synx/proc/randomspeech)
+ add_verb(src,/mob/living/simple_mob/animal/synx/proc/set_style)
+ realname = name
+ voices += "Garbled voice"
+ voices += "Unidentifiable Voice"
+ speak += "Who is there?"
+ speak += "What is that thing?!"
+
+//////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////// SPECIAL ITEMS/REAGENTS !!!! ////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////// //keeping most of these the same except the stuff that apply to the standard synx. -lo
+/*
+/datum/seed/hardlightseed/
+ name = PLANT_NULLHARDLIGHT
+ seed_name = "Biomechanical Hardlight generator seed"
+ display_name = "Biomechanical Hardlight stem"
+ mutants = null
+ can_self_harvest = 1
+ has_mob_product = null
+
+/datum/seed/hardlightseed/New()
+ ..()
+ set_trait(TRAIT_IMMUTABLE,1) //Normal genetics wont be able to do much with the mechanical parts, its more a machine than a real plant
+ set_trait(TRAIT_MATURATION,1)
+ set_trait(TRAIT_PRODUCTION,1)
+ set_trait(TRAIT_YIELD,1)
+ set_trait(TRAIT_POTENCY,1)
+ set_trait(TRAIT_PRODUCT_ICON,"alien4")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#00FFFF")
+ set_trait(TRAIT_PLANT_COLOUR,"#00FFFF")
+ set_trait(TRAIT_PLANT_ICON,"alien4") //spooky pods
+ set_trait(TRAIT_IDEAL_HEAT, 283)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0)
+ set_trait(TRAIT_WATER_CONSUMPTION, 0)
+
+/datum/seed/hardlightseed/typesx //Respawn mechanism for the synx
+ name = "hardlightseedsx"
+ seed_name = "hardlightseedsx"
+ display_name = "Biomechanical Hardlight Generator SX"//PLant that is part mechanical part biological
+ has_mob_product = /mob/living/simple_mob/animal/synx/ai/pet/holo
+*/ //This is defined in seed_datums_ch
+
+/obj/item/seeds/hardlightseed/typesx
+ seed_type = "hardlightseedsx"
+
+/datum/reagent/inaprovaline/synxchem
+ name = "Alien nerveinhibitor"
+ description = "A toxin that slowly metabolizes damaging the person, but makes them unable to feel pain."
+ id = "synxchem"
+ metabolism = REM * 0.1 //Slow metabolization to try and mimic permanent nerve damage without actually being too cruel to people
+ color = "#FFFFFF"
+ overdose = REAGENTS_OVERDOSE * 4 //But takes a lot to OD
+
+/datum/reagent/inaprovaline/synxchem/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
+ if(alien != IS_DIONA)
+ if(prob(8))
+ M.custom_pain("You [pick("feel numb!","feel dizzy and heavy.","feel strange!")]",60)
+ if(prob(2))
+ M.custom_pain("You [pick("suddenly lose control over your body!", "can't move!", "are frozen in place.", "can't struggle!")]",60)
+ M.AdjustParalysis(1)
+// M.add_chemical_effect(CE_STABLE, 15)
+ M.add_chemical_effect(CE_PAINKILLER, 60)
+ // M.adjustToxLoss(0.4) //Dealing twice of it as tox, even if you have no brute, its not true conversion. Synxchem without stomach shoved out of its mouth isn't going to do tox. -Lo
+ // M.adjustHalLoss(1) //we do not need halloss as well as paralyze. lo-
+
+/datum/reagent/inaprovaline/synxchem/holo
+ name = "SX type simulation nanomachines" //Educational!
+ description = "Type SX nanomachines to simulate what it feels like to come in contact with a synx, minus the damage"
+ id = "fakesynxchem"
+ metabolism = REM * 1 //ten times faster for convenience of testers.
+ color = "#00FFFF"
+ overdose = REAGENTS_OVERDOSE * 20 //it's all fake. But having nanomachines move through you is not good at a certain amount.
+
+/datum/reagent/inaprovaline/synxchem/holo/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
+ if(alien != IS_DIONA)
+ if(prob(5))
+ M.custom_pain("You feel no pain!",60)
+ if(prob(2))
+ M.custom_pain("You suddenly lose control over your body!",60)
+ M.AdjustParalysis(1)
+ M.add_chemical_effect(CE_STABLE, 15)
+ M.add_chemical_effect(CE_PAINKILLER, 50)
+ M.adjustBruteLoss(-0.2)//Made to simulate combat, also useful as very odd healer.
+ M.adjustToxLoss(-0.2) //HELP ITS MAULING ME!
+ M.adjustFireLoss(-0.2) //huh this mauling aint so bad
+ //M.adjustHalLoss(10) //OH MY GOD END MY PAIN NOW WHO MADE THIS SIMULATION //Removing because this is spammy and stunlocks for absurd durations
+
+/datum/reagent/inaprovaline/synxchem/clown
+ name = "HONK"
+ description = "HONK"
+ id = "clownsynxchem"
+ metabolism = REM * 0.5
+ color = "#FFFFFF"
+ overdose = REAGENTS_OVERDOSE * 200
+
+/datum/reagent/inaprovaline/synxchem/clown/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
+ M.adjustToxLoss(0.01)
+ playsound(M.loc, 'sound/items/bikehorn.ogg', 50, 1)
+ M.adjustBruteLoss(-2)//healing brute
+ if(prob(1))
+ M.custom_pain("I have no horn but i must honk!",60)
+ if(prob(2))
+ var/location = get_turf(M)
+ new /obj/item/bikehorn(location)
+ M.custom_pain("You suddenly cough up a bikehorn!",60)
+
+/*why is this in here twice? -Lo
+ /datum/reagent/inaprovaline/synxchem/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
+ if(alien != IS_DIONA)
+ if(prob(5))
+ M.custom_pain("You feel no pain despite the clear signs of damage to your body!",0)
+ if(prob(2))
+ M.custom_pain("You suddenly lose control over your body!",0)
+ M.AdjustParalysis(1)
+ M.add_chemical_effect(CE_STABLE, 15)
+ M.add_chemical_effect(CE_PAINKILLER, 50)
+ M.adjustBruteLoss(-0.2)//healing brute
+ M.adjustToxLoss(0.1) //Dealing half of it as tox
+ M.adjustHalLoss(1) //dealing 5 times the amount of brute healed as halo, but we cant feel pain yet
+ // ^ I have no idea what this might cause, my ideal plan is that once the pain killer wears off you suddenly collapse;
+ //Since Halloss is not "real" damage this should not cause death
+*/
+
+/datum/reagent/inaprovaline/synxchem/overdose(var/mob/living/carbon/M, var/alien, var/removed)
+ ..()
+ if(alien != IS_DIONA)
+ M.make_dizzy(10)
+ if(prob(5))
+ M.AdjustStunned(1)
+ if(prob(2))
+ M.AdjustParalysis(1)
+
+
+/datum/reagent/inaprovaline/synxchem/holo/overdose(var/mob/living/carbon/M, var/alien, var/removed)
+ return
+
+/datum/reagent/inaprovaline/synxchem/clown/overdose(var/mob/living/carbon/M, var/alien, var/removed)
+ return
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////// PASSIVE POWERS!!!! /////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////
+// nevermind. I added any roleplay flavor weird fur mechanics to happen when you touch or attack the synx.
+
+/mob/living/simple_mob/animal/synx/apply_melee_effects(var/atom/A) //Re-adding this for AI synx
+ if(stomach_distended) //Hacky burn damage code
+ if(isliving(A)) //Only affect living mobs, should include silicons. This could be expanded to deal special effects to acid-vulnerable objects.
+ var/mob/living/L = A
+ var/armor_modifier = abs((L.getarmor(null, "bio") / 100) - 1) //Factor in victim bio armor
+ var/amount = rand(acid_damage_lower, acid_damage_upper) //Select a damage value
+ var/damage_done = amount * armor_modifier
+ if(damage_done > 0) //sanity check, no healing the victim if somehow this is a negative value.
+ L.adjustFireLoss(damage_done)
+ return
+ else
+ to_chat(src,span_notice("Your stomach bounces off of the victim's armor!"))
+ return
+ return //If stomach is distended, return here to perform no forcefeeding or poison injecton.
+
+ if(isliving(A))
+ var/mob/living/L = A
+
+/* if(prob(forcefeedchance) && !ckey)//Forcefeeding code //Only triggers if not player-controlled //This does not currently work
+ L.Weaken(2)
+ update_icon()
+ set_AI_busy(TRUE)
+ src.feed_self_to_grabbed(src,L)
+ update_icon()
+ set_AI_busy(FALSE)
+*/
+ if(L.reagents) //Seemingly broken. Would probably be really annoying anyways, so probably for the best that it doesn't work. -Azel
+ var/target_zone = pick(BP_TORSO,BP_TORSO,BP_TORSO,BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_HEAD)
+ if(L.can_inject(src, null, target_zone))
+ if(prob(poison_chance))
+ to_chat(L, span_warning("You feel a strange substance on you."))
+ L.reagents.add_reagent(poison_type, poison_per_bite)
+
+
+
+/mob/living/simple_mob/animal/synx/hear_say(message,verb,language,fakename,isItalics,var/mob/living/speaker)
+ . = ..()
+ if(!message || !speaker) return
+ if (speaker == src) return
+ speaker = speaker.GetVoice()
+ speak += message
+ voices += speaker
+ if(voices.len>=memorysize)
+ voices -= (pick(voices))//making the list more dynamic
+ if(speak.len>=memorysize)
+ speak -= (pick(speak))//making the list more dynamic
+ if(resting)
+ resting = !resting
+ if(message=="Honk!")
+ bikehorn()
+
+/mob/living/simple_mob/animal/synx/ai/pet/clown/Life()
+ ..()
+ if(vore_fullness)
+ size_multiplier = 1+(0.5*vore_fullness)
+ update_icons()
+ if(!vore_fullness && size_multiplier != 1)
+ size_multiplier = 1
+ update_icons()
+/mob/living/simple_mob/animal/synx/Life()
+ ..()
+//mob/living/simple_mob/animal/synx/ai/handle_idle_speaking() //Only ai-controlled synx will randomly speak
+ if(voices && prob(speak_chance/2))
+ randomspeech()
+
+/mob/living/simple_mob/animal/synx/perform_the_nom(mob/living/user, mob/living/prey, mob/living/pred, obj/belly/belly, delay) //Synx can only eat people if their organs are on the inside.
+ if(stomach_distended)
+ to_chat(src,span_notice("You can't eat people without your stomach inside of you!"))
+ return
+ else
+ ..()
+
+//////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////// POWERS!!!! /////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////
+
+/mob/living/simple_mob/proc/contort()
+ set name = "contort"
+ set desc = "Allows to hide beneath tables or certain items. Toggled on or off."
+ set category = "Abilities.Synx"
+
+ if(stat == DEAD || paralysis || weakened || stunned || restrained())
+ return
+
+ if(status_flags & HIDING)
+ status_flags &= ~HIDING
+ reset_plane_and_layer()
+ to_chat(src,span_notice("You have stopped hiding."))
+ else
+ status_flags |= HIDING
+ layer = HIDING_LAYER //Just above cables with their 2.44
+ plane = OBJ_PLANE
+ to_chat(src,span_notice("You are now hiding."))
+
+
+ update_icons()
+
+/mob/living/simple_mob/animal/synx/proc/disguise()
+ set name = "Toggle Form"
+ set desc = "Switch between amorphous and humanoid forms."
+ set category = "Abilities.Synx"
+
+ if(stat == DEAD || paralysis || weakened || stunned || restrained())
+ return
+
+ // If transform isn't true
+ if(stomach_distended)
+ to_chat(src,span_warning("You can't disguise with your stomach outside of your body!"))
+ return
+ if(!transformed)
+ to_chat(src,span_warning("Now they see your true form."))
+ icon_living = transformed_state //Switch state to transformed state
+ movement_cooldown = 3
+ else // If transformed is true.
+ to_chat(src,span_warning("You changed back into your disguise."))
+ icon_living = initial(icon_living) //Switch state to what it was originally defined.
+ movement_cooldown = 6
+
+
+ transformed = !transformed
+ update_icons()
+
+/mob/living/simple_mob/animal/synx/proc/randomspeech()
+ set name = "speak"
+ set desc = "Take a sentence you heard and speak it."
+ set category = "Abilities.Synx"
+ if(speak && voices)
+ handle_mimic()
+ else
+ usr << span_warning("YOU NEED TO HEAR THINGS FIRST, try using Ventcrawl to eevesdrop on nerds.")
+
+/mob/living/simple_mob/animal/synx/proc/handle_mimic()
+ name = pick(voices)
+ spawn(2)
+ src.say(pick(speak))
+ spawn(5)
+ name = realname
+
+//lo- procs adjusted to mobs.
+
+/mob/living/simple_mob/animal/synx
+ var/next_sonar_ping = 0
+
+/mob/living/simple_mob/animal/synx/proc/sonar_ping()
+ set name = "Listen In"
+ set desc = "Allows you to listen in to movement and noises around you."
+ set category = "Abilities.Synx"
+
+ if(incapacitated())
+ to_chat(src, span_warning("You need to recover before you can use this ability."))
+ return
+ if(world.time < next_sonar_ping)
+ to_chat(src, span_warning("You need another moment to focus."))
+ return
+ if(is_deaf() || is_below_sound_pressure(get_turf(src)))
+ to_chat(src, span_warning("You are for all intents and purposes currently deaf!"))
+ return
+ next_sonar_ping += 10 SECONDS
+ var/heard_something = FALSE
+ to_chat(src, span_notice("You take a moment to listen in to your environment..."))
+ for(var/mob/living/L in range(client.view, src))
+ var/turf/T = get_turf(L)
+ if(!T || L == src || L.stat == DEAD || is_below_sound_pressure(T))
+ continue
+ heard_something = TRUE
+ var/feedback = list()
+ feedback += "There are noises of movement "
+ var/direction = get_dir(src, L)
+ if(direction)
+ feedback += "towards the [dir2text(direction)], "
+ switch(get_dist(src, L) / client.view)
+ if(0 to 0.2)
+ feedback += "very close by."
+ if(0.2 to 0.4)
+ feedback += "close by."
+ if(0.4 to 0.6)
+ feedback += "some distance away."
+ if(0.6 to 0.8)
+ feedback += "further away."
+ else
+ feedback += "far away."
+ else // No need to check distance if they're standing right on-top of us
+ feedback += "right on top of you."
+ to_chat(src,span_notice(jointext(feedback,null)))
+ if(!heard_something)
+ to_chat(src, span_notice("You hear no movement but your own."))
+
+
+
+
+
+/mob/living/simple_mob/animal/synx/proc/distend_stomach()
+ set name = "Distend Stomach"
+ set desc = "Allows you to throw up your stomach, giving your attacks burn damage at the cost of your stomach contents going everywhere. Yuck."
+ set category = "Abilities.Synx"
+
+ if(transformed)
+ to_chat(src,span_warning("Your limbs are in the way!")) //Kind of a weak excuse but since you already can't transform when your stomach is out, this avoids situations calling a sprite that doesn't exist and lightens my workload on making and implementing them
+ return
+
+ if(!stomach_distended && !transformed) //true if stomach distended is null, 0, or ""
+ stomach_distended = !stomach_distended //switch statement
+ to_chat (src, span_notice("You disgorge your stomach, spilling its contents!"))
+ melee_damage_lower = 1 //Hopefully this will make all brute damage not apply while stomach is distended. I don't see a better way to do this.
+ melee_damage_upper = 1
+ icon_living = stomach_distended_state
+ attack_armor_type = "bio" //apply_melee_effects should handle all burn damage code so this might not be necessary.
+ attacktext += distend_attacktext
+ attacktext -= initial_attacktext
+
+ for(var/belly in src.vore_organs) //Spit out all contents because our insides are now outsides
+ var/obj/belly/B = belly
+ for(var/atom/movable/A in B)
+ playsound(src, 'sound/effects/splat.ogg', 50, 1)
+ B.release_specific_contents(A)
+ update_icons()
+ return
+
+ if(stomach_distended) //If our stomach has been vomitted
+ stomach_distended = !stomach_distended
+ to_chat (src, span_notice("You swallow your insides!"))
+ melee_damage_lower = SYNX_LOWER_DAMAGE //This is why I'm using a define
+ melee_damage_upper = SYNX_UPPER_DAMAGE
+ icon_living = initial(icon_living)
+ attack_armor_type = "melee"
+ attacktext += initial_attacktext
+ attacktext -= distend_attacktext
+ update_icons()
+ return
+
+///
+/// Icon generation stuff
+///
+
+/mob/living/simple_mob/animal/synx/update_icon()
+ update_fullness()
+ build_icons()
+ for(var/belly_class in vore_fullness_ex)
+ var/vs_fullness = vore_fullness_ex[belly_class]
+ if(vs_fullness > 0)
+ if(transformed)
+ //transformed bellysprites dont exist yet. Uncomment this when they do. -Reo
+ //add_overlay("[iconstate]-t_[belly_class]-[vs_fullness]")
+ pass()
+ else
+ add_overlay("[icon_state]_[belly_class]-[vs_fullness]")
+
+
+/mob/living/simple_mob/animal/synx/proc/build_icons(var/random)
+ cut_overlays()
+ if(stat == DEAD)
+ icon_state = "synx_dead"
+ plane = MOB_LAYER
+ return
+ if(random)
+ var/list/bodycolors = list("#FFFFFF")
+ body = pick(body_styles)
+ overlay_colors["Body"] = pick(bodycolors)
+ horns = pick(horn_styles)
+ var/list/horncolors = list("#FFE100","#A75A35","#1C4DFF","#FF0000","#404C6D","#2F2F2F","#55CE21","#711BFF","#DEDEE0")
+ overlay_colors["Horns"] = pick(horncolors)
+ var/list/markingcolors = list("#2F2F2F")
+ markings = pick(marking_styles)
+ overlay_colors["Marks"] = pick(markingcolors)
+ var/list/eyecolors = list("#FFE100","#FF6A00","#1C4DFF","#FF0000","#3D5EBE","#FF006E","#55CE21","#711BFF","#939EFF")
+ eyes = pick(eye_styles)
+ overlay_colors["Eyes"] = pick(eyecolors)
+
+
+ var/image/I = image(icon, "synx_body[body][transformed? "-t" : null][stomach_distended? "-s" : null]")
+ I.color = overlay_colors["Body"]
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
+ I.plane = (status_flags & HIDING)? OBJ_PLANE : MOB_PLANE
+ I.layer = (status_flags & HIDING)? HIDING_LAYER : MOB_LAYER
+ add_overlay(I)
+
+ I = image(icon, "synx_horns[horns][transformed? "-t" : null]")
+ I.color = overlay_colors["Horns"]
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
+ I.plane = (status_flags & HIDING)? OBJ_PLANE : MOB_PLANE
+ I.layer = (status_flags & HIDING)? HIDING_LAYER : MOB_LAYER
+ add_overlay(I)
+
+ I = image(icon, "synx_markings[markings][transformed? "-t" : null]")
+ I.color = overlay_colors["Marks"]
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
+ I.plane = (status_flags & HIDING)? OBJ_PLANE : MOB_PLANE
+ I.layer = (status_flags & HIDING)? HIDING_LAYER : MOB_LAYER
+ add_overlay(I)
+
+ I = image(icon, "synx_eyes[eyes][transformed? "-t" : null]")
+ I.color = overlay_colors["Eyes"]
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
+ I.plane = (status_flags & HIDING)? OBJ_PLANE : MOB_PLANE
+ I.layer = (status_flags & HIDING)? HIDING_LAYER : MOB_LAYER
+ add_overlay(I)
+
+/mob/living/simple_mob/animal/synx/proc/set_style()
+ set name = "Set Style"
+ set desc = "Customise your icons."
+ set category = "Abilities.Synx"
+
+ var/list/options = list("Body","Horns","Marks","Eyes")
+ for(var/option in options)
+ LAZYSET(options, option, new /image('icons/effects/synx_labels.dmi', option))
+ var/choice = show_radial_menu(src, src, options, radius = 60)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return FALSE
+ . = TRUE
+ switch(choice)
+ if("Body")
+ options = body_styles
+ for(var/option in options)
+ var/image/I = new /image('icons/mob/synx_modular.dmi', "synx_body[option]", dir = 2)
+ LAZYSET(options, option, I)
+ choice = show_radial_menu(src, src, options, radius = 90)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return 0
+ var/new_color = tgui_color_picker(src, "Pick body color:","Body Color", overlay_colors["Body"])
+ if(!new_color)
+ return 0
+ body = choice
+ overlay_colors["Body"] = new_color
+ if("Horns")
+ options = horn_styles
+ for(var/option in options)
+ var/image/I = new /image('icons/mob/synx_modular.dmi', "synx_horns[option]", dir = 2)
+ LAZYSET(options, option, I)
+ choice = show_radial_menu(src, src, options, radius = 90)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return 0
+ var/new_color = tgui_color_picker(src, "Pick horn color:","Horn Color", overlay_colors["Horns"])
+ if(!new_color)
+ return 0
+ horns = choice
+ overlay_colors["Horns"] = new_color
+ if("Marks")
+ options = marking_styles
+ for(var/option in options)
+ var/image/I = new /image('icons/mob/synx_modular.dmi', "synx_markings[option]", dir = 2)
+ LAZYSET(options, option, I)
+ choice = show_radial_menu(src, src, options, radius = 90)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return 0
+ var/new_color = tgui_color_picker(src, "Pick marking color:","Marking Color", overlay_colors["Marks"])
+ if(!new_color)
+ return 0
+ markings = choice
+ overlay_colors["Marks"] = new_color
+ if("Eyes")
+ options = eye_styles
+ for(var/option in options)
+ var/image/I = new /image('icons/mob/synx_modular.dmi', "synx_eyes[option]", dir = 2)
+ LAZYSET(options, option, I)
+ choice = show_radial_menu(src, src, options, radius = 90)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return 0
+ var/new_color = tgui_color_picker(src, "Pick eye color:","Eye Color", overlay_colors["Eyes"])
+ if(!new_color)
+ return 0
+ eyes = choice
+ overlay_colors["Eyes"] = new_color
+ if(.)
+ build_icons()
+
+////////////////////////////////////////
+////////////////PET VERSION/////////////
+////////////////////////////////////////
+/mob/living/simple_mob/animal/synx/ai/pet
+ faction = "Cargonia" //Should not share a faction with those pesky non station synxes.//This is so newspaper has a failchance
+ name = "Bob"
+ desc = "A very regular pet."
+ tt_desc = "synxus pergulus"
+ glow_range = 4
+ glow_toggle = 1
+ player_msg = "You aren't supposed to be in this. Wrong mob."
+
+/mob/living/simple_mob/animal/synx/ai/pet/load_default_bellies()
+ . = ..()
+ var/obj/belly/B = vore_selected
+ B.vore_verb = "swallow"
+ B.digest_burn = 1
+ B.digest_brute = 0
+
+/mob/living/simple_mob/animal/synx/ai/pet/holo/load_default_bellies()
+ . = ..()
+ var/obj/belly/B = vore_selected
+ B.vore_verb = "swallow"
+ B.digest_burn = 5
+ B.digest_brute = 5
+
+/mob/living/simple_mob/animal/synx/ai/pet
+ speak_chance = 2.0666
+
+//HONKMOTHER Code.
+/*/mob/living/simple_mob/animal/synx/proc/honk()
+ set name = "HONK"
+ set desc = "TAAA RAINBOW"
+ set category = "Abilities.Synx"
+ icon_state = "synx_pet_rainbow"
+ icon_living = "synx_pet_rainbow"
+ playsound(src.loc, 'sound/items/bikehorn.ogg', 50, 1)
+*/
+/mob/living/simple_mob/animal/synx/proc/bikehorn()
+ playsound(src.loc, 'sound/items/bikehorn.ogg', 50, 1)
+
+//HOLOSEEDSPAWNCODE
+/mob/living/simple_mob/animal/synx/ai/pet/holo/death()
+ ..()
+ visible_message(span_notice("\The [src] fades away!"))
+ var/location = get_turf(src)
+ new /obj/item/seeds/hardlightseed/typesx(location)
+ qdel(src)
+
+/mob/living/simple_mob/animal/synx/ai/pet/holo/gib()
+ visible_message(span_notice("\The [src] fades away!"))
+ var/location = get_turf(src)
+ new /obj/item/seeds/hardlightseed/typesx(location)
+ qdel(src)
+
+////////////////////////////////////////
+////////////////SYNX VARIATIONS/////////
+////////////////////////////////////////
+//TODO: Figure out a way to properly implement these into the customization system. Not important rn as far as getting the system out goes, since none of them are actually in use, but these should probably be either commented out/removed or otherwise implemented into the system- their sprites don't play nice with it as things stand!
+/mob/living/simple_mob/animal/synx/ai/pet/holo
+ poison_chance = 100
+ poison_type = "fakesynxchem" //unlike synxchem this one heals!
+ name = "Hardlight synx"
+ desc = "A cold blooded, genderless, space eel.. or a hologram of one. Guess the current synx are undergoing re-training? Either way this one is probably infinitely more friendly.. and less deadly."
+ icon_state = "synx_hardlight_living"
+ icon_living = "synx_hardlight_living"
+ icon_dead = "synx_hardlight_dead"
+ icon_gib = null
+ alpha = 127
+ speak = list("SX System Online")
+ faction = "neutral"//Can be safely bapped with newspaper.
+ melee_damage_lower = 0 //Holos do no damage
+ melee_damage_upper = 0
+ meat_amount = 0
+ meat_type = null
+ //Vore Section
+ vore_default_mode = DM_HEAL
+ vore_capacity = 2
+ vore_digest_chance = 0 //Holos cannot digest
+ vore_pounce_chance = 40 //Shouldn't fight
+ vore_bump_chance = 0 //lowered bump chance
+ vore_escape_chance = 30 //Much higher escape chance.. it's a hologram.
+ swallowTime = 10 SECONDS //Much more time to run
+
+//Commenting out OC content as to fit with content policy while I'm at it-- it won't work with the modular system anyways currently. Sorry, Shark!! I might try to add in a back marking category at some point so Greed can be recreated here at least, though. -Azel
+/*/mob/living/simple_mob/animal/synx/ai/pet/greed
+ name = "Greed"
+ desc = "A cold blooded, genderless, parasitic eel from the more distant and stranger areas of the cosmos. black, perpetually grinning and possessing a hunger as enthusiastic and endless as humanity's sense of exploration.. This one has the name Greed burnt into its back, the burnt in name seems to be luminescent making it harder for it to blend into the dark."
+ //icon= //icon= would just set what DMI we are using, we already have our special one set.
+ icon_state = "synx_greed_living"
+ icon_living = "synx_greed_living"
+ icon_dead = "synx_greed_dead"
+ speak = list("Who is there?")//preset unique words Greed remembers, to be defined more
+ player_msg = "You Hunger."
+ health = 100//Slightly lower health due to being damaged permanently.
+ speak_chance = 5
+ //Vore Section
+ vore_capacity = 4 //What a fat noodle.
+ vore_digest_chance = 1 //Multivore but lower digest chance
+ vore_pounce_chance = 90 //Fighting is effort, engulf them whole.
+ vore_bump_chance = 2 //lowered bump chance
+ vore_escape_chance = 5 //Multivore allows for people to shove eachother out so lower normal escape chance.
+
+/mob/living/simple_mob/animal/synx/ai/pet/greed/synth
+
+/*
+ * ▓███▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓ ▓███▓
+ * â–“â–“ â–“â–“â–“â–ˆ â–“â–“ â–“â–“â–ˆ â–“â–“ â–“â–“â–ˆ â–“â–“ â–“â–“â–ˆ â–“â–“ â–“â–“â–ˆ â–“â–“ â–“â–“â–“â–ˆ
+ * â–“ â–“â–“â–“â–“ â–“â–“â–“ â–“â–“â–“ â–“â–“â–“ â–“â–“â–“ â–“â–“â–“â–“
+ * ▓ █▓▓▓ █▓▓ █▓▓ █▓▓ █▓▓ █▓▓▓
+ * ▓ █▓▓▓▓█ █▓▓ ▓█ █▓▓ ▓█ █▓▓█▓█ █▓▓▓ █▓▓▓
+ * ▓ █▓▓▓ ▓█▓ █▓█▓█ █▓█▓█ ▓▓█ ▓█ █▓▓▓
+ * ▓█ █▓▓▓ ▓▓▓ ▓▓▓ ▓▓ █▓▓▓
+ * ▓▓ █▓▓ ▓ ▓ ▓ █▓▓▓
+ * ▓ █▓▓ ▓█ █▓▓
+ * ▓ ▓▓▓ ▓▓ █▓▓
+ * █\ ▓▓ ▓▓ ▓█ ▓ █▓▓
+ * ▓█\ ▓█ ▓█▓ ▓▓▓ █▓ █▓▓
+ * ▓▓▓█ ▓ ▓▓▓▓ ▓ ▓▓ ▓ █▓▓
+ * ▓█▓ ▓▓█▓▓ ▓ ▓▓ ▓▓▓
+ * ▓▓ █▓▓█ █▓ █▓▓
+ * ▓▓ ▓▓▓ ▓▓ █▓▓
+ * ▓ ▓▓▓ ▓ █▓▓
+ * ▓▓ █▓▓█ █▓ █▓▓▓
+ * ▓ █▓▓▓ ▓▓█ █▓█ ▓▓ █▓▓▓
+ * ▓ █▓▓▓▓▓ ▓▓█ ▓▓ ▓▓█▓ █▓▓▓
+ * ▓ █▓▓▓ ▓▓▓ ▓▓▓ █▓▓▓
+ * ▓ █▓▓▓ ▓▓▓ ▓▓▓ █▓▓▓
+ * ▓█▓██▓▓▓█▓█▓█▓▓▓█▓█▓█▓▓▓█▓█▓██▓▓▓
+ */
+ icon_state = "synx_C_living"
+ icon_living = "synx_C_living"
+ icon_dead = "synx_C_dead"
+ //hostile = 1
+ name = "SYN-KinC"
+ desc = "A robotic recreation of a an Alien parasite. The metal plates seem quite thick."
+ humanoid_hands = 1
+ health = 200 //Metally
+ player_msg = "All systems nominal."
+ /////////////////////ARMOR
+ armor = list(
+ "melee" = 50,
+ "bullet" = 50,
+ "laser" = -50,
+ "energy" = -50,
+ "bomb" = 50,
+ "bio" = 100,
+ "rad" = 100)
+ ////////////////////////////MED INJECTOR
+ poison_type = REAGENT_ID_OXYCODONE //OD effects, eye_blurry | Confuse + for slimes | stuttering
+ poison_chance = 77 //high but not guranteed.
+ poison_per_bite = 9 //OD for oxyc is 20
+ //////////////////////////////////////////////FACTION
+ faction = "SYN"
+
+
+/mob/living/simple_mob/animal/synx/ai/pet/greed/synth/Initialize(mapload)
+ . = ..()
+ name = "SYN-KinC-([rand(100,999)])"
+
+/mob/living/simple_mob/animal/synx/ai/pet/greed/synth/goodboy
+ //hostile = 0
+ faction = "neutral"
+
+/mob/living/simple_mob/animal/synx/ai/pet/diablo
+ //var/diablo_LIVING = "synx_diablo_living"
+ //var/diablo_DEAD = "synx_diablo_dead"
+ name = "diablo"
+ desc = "A cold blooded, genderless, parasitic eel from the more distant and stranger areas of the cosmos. grey, perpetually grinning and possessing a hunger as enthusiastic and endless as humanity's sense of exploration.. This one has a small shock collar on it that reads 'diablo'."
+ icon_state = "synx_diablo_living"
+ icon_living = "synx_diablo_living"
+ icon_dead = "synx_diablo_dead"
+ speak = list( )
+ //Vore Section
+ vore_capacity = 2
+*/
+/mob/living/simple_mob/animal/synx/ai/pet/clown
+ //hostile = 1
+ poison_chance = 100
+ poison_type = "clownsynxchem" //unlike synxchem this one HONKS
+ name = "Inflatable Clown Synx"
+ desc = "Honk!, made this here with all the fun on in the booth. At the gate outside, when they pull up, they get me loose. Yeah, Jump Out Clowns, that's Clown gang, hoppin' out tiny cars. This shit way too funny, when we pull up give them the honk hard!"
+ icon_state = "synx_pet_rainbow"
+ icon_living = "synx_pet_rainbow"
+ //icon_dead = "synx_hardlight_dead"
+ icon_gib = null
+ faction = "clown"
+ melee_damage_lower = 1
+ melee_damage_upper = 1
+ //environment_smash = 0
+ //destroy_surroundings = 0
+ //Vore Section
+ vore_default_mode = DM_HEAL
+ vore_capacity = 10
+ vore_digest_chance = 0
+ vore_pounce_chance = 1 //MAKE THEM HONK
+ vore_bump_chance = 0 //lowered bump chance
+ vore_escape_chance = 100
+
+////////////////////////////////////////
+////////////////SYNX DEBUG//////////////
+////////////////////////////////////////
+/mob/living/simple_mob/animal/synx/ai/pet/debug
+ name = "Syntox"
+ desc = "ERROR Connection to translation server could not be established!"
+
+/mob/living/simple_mob/animal/synx/ai/pet/debug/proc/rename()
+ set name = "rename"
+ set desc = "Renames the synx"
+ set category = "DEBUG"
+ name = input(usr, "What would you like to change name to?", "Renaming", null)
+
+/mob/living/simple_mob/animal/synx/ai/pet/debug/proc/redesc()
+ set name = "redesc"
+ set desc = "Redescribes the synx"
+ set category = "DEBUG"
+ desc = input(usr, "What would you like to change desc to?", "Redescribing", null)
+
+/mob/living/simple_mob/animal/synx/ai/pet/debug/proc/resprite()
+ set name = "resprite"
+ set desc = "Resprite the synx"
+ set category = "DEBUG"
+ icon_state = input(usr, "What would you like to change icon_state to?", "Respriting", null)
+
+/mob/living/simple_mob/animal/synx/ai/pet/debug/Initialize(mapload)
+ . = ..(mapload, TRUE)
+ add_verb(src,/mob/living/simple_mob/animal/synx/ai/pet/debug/proc/rename)
+ add_verb(src,/mob/living/simple_mob/animal/synx/ai/pet/debug/proc/resprite)
+ add_verb(src,/mob/living/simple_mob/animal/synx/ai/pet/debug/proc/redesc)
+
+////////////////////////////////////////
+////////////////SYNX SPAWNER////////////
+////////////////////////////////////////
+/obj/random/mob/synx
+ name = "This is synxes"
+
+/obj/random/mob/synx/item_to_spawn()
+// return pick(prob(66);/mob/living/simple_mob/animal/synx/ai/pet/greed,
+// prob(33);/mob/living/simple_mob/animal/synx/ai/pet/holo, // Commented out as it doesn't currently work with the modular sprite system. Will try and get this up and working before TOO long, hopefully. -Azel
+ return /*pick (prob(50);*//mob/living/simple_mob/animal/synx/ai///) //normal eel boyo.
+
+
+////////////////////////////////////////////////////////////////////////////
+//////////////////////////NOT A SYNX///////but acts kinda like one/////////
+////////////////////////////////////////////////////////////////////////////
+/*
+Content relating to the SCP Foundation, including the SCP Foundation logo, is licensed under
+Creative Commons Sharealike 3.0 and all concepts originate from http://www.scp-wiki.net and its authors.
+This includes the sprites of the below Mob which are based upon SCP 939.
+*/
+//SCP-939
+//sprites to be made.
+/datum/ai_holder/simple_mob/scp
+ hostile = TRUE // The majority of simplemobs are hostile.
+ retaliate = TRUE // The majority of simplemobs will fight back.
+ cooperative = TRUE
+ returns_home = FALSE
+ can_flee = TRUE
+ speak_chance = 0 // If the mob's saylist is empty, nothing will happen.
+ wander = TRUE
+ base_wander_delay = 3
+ autopilot = TRUE //As the ghost in this shell you only control the voices.
+ wander_when_pulled = TRUE
+ outmatched_threshold = 100 //pussy
+ flee_when_outmatched = TRUE
+ call_distance = 100
+ mauling = FALSE
+ vision_range = 10 //no kiting, they have ears.
+ use_astar = TRUE //Clever boy!
+ threaten = TRUE
+
+/mob/living/simple_mob/animal/synx/scp
+ name = "Unknown"
+ desc = "It's a red canine looking creature."
+ tt_desc = "Unknown Alien Lifeform"
+
+ poison_chance = 0 //no poison,
+ ai_holder_type = /datum/ai_holder/simple_mob/scp
+ say_list_type = /datum/say_list/malf_drone
+
+ icon = 'icons/mob/synxmanyvoices.dmi'
+ icon_state = "939_living"
+ icon_living = "939_living"
+ icon_dead = "939_dead"
+ pixel_x = -15
+
+#undef SYNX_LOWER_DAMAGE
+#undef SYNX_UPPER_DAMAGE
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/teppi.dm b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/teppi.dm
index fb752ff87b..d2ef832f0a 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/teppi.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/alien animals/teppi.dm
@@ -164,6 +164,7 @@ GLOBAL_VAR_INIT(teppi_count, 0) // How mant teppi DO we have?
vore_pounce_chance = 35
vore_pounce_falloff = 0
vore_standing_too = TRUE
+ can_be_drop_prey = FALSE
/mob/living/simple_mob/vore/alienanimals/teppi/load_default_bellies()
. = ..()
@@ -171,7 +172,6 @@ GLOBAL_VAR_INIT(teppi_count, 0) // How mant teppi DO we have?
B.name = "stomach"
B.desc = "The heat of the roiling flesh around you bakes into you immediately as you're cast into the gloom of a Teppi's primary gastric chamber. The undulations are practically smothering, clinging to you and grinding you all over as the Teppi continues about its day. The walls are heavy against you, so it's really difficult to move at all, while the heart of this creature pulses rhythmically somewhere nearby, and you can feel the throb of its pulse in the doughy squish pressing up against you. Your figure sinks a ways into the flesh as it presses in, wrapping limbs up between countless slick folds and kneading waves. It's not long before you're positively soaked in a thin layer of slime as you're rocked and squeezed and jostled in the stomach of your captor."
B.mode_flags = 40
- B.belly_fullscreen = "yet_another_tumby"
B.digest_brute = 0.05
B.digest_burn = 0.05
B.digestchance = 5
@@ -301,7 +301,6 @@ GLOBAL_VAR_INIT(teppi_count, 0) // How mant teppi DO we have?
p.contamination_flavor = "Wet"
p.contamination_color = "grey"
p.item_digest_mode = IM_HOLD
- p.belly_fullscreen = "yet_another_tumby"
p.fancy_vore = 1
p.vore_verb = "nyomp"
friend_zone = p
@@ -621,7 +620,8 @@ GLOBAL_VAR_INIT(teppi_count, 0) // How mant teppi DO we have?
if(prob(25))
M.visible_message(span_notice("\The [src] rumbles happily at \the [M]"),span_notice("\The [src] rumbles happily at you!"))
playsound(src, 'sound/voice/teppi/rumble.ogg', 75, 1)
- vore_selected.digest_mode = DM_DRAIN //People outside can help calm the tumby if you squirm too much
+ if(vore_selected)
+ vore_selected.digest_mode = DM_DRAIN //People outside can help calm the tumby if you squirm too much
else if(prob(25))
M.visible_message(span_notice("\The [src] rumbles happily at \the [M]"),span_notice("\The [src] rumbles happily at you!"))
playsound(src, 'sound/voice/teppi/cute_rumble.ogg', 75, 1)
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm b/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm
index 52d7881e59..de04712591 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/borer/borer.dm
@@ -44,6 +44,8 @@
var/used_dominate // world.time when the dominate power was last used.
var/datum/ghost_query/Q // Used to unregister our signal
+ can_be_drop_prey = FALSE
+
/mob/living/simple_mob/animal/borer/roundstart
roundstart = TRUE
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/_giant_spider.dm b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/_giant_spider.dm
index 75b124f87e..e18a04cd27 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/_giant_spider.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/_giant_spider.dm
@@ -69,7 +69,7 @@
icon_dead = "guard_dead"
has_eye_glow = TRUE
density = FALSE
-
+ minbodytemp = 175
faction = FACTION_SPIDERS
maxHealth = 200
health = 200
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/broodmother_spawn.dm b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/broodmother_spawn.dm
index f715216a56..00a2a4e787 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/broodmother_spawn.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/broodmother_spawn.dm
@@ -14,7 +14,9 @@
/mob/living/simple_mob/animal/giant_spider/frost/broodling/death()
new /obj/effect/decal/cleanable/spiderling_remains(src.loc)
- qdel(src)
+
+ if(!QDELETED(src))
+ qdel(src)
/mob/living/simple_mob/animal/giant_spider/electric/broodling
maxHealth = 30
@@ -32,7 +34,9 @@
/mob/living/simple_mob/animal/giant_spider/electric/broodling/death()
new /obj/effect/decal/cleanable/spiderling_remains(src.loc)
- qdel(src)
+
+ if(!QDELETED(src))
+ qdel(src)
/mob/living/simple_mob/animal/giant_spider/hunter/broodling
maxHealth = 40
@@ -47,7 +51,9 @@
/mob/living/simple_mob/animal/giant_spider/hunter/broodling/death()
new /obj/effect/decal/cleanable/spiderling_remains(src.loc)
- qdel(src)
+
+ if(!QDELETED(src))
+ qdel(src)
/mob/living/simple_mob/animal/giant_spider/lurker/broodling
maxHealth = 40
@@ -62,7 +68,9 @@
/mob/living/simple_mob/animal/giant_spider/lurker/broodling/death()
new /obj/effect/decal/cleanable/spiderling_remains(src.loc)
- qdel(src)
+
+ if(!QDELETED(src))
+ qdel(src)
/mob/living/simple_mob/animal/giant_spider/nurse/broodling
maxHealth = 60
@@ -78,7 +86,9 @@
/mob/living/simple_mob/animal/giant_spider/nurse/broodling/death()
new /obj/effect/decal/cleanable/spiderling_remains(src.loc)
- qdel(src)
+
+ if(!QDELETED(src))
+ qdel(src)
/mob/living/simple_mob/animal/giant_spider/pepper/broodling
maxHealth = 40
@@ -93,7 +103,9 @@
/mob/living/simple_mob/animal/giant_spider/pepper/broodling/death()
new /obj/effect/decal/cleanable/spiderling_remains(src.loc)
- qdel(src)
+
+ if(!QDELETED(src))
+ qdel(src)
/mob/living/simple_mob/animal/giant_spider/thermic/broodling
maxHealth = 40
@@ -111,7 +123,9 @@
/mob/living/simple_mob/animal/giant_spider/thermic/broodling/death()
new /obj/effect/decal/cleanable/spiderling_remains(src.loc)
- qdel(src)
+
+ if(!QDELETED(src))
+ qdel(src)
/mob/living/simple_mob/animal/giant_spider/tunneler/broodling
maxHealth = 40
@@ -126,7 +140,9 @@
/mob/living/simple_mob/animal/giant_spider/tunneler/broodling/death()
new /obj/effect/decal/cleanable/spiderling_remains(src.loc)
- qdel(src)
+
+ if(!QDELETED(src))
+ qdel(src)
/mob/living/simple_mob/animal/giant_spider/webslinger/broodling
maxHealth = 30
@@ -143,7 +159,9 @@
/mob/living/simple_mob/animal/giant_spider/webslinger/broodling/death()
new /obj/effect/decal/cleanable/spiderling_remains(src.loc)
- qdel(src)
+
+ if(!QDELETED(src))
+ qdel(src)
/mob/living/simple_mob/animal/giant_spider/broodling
maxHealth = 60
@@ -154,11 +172,21 @@
movement_cooldown = 3
+ var/deathtimer
+
/mob/living/simple_mob/animal/giant_spider/broodling/Initialize(mapload)
. = ..()
adjust_scale(0.75)
- addtimer(CALLBACK(src, PROC_REF(death)), 2 MINUTES)
+ deathtimer = addtimer(CALLBACK(src, PROC_REF(death)), 2 MINUTES, TIMER_STOPPABLE)
+
+/mob/living/simple_mob/animal/giant_spider/broodling/Destroy()
+ if(deathtimer)
+ deltimer(deathtimer)
+ deathtimer = null
+ . = ..()
/mob/living/simple_mob/animal/giant_spider/broodling/death()
new /obj/effect/decal/cleanable/spiderling_remains(src.loc)
- qdel(src)
+
+ if(!QDELETED(src))
+ qdel(src)
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/carrier.dm b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/carrier.dm
index e120a452f0..9d2085d444 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/carrier.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/carrier.dm
@@ -85,3 +85,6 @@
catalogue_data = list(/datum/category_item/catalogue/fauna/giant_spider/recursive_carrier_spider)
swarmling_type = /mob/living/simple_mob/animal/giant_spider/carrier/recursive
+
+/mob/living/simple_mob/animal/giant_spider/carrier/event
+ ai_holder_type = /datum/ai_holder/simple_mob/event
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/electric.dm b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/electric.dm
index 937b1d8ce2..fa4391f099 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/electric.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/electric.dm
@@ -60,3 +60,6 @@
if(L.incapacitated(INCAPACITATION_DISABLED) || L.stat == UNCONSCIOUS) // If our target is stunned, go in for the kill.
return 1
return ..() // Do ranged if possible otherwise.
+
+/mob/living/simple_mob/animal/giant_spider/electric/event
+ ai_holder_type = /datum/ai_holder/simple_mob/event
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/frost.dm b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/frost.dm
index 4b44839d9b..b9a524a7df 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/frost.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/frost.dm
@@ -35,3 +35,6 @@
/mob/living/simple_mob/animal/giant_spider/frost/sif
desc = "Icy and blue, it makes you shudder to look at it. This one has brilliant blue eyes. \
It isn't native to Sif."
+
+/mob/living/simple_mob/animal/giant_spider/frost/event
+ ai_holder_type = /datum/ai_holder/simple_mob/event
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/giant_spider_vr.dm b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/giant_spider_vr.dm
index 5cbb3d9fa0..cadc20d758 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/giant_spider_vr.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/giant_spider_vr.dm
@@ -55,6 +55,12 @@
egg_type = /obj/effect/spider/eggcluster/royal
+/mob/living/simple_mob/animal/giant_spider/webslinger/event
+ ai_holder_type = /datum/ai_holder/simple_mob/event
+
+/mob/living/simple_mob/animal/giant_spider/nurse/queen/event
+ ai_holder_type = /datum/ai_holder/simple_mob/event
+
/mob/living/simple_mob/animal/giant_spider/nurse
var/can_lay_eggs = TRUE
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/hunter.dm b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/hunter.dm
index 803bfd688b..6fcbdcc3a2 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/hunter.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/hunter.dm
@@ -178,3 +178,5 @@
if(move_to)
give_destination(move_to, min_distance = 2, combat = TRUE) // This will switch our stance.
*/
+/mob/living/simple_mob/animal/giant_spider/hunter/event
+ ai_holder_type = /datum/ai_holder/simple_mob/event
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/lurker.dm b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/lurker.dm
index 89019b727f..2f10c1ebe5 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/lurker.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/lurker.dm
@@ -102,7 +102,7 @@
if(cloaked)
if(isliving(A))
var/mob/living/L = A
- L.Weaken(cloaked_weaken_amount)
+ L.add_modifier(/datum/modifier/entangled, 2 SECONDS) //L.Weaken(cloaked_weaken_amount)
to_chat(L, span_danger("\The [src] ambushes you!"))
playsound(src, 'sound/weapons/spiderlunge.ogg', 75, 1)
uncloak()
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/nurse.dm b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/nurse.dm
index 00b380b2ec..c6682c40bb 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/nurse.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/nurse.dm
@@ -82,6 +82,12 @@
var/mob/living/L = A
if(!L.stat)
return ..()
+ else
+ if (L.anchored && L.buckled && !(L.pulledby || L.buckled.pulledby)) //don't have them trying to unbuckle someone on something that's being pulled because that's just annoying as fuck esp for a medic or something
+ L.buckled.unbuckle_mob(L)
+ if (!L.anchored)
+ return spin_cocoon(L)
+ return
if(!istype(A, /atom/movable))
return
@@ -95,7 +101,9 @@
/mob/living/simple_mob/animal/giant_spider/nurse/proc/spin_cocoon(atom/movable/AM)
if(!istype(AM))
return FALSE // We can't cocoon walls sadly.
- visible_message(span_notice("\The [src] begins to secrete a sticky substance around \the [AM].") )
+ if(istype(AM, /mob/living/simple_mob/animal/giant_spider))
+ return FALSE
+ visible_message(span_notice("\The [src] begins to secrete a sticky substance around \the [AM]."))
// Get our AI to stay still.
set_AI_busy(TRUE)
@@ -263,7 +271,11 @@
/datum/ai_holder/simple_mob/melee/nurse_spider/can_attack(atom/movable/the_target, var/vision_required = TRUE)
. = ..()
if(!.) // Parent returned FALSE.
- if(istype(the_target, /obj))
+ if (istype(the_target, /mob/living/simple_mob/animal/giant_spider))
+ var/mob/living/L = the_target
+ if (L.stat)
+ return FALSE
+ if(istype(the_target, /obj) && (!vision_required || can_see_target(the_target)))
var/obj/O = the_target
if(!O.anchored)
return TRUE
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/tunneler.dm b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/tunneler.dm
index f9680ccd68..e757328cf2 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/tunneler.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/tunneler.dm
@@ -116,7 +116,7 @@
visible_message(span_danger("\The [src] erupts from underneath, and hits \the [L]!"))
playsound(src, 'sound/weapons/heavysmash.ogg', 75, 1)
- L.Weaken(3)
+ L.add_modifier(/datum/modifier/entangled, 3 SECONDS) //L.Weaken(3)
overshoot = FALSE
if(!overshoot) // We hit the target, or something, at destination, so we're done.
@@ -207,3 +207,18 @@
incoming_damage_percent = 2
evasion = -100
+
+/mob/living/simple_mob/animal/giant_spider/tunneler/cave
+ name = "cave spider"
+ desc = "Sandy and brown, it makes you shudder to look at it. However, this one doesn't seem very interested in bothering you."
+ maxHealth = 25
+ health = 25
+ harm_intent_damage = 5
+ melee_damage_lower = 5
+ melee_damage_upper = 5
+ ai_holder_type = /datum/ai_holder/simple_mob/retaliate
+ meat_amount = 1 // Scrawny little things! It's no wonder they don't want to fight you!
+
+/mob/living/simple_mob/animal/giant_spider/tunneler/cave/Initialize(mapload)
+ . = ..()
+ resize(0.50)
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/hyena/hyena.dm b/code/modules/mob/living/simple_mob/subtypes/animal/hyena/hyena.dm
new file mode 100644
index 0000000000..57f1f7387f
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/hyena/hyena.dm
@@ -0,0 +1,169 @@
+/*
+
+Hyenas are any feliform carnivoran mammals of the family Hyaenidae. With only four extant species (in three genera), it is the fifth-smallest biological family in the Carnivora, and one of the smallest in the class Mammalia.
+They're also cool, and Rykka/Nyria wrote this uwu
+
+*/
+
+// Cataloguer data here
+/datum/category_item/catalogue/fauna/hyena
+ name = "Desert Fauna - Hyena"
+ desc = "Classification: Crocuta crocuta \
+
\
+ It is primarily a hunter but may also scavenge, with the capacity to eat and digest skin, bone and other animal waste. \
+ The spotted hyena displays greater plasticity in its hunting and foraging behaviour than other similar carnivores; \
+ it hunts alone, in small parties of 2–5 individuals or in large groups. \
+ During a hunt, spotted hyenas often run through ungulate herds in order to select an individual to attack. \
+ Once selected, their prey is chased over a long distance, often several kilometres, at speeds of up to 60 km/h."
+ value = CATALOGUER_REWARD_MEDIUM
+
+// Start Defining the mob here
+/mob/living/simple_mob/animal/hyena
+ name = "Hyena"
+ desc = "Yeen! Its fur is a dusty yellow-brown color with black spots, and it has rounded ears... and SHARP TEETH! You inexplicably want to pet it, though."
+ tt_desc = "Crocuta crocuta"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/hyena)
+
+ icon = 'icons/mob/hyena.dmi'
+ icon_state = "yeen"
+ icon_living = "yeen"
+ icon_dead = "yeen_dead"
+ has_eye_glow = FALSE // Change this to true for fun spooky eye glow in darkness. <3
+ minbodytemp = 175 // Make hyenas able to survive freezing cold. Someone criticize me later uwu
+ faction = "yeen" // gon fight any other mobs. grr
+ maxHealth = 125 // not as tanky as a spider for obvious reasons, but not a pushover.
+ health = 125
+ pass_flags = PASSTABLE
+ movement_cooldown = 0 // Yeen go fast - nah, yeen still slower. gottagofast.
+ // movement_sound = null - TODO: find good animal pawb sounds
+ poison_resist = 0.1
+
+ see_in_dark = 25 // Hyenas are nocturnal, they should be able to see anything in the dark. <3
+
+ response_help = "rubrubs"
+ response_disarm = "boops aside"
+ response_harm = "smacks"
+
+ melee_damage_lower = 12 // hyenas go for the legs/lower bits
+ melee_damage_upper = 6 // not as high damage, but faster bites. nomnomnom <3
+ attack_sharp = 1
+ attack_edge = 1
+ base_attack_cooldown = 2
+ attacktext = list("bit", "nipped", "chomped", "clawed", "scratched", "lewded")
+ attack_sound = 'sound/weapons/bite.ogg' // placeholder till I find a better bite
+
+ vore_active = 1 // nom settings. <3
+ vore_capacity = 3 // yeens can eat something like 85% of their weight in meat. nom~
+ vore_bump_chance = 25
+ vore_bump_emote = "nomfs!"
+ vore_pounce_chance = 35
+ vore_pounce_maxhealth = 90
+ vore_standing_too = 1 // nomf people while they're standing, yus.
+ swallowsound = 'sound/vore/sunesound/pred/insertion_01.ogg'
+
+ vore_default_mode = DM_HOLD // yeengut takes a sec to kick in :3
+ vore_digest_chance = 95 // you move, yeengut is gonna kick in~
+ vore_escape_chance = 8 // 8% chance to escape a hot, slimy, kneading gut. Why would you want to leave~?
+
+ vore_stomach_name = "gut"
+ vore_stomach_flavor = "Hot, slimy, and kneading constantly around you, as the hyena's heartbeat thuds away above. All you can see are pink, slimy walls, \
+ kneading all over your entire form, and what looks like digestive acids pooling along the bottom of it's gut. \
+ You can hear cackling laughter and yaps, as well as the lurid sloshing of the hyena's belly as you're rocked around. Best not squirm, since it's belly isn't digesting you... yet."
+
+ vore_default_contamination_flavor = "Acrid"
+ vore_default_contamination_color = "yellow"
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/pack_mob // Define here what type of enemy hyena is.
+
+ heat_damage_per_tick = 20
+ cold_damage_per_tick = 20
+
+ speak_emote = list("yaps")
+
+ say_list_type = /datum/say_list/hyena
+
+ allow_mind_transfer = TRUE
+
+ var/obj/item/clothing/head/hat = null // The hat the yeen is wearing when initialized, var will update with the chosen hat.
+
+// Silly stuff. HATS! Give your yeen a hat today <3
+/mob/living/simple_mob/animal/hyena/verb/remove_hat()
+ set name = "Remove Hat"
+ set desc = "Remove the yeen's hat. You monster. ;~;"
+ set category = "Abilities.Hyena"
+ set src in view(1)
+
+ drop_hat(usr)
+
+/mob/living/simple_mob/animal/hyena/proc/drop_hat(var/mob/user)
+ if(hat)
+ hat.forceMove(get_turf(user))
+ hat = null
+ update_icon()
+ if(user == src)
+ to_chat(user, span_notice("You removed your hat."))
+ return
+ to_chat(user, span_warning("You removed \the [src]'s hat. You monster. ;~;"))
+ else
+ if(user == src)
+ to_chat(user, span_notice("You are not wearing a hat!"))
+ return
+ to_chat(user, span_notice("\The [src] is not wearing a hat!"))
+
+/mob/living/simple_mob/animal/hyena/verb/give_hat()
+ set name = "Give Hat"
+ set desc = "Give the yeen a hat. You wonderful bean. <3"
+ set category = "Abilities.Hyena"
+ set src in view(1)
+
+ take_hat(usr)
+
+/mob/living/simple_mob/animal/hyena/proc/take_hat(var/mob/user)
+ if(hat)
+ if(user == src)
+ to_chat(user, span_notice("You already have a hat!"))
+ return
+ to_chat(user, span_notice("\The [src] already has a hat!"))
+ else
+ if(user == src)
+ if(istype(get_active_hand(), /obj/item/clothing/head))
+ hat = get_active_hand()
+ drop_from_inventory(hat, src)
+ hat.forceMove(src)
+ to_chat(user, span_notice("You put on the hat."))
+ update_icon()
+ return
+ else if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+
+ if(istype(H.get_active_hand(), /obj/item/clothing/head) && !get_active_hand())
+ var/obj/item/clothing/head/newhat = H.get_active_hand()
+ H.drop_from_inventory(newhat, get_turf(src))
+ if(!stat)
+ a_intent = I_HELP
+ newhat.attack_hand(src)
+ else if(src.get_active_hand())
+ to_chat(user, span_notice("\The [src] seems busy with \the [get_active_hand()] already!"))
+
+ else
+ to_chat(user, span_warning("You aren't holding a hat..."))
+
+/datum/say_list/hyena
+ speak = list("Huff.", "|R|rr?", "Yap.", "Grr.", "Yip.", "SCREM!")
+ emote_see = list("sniffs", "looks around", "grooms itself", "rolls around")
+ emote_hear = list("yawns", "cackles", "playfully yaps")
+
+/mob/living/simple_mob/animal/hyena/Destroy()
+ if(hat)
+ drop_hat(src) // ;w;
+ ..()
+
+/mob/living/simple_mob/animal/hyena/update_icon()
+ overlays.Cut()
+ ..()
+ if(hat)
+ var/hat_state = hat.item_state ? hat.item_state : hat.icon_state
+ var/image/I = image('icons/inventory/head/mob.dmi', src, hat_state)
+ I.pixel_y = -15 // Hyenas are smol! - TODO: Test this.
+ I.appearance_flags = RESET_COLOR
+ add_overlay(I)
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/passive/armadillo.dm b/code/modules/mob/living/simple_mob/subtypes/animal/passive/armadillo.dm
new file mode 100644
index 0000000000..2d705e7c10
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/passive/armadillo.dm
@@ -0,0 +1,157 @@
+//Straight import from Mexico and a direct hit to your heart
+/mob/living/simple_mob/animal/passive/armadillo
+ name = "armadillo"
+ desc = "A small, armored mammal. It seems to enjoy rolling around and sleep as a ball."
+ tt_desc = "Dasypus novemcinctus"
+ //faction = "mexico" //They are from Mexico. //Amusing but this prompts aggression from crew-aligned mobs.
+
+ icon = 'icons/mob/animal.dmi'
+ icon_state = "armadillo"
+ item_state = "armadillo_rest"
+ icon_living = "armadillo"
+ icon_rest = "armadillo_rest"
+ icon_dead = "armadillo_dead"
+
+ health = 30
+ maxHealth = 30
+
+ mob_size = MOB_SMALL
+ pass_flags = PASSTABLE
+ can_pull_size = ITEMSIZE_TINY
+ can_pull_mobs = MOB_PULL_NONE
+ layer = MOB_LAYER
+ density = 0
+ movement_cooldown = 0.75 //roughly a bit faster than a person
+
+ response_help = "pets"
+ response_disarm = "rolls aside"
+ response_harm = "stomps"
+
+ melee_damage_lower = 2
+ melee_damage_upper = 1
+ attacktext = list("nips", "bumps", "scratches")
+
+ vore_taste = "sand"
+
+ min_oxy = 16 //Require atleast 16kPA oxygen
+ minbodytemp = 223 //Below -50 Degrees Celcius
+ maxbodytemp = 523 //Above 80 Degrees Celcius
+ heat_damage_per_tick = 3
+ cold_damage_per_tick = 3
+
+ meat_amount = 2
+ holder_type = /obj/item/holder/armadillo
+ ai_holder_type = /datum/ai_holder/simple_mob/armadillo
+
+ speak_emote = list("rumbles", "chirr?", "churr")
+
+ say_list_type = /datum/say_list/armadillo
+
+ var/obj/item/clothing/head/hat = null // The hat the armadillo may be wearing.
+
+//Hat simulator stolen from slime code.
+/mob/living/simple_mob/animal/passive/armadillo/Destroy()
+ if(hat)
+ drop_hat()
+ return ..()
+
+/mob/living/simple_mob/animal/passive/armadillo/update_icon()
+ ..() // Do the regular stuff first.
+
+ // Hat simulator.
+ if(hat)
+ var/hat_state = hat.item_state ? hat.item_state : hat.icon_state
+ var/image/I = image('icons/inventory/head/mob.dmi', src, hat_state)
+ I.pixel_y = -7 // Smol
+ I.appearance_flags = RESET_COLOR
+ add_overlay(I)
+
+// Clicked on by empty hand.
+/mob/living/simple_mob/animal/passive/armadillo/attack_hand(mob/living/L)
+ if(L.a_intent == I_GRAB && hat)
+ remove_hat(L)
+ else
+ ..()
+
+/mob/living/simple_mob/animal/passive/armadillo/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/clothing/head)) // Handle hat simulator.
+ give_hat(I, user)
+ return
+ ..()
+
+// Hat simulator
+/mob/living/simple_mob/animal/passive/armadillo/proc/give_hat(var/obj/item/clothing/head/new_hat, var/mob/living/user)
+ if(!istype(new_hat))
+ to_chat(user, span_warning("\The [new_hat] isn't a hat."))
+ return
+ if(hat)
+ to_chat(user, span_warning("\The [src] is already wearing \a [hat]."))
+ return
+ else
+ user.drop_item(new_hat)
+ hat = new_hat
+ new_hat.forceMove(src)
+ to_chat(user, span_notice("You place \a [new_hat] on \the [src]. How adorable!"))
+ update_icon()
+ return
+
+/mob/living/simple_mob/animal/passive/armadillo/proc/remove_hat(var/mob/living/user)
+ if(!hat)
+ to_chat(user, span_warning("\The [src] doesn't have a hat to remove."))
+ else
+ hat.forceMove(get_turf(src))
+ user.put_in_hands(hat)
+ to_chat(user, span_warning("You take away \the [src]'s [hat.name]. How mean."))
+ hat = null
+ update_icon()
+
+/mob/living/simple_mob/animal/passive/armadillo/proc/drop_hat()
+ if(!hat)
+ return
+ hat.forceMove(get_turf(src))
+ hat = null
+ update_icon()
+
+/obj/item/holder/armadillo
+ origin_tech = list(TECH_BIO = 1)
+ default_worn_icon = 'icons/mob/head.dmi'
+ //item_state = "armadillo_rest" //Commented here as a reminder that holders will always set the item_state to icon_rest. You cannot override it like this.
+
+/mob/living/simple_mob/animal/passive/armadillo/torta
+ name = "Torta"
+ desc = "A small, armored mammal. It seems to be territorial and protective of the dorms."
+ ai_holder_type = /datum/ai_holder/simple_mob/armadillo/torta
+
+/mob/living/simple_mob/animal/passive/armadillo/torta/Initialize(mapload)
+ . = ..()
+ if(!hat)
+ hat = new /obj/item/clothing/head/sombrero
+ hat.forceMove(src)
+ update_icon()
+
+/datum/say_list/armadillo
+ emote_hear = list("churrs","rumbles","chirrs")
+ emote_see = list("rolls in place", "shuffles", "scritches at something")
+
+/datum/ai_holder/simple_mob/armadillo
+ hostile = FALSE
+ retaliate = TRUE
+ can_flee = TRUE
+ flee_when_dying = TRUE
+ dying_threshold = 0.9
+ speak_chance = 1
+
+/datum/ai_holder/simple_mob/armadillo/torta
+
+/datum/ai_holder/simple_mob/armadillo/torta/on_hear_say(mob/living/speaker, message)
+ . = ..()
+ addtimer(CALLBACK(src, PROC_REF(grande), message), 1 SECOND)
+
+/datum/ai_holder/simple_mob/armadillo/torta/proc/grande(var/message)
+ var/mob/living/simple_mob/animal/passive/armadillo/bol = holder
+ if(!istype(bol))
+ return
+ message = lowertext(message)
+ if(findtext(message, "grande"))
+ bol.resize(bol.size_multiplier + 0.01)
+ return
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/passive/cockroach.dm b/code/modules/mob/living/simple_mob/subtypes/animal/passive/cockroach.dm
index 1786771b20..345cae7bcc 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/passive/cockroach.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/passive/cockroach.dm
@@ -13,6 +13,7 @@
maxHealth = 1
health = 1
+ nutrition = 20
movement_cooldown = -1
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/passive/lizard_mutant_event.dm b/code/modules/mob/living/simple_mob/subtypes/animal/passive/lizard_mutant_event.dm
new file mode 100644
index 0000000000..703480bf68
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/passive/lizard_mutant_event.dm
@@ -0,0 +1,26 @@
+/mob/living/simple_mob/animal/passive/lizard/event
+ desc = "This one looks like it is growing huge!"
+ var/amount_grown = 0
+ faction = "lizard"
+
+/mob/living/simple_mob/animal/passive/lizard/event/Life()
+ . = ..()
+ if(amount_grown >= 0)
+ amount_grown += rand(0,4)
+ if(amount_grown >= 100 && icon_state != icon_dead)
+ man()
+ return
+
+/mob/living/simple_mob/animal/passive/lizard/event/proc/man()
+ var/mob/bigger = new /mob/living/simple_mob/vore/aggressive/lizardman(get_turf(src))
+
+ if(istype(loc,/obj/belly))
+ var/obj/belly/B = loc
+ B.owner.visible_message(span_boldwarning("Something grows inside [B.owner]'s [lowertext(B.name)]!"))
+ to_chat(B.owner, span_warning("\The [src] suddenly evolves inside your [lowertext(B.name)]!"))
+ B.release_specific_contents(src, TRUE)
+ B.nom_mob(bigger, null)
+ qdel(src)
+ else
+ visible_message(span_warning("\The [src] suddenly evolves!"))
+ qdel(src)
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/passive/mouse.dm b/code/modules/mob/living/simple_mob/subtypes/animal/passive/mouse.dm
index 7536008348..dc2445e3d9 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/passive/mouse.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/passive/mouse.dm
@@ -46,8 +46,22 @@
var/list/datum/disease/rat_diseases
+ can_be_drop_prey = TRUE
+ can_be_drop_pred = FALSE
+ species_sounds = "Mouse"
+
+ pain_emote_1p = list("squeak", "squik")
+ pain_emote_1p = list("squeaks", "squiks")
+
+/mob/living/simple_mob/animal/passive/mouse/Destroy()
+ GLOB.active_ghost_pods -= src
+ return ..()
+
/mob/living/simple_mob/animal/passive/mouse/Initialize(mapload, keep_parent_data)
. = ..()
+ ghostjoin = TRUE
+ ghostjoin_icon()
+ GLOB.active_ghost_pods += src
add_verb(src, /mob/living/proc/ventcrawl)
add_verb(src, /mob/living/proc/hide)
@@ -201,6 +215,22 @@
emote_hear = list("squeeks","squeaks","squiks")
emote_see = list("runs in a circle", "shakes", "scritches at something")
+/mob/living/simple_mob/animal/passive/mouse/verb/set_mouse_colour()
+ set name = "Set Mouse Colour"
+ set category = "Abilities.Mouse"
+ set desc = "Set the colour of your mouse."
+ var/new_mouse_colour = tgui_input_list(usr, "Set Mouse Colour", "Pick a colour", list("brown","gray","white","black"))
+ if(!new_mouse_colour) return
+ icon_state = resting ? "mouse_[new_mouse_colour]_sleep" : "mouse_[new_mouse_colour]"
+ item_state = "mouse_[new_mouse_colour]"
+ icon_living = "mouse_[new_mouse_colour]"
+ icon_dead = "mouse_[new_mouse_colour]_dead"
+ icon_rest = "mouse_[new_mouse_colour]_sleep"
+ desc = "A small [new_mouse_colour] rodent, often seen hiding in maintenance areas and making a nuisance of itself."
+ holder_type = text2path("/obj/item/holder/mouse/[new_mouse_colour]")
+ to_chat(src, span_notice("You are now a [new_mouse_colour] mouse!"))
+ remove_verb(src,/mob/living/simple_mob/animal/passive/mouse/verb/set_mouse_colour)
+
/mob/living/simple_mob/animal/passive/mouse/white/virology
name = "Fleming"
desc = "A small white rodent, often found in Virology. This one isn't quite the nuisance!"
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/passive/mouse_mutant_event.dm b/code/modules/mob/living/simple_mob/subtypes/animal/passive/mouse_mutant_event.dm
new file mode 100644
index 0000000000..08ba188e2b
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/passive/mouse_mutant_event.dm
@@ -0,0 +1,29 @@
+/mob/living/simple_mob/animal/passive/mouse/event
+ desc = "This one looks like it is growing huge!"
+ var/amount_grown = 0
+
+/mob/living/simple_mob/animal/passive/mouse/event/Life()
+ . = ..()
+ if(amount_grown >= 0)
+ amount_grown += rand(0,4)
+ if(amount_grown >= 100 && icon_state != icon_dead)
+ rat()
+ return
+
+/mob/living/simple_mob/animal/passive/mouse/event/proc/rat()
+ var/mob/bigger = null
+ if(prob(99.5))
+ bigger = new /mob/living/simple_mob/vore/aggressive/rat/event(get_turf(src))
+ else
+ bigger = new /mob/living/simple_mob/vore/aggressive/chungus(get_turf(src))
+
+ if(istype(loc,/obj/belly))
+ var/obj/belly/B = loc
+ B.owner.visible_message(span_boldwarning("Something grows inside [B.owner]'s [lowertext(B.name)]!"))
+ to_chat(B.owner, span_warning("\The [src] suddenly evolves inside your [lowertext(B.name)]!"))
+ B.release_specific_contents(src, TRUE)
+ B.nom_mob(bigger, null)
+ qdel(src)
+ else
+ visible_message(span_warning("\The [src] suddenly evolves!"))
+ qdel(src)
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/passive/mouse_vr.dm b/code/modules/mob/living/simple_mob/subtypes/animal/passive/mouse_vr.dm
index 25fa2dc865..9cfe40f2e0 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/passive/mouse_vr.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/passive/mouse_vr.dm
@@ -65,3 +65,34 @@
if(isanimal(L))
var/mob/living/simple_mob/S = L
user.visible_message(span_notice("[user] [S.response_help] \the [S]."))
+
+/mob/living/simple_mob/animal/passive/mouse/mining
+ body_color = "brown"
+ icon = 'icons/mob/animal.dmi'
+ icon_state = "mouse_miner"
+ item_state = "mouse_miner"
+ icon_living = "mouse_miner"
+ name = "Cooper"
+ desc = "A lonely miner's best friend."
+
+/mob/living/simple_mob/animal/passive/mouse/mining/Initialize(mapload)
+ . = ..()
+
+ add_verb(src,/mob/living/proc/ventcrawl)
+ add_verb(src,/mob/living/proc/hide)
+ icon_state = "mouse_miner"
+ item_state = "mouse_miner"
+ icon_living = "mouse_miner"
+ icon_dead = "mouse_miner_dead"
+ icon_rest = "mouse_miner_sleep"
+ desc = "A lonely miner's best friend."
+
+
+/mob/living/simple_mob/animal/passive/mouse/mining/splat()
+ src.health = 0
+ src.set_stat(DEAD)
+ src.icon_dead = "mouse_miner_splat"
+ src.icon_state = "mouse_miner_splat"
+ layer = MOB_LAYER
+ if(client)
+ client.time_died_as_mouse = world.time
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/pets/dog.dm b/code/modules/mob/living/simple_mob/subtypes/animal/pets/dog.dm
index 4b94b39de1..96672965d0 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/pets/dog.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/pets/dog.dm
@@ -113,6 +113,11 @@
name = "Bockscar"
real_name = "Bockscar"
+/mob/living/simple_mob/animal/passive/dog/corgi/puppy/wiggle
+ name = "Mister Wiggles"
+ real_name = "Mister Wiggles"
+ desc = "An emotional support corgi! He gets along with everyone, even Runtime."
+
//IAN! SQUEEEEEEEEE~
/mob/living/simple_mob/animal/passive/dog/corgi/Ian
name = "Ian"
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/frostfly.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/frostfly.dm
index 981b5967f7..d38976d53e 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/frostfly.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/frostfly.dm
@@ -29,10 +29,12 @@
icon_rest = "firefly_dead"
icon = 'icons/mob/animal.dmi'
has_eye_glow = TRUE
+ heat_resist = -0.50
+ cold_resist = 0.75
maxHealth = 65
health = 65
-
+ minbodytemp = 175
pass_flags = PASSTABLE
var/energy = 100
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/hare.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/hare.dm
index ca8d908412..d35b44a7c8 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/hare.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/hare.dm
@@ -65,6 +65,8 @@
say_list_type = /datum/say_list/hare
+ can_be_drop_prey = TRUE
+
/datum/say_list/hare
speak = list("Snrf...","Crk!")
emote_hear = list("crackles","sniffles")
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/kururak.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/kururak.dm
index 55e610e490..f930b29e92 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/kururak.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/kururak.dm
@@ -33,7 +33,7 @@
default_pixel_x = -16
pixel_x = -16
-
+ minbodytemp = 175
maxHealth = 200
health = 200
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/leech.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/leech.dm
index 4a117d683f..b2796040d1 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/leech.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/leech.dm
@@ -33,7 +33,7 @@
status_flags = CANPUSH
pass_flags = PASSTABLE
-
+ minbodytemp = 175
maxHealth = 100
health = 100
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/racoon.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/racoon.dm
index 9594519f26..672f6f6851 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/racoon.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/racoon.dm
@@ -29,7 +29,7 @@
health = 50
has_hands = TRUE
humanoid_hands = TRUE
-
+ minbodytemp = 175
pass_flags = PASSTABLE
universal_understand = 1
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/savik.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/savik.dm
index 934dfebb48..797262d82f 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/savik.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/savik.dm
@@ -30,9 +30,10 @@
maxHealth = 125
health = 125
-
+ minbodytemp = 175
movement_cooldown = -1
-
+ heat_resist = -0.50
+ cold_resist = 0.75
melee_damage_lower = 15
melee_damage_upper = 35
attack_armor_pen = 15
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/shantak.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/shantak.dm
index d02178ddd0..4fd11d892e 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/shantak.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/shantak.dm
@@ -42,9 +42,10 @@
"bio" = 0,
"rad" = 0
)
-
+ heat_resist = -0.50
+ cold_resist = 0.75
movement_cooldown = -1
-
+ minbodytemp = 175
melee_damage_lower = 6
melee_damage_upper = 14
base_attack_cooldown = 1 SECOND
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/sif.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/sif.dm
index 970365d457..bc7123653e 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/sif.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/sif.dm
@@ -9,3 +9,5 @@
/obj/item/reagent_containers/food/snacks/crabmeat = 20,
/obj/item/reagent_containers/food/snacks/meat = 10
)
+
+ can_be_drop_prey = FALSE
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/sif/siffet.dm b/code/modules/mob/living/simple_mob/subtypes/animal/sif/siffet.dm
index b49d86947f..1d45aaa4f4 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/sif/siffet.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/sif/siffet.dm
@@ -57,5 +57,8 @@
/mob/living/simple_mob/animal/sif/siffet/IIsAlly(mob/living/L)
. = ..()
- if(!. && L.mob_size > 10) //Attacks things it considers small enough to take on, otherwise only attacks if attacked.
+ if(!. && !istype(L, /mob/living))
return TRUE
+ else
+ if(!. && L.mob_size > 10) //Attacks things it considers small enough to take on, otherwise only attacks if attacked.
+ return TRUE
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/alien.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/alien.dm
index cbd4033456..bc0d04ad16 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/space/alien.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/alien.dm
@@ -33,6 +33,8 @@
meat_type = /obj/item/reagent_containers/food/snacks/xenomeat
meat_amount = 5
+ can_be_drop_prey = FALSE
+
/mob/living/simple_mob/animal/space/alien/drone
name = "alien drone"
icon_state = "aliend_running"
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/bats.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/bats.dm
index d3256a6c56..610664af4a 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/space/bats.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/bats.dm
@@ -39,6 +39,8 @@
var/scare_chance = 15
+ can_be_drop_prey = FALSE
+
/mob/living/simple_mob/animal/space/bats/apply_melee_effects(var/atom/A)
if(isliving(A))
var/mob/living/L = A
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/bear.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/bear.dm
index d2b1466df0..9674d4230b 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/space/bear.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/bear.dm
@@ -27,6 +27,7 @@
say_list_type = /datum/say_list/bear
+ can_be_drop_prey = FALSE
allow_mind_transfer = TRUE
/datum/say_list/bear
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/carp.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/carp.dm
index e8abc88d9d..3bccc69cc3 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/space/carp.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/carp.dm
@@ -43,7 +43,7 @@
density = FALSE
vore_active = TRUE
- vore_icons = SA_ICON_LIVING
+ vore_icons = 0
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "hits"
@@ -86,6 +86,7 @@
var/static/list/carp_colors_rare = list(\
"silver" = "#fdfbf3", \
)
+ can_be_drop_prey = FALSE
/mob/living/simple_mob/animal/space/carp/Initialize(mapload)
. = ..()
@@ -147,9 +148,47 @@
if(isliving(A))
var/mob/living/L = A
if(prob(knockdown_chance))
- L.Weaken(3)
+ L.add_modifier(/datum/modifier/entangled, 4 SECONDS) // replacing weaken/slowdown with slow down
L.visible_message(span_danger("\The [src] knocks down \the [L]!"))
+/mob/living/simple_mob/animal/space/carp/load_default_bellies()
+ . = ..()
+ var/obj/belly/B = vore_selected
+ B.name = "Stomach"
+ B.desc = "The toothy jaws of the space carp gnash down around your body while its throat opens up to suck you inside. The vicious attack is too swift for you to stop it. You're dragged down its short esophagus, then dumped into its muscular digestive system. Your body curls tight in the cramped confines of its slimy stomach; pushing aside a caustic mixture of other unrecognizable detritus. You realize the soupy chime consists of past explorers who went missing long ago. If you can't push your way back up to freedom, your fate will be the same."
+ B.mode_flags = DM_FLAG_THICKBELLY
+ B.digest_brute = 0.5
+ B.digest_burn = 0.5
+ B.escapechance = 20
+ B.belly_fullscreen = "anim_belly"
+ B.belly_fullscreen_color = "#660021"
+ B.belly_fullscreen_color2 = "#660021"
+ B.fancy_vore = 1
+
+ B.emote_lists[DM_DIGEST] = list(
+ "They say a space carp's belly can digest almost anything. You're going to find out first hand if you stay here for much longer.",
+ "The gastric fluids sizzle ferociously as they ooze across your form.",
+ "A possessive squeeze of the wrinkled walls forces you to scrunch against yourself, as if to say you're not even a bother. This powerful digestive system has processed far more hazardous prey than you.",
+ "The rubbery flesh of the carp's stomach lining constantly pulverizes you from all sides.",
+ "Slowly but surely, everything around you is digested. Organic or not, it's all nourishment to the carp.",
+ "The carp's disgusting innards slowly mix you around with acid. As far as it's concerned, you're nothing but fish food now.",
+ "The stomach walls of the fishy predator push against you from all sides, smushing you into the leftovers of the last adventurer to wind up here.",
+ "The carp's belly gushes over you with slow, muscular compressions. Every passing second allows more acid to be rubbed against you."
+ )
+
+ B.struggle_messages_inside = list(
+ "You jab with all your strength to free yourself from the carp's putrid gut.",
+ "The carp's belly bounces at your thrashing while the creature hunts its next meal.",
+ "You push and pry at the stomach sphincter, trying to force your way out.",
+ "You shove against the back of the carp's stomach for leverage as you try forcing your head up its throat.",
+ "You try to wriggle yourself out of the carp's belly before it grinds you into chum.",
+ "Your feisty squirming is rewarded with a tight CLENCH from all sides. The carp stubbornly reminds you that it has eaten far worse."
+ )
+
+ B.struggle_messages_outside = list(
+ "%pred's stomach lurches with movement beneath its underbelly scales. Someone is alive in there!"
+ )
+
// Subtypes.
// Won't wander away.
@@ -164,7 +203,6 @@
icon_state = "shark"
icon_living = "shark"
icon_dead = "shark_dead"
- vore_icons = FALSE
maxHealth = 50
health = 50
@@ -182,11 +220,11 @@
/mob/living/simple_mob/animal/space/carp/large/huge
name = "great white carp"
desc = "A very rare breed of carp- and a very aggressive one."
- icon = 'icons/mob/64x64.dmi'
+ icon = 'icons/mob/vore64x64.dmi'
icon_dead = "megacarp_dead"
icon_living = "megacarp"
icon_state = "megacarp"
- vore_icons = FALSE
+ vore_icons = SA_ICON_LIVING
maxHealth = 230
health = 230
@@ -207,10 +245,6 @@
/mob/living/simple_mob/animal/space/carp/large/huge/vorny
name = "great white carp"
desc = "A very rare breed of carp- and a very hungry one."
- icon = 'icons/mob/64x64.dmi'
- icon_dead = "megacarp_dead"
- icon_living = "megacarp"
- icon_state = "megacarp"
maxHealth = 230
health = 230
@@ -235,7 +269,6 @@
B.name = "stomach"
B.desc = "You've been swallowed whole and alive by a massive white carp! The stomach around you is oppressively tight, squeezing and grinding wrinkled walls across your body, making it hard to make any movement at all. The chamber is flooded with fluids that completely overwhelm you."
B.mode_flags = DM_FLAG_THICKBELLY
- B.belly_fullscreen = "yet_another_tumby"
B.digest_brute = 2
B.digest_burn = 2
B.digest_oxy = 1
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/clockwork.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/clockwork.dm
new file mode 100644
index 0000000000..843ec987df
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/clockwork.dm
@@ -0,0 +1,123 @@
+//Code for chaplains pet.
+/mob/living/simple_mob/clockwork
+ name = "Clockwork Marauder"
+ desc = "The stalwart apparition of a clockwork flame guardian. It's eternal flame glows a firey-red."
+ tt_desc = "Aeterna flamma armis"
+ icon = 'icons/mob/clockwork_mobs.dmi'
+ icon_state = "clockwork_marauder_r"
+ item_state = "clockwork_marauder_r"
+ icon_living = "clockwork_marauder_r"
+ icon_dead = "fallen_armor"
+ icon_rest = "clockwork_marauder_r"
+
+ movement_cooldown = 0.5 SECONDS
+
+ see_in_dark = 6 // Not sure if this actually works.
+
+
+ response_help = "pats"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+
+ min_oxy = 16 //Require atleast 16kPA oxygen
+ minbodytemp = 223 //Below -50 Degrees Celcius
+ maxbodytemp = 323 //Above 50 Degrees Celcius
+
+ has_langs = list("Occursus")
+/* speak_chance = 1
+ speak = list("Heretics!","Burn them!","Protect believers!","Hail Helios")
+ speak_emote = list("crackles", "burns")
+ emote_hear = list("crackles","burns")
+ emote_see = list("twists their sword", "adjusts their shield")
+ say_maybe_target = list("Who?","Strange.")
+ say_got_target = list("Purge!","Cleanse!","Burn!") */
+
+ meat_amount = 0
+ meat_type = /obj/item/reagent_containers/food/snacks/meat
+
+ var/turns_since_scan = 0
+ var/mob/flee_target
+
+ can_be_drop_prey = FALSE
+
+/mob/living/simple_mob/clockwork/handle_special()
+ if(!stat && prob(2)) // spooky
+ var/mob/observer/dead/spook = locate() in range(src, 5)
+ if(spook)
+ var/turf/T = get_turf(spook)
+ var/list/visible = list()
+ for(var/obj/O in T.contents)
+ if(!O.invisibility && O.name)
+ visible += O
+ if(visible.len)
+ var/atom/A = pick(visible)
+ visible_emote("suddenly stops and stares at something unseen[istype(A) ? " near [A]":""].")
+
+
+
+//Basic friend AI
+/*/mob/living/simple_animal/clockwork/fluff
+ var/mob/living/carbon/human/friend
+ var/befriend_job = null
+
+/mob/living/simple_animal/clockwork/fluff/Life()
+ . = ..()
+ if(!. || ai_inactive || !friend) return
+
+ var/friend_dist = get_dist(src,friend)
+
+ if (friend_dist <= 4)
+ if(stance == STANCE_IDLE)
+ if(set_follow(friend))
+ handle_stance(STANCE_FOLLOW)
+
+ if (friend_dist <= 1)
+ if (friend.stat >= DEAD || friend.health <= config.health_threshold_softcrit)
+ if (prob((friend.stat < DEAD)? 50 : 15))
+ var/verb = pick("meows", "mews", "mrowls")
+ audible_emote(pick("[verb] in distress.", "[verb] anxiously."))
+ else
+ if (prob(5))
+ visible_emote(pick("nuzzles [friend].",
+ "brushes against [friend].",
+ "rubs against [friend].",
+ "purrs."))
+ else if (friend.health <= 50)
+ if (prob(10))
+ var/verb = pick("meows", "mews", "mrowls")
+ audible_emote("[verb] anxiously.")
+
+/mob/living/simple_animal/cat/fluff/verb/become_friends()
+ set name = "Become Friends"
+ set category = "Abilities.General
+ set src in view(1)
+
+ if(!friend)
+ var/mob/living/carbon/human/H = usr
+ if(istype(H) && (!befriend_job || H.job == befriend_job))
+ friend = usr
+ . = 1
+ else if(usr == friend)
+ . = 1 //already friends, but show success anyways
+
+ if(.)
+ set_dir(get_dir(src, friend))
+ visible_emote(pick("nuzzles [friend].",
+ "brushes against [friend].",
+ "rubs against [friend].",
+ "purrs."))
+ else
+ usr << span_notice("[src] ignores you.")
+ return */
+
+/mob/living/simple_mob/clockwork/fluff/Ignis
+ name = "Ignis"
+ desc = "The stalwart apparition of a clockwork flame guardian. This one appears to be to be have been somehow modified to be 'docile', it's living fire turned blue."
+// tt_desc = "Aeterna flamma armis" //Chaplains new pet!
+ icon = 'icons/mob/clockwork_mobs.dmi'
+ icon_state = "ignis"
+ item_state = "ignis"
+// icon_living = "ignis"
+// icon_dead = "fallen_armor"
+// icon_rest = "ignis"
+// retaliate = 1 // In theory this will make Ignis fight back. Maybe. -RF
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/gaslamp_vr.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/gaslamp_vr.dm
index d8c989d2ca..50870b6e94 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/space/gaslamp_vr.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/gaslamp_vr.dm
@@ -109,3 +109,41 @@ TODO: Make them light up and heat the air when exposed to oxygen.
"Light occasionally filters down through the gaslamp’s various membranes, but it is becoming hard to notice, your eyelids feeling leaden, weighed down as the looming creature comes ever closer to claiming you!",
"The gaslamp’s rhythmically undulating innards abruptly squish and massage down into your curled-up body, each squeeze bringing another brief increase to the heat already sinking deep into you... making it harder to tell where you end, and it begins!",
"Every moment longer spent trapped within the gaslamp drains evermore energy out of you, squelching away your will to resist its possessive advances… and as its innards force submission into you, the swell you make visibly softens away!")
+
+/mob/living/simple_mob/animal/passive/gaslamp/snow //Frostlamnp
+ name = "Frostlit Lamp"
+ desc = "Some sort of floaty alien with a surprisingly warm glow. This creature is looks like an evolutionary offshute of the Gaslamp family."
+ tt_desc = "Semaeostomeae virginus"
+ icon = 'icons/mob/vore32x64.dmi'
+ icon_state = "gaslamp_snow"
+ icon_living = "gaslamp_snow"
+ icon_dead = "gaslamp_snow-dead"
+
+ faction = "virgo3b"
+ maxHealth = 100
+ health = 100
+ movement_cooldown = 12
+
+ say_list_type = /datum/say_list/gaslamp
+ ai_holder_type = /datum/ai_holder/simple_mob/gaslamp
+
+ melee_damage_lower = 5
+ melee_damage_upper = 10
+ attacktext = list("thrashed")
+ friendly = "caressed"
+
+ response_help = "brushes" // If clicked on help intent
+ response_disarm = "pushes" // If clicked on disarm intent
+ response_harm = "swats" // If clicked on harm intent
+
+ minbodytemp = 0
+ maxbodytemp = 350
+
+ min_oxy = 1 //Needs Oxy to survive on cryogaia
+ max_oxy = 0 // Hopefully no Max oxy
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/goose.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/goose.dm
index e6b642b6d8..c43370ca57 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/space/goose.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/goose.dm
@@ -28,6 +28,8 @@
meat_type = /obj/item/reagent_containers/food/snacks/meat/chicken
meat_amount = 3
+ can_be_drop_prey = FALSE
+
/datum/say_list/goose
speak = list("HONK!")
emote_hear = list("honks loudly!")
@@ -56,3 +58,27 @@
icon_dead = "whitegoose_dead"
name = "white goose"
desc = "And just when you thought it was a lovely day..."
+
+/mob/living/simple_mob/animal/space/goose/domesticated
+ name = "domesticated goose"
+ desc = "It's a domesticated goose. It still looks pretty angry."
+ faction = "neutral" //Mess with this and the goose will eat anyones face, will eat other factions faces, appropiate considering its a hellbird - Jack
+
+ can_be_drop_prey = TRUE
+
+/mob/living/simple_mob/animal/space/goose/domesticated/casino
+ name = "Donella"
+ desc = "It's a golden goose named Donella, she is a beloved treasure of the golden goose casino, nobody knows where she comes from."
+ icon_state = "golden_goose"
+ icon_living = "golden_goose"
+ icon_dead = "golden_goose_dead"
+ icon = 'icons/mob/animal.dmi'
+
+ faction = "neutral" //Mess with this and the goose will eat anyones face, will eat other factions faces, appropiate considering its a hellbird - Jack
+
+ maxHealth = 75
+ health = 75
+
+ harm_intent_damage = 10
+ melee_damage_lower = 10
+ melee_damage_upper = 10
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/mouse_army.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/mouse_army.dm
new file mode 100644
index 0000000000..8add800d27
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/mouse_army.dm
@@ -0,0 +1,467 @@
+/mob/living/simple_mob/animal/space/mouse_army
+ name = "mouse"
+ real_name = "mouse"
+ desc = "It's a small militarized rodent."
+ tt_desc = "E Mus musculus"
+ icon = 'icons/mob/mouse_army.dmi'
+ icon_state = "mouse_gray"
+ item_state = "mouse_gray"
+ icon_living = "mouse_gray"
+ icon_dead = "mouse_gray_dead"
+ icon_rest = "mouse_gray_sleep"
+ faction = "mouse_army"
+
+ maxHealth = 50
+ health = 50
+ universal_understand = 1
+
+ taser_kill = 0
+
+ mob_size = MOB_MINISCULE
+ pass_flags = PASSTABLE
+// can_pull_size = ITEMSIZE_TINY
+// can_pull_mobs = MOB_PULL_NONE
+ layer = MOB_LAYER
+ density = 0
+
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "stamps on"
+
+ min_oxy = 0 //Require atleast 16kPA oxygen
+ minbodytemp = 0 //Below -50 Degrees Celcius
+ maxbodytemp = 5000 //Above 50 Degrees Celcius
+
+ //Mob melee settings
+ melee_damage_lower = 5
+ melee_damage_upper = 15
+ attacktext = list("attacked", "chomped", "gnawed on")
+ friendly = list("baps", "nuzzles")
+ attack_armor_type = "melee"
+ attack_sharp = 1
+ attack_edge = 1
+
+ //Damage resistances
+ shock_resist = 1
+ armor = list(
+ "melee" = 30,
+ "bullet" = 20,
+ "laser" = 20,
+ "energy" = 10,
+ "bomb" = 10,
+ "bio" = 0,
+ "rad" = 0) //Standard armor vest stats, slightly dropped due to scale.
+
+ has_langs = list("Mouse")
+
+ holder_type = /obj/item/holder/mouse
+ meat_type = /obj/item/reagent_containers/food/snacks/meat
+
+ say_list_type = /datum/say_list/mouse
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive
+
+ var/rank //pyro, operative, ammo, stealth. more to come. Do not leave blank.
+
+ can_be_drop_prey = FALSE
+ species_sounds = "Mouse"
+ pain_emote_1p = list("squeak", "squik")
+ pain_emote_1p = list("squeaks", "squiks")
+
+/mob/living/simple_mob/animal/space/mouse_army/Initialize(mapload)
+ . = ..()
+
+ add_verb(src,/mob/living/proc/ventcrawl)
+ add_verb(src,/mob/living/proc/hide)
+
+ if(name == initial(name))
+ name = "[name] ([rand(1, 1000)])"
+ real_name = name
+
+ if(!rank)
+ rank = pick( list("operative","pyro", "ammo", "stealth") )
+ icon_state = "mouse_[rank]"
+ item_state = "mouse_[rank]"
+ icon_living = "mouse_[rank]"
+ icon_dead = "mouse_[rank]_dead"
+ icon_rest = "mouse_[rank]_sleep"
+
+/mob/living/simple_mob/animal/space/mouse_army/Crossed(AM as mob|obj)
+ var/mob/SK = AM
+ if(SK.is_incorporeal())
+ return
+ if( ishuman(AM) )
+ if(!stat)
+ var/mob/M = AM
+ M.visible_message(span_blue("[icon2html(src,viewers(M))] Squeek!"))
+ playsound(src, 'sound/effects/mouse_squeak.ogg', 35, 1)
+ ..()
+
+/mob/living/simple_mob/animal/space/mouse_army/death()
+ layer = MOB_LAYER
+ playsound(src, 'sound/effects/mouse_squeak_loud.ogg', 35, 1)
+ if(client)
+ client.time_died_as_mouse = world.time
+ ..()
+
+/mob/living/simple_mob/animal/space/mouse_army/cannot_use_vents()
+ return
+
+/mob/living/simple_mob/animal/space/mouse_army/proc/splat()
+ src.health = 0
+ src.stat = DEAD
+ src.icon_dead = "mouse_[rank]_splat"
+ src.icon_state = "mouse_[rank]_splat"
+ layer = MOB_LAYER
+ if(client)
+ client.time_died_as_mouse = world.time
+
+//Base ported from vgstation. Operative Mice.
+//Icon artists: DeityLink and plosky1
+/mob/living/simple_mob/animal/space/mouse_army/operative
+ name = "operative mouse"
+ desc = "Where did it get that? Oh no..."
+ tt_desc = "E Mus sinister"
+ rank = "operative"
+
+ shock_resist = 1
+ armor = list(
+ "melee" = 40,
+ "bullet" = 40,
+ "laser" = 30,
+ "energy" = 15,
+ "bomb" = 35,
+ "bio" = 100,
+ "rad" = 100) //Mercenary Voidsuit Resistances, slightly downscaled, due to size.
+
+//Pyro Mouse
+/mob/living/simple_mob/animal/space/mouse_army/pyro
+ name = "pyro mouse"
+ desc = "What kind of madman would strap this to a mouse?"
+ tt_desc = "E Mus phlogiston"
+ rank = "pyro"
+
+ maxHealth = 30
+ health = 30
+
+ //Mob melee settings
+ melee_damage_lower = 5
+ melee_damage_upper = 10
+ attack_sharp = 0
+ attack_edge = 0
+
+ //Damage resistances
+ shock_resist = 0.6
+ armor = list(
+ "melee" = 20,
+ "bullet" = 20,
+ "laser" = 20,
+ "energy" = 20,
+ "bomb" = 90,
+ "bio" = 100,
+ "rad" = 100)
+
+ projectiletype = /obj/item/projectile/bullet/incendiary/flamethrower
+ base_attack_cooldown = 10
+
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged
+ var/ruptured = 0
+
+/mob/living/simple_mob/animal/space/mouse_army/pyro/death()
+ visible_message(span_critical("\The [src]'s tank groans!"))
+ var/delay = rand(1, 3)
+ spawn(0)
+ // Flash black and red as a warning.
+ for(var/i = 1 to delay)
+ if(i % 2 == 0)
+ color = "#000000"
+ else
+ color = "#FF0000"
+ sleep(1)
+
+ spawn(rand (1,5))
+ if(!ruptured)
+ visible_message(span_critical("\The [src]'s tank ruptures!"))
+ ruptured = 1
+ adjust_fire_stacks(2)
+ IgniteMob()
+ return ..()
+
+//Ammo Mouse
+/mob/living/simple_mob/animal/space/mouse_army/ammo
+ name = "ammo mouse"
+ desc = "Aww! It's carrying a bunch of tiny bullets!"
+ tt_desc = "E Mus tela"
+ rank = "ammo"
+
+ maxHealth = 30
+ health = 30
+
+ //Mob melee settings
+ melee_damage_lower = 1
+ melee_damage_upper = 5
+ attack_sharp = 0
+ attack_edge = 0
+
+ //Damage resistances
+ shock_resist = 0.6
+ armor = list(
+ "melee" = 40,
+ "bullet" = 30,
+ "laser" = 10,
+ "energy" = 10,
+ "bomb" = 15,
+ "bio" = 100,
+ "rad" = 100)
+
+ var/exploded = FALSE
+ var/explosion_dev_range = 0
+ var/explosion_heavy_range = 0
+ var/explosion_light_range = 2
+ var/explosion_flash_range = 4 // This doesn't do anything iirc.
+
+ var/explosion_delay_lower = 1 SECOND // Lower bound for explosion delay.
+ var/explosion_delay_upper = 3 SECONDS // Upper bound.
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive
+
+/mob/living/simple_mob/animal/space/mouse_army/ammo/death()
+ visible_message(span_critical("\The [src]'s body begins to rupture!"))
+ var/delay = rand(explosion_delay_lower, explosion_delay_upper)
+ spawn(0)
+ // Flash black and red as a warning.
+ for(var/i = 1 to delay)
+ if(i % 2 == 0)
+ color = "#000000"
+ else
+ color = "#FF0000"
+ sleep(1)
+
+ spawn(rand(1,5))
+ if(src && !exploded)
+ visible_message(span_critical("\The [src]'s body detonates!"))
+ exploded = 1
+ explosion(src.loc, explosion_dev_range, explosion_heavy_range, explosion_light_range, explosion_flash_range)
+ qdel(src)
+ return ..()
+
+/mob/living/simple_mob/animal/space/mouse_army/stealth
+ name = "stealth mouse"
+ desc = "I bet you thought the normal ones were scary!"
+ tt_desc = "E Mus insidiis"
+ rank = "stealth"
+
+ //Mob melee settings
+ melee_damage_lower = 15
+ melee_damage_upper = 20
+ attack_sharp = 1
+ attack_edge = 1
+
+ //Damage resistances
+ shock_resist = 0.6
+ armor = list(
+ "melee" = 50,
+ "bullet" = 10,
+ "laser" = 10,
+ "energy" = 10,
+ "bomb" = 10,
+ "bio" = 100,
+ "rad" = 100)
+
+ player_msg = "You have an imperfect, but automatic stealth. If you attack something while 'hidden', then \
+ you will do bonus damage, stun the target, and unstealth for a period of time.
\
+ Getting attacked will also break your stealth."
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/hit_and_run
+
+ var/cloaked_alpha = 45
+ var/cloaked_bonus_damage = 20
+ var/cloaked_weaken_amount = 3
+ var/cloak_cooldown = 10 SECONDS
+ var/last_uncloak = 0
+
+
+/mob/living/simple_mob/animal/space/mouse_army/stealth/proc/can_cloak()
+ if(stat)
+ return FALSE
+ if(last_uncloak + cloak_cooldown > world.time)
+ return FALSE
+
+ return TRUE
+
+/mob/living/simple_mob/animal/space/mouse_army/stealth/uncloak()
+ last_uncloak = world.time
+ if(!cloaked)
+ return
+ animate(src, alpha = initial(alpha), time = 1 SECOND)
+ cloaked = FALSE
+
+/mob/living/simple_mob/animal/space/mouse_army/stealth/break_cloak()
+ uncloak()
+
+
+/mob/living/simple_mob/animal/space/mouse_army/stealth/is_cloaked()
+ return cloaked
+
+/mob/living/simple_mob/animal/space/mouse_army/stealth/handle_special()
+ if(!cloaked && can_cloak())
+ cloak()
+
+/mob/living/simple_mob/animal/space/mouse_army/stealth/apply_bonus_melee_damage(atom/A, damage_amount)
+ if(cloaked)
+ return damage_amount + cloaked_bonus_damage
+ return ..()
+
+/mob/living/simple_mob/animal/space/mouse_army/stealth/apply_melee_effects(atom/A)
+ if(cloaked)
+ if(isliving(A))
+ var/mob/living/L = A
+ L.Weaken(cloaked_weaken_amount)
+ to_chat(L, span_danger("\The [src] ambushes you!"))
+ playsound(L, 'sound/weapons/spiderlunge.ogg', 75, 1)
+ uncloak()
+ ..()
+
+/mob/living/simple_mob/animal/space/mouse_army/stealth/bullet_act(obj/item/projectile/P)
+ . = ..()
+ break_cloak()
+
+/mob/living/simple_mob/animal/space/mouse_army/stealth/hit_with_weapon(obj/item/O, mob/living/user, effective_force, hit_zone)
+ . = ..()
+ break_cloak()
+
+
+// Mouse noises
+/datum/say_list/mouse
+ speak = list("Squeek!","SQUEEK!","Squeek?")
+ emote_hear = list("squeeks","squeaks","squiks")
+ emote_see = list("runs in a circle", "shakes", "scritches at something")
+
+
+
+
+
+////////////////////
+// Mouse Tanks
+////////////////////
+
+// Tiny mecha.
+// Designed for ranged attacks.
+
+/datum/category_item/catalogue/technology/mouse_tank
+ name = "Whisker Tank"
+ desc = "Unofficially dubbed the 'Whisker Tank', this micro mecha is not unfamiliar \
+ in several neighboring sectors. Known for its speed and small size, theories \
+ on the origin of these devices cover a wide array of probabilities. The general \
+ consensus is that these tanks were designed as weapons of sabotage that never saw wide\
+ deployment. Since that theoretical time, others may have discovered and modified this \
+ technology for their own twisted ends."
+ value = CATALOGUER_REWARD_EASY
+
+
+/mob/living/simple_mob/mechanical/mecha/mouse_tank
+ name = "\improper Whisker Tank"
+ desc = "A shockingly functional, miniaturized tank. Its inventor is unknown, but widely reviled."
+ catalogue_data = list(/datum/category_item/catalogue/technology/mouse_tank)
+ icon = 'icons/mob/mouse_army.dmi'
+ icon_state = "whisker"
+ wreckage = /obj/structure/loot_pile/mecha/mouse_tank
+ faction = "mouse_army"
+
+ maxHealth = 150
+ armor = list(
+ "melee" = 25,
+ "bullet" = 20,
+ "laser" = 30,
+ "energy" = 15,
+ "bomb" = 0,
+ "bio" = 100,
+ "rad" = 100
+ )
+
+ projectiletype = /obj/item/projectile/bullet/pistol/medium
+
+ movement_cooldown = 2
+ base_attack_cooldown = 8
+
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged/kiting
+
+/mob/living/simple_mob/mechanical/mecha/mouse_tank/manned
+ pilot_type = /mob/living/simple_mob/animal/space/mouse_army/operative
+
+// Immune to heat damage, resistant to lasers, and it spits fire.
+/datum/category_item/catalogue/technology/mouse_tank/livewire
+ name = "Livewire Assault Tank"
+ desc = "Dubbed the 'Livewire Assault Tank', this pattern of the 'standard' Whisker \
+ tank has been condemned by multiple governments and corporations due to the \
+ infamous brutality of its armaments. The utilization of this kind of technology would \
+ spark a major scandal if its origins could ever be proven."
+ value = CATALOGUER_REWARD_EASY
+
+
+/mob/living/simple_mob/mechanical/mecha/mouse_tank/livewire
+ name = "\improper Livewire Assault Tank"
+ desc = "A scorched, miniaturized light tank. It is mentioned only in hushed whispers."
+ catalogue_data = list(/datum/category_item/catalogue/technology/mouse_tank/livewire)
+ icon_state = "livewire"
+ wreckage = /obj/structure/loot_pile/mecha/mouse_tank/livewire
+
+ maxHealth = 200
+ heat_resist = 1
+ armor = list(
+ "melee" = 0,
+ "bullet" = 20,
+ "laser" = 50,
+ "energy" = 0,
+ "bomb" = 50,
+ "bio" = 100,
+ "rad" = 100
+ )
+
+ projectiletype = /obj/item/projectile/bullet/incendiary/dragonflame
+
+ movement_cooldown = 3
+ base_attack_cooldown = 15
+
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged/kiting
+
+/mob/living/simple_mob/mechanical/mecha/mouse_tank/livewire/manned
+ pilot_type = /mob/living/simple_mob/animal/space/mouse_army/pyro
+
+//Rockets? Rockets.
+/datum/category_item/catalogue/technology/mouse_tank/eraticator
+ name = "Eraticator Artillery Platform"
+ desc = "Rare and fearsome weapons platforms, 'Eraticators', as they have come to be \
+ known, are frighteningly powerful long ranged tanks built entirely around exotic \
+ gyrojet technology. The raw cost and specialized nature of its design makes it a rare \
+ but formidable foe. It is often accompanied by mechanized reinforcements."
+ value = CATALOGUER_REWARD_EASY
+
+/mob/living/simple_mob/mechanical/mecha/mouse_tank/eraticator
+ name = "\improper Eraticator Artillery Platform"
+ desc = "A heavy, miniaturized artillery platform. If you can hear it squeaking, you're too close."
+ catalogue_data = list(/datum/category_item/catalogue/technology/mouse_tank/eraticator)
+ icon_state = "eraticator"
+ wreckage = /obj/structure/loot_pile/mecha/mouse_tank/eraticator
+
+ maxHealth = 300
+ heat_resist = 1
+ armor = list(
+ "melee" = 20,
+ "bullet" = 50,
+ "laser" = 50,
+ "energy" = 20,
+ "bomb" = 80,
+ "bio" = 100,
+ "rad" = 100
+ )
+
+ projectiletype = /obj/item/projectile/bullet/gyro
+
+ movement_cooldown = 5
+ base_attack_cooldown = 15
+
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged/kiting
+
+/mob/living/simple_mob/mechanical/mecha/mouse_tank/eraticator/manned
+ pilot_type = /mob/living/simple_mob/animal/space/mouse_army/ammo
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/ray.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/ray.dm
index 18e03d2a88..1a1b67cbba 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/space/ray.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/ray.dm
@@ -69,7 +69,7 @@
if(isliving(A))
var/mob/living/L = A
if(prob(knockdown_chance))
- L.Weaken(4)
+ L.add_modifier(/datum/modifier/entangled, 4 SECONDS) // replacing weaken/slowdown with slow down
L.visible_message(span_danger("\The [src] buffets \the [L]!"))
src.ai_holder.remove_target()
L.visible_message(span_notice("\The [src] seems to lose interest in \the [L]..."))
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/shark.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/shark.dm
index a611bb9dec..2ed7bab887 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/space/shark.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/shark.dm
@@ -49,7 +49,7 @@
if(isliving(A))
var/mob/living/L = A
if(prob(knockdown_chance))
- L.Weaken(3)
+ L.add_modifier(/datum/modifier/entangled, 4 SECONDS) // replacing weaken/slowdown with slow down
L.visible_message(span_danger("\The [src] knocks down \the [L]!"))
/mob/living/simple_mob/animal/space/shark/event
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/snake_vr.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/snake_vr.dm
index b0b1810ae2..389a4222c8 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/space/snake_vr.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/snake_vr.dm
@@ -23,9 +23,10 @@
tt_desc = "E Reptilia Serpentes"
catalogue_data = list(/datum/category_item/catalogue/fauna/snake)
- icon_state = "green"
- icon_living = "green"
- icon_dead = "green_dead"
+ icon_state = "snek"
+ icon_living = "snek"
+ icon_dead = "snek_dead"
+ icon_rest = "snek_rest"
icon = 'icons/mob/snake_vr.dmi'
maxHealth = 15
@@ -47,15 +48,11 @@
say_list_type = /datum/say_list/snake
ai_holder_type = /datum/ai_holder/simple_mob/passive
- icon_state = "python"
- icon_living = "python"
- icon_dead = "python_dead"
- icon = 'icons/mob/snake_vr.dmi'
vore_active = 1
vore_capacity = 1
vore_default_mode = DM_DIGEST
- // vore_icons = SA_ICON_LIVING | SA_ICON_REST // Woul require the downstream sprites
+ vore_icons = SA_ICON_LIVING | SA_ICON_REST
vore_escape_chance = 20
swallowTime = 50
vore_bump_chance = 10
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/worm.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/worm.dm
index bd7e0beab2..c3f04429c4 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/space/worm.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/worm.dm
@@ -59,6 +59,8 @@
var/maw_cooldown = 30 SECONDS
var/open_maw = FALSE // Are we trying to eat things?
+ can_be_drop_prey = FALSE
+
/mob/living/simple_mob/animal/space/space_worm/head
name = "space worm"
icon_state = "spacewormhead"
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/squirrel.dm b/code/modules/mob/living/simple_mob/subtypes/animal/squirrel.dm
index 727fd5c685..1f3593e913 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/squirrel.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/squirrel.dm
@@ -50,7 +50,7 @@
var/static/list/overlays_cache = list()
var/do_seasons = TRUE
- var/picked_color = FALSE
+ picked_color = FALSE
allow_mind_transfer = TRUE
@@ -75,7 +75,6 @@
B.name = "stomach"
B.digest_mode = DM_SELECT
B.mode_flags = DM_FLAG_THICKBELLY
- B.belly_fullscreen = "yet_another_tumby"
B.digest_brute = 1
B.digest_burn = 1
B.escapechance = 35
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/vox.dm b/code/modules/mob/living/simple_mob/subtypes/animal/vox.dm
new file mode 100644
index 0000000000..f9ac37507c
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/vox.dm
@@ -0,0 +1,170 @@
+/mob/living/simple_mob/vox
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 5
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 5
+ min_n2 = 0 //breathe N2
+ max_n2 = 0
+
+ species_sounds = "Vox"
+ pain_emote_1p = list("shriek")
+ pain_emote_3p = list("shrieks")
+
+/mob/living/simple_mob/vox/armalis
+ name = "serpentine alien"
+ real_name = "serpentine alien"
+ desc = "A one-eyed, serpentine creature, half-machine, easily nine feet from tail to beak!"
+ icon = 'icons/mob/vox.dmi'
+ icon_state = "armalis"
+ icon_living = "armalis"
+ maxHealth = 500
+ health = 500
+ response_harm = "slashes at the"
+ harm_intent_damage = 0
+ melee_damage_lower = 30
+ melee_damage_upper = 40
+ attacktext = "slammed its enormous claws into"
+ movement_cooldown = 2
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ status_flags = 0
+ max_oxy = 0
+
+ var/armour = null
+ var/amp = null
+ var/quills = 3
+
+/mob/living/simple_mob/vox/armalis/death(var/gibbed = FALSE)
+ ..(TRUE)
+ var/turf/gloc = get_turf(loc)
+ visible_message(span_bolddanger("[src] shudders violently and explodes!"),span_warning("You feel your body rupture!"))
+ gib()
+ explosion(gloc, -1, -1, 3, 5)
+ qdel(src)
+
+/mob/living/simple_mob/vox/armalis/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ base_attack_cooldown = 5
+ if(O.force)
+ if(O.force >= 25)
+ var/damage = O.force
+ if (O.damtype == HALLOSS)
+ damage = 0
+ health -= damage
+ for(var/mob/M in viewers(src, null))
+ if ((M.client && !( M.blinded )))
+ M.show_message(span_danger("[src] has been attacked with the [O] by [user]. "))
+ else
+ for(var/mob/M in viewers(src, null))
+ if ((M.client && !( M.blinded )))
+ M.show_message(span_danger("The [O] bounces harmlessly off of [src]. "))
+ else
+ to_chat(usr, span_warning("This weapon is ineffective, it does no damage."))
+ for(var/mob/M in viewers(src, null))
+ if ((M.client && !( M.blinded )))
+ M.show_message(span_warning("[user] gently taps [src] with the [O]. "))
+
+/mob/living/simple_mob/vox/armalis/verb/fire_quill(mob/target as mob in oview())
+
+
+ set name = "Fire quill"
+ set desc = "Fires a viciously pointed quill at a high speed."
+ set category = "Alien"
+
+ if(quills<=0)
+ return
+
+ to_chat(src, span_warning("You launch a razor-sharp quill at [target]!"))
+ for(var/mob/O in oviewers())
+ if ((O.client && !( O.blinded )))
+ to_chat(O, span_warning("[src] launches a razor-sharp quill at [target]!"))
+
+ var/obj/item/arrow/quill/Q = new(loc)
+ Q.add_fingerprint(ckey)
+ Q.throw_at(target,10,30)
+ quills--
+
+ spawn(100)
+ to_chat(src, span_warning("You feel a fresh quill slide into place."))
+ quills++
+
+/mob/living/simple_mob/vox/armalis/verb/message_mob()
+ set category = "Alien"
+ set name = "Commune with creature"
+ set desc = "Send a telepathic message to an unlucky recipient."
+
+ var/list/targets = list()
+ var/target = null
+ var/text = null
+
+ targets += getmobs() //Fill list, prompt user with list
+ target = tgui_input_list(src, "Select a creature!", "Speak to creature", targets)
+ text = tgui_input_text(src, "What would you like to say?", "Speak to creature")
+
+ if (!target || !text)
+ return
+
+ var/mob/M = targets[target]
+
+ if(istype(M, /mob/observer/dead) || M.stat == DEAD)
+ to_chat(src, "Not even the armalis can speak to the dead.")
+ return
+
+ to_chat(M, span_notice("Like lead slabs crashing into the ocean, alien thoughts drop into your mind: [text]"))
+ if(istype(M,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = M
+ if(H.species.name == "Vox")
+ return
+ to_chat(H, span_warning("Your nose begins to bleed..."))
+ H.drip(1)
+
+/mob/living/simple_mob/vox/armalis/verb/shriek()
+ set category = "Alien"
+ set name = "Shriek"
+ set desc = "Give voice to a psychic shriek."
+
+/mob/living/simple_mob/vox/armalis/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ if(istype(O,/obj/item/vox/armalis_armour))
+ user.drop_item(O)
+ armour = O
+ movement_cooldown = 4
+ maxHealth += 200
+ health += 200
+ visible_message(span_notice("[src] is quickly outfitted in [O] by [user]."),span_notice("You quickly outfit [src] in [O]."))
+ regenerate_icons()
+ return
+ if(istype(O,/obj/item/vox/armalis_amp))
+ user.drop_item(O)
+ amp = O
+ visible_message(span_notice("[src] is quickly outfitted in [O] by [user]."),span_notice("You quickly outfit [src] in [O]."))
+ regenerate_icons()
+ return
+ return ..()
+
+/mob/living/simple_mob/vox/armalis/regenerate_icons()
+ ..()
+ overlays = list()
+ if(armour)
+ var/icon/armour = image('icons/mob/vox.dmi',"armour")
+ movement_cooldown = 4
+ overlays += armour
+ if(amp)
+ var/icon/amp = image('icons/mob/vox.dmi',"amplifier")
+ overlays += amp
+ return
+
+/obj/item/vox/armalis_armour
+
+ name = "strange armour"
+ desc = "Hulking reinforced armour for something huge."
+ icon = 'icons/inventory/suit/item.dmi'
+ icon_state = "armalis_armour"
+ item_state = "armalis_armour"
+
+/obj/item/vox/armalis_amp
+
+ name = "strange lenses"
+ desc = "A series of metallic lenses and chains."
+ icon = 'icons/inventory/head/item.dmi'
+ icon_state = "amp"
+ item_state = "amp"
diff --git a/code/modules/mob/living/simple_mob/subtypes/glamour/ddraig.dm b/code/modules/mob/living/simple_mob/subtypes/glamour/ddraig.dm
index 8db916f2f2..757b8034e5 100644
--- a/code/modules/mob/living/simple_mob/subtypes/glamour/ddraig.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/glamour/ddraig.dm
@@ -263,7 +263,7 @@
/obj/item/projectile/beam/mouselaser/ddraig/spawn_mob(var/mob/living/target)
var/list/tf_list = list(/mob/living/simple_mob/animal/passive/mouse,
- /mob/living/simple_mob/animal/passive/mouse/rat,
+ /mob/living/simple_mob/animal/passive/mouse/rat/strong,
/mob/living/simple_mob/vore/alienanimals/dustjumper,
/mob/living/simple_mob/vore/woof,
/mob/living/simple_mob/animal/passive/dog/corgi,
diff --git a/code/modules/mob/living/simple_mob/subtypes/horror/Eddy.dm b/code/modules/mob/living/simple_mob/subtypes/horror/Eddy.dm
new file mode 100644
index 0000000000..1dd3a81dbe
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/horror/Eddy.dm
@@ -0,0 +1,57 @@
+/mob/living/simple_mob/horror/Eddy
+ name = "???"
+ desc = "A dark green, sluglike creature, covered in glowing green ooze, and carrying what look to be eggs on its back."
+
+ icon_state = "Eddy"
+ icon_living = "Eddy"
+ icon_dead = "e_head"
+ icon_rest = "Eddy"
+ faction = "horror"
+ icon = 'icons/mob/horror_show/GHPS.dmi'
+ icon_gib = "generic_gib"
+
+ attack_sound = 'sound/h_sounds/negative.ogg'
+
+ maxHealth = 175
+ health = 175
+
+ melee_damage_lower = 25
+ melee_damage_upper = 35
+ grab_resist = 100
+
+ response_help = "pets the"
+ response_disarm = "bops the"
+ response_harm = "hits the"
+ attacktext = list("smashed")
+ friendly = list("nuzzles", "boops", "bumps against", "leans on")
+
+
+ say_list_type = /datum/say_list/Eddy
+ ai_holder_type = /datum/ai_holder/simple_mob/horror
+
+/mob/living/simple_mob/horror/Eddy/death()
+ playsound(src, 'sound/h_sounds/headcrab.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Eddy/bullet_act()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Eddy/attack_hand()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Eddy/hitby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Eddy/attackby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/datum/say_list/Eddy
+ speak = list("Uuurrgh?","Aauuugghh...", "AAARRRGH!")
+ emote_hear = list("shrieks horrifically", "groans in pain", "cries", "whines")
+ emote_see = list("blinks its many eyes", "shakes violently in place", "stares aggressively")
+ say_maybe_target = list("Uuurrgghhh?")
+ say_got_target = list("AAAHHHHH!")
diff --git a/code/modules/mob/living/simple_mob/subtypes/horror/Master.dm b/code/modules/mob/living/simple_mob/subtypes/horror/Master.dm
new file mode 100644
index 0000000000..072e8adcec
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/horror/Master.dm
@@ -0,0 +1,51 @@
+/mob/living/simple_mob/horror/Master
+ name = "Dr. Helix"
+ desc = "A massive pile of grotesque flesh and bulging tumor like growths. Every inch of its skin is undulating in every direction possible, bringing a literal definition to 'Skin Crawling.' Stuck in the middle of this monstrosity is a large AI core with a bloodied, emaciated man sewn into its circuitry."
+
+ icon_state = "Helix"
+ icon_living = "Helix"
+ icon_dead = "m_dead"
+ icon_rest = "Helix"
+ faction = "horror"
+ icon = 'icons/mob/horror_show/master.dmi'
+ vis_height = 64
+ icon_gib = "generic_gib"
+ anchored = TRUE
+
+ attack_sound = 'sound/h_sounds/shitty_tim.ogg'
+
+ maxHealth = 400
+ health = 400
+
+ melee_damage_lower = 5
+ melee_damage_upper = 8
+ grab_resist = 100
+
+ response_help = "pets the"
+ response_disarm = "bops the"
+ response_harm = "hits the"
+ attacktext = list("smushed")
+ friendly = list("nuzzles", "boops", "bumps against", "leans on")
+
+
+ ai_holder_type = null
+
+/mob/living/simple_mob/horror/Master/death()
+ playsound(src, 'sound/h_sounds/imbeciles.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Master/bullet_act()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Master/attack_hand()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Master/hitby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Master/attackby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
diff --git a/code/modules/mob/living/simple_mob/subtypes/horror/Rickey.dm b/code/modules/mob/living/simple_mob/subtypes/horror/Rickey.dm
new file mode 100644
index 0000000000..40e05f54a6
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/horror/Rickey.dm
@@ -0,0 +1,57 @@
+/mob/living/simple_mob/horror/Rickey
+ name = "???"
+ desc = "What a handsome Man, his mother must think."
+
+ icon_state = "Rickey"
+ icon_living = "Rickey"
+ icon_dead = "r_head"
+ icon_rest = "Rickey"
+ faction = "horror"
+ icon = 'icons/mob/horror_show/GHPS.dmi'
+ icon_gib = "generic_gib"
+
+ attack_sound = 'sound/h_sounds/wor.ogg'
+
+ maxHealth = 175
+ health = 175
+
+ melee_damage_lower = 25
+ melee_damage_upper = 35
+ grab_resist = 100
+
+ response_help = "pets the"
+ response_disarm = "bops the"
+ response_harm = "hits the"
+ attacktext = list("smashed")
+ friendly = list("nuzzles", "boops", "bumps against", "leans on")
+
+
+ say_list_type = /datum/say_list/Rickey
+ ai_holder_type = /datum/ai_holder/simple_mob/horror
+
+/mob/living/simple_mob/horror/Rickey/death()
+ playsound(src, 'sound/h_sounds/headcrab.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Rickey/bullet_act()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Rickey/attack_hand()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Rickey/hitby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Rickey/attackby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/datum/say_list/Rickey
+ speak = list("Uuurrgh?","Aauuugghh...", "AAARRRGH!")
+ emote_hear = list("shrieks horrifically", "groans in pain", "cries", "whines")
+ emote_see = list("flexes to no one in particular", "shakes violently in place", "stares aggressively")
+ say_maybe_target = list("Uuurrgghhh?")
+ say_got_target = list("AAAHHHHH!")
diff --git a/code/modules/mob/living/simple_mob/subtypes/horror/Smiley.dm b/code/modules/mob/living/simple_mob/subtypes/horror/Smiley.dm
new file mode 100644
index 0000000000..185f9cfc50
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/horror/Smiley.dm
@@ -0,0 +1,57 @@
+/mob/living/simple_mob/horror/Smiley
+ name = "???"
+ desc = "A giant hand, with a large, smiling head on top."
+
+ icon_state = "Smiley"
+ icon_living = "Smiley"
+ icon_dead = "s_head"
+ icon_rest = "Smiley"
+ faction = "horror"
+ icon = 'icons/mob/horror_show/GHPS.dmi'
+ icon_gib = "generic_gib"
+
+ attack_sound = 'sound/h_sounds/holla.ogg'
+
+ maxHealth = 175
+ health = 175
+
+ melee_damage_lower = 25
+ melee_damage_upper = 35
+ grab_resist = 100
+
+ response_help = "pets the"
+ response_disarm = "bops the"
+ response_harm = "hits the"
+ attacktext = list("smashed")
+ friendly = list("nuzzles", "boops", "bumps against", "leans on")
+
+
+ say_list_type = /datum/say_list/Smiley
+ ai_holder_type = /datum/ai_holder/simple_mob/horror
+
+/mob/living/simple_mob/horror/Smiley/death()
+ playsound(src, 'sound/h_sounds/lynx.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Helix/bullet_act()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Helix/attack_hand()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Helix/hitby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Helix/attackby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/datum/say_list/Smiley
+ speak = list("Uuurrgh?","Aauuugghh...", "AAARRRGH!")
+ emote_hear = list("shrieks horrifically", "groans in pain", "cries", "whines")
+ emote_see = list("squeezes its fingers together", "shakes violently in place", "stares aggressively")
+ say_maybe_target = list("Uuurrgghhh?")
+ say_got_target = list("AAAHHHHH!")
diff --git a/code/modules/mob/living/simple_mob/subtypes/horror/Steve.dm b/code/modules/mob/living/simple_mob/subtypes/horror/Steve.dm
new file mode 100644
index 0000000000..b72edb1324
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/horror/Steve.dm
@@ -0,0 +1,64 @@
+/mob/living/simple_mob/horror/Steve
+ name = "???"
+ desc = "A formless blob of flesh with one, giant, everblinking eye. It has a large machine gun and a watercooler stuck stright into its skin."
+
+ icon_state = "Steve"
+ icon_living = "Steve"
+ icon_dead = "sg_head"
+ icon_rest = "Steve"
+ faction = "horror"
+ icon = 'icons/mob/horror_show/GHPS.dmi'
+ icon_gib = "generic_gib"
+
+ attack_sound = 'sound/h_sounds/mumble.ogg'
+
+ maxHealth = 175
+ health = 175
+
+ melee_damage_lower = 25
+ melee_damage_upper = 35
+ grab_resist = 100
+
+ projectiletype = /obj/item/projectile/bullet/pistol/medium
+ projectilesound = 'sound/weapons/Gunshot_light.ogg'
+
+ needs_reload = TRUE
+ base_attack_cooldown = 5 // Two attacks a second or so.
+ reload_max = 20
+
+ response_help = "pets the"
+ response_disarm = "bops the"
+ response_harm = "hits the"
+ attacktext = list("smashed")
+ friendly = list("nuzzles", "boops", "bumps against", "leans on")
+
+
+ say_list_type = /datum/say_list/Steve
+ ai_holder_type = /datum/ai_holder/simple_mob/horror
+
+/mob/living/simple_mob/horror/Steve/death()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Steve/bullet_act()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Steve/attack_hand()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Steve/hitby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Steve/attackby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/datum/say_list/Steve
+ speak = list("Uuurrgh?","Aauuugghh...", "AAARRRGH!")
+ emote_hear = list("shrieks horrifically", "groans in pain", "cries", "whines")
+ emote_see = list("blinks aggressively at", "shakes violently in place", "stares aggressively")
+ say_maybe_target = list("Uuurrgghhh?")
+ say_got_target = list("AAAHHHHH!")
diff --git a/code/modules/mob/living/simple_mob/subtypes/horror/Willy.dm b/code/modules/mob/living/simple_mob/subtypes/horror/Willy.dm
new file mode 100644
index 0000000000..420b70544f
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/horror/Willy.dm
@@ -0,0 +1,57 @@
+/mob/living/simple_mob/horror/Willy
+ name = "???"
+ desc = "It looks like a giant mascot costume made of flesh and fabric. The two bulging eyes aren't comforting to look at either. At least it smells like a burger and fries."
+
+ icon_state = "Willy"
+ icon_living = "Willy"
+ icon_dead = "w_head"
+ icon_rest = "Willy"
+ faction = "horror"
+ icon = 'icons/mob/horror_show/GHPS.dmi'
+ icon_gib = "generic_gib"
+
+ attack_sound = 'sound/h_sounds/negative.ogg'
+
+ maxHealth = 175
+ health = 175
+
+ melee_damage_lower = 25
+ melee_damage_upper = 35
+ grab_resist = 100
+
+ response_help = "pets the"
+ response_disarm = "bops the"
+ response_harm = "hits the"
+ attacktext = list("smashed")
+ friendly = list("nuzzles", "boops", "bumps against", "leans on")
+
+
+ say_list_type = /datum/say_list/Willy
+ ai_holder_type = /datum/ai_holder/simple_mob/horror
+
+/mob/living/simple_mob/horror/Willy/death()
+ playsound(src, 'sound/h_sounds/sampler.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Willy/bullet_act()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Willy/attack_hand()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Willy/hitby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Willy/attackby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/datum/say_list/Willy
+ speak = list("Uuurrgh?","Aauuugghh...", "AAARRRGH!")
+ emote_hear = list("shrieks horrifically", "groans in pain", "cries", "whines")
+ emote_see = list("headbobs", "shakes violently in place", "stares aggressively")
+ say_maybe_target = list("Uuurrgghhh?")
+ say_got_target = list("AAAHHHHH!")
diff --git a/code/modules/mob/living/simple_mob/subtypes/horror/bradley.dm b/code/modules/mob/living/simple_mob/subtypes/horror/bradley.dm
new file mode 100644
index 0000000000..2a6606e839
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/horror/bradley.dm
@@ -0,0 +1,57 @@
+/mob/living/simple_mob/horror/bradley
+ name = "Bradley"
+ desc = "What you see is a ball of seemingly melty flesh, stitched together hastily over large, bulging scars. Four metal legs extend out of its sides, The two in the front are larger than the back; and all of the legs are segmented with a unique steel looking metal. In the middle of this monstrosity is a constantly tremmoring eye. While the eye never blinks, it is dyed faintly yellow, with a vertical, read pupil. It seems like it's crying, a weird, oil like liquid seeping from its socket."
+
+ icon_state = "Bradley"
+ icon_living = "Bradley"
+ icon_dead = "b_head"
+ icon_rest = "Bradley"
+ faction = "horror"
+ icon = 'icons/mob/horror_show/GHPS.dmi'
+ icon_gib = "generic_gib"
+
+ attack_sound = 'sound/h_sounds/holla.ogg'
+
+ maxHealth = 175
+ health = 175
+
+ melee_damage_lower = 25
+ melee_damage_upper = 35
+ grab_resist = 100
+
+ response_help = "pets the"
+ response_disarm = "bops the"
+ response_harm = "hits the"
+ attacktext = list("mutilated")
+ friendly = list("nuzzles", "eyeboops", "headbumps against", "leans on")
+
+
+ say_list_type = /datum/say_list/bradley
+ ai_holder_type = /datum/ai_holder/simple_mob/horror
+
+/mob/living/simple_mob/horror/bradley/death()
+ playsound(src, 'sound/h_sounds/mumble.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/bradley/bullet_act()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/bradley/attack_hand()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/bradley/hitby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/bradley/attackby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/datum/say_list/bradley
+ speak = list("Uuurrgh?","Aauuugghh...", "AAARRRGH!")
+ emote_hear = list("shrieks through its skin", "groans in pain", "creaks", "clanks")
+ emote_see = list("taps its limbs against the ground", "shakes", "stares aggressively")
+ say_maybe_target = list("Uuurrgghhh?")
+ say_got_target = list("AAAHHHHH!")
diff --git a/code/modules/mob/living/simple_mob/subtypes/horror/horror .dm b/code/modules/mob/living/simple_mob/subtypes/horror/horror .dm
new file mode 100644
index 0000000000..e31ef5e512
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/horror/horror .dm
@@ -0,0 +1,31 @@
+/mob/living/simple_mob/horror
+ tt_desc = "Homo Horrificus"
+ faction = "horror"
+ icon = 'icons/mob/horror_show/GHPS.dmi'
+ icon_gib = "generic_gib"
+
+ can_pain_emote = FALSE
+
+/datum/ai_holder/simple_mob/horror
+ hostile = TRUE // The majority of simplemobs are hostile, gaslamps are nice.
+ cooperative = FALSE
+ retaliate = TRUE //so the monster can attack back
+ returns_home = FALSE
+ can_flee = FALSE
+ speak_chance = 3
+ wander = TRUE
+ base_wander_delay = 9
+
+/mob/living/simple_mob/horror
+ 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
+ maxbodytemp = 700
+
+ can_be_drop_prey = FALSE
diff --git a/code/modules/mob/living/simple_mob/subtypes/horror/sally.dm b/code/modules/mob/living/simple_mob/subtypes/horror/sally.dm
new file mode 100644
index 0000000000..430da4fd7c
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/horror/sally.dm
@@ -0,0 +1,57 @@
+/mob/living/simple_mob/horror/Sally
+ name = "???"
+ desc = "A mass of tentacles hold up a large head, graced with one of the grandest smiles in the galaxy. It's a shame about the constant oil leaking from its eyes."
+
+ icon_state = "Sally"
+ icon_living = "Sally"
+ icon_dead = "ws_head"
+ icon_rest = "Sally"
+ faction = "horror"
+ icon = 'icons/mob/horror_show/widehorror.dmi'
+ icon_gib = "generic_gib"
+
+ attack_sound = 'sound/h_sounds/sampler.ogg'
+
+ maxHealth = 200
+ health = 200
+
+ melee_damage_lower = 30
+ melee_damage_upper = 40
+ grab_resist = 100
+
+ response_help = "pets the"
+ response_disarm = "bops the"
+ response_harm = "hits the"
+ attacktext = list("smashed")
+ friendly = list("nuzzles", "boops", "headbumps against", "leans on")
+
+
+ say_list_type = /datum/say_list/Sally
+ ai_holder_type = /datum/ai_holder/simple_mob/horror
+
+/mob/living/simple_mob/horror/Sally/death()
+ playsound(src, 'sound/h_sounds/lynx.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Sally/bullet_act()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Sally/attack_hand()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Sally/hitby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/Sally/attackby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/datum/say_list/Sally
+ speak = list("Yeeeeee?","Haaah! Gashuuuuuh!", "Gahgahgahgah...")
+ emote_hear = list("shrieks", "groans in pain", "breathes heavily", "gnashes its teeth")
+ emote_see = list("wiggles its head", "shakes violently", "stares aggressively")
+ say_maybe_target = list("Uuurrgghhh?")
+ say_got_target = list("AAAHHHHH!")
diff --git a/code/modules/mob/living/simple_mob/subtypes/horror/shittytim.dm b/code/modules/mob/living/simple_mob/subtypes/horror/shittytim.dm
new file mode 100644
index 0000000000..86b52d83b8
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/horror/shittytim.dm
@@ -0,0 +1,58 @@
+/mob/living/simple_mob/horror/BigTim
+ name = "Shitty Tim"
+ desc = "A tall figure wearing ripped clothes. Its eyes are placed on the bulb of skin that's folded over the front of its face. He has a gold clock hanging on a gold chain around his neck, and he has a gold and diamond bracelet on his wrist."
+
+ icon_state = "shitty_tim"
+ icon_living = "shitty_tim"
+ icon_dead = "tst_head"
+ icon_rest = "shitty_tim"
+ faction = "horror"
+ icon = 'icons/mob/horror_show/tallhorror.dmi'
+ vis_height = 64
+ icon_gib = "generic_gib"
+
+ attack_sound = 'sound/h_sounds/youknowwhoitis.ogg'
+
+ maxHealth = 250
+ health = 250
+
+ melee_damage_lower = 35
+ melee_damage_upper = 45
+ grab_resist = 100
+
+ response_help = "pets the"
+ response_disarm = "bops the"
+ response_harm = "hits the"
+ attacktext = list("mutilated")
+ friendly = list("nuzzles", "boops", "headbumps against", "leans on")
+
+
+ say_list_type = /datum/say_list/BigTim
+ ai_holder_type = /datum/ai_holder/simple_mob/horror
+
+/mob/living/simple_mob/horror/BigTim/death()
+ playsound(src, 'sound/h_sounds/shitty_tim.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/BigTim/bullet_act()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/BigTim/attack_hand()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/BigTim/hitby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/BigTim/attackby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/datum/say_list/BigTim
+ speak = list("Wuuuuuhhuuhhhhh?","Urk! Aaaaahaaa!", "Yuhyuhyuhyuh...")
+ emote_hear = list("shrieks", "groans in pain", "flaps", "gnashes its teeth")
+ emote_see = list("jiggles its teeth", "shakes violently", "stares aggressively")
+ say_maybe_target = list("Uuurrgghhh?")
+ say_got_target = list("AAAHHHHH!")
diff --git a/code/modules/mob/living/simple_mob/subtypes/horror/timling.dm b/code/modules/mob/living/simple_mob/subtypes/horror/timling.dm
new file mode 100644
index 0000000000..4e77ad820d
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/horror/timling.dm
@@ -0,0 +1,58 @@
+/mob/living/simple_mob/horror/TinyTim
+ name = "???"
+ desc = "A tall figure wearing ripped clothes. Its eyes are placed on the bulb of skin that's folded over the front of its face."
+
+ icon_state = "timling"
+ icon_living = "timling"
+ icon_dead = "tt_head"
+ icon_rest = "timling"
+ faction = "horror"
+ icon = 'icons/mob/horror_show/tallhorror.dmi'
+ vis_height = 64
+ icon_gib = "generic_gib"
+
+ attack_sound = 'sound/h_sounds/youknowwhoitis.ogg'
+
+ maxHealth = 200
+ health = 200
+
+ melee_damage_lower = 30
+ melee_damage_upper = 40
+ grab_resist = 100
+
+ response_help = "pets the"
+ response_disarm = "bops the"
+ response_harm = "hits the"
+ attacktext = list("mutilated")
+ friendly = list("nuzzles", "boops", "headbumps against", "leans on")
+
+
+ say_list_type = /datum/say_list/TinyTim
+ ai_holder_type = /datum/ai_holder/simple_mob/horror
+
+/mob/living/simple_mob/horror/TinyTim/death()
+ playsound(src, 'sound/h_sounds/shitty_tim.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/TinyTim/bullet_act()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/TinyTim/attack_hand()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/TinyTim/hitby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/horror/TinyTim/attackby()
+ playsound(src, 'sound/h_sounds/holla.ogg', 50, 1)
+ ..()
+
+/datum/say_list/TinyTim
+ speak = list("Wuuuuuhhuuhhhhh?","Urk! Aaaaahaaa!", "Yuhyuhyuhyuh...")
+ emote_hear = list("shrieks", "groans in pain", "flaps", "gnashes its teeth")
+ emote_see = list("jiggles its teeth", "shakes violently", "stares aggressively")
+ say_maybe_target = list("Uuurrgghhh?")
+ say_got_target = list("AAAHHHHH!")
diff --git a/code/modules/mob/living/simple_mob/subtypes/humanoid/cultist.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/cultist.dm
new file mode 100644
index 0000000000..581b143dc0
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/cultist.dm
@@ -0,0 +1,678 @@
+////////////////////////////
+// Basic Cultist
+////////////////////////////
+
+/datum/category_item/catalogue/fauna/cultist
+ name = "Cultists"
+ desc = "The Galactic Awakening unlocked the psionic potential of many \
+ from rim to rim. The first to notice this font of power were those who \
+ were already the faithful devotees of esoteric religions. The rise of Blood \
+ Cultists in service to the Geometer quickly became an intergalactic incident. \
+ Although NanoTrasen and other entities have risen to combat these foes, a \
+ vast array of Hermetic Orders now command frightening power."
+ value = CATALOGUER_REWARD_TRIVIAL
+ unlocked_by_any = list(/datum/category_item/catalogue/fauna/cultist)
+
+// Obtained by scanning all X.
+/datum/category_item/catalogue/fauna/all_cultists
+ name = "Collection - Cultists"
+ desc = "You have scanned a large array of different types of Cultist, \
+ and therefore you have been granted a large sum of points, through this \
+ entry."
+ value = CATALOGUER_REWARD_SUPERHARD
+ unlocked_by_all = list(
+ /datum/category_item/catalogue/fauna/cultist/human,
+ /datum/category_item/catalogue/fauna/cultist/tesh,
+ /datum/category_item/catalogue/fauna/cultist/lizard,
+ /datum/category_item/catalogue/fauna/cultist/caster,
+ /datum/category_item/catalogue/fauna/cultist/initiate,
+ /datum/category_item/catalogue/fauna/cultist/castertesh,
+ /datum/category_item/catalogue/fauna/cultist/elite,
+ /datum/category_item/catalogue/fauna/cultist/magus,
+ /datum/category_item/catalogue/fauna/cultist/hunter
+ )
+
+/mob/living/simple_mob/humanoid/cultist //Do not spawn this on in directly it is simply a base for the rest namely the unique death animations.
+ name = "Cultist"
+ desc = "An awfully frail and ghastly looking individual"
+ tt_desc = "NULL"
+ icon = 'icons/mob/cultists.dmi'
+ icon_state = "initiate"
+ faction = "cult"
+ mob_class = MOB_CLASS_DEMONIC
+
+/datum/category_item/catalogue/fauna/cultist/human
+ name = "Cultists - Human"
+ desc = "The first wave of zealots faced by many on the Frontier were \
+ human. For a short while it was assumed that humans were somehow more \
+ susecptible to Paracausal influence. Although this belief has long since \
+ been disproven, the large Human population on the Frontier has ensured \
+ that the species is overrepresented amongst the ranks of Cult aggressors."
+ value = CATALOGUER_REWARD_EASY
+
+/mob/living/simple_mob/humanoid/cultist/human
+ name = "cultist"
+ desc = "A fanatical zealot armed with a darkly colored sword."
+ icon_state = "cultist"
+ icon_living = "cultist"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/cultist/human)
+
+ status_flags = 0
+
+ response_help = "pokes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+ harm_intent_damage = 5
+ melee_damage_lower = 30 //Cult Sword Damage
+ melee_damage_upper = 30
+ attack_sharp = 1
+ attack_edge = 1
+ attacktext = list("slashed", "stabbed")
+ armor = list(melee = 60, bullet = 50, laser = 30, energy = 80, bomb = 30, bio = 100, rad = 100) // Same armor are cult armor, may nerf since DAMN THAT IS GOOD ARMOR
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ movement_cooldown = 3
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee
+
+/mob/living/simple_mob/humanoid/cultist/human/death()
+ new /obj/effect/decal/remains/human (src.loc)
+ ..(null,"let's out a maddening laugh as his body crumbles away.")
+ ghostize()
+ qdel(src)
+
+/mob/living/simple_mob/humanoid/cultist/human/bloodjaunt //Teleporting Cultists
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive
+
+ var/jaunt_warning = 0.5 SECONDS // How long the jaunt telegraphing is.
+ var/jaunt_tile_speed = 20 // How long to wait between each tile. Higher numbers result in an easier to dodge tunnel attack.
+
+// In Theory this Jury Rigged Code form Tunneler Spiders Should Allow Wraiths to Jaunt
+ special_attack_min_range = 2
+ special_attack_max_range = 6
+ special_attack_cooldown = 10 SECONDS
+
+/mob/living/simple_mob/humanoid/cultist/human/bloodjaunt/do_special_attack(atom/A)
+ set waitfor = FALSE
+ set_AI_busy(TRUE)
+
+ // Save where we're gonna go soon.
+ var/turf/destination = get_turf(A)
+ var/turf/starting_turf = get_turf(src)
+
+ // Telegraph to give a small window to dodge if really close.
+ flick("bloodout",A)
+ icon_state = "bloodout"
+ sleep(jaunt_warning) // For the telegraphing.
+
+ // Do the dig!
+ visible_message(span_danger("\The [src] sinks into a puddle of blood \the [A]!"))
+ new /obj/effect/decal/cleanable/blood (src.loc)
+ flick("blood_out",A)
+ icon_state = "bloodout"
+
+ if(handle_jaunt(destination) == FALSE)
+ set_AI_busy(FALSE)
+ flick("bloodin",A)
+ icon_state = "bloodin"
+ return FALSE
+
+ // Did we make it?
+ if(!(src in destination))
+ set_AI_busy(FALSE)
+ icon_state = "bloodin"
+ flick("bloodin",A)
+ return FALSE
+
+ var/overshoot = TRUE
+
+ // Test if something is at destination.
+ for(var/mob/living/L in destination)
+ if(L == src)
+ continue
+
+ visible_message(span_danger("\The [src] suddenly rises from a pool of blood \the [L]!"))
+ new /obj/effect/decal/cleanable/blood (src.loc)
+ playsound(L, 'sound/weapons/heavysmash.ogg', 75, 1)
+ L.add_modifier(/datum/modifier/entangled, 1 SECONDS)
+ overshoot = FALSE
+
+ if(!overshoot) // We hit the target, or something, at destination, so we're done.
+ set_AI_busy(FALSE)
+ icon_state = "bloodin"
+ flick("bloodin",A)
+ return TRUE
+
+ // Otherwise we need to keep going.
+ to_chat(src, span_warning("You overshoot your target!"))
+ playsound(src, 'sound/weapons/punchmiss.ogg', 75, 1)
+ var/dir_to_go = get_dir(starting_turf, destination)
+ for(var/i = 1 to rand(2, 4))
+ destination = get_step(destination, dir_to_go)
+
+ if(handle_jaunt(destination) == FALSE)
+ set_AI_busy(FALSE)
+ icon_state = "bloodin"
+ flick("bloodin",A)
+ return FALSE
+
+ set_AI_busy(FALSE)
+ icon_state = "bloodin"
+ flick("bloodin",A)
+ return FALSE
+
+// Does the jaunt movement
+/mob/living/simple_mob/humanoid/cultist/human/bloodjaunt/proc/handle_jaunt(turf/destination)
+ var/turf/T = get_turf(src) // Hold our current tile.
+
+ // Regular tunnel loop.
+ for(var/i = 1 to get_dist(src, destination))
+ if(stat)
+ return FALSE // We died or got knocked out on the way.
+ if(loc == destination)
+ break // We somehow got there early.
+
+ // Update T.
+ T = get_step(src, get_dir(src, destination))
+ if(T.check_density(ignore_mobs = TRUE))
+ to_chat(src, span_critical("You hit something really solid!"))
+ playsound(src, "punch", 75, 1)
+ Weaken(5)
+ add_modifier(/datum/modifier/tunneler_vulnerable, 10 SECONDS)
+ return FALSE // Hit a wall.
+
+ // Get into the tile.
+ forceMove(T)
+
+
+/mob/living/simple_mob/humanoid/cultist/human/bloodjaunt/should_special_attack(atom/A)
+ // Make sure its possible for the wraith to reach the target so it doesn't try to go through a window.
+ var/turf/destination = get_turf(A)
+ var/turf/starting_turf = get_turf(src)
+ var/turf/T = starting_turf
+ for(var/i = 1 to get_dist(starting_turf, destination))
+ if(T == destination)
+ break
+
+ T = get_step(T, get_dir(T, destination))
+ if(T.check_density(ignore_mobs = TRUE))
+ return FALSE
+ return T == destination
+
+////////////////////////////
+// Teshari Cultist
+////////////////////////////
+
+/datum/category_item/catalogue/fauna/cultist/tesh
+ name = "Cultists - Teshari"
+ desc = "Teshari cultists project a curiously sinister air. Perhaps \
+ due to their diminutive stature, these creatures are sometimes not \
+ regarded as genuine threats when compared to their more imposing companions. \
+ To ignore a Teshari fanatic is a fool's errand. Fast, hard to hit, and \
+ tenacious, Teshari form the vanguard of many fanatical assaults."
+ value = CATALOGUER_REWARD_EASY
+
+/mob/living/simple_mob/humanoid/cultist/tesh
+ name = "cultist"
+ desc = "A sinister looking hooded Teshari armed with a curved knife."
+ icon_state = "culttesh"
+ icon_living = "culttesh"
+ maxHealth = 75
+ health = 75
+ catalogue_data = list(/datum/category_item/catalogue/fauna/cultist/tesh)
+
+ faction = "cult"
+
+ status_flags = 0
+
+ response_help = "pokes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+ harm_intent_damage = 5
+ melee_damage_lower = 15 //Ritual Knife
+ melee_damage_upper = 15
+ attack_armor_pen = 25
+ attack_sharp = 1
+ attack_edge = 1
+ attacktext = list("slashed", "stabbed")
+ armor = list(melee = 45, bullet = 40, laser = 30, energy = 80, bomb = 20, bio = 100, rad = 100) // Reduced Resistance to Approximate increased Tesh damage.
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ movement_cooldown = 2
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee
+
+/mob/living/simple_mob/humanoid/cultist/tesh/death()
+ new /obj/effect/decal/cleanable/ash (src.loc)
+ ..(null,"let's out a shrill chirp as his body turns to dust.")
+ ghostize()
+ qdel(src)
+
+////////////////////////////
+// Lizard Cultist
+////////////////////////////
+
+/datum/category_item/catalogue/fauna/cultist/lizard
+ name = "Cultists - Lizard"
+ desc = "The Unathi Kingdom of Moghes has stamped down heavily on the \
+ heretical activities of religious sects not approved by the State. Due \
+ to this, many Unathi seeking religious freedom have fled to the Frontier. \
+ Unfortunately, some of those who took this path have fallen prey to true \
+ evil. Possessing the zeal of the oppressed, Unathi cultists are deadly \
+ fanatics, eager to shred their enemies apart in close quarters, regardless \
+ of what damage they themselves incur."
+ value = CATALOGUER_REWARD_EASY
+
+/mob/living/simple_mob/humanoid/cultist/lizard
+ name = "cultist"
+ desc = "With a knife in each hand, this lizard looks ready to disect you."
+ icon_state = "cultliz"
+ icon_living = "cultliz"
+ maxHealth = 200
+ health = 200
+ catalogue_data = list(/datum/category_item/catalogue/fauna/cultist/lizard)
+
+ faction = "cult"
+
+ status_flags = 0
+
+ response_help = "pokes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+ harm_intent_damage = 5
+ melee_damage_lower = 15 //Ritual Knife
+ melee_damage_upper = 15
+ attack_sharp = 1
+ attack_edge = 1
+ attacktext = list("slashed", "stabbed")
+ armor = list(melee = 70, bullet = 60, laser = 30, energy = 80, bomb = 35, bio = 100, rad = 100) // Better Armor to match lizard brute resist
+ attack_sound = 'sound/weapons/rapidslice.ogg'
+ movement_cooldown = 4
+ base_attack_cooldown = 7.5 //Two knives mean double stab.
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee
+
+/mob/living/simple_mob/humanoid/cultist/lizard/death()
+ new /obj/effect/decal/remains/unathi (src.loc)
+ ..(null,"hisses as he collapses into a pile of bones.")
+ ghostize()
+ qdel(src)
+
+////////////////////////////
+// Blood Mage
+////////////////////////////
+
+/datum/category_item/catalogue/fauna/cultist/caster
+ name = "Cultists - Blood Mage"
+ desc = "For those servants of a Cult who possess enough latent ability, \
+ the channelling of Paracausal power is a very real skill to be honed and \
+ exploited. Blood Mages learn to fuel paranatural assaults using their own \
+ life force. Necessarily short lived, these cultists believe that bleeding \
+ themselves dry is a statement of faith. Able to fire beams of dark energy \
+ at their foes, these fanatics should be primarily engaged by PMD response \
+ teams."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/mob/living/simple_mob/humanoid/cultist/caster
+ name = "Blood Mage"
+ desc = "A Robed individual whose hands pulsate with unnatural power."
+ icon_state = "caster"
+ icon_living = "caster"
+ maxHealth = 150
+ health = 150
+ catalogue_data = list(/datum/category_item/catalogue/fauna/cultist/caster)
+
+ faction = "cult"
+
+ status_flags = 0
+
+ response_help = "pokes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+ harm_intent_damage = 5
+ melee_damage_lower = 15 //Ritual Knife
+ melee_damage_upper = 15
+ attack_sharp = 1
+ attack_edge = 1
+ attacktext = list("slashed", "stabbed")
+ armor = list(melee = 50, bullet = 30, laser = 50, energy = 80, bomb = 25, bio = 100, rad = 100) //Armor Rebalanced for Cult Robes.
+ attack_sound = 'sound/weapons/rapidslice.ogg'
+ movement_cooldown = 4
+ projectiletype = /obj/item/projectile/beam/inversion
+ projectilesound = 'sound/weapons/spiderlunge.ogg'
+
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged
+
+/mob/living/simple_mob/humanoid/cultist/caster/death()
+ new /obj/effect/decal/remains/human (src.loc)
+ new /obj/effect/decal/cleanable/blood/gibs (src.loc)
+ ..(null,"melts into a pile of blood and bones.")
+ ghostize()
+ qdel(src)
+
+////////////////////////////
+// Blood Initiate
+////////////////////////////
+
+/datum/category_item/catalogue/fauna/cultist/initiate
+ name = "Cultists - Initiate"
+ desc = "After the Awakening, some who thirst for power or belonging \
+ saw an opportunity to have their darker desires fulfilled. These converts \
+ are accepted into the ranks of Cults across the galaxy regardless of whether \
+ they possess psionic potential are not. Those that do ascend through the \
+ ranks, whereas those that don't may still serve as cannon fodder and sacrifices."
+ value = CATALOGUER_REWARD_EASY
+
+/mob/living/simple_mob/humanoid/cultist/initiate
+ name = "Blood Intiate"
+ desc = "A Novice Amongst his betters, he still seems determined to slice you to bits."
+ icon_state = "initiate"
+ icon_living = "initiate"
+ maxHealth = 150
+ health = 150
+ catalogue_data = list(/datum/category_item/catalogue/fauna/cultist/initiate)
+
+ faction = "cult"
+
+ status_flags = 0
+
+ response_help = "pokes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+ harm_intent_damage = 5
+ melee_damage_lower = 15 //Ritual Knife
+ melee_damage_upper = 15
+ attack_sharp = 1
+ attack_edge = 1
+ attacktext = list("slashed", "stabbed")
+ armor = list(melee = 50, bullet = 30, laser = 50, energy = 80, bomb = 25, bio = 100, rad = 100) //Armor Rebalanced for Cult Robes.
+ attack_sound = 'sound/weapons/rapidslice.ogg'
+ movement_cooldown = 4
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee
+
+/mob/living/simple_mob/humanoid/cultist/initiate/death()
+ new /obj/effect/decal/remains/human (src.loc)
+ ..(null,"lets out a horrified scream as his body crumbles away.")
+ ghostize()
+ qdel(src)
+
+////////////////////////////
+// Teshari Mage
+////////////////////////////
+
+/datum/category_item/catalogue/fauna/cultist/castertesh
+ name = "Cultists - Teshari Mage"
+ desc = "Similar in skill to their human counter parts, Teshari mages \
+ are regarded as more ferocious combatants. Able to cast paracausal beams \
+ at a rapid pace with ease, Teshari Mages are a priority target of any \
+ response team, and any who discount their threat are quickly shown the \
+ error of their ways."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/mob/living/simple_mob/humanoid/cultist/castertesh
+ name = "Teshari Mage"
+ desc = "This Teshari seems to have forsoken weapons for unfanthomable power."
+ icon_state = "castertesh"
+ icon_living = "castertesh"
+ maxHealth = 75
+ health = 75
+ catalogue_data = list(/datum/category_item/catalogue/fauna/cultist/castertesh)
+
+ faction = "cult"
+
+ status_flags = 0
+
+ response_help = "pokes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+ harm_intent_damage = 5
+ melee_damage_lower = 15 //Ritual Knife
+ melee_damage_upper = 15
+ attack_sharp = 1
+ attack_edge = 1
+ attacktext = list("slashed", "stabbed")
+ armor = list(melee = 35, bullet = 20, laser = 35, energy = 60, bomb = 20, bio = 100, rad = 100) //Rebalanced for Robes and Tesh damage
+ attack_sound = 'sound/weapons/rapidslice.ogg'
+ movement_cooldown = 2
+ base_attack_cooldown = 7.5
+ projectiletype = /obj/item/projectile/beam/inversion
+ projectilesound = 'sound/weapons/spiderlunge.ogg'
+
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged/kiting
+
+/mob/living/simple_mob/humanoid/cultist/castertesh/death()
+ new /obj/effect/decal/cleanable/ash (src.loc)
+ ..(null,"burns away into nothing.")
+ ghostize()
+ qdel(src)
+
+////////////////////////////
+// Elite Cultist
+////////////////////////////
+
+/datum/category_item/catalogue/fauna/cultist/elite
+ name = "Cultists - Elite"
+ desc = "Cultists who preceded the Great Awakening are often regarded \
+ with immense respect. Truly devoted, these adherents learned many rites \
+ and rituals before they ever bore true power. As such, Elite Cultists \
+ possess a working knowledge of many arcane arts, and are trusted with \
+ the rare Paracausal artifacts possessed by their orders. From mirror \
+ shields to arcane sets of armor, Elites command fear, and inspire the \
+ fanaticism of their subordinates."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/mob/living/simple_mob/humanoid/cultist/elite
+ name = "Elite Cultist"
+ desc = "A heavily armed cultist with a mirror shield that hurts to look at."
+ icon_state = "cult_elite"
+ icon_living = "cult_elite"
+ faction = "cult"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/cultist/elite)
+
+ status_flags = 0
+
+ response_help = "pokes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+ harm_intent_damage = 5
+ melee_damage_lower = 30 //Cult Sword Damage
+ melee_damage_upper = 30
+ attack_sharp = 1
+ attack_edge = 1
+ attacktext = list("slashed", "stabbed")
+ armor = list(melee = 60, bullet = 50, laser = 30, energy = 80, bomb = 30, bio = 100, rad = 100) // Same armor are cult armor, may nerf since DAMN THAT IS GOOD ARMOR
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ movement_cooldown = 3
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee
+
+/mob/living/simple_mob/humanoid/cultist/elite/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ if(O.force)
+ if(prob(30))
+ visible_message(span_danger("\The [src] blocks \the [O] with its shield!"))
+ if(user)
+ ai_holder.react_to_attack(user)
+ return
+ else
+ ..()
+ else
+ to_chat(user, span_warning("This weapon is ineffective, it does no damage."))
+ visible_message(span_warning("\The [user] gently taps [src] with \the [O]."))
+
+/mob/living/simple_mob/humanoid/cultist/elite/bullet_act(var/obj/item/projectile/Proj)
+ if(!Proj) return
+ if(prob(50))
+ visible_message(span_bolddanger("[Proj] disappears into the mirror world as it hits the shield."))
+ if(Proj.firer)
+ ai_holder.react_to_attack(Proj.firer)
+ return
+ else
+ ..()
+
+/mob/living/simple_mob/humanoid/cultist/elite/death()
+ new /obj/effect/decal/remains/human (src.loc)
+ new /obj/effect/decal/cleanable/blood/gibs (src.loc)
+ new /obj/item/material/shard (src.loc)
+ ..(null,"shatters into bone and blood like pieces like the now shattered mirror.")
+ playsound(src, 'sound/effects/Glassbr2.ogg', 100, 1)
+ ghostize()
+ qdel(src)
+
+////////////////////////////
+// Cult Magus
+////////////////////////////
+
+/datum/category_item/catalogue/fauna/cultist/magus
+ name = "Cultists - Blood Magus"
+ desc = "The Blood Magus commands their local chapter with total authority. \
+ These religious leaders possess an unparalleled knowledge of their cult's \
+ secrets, rituals, and tenets. To attain the rank of Magus, a Cultist must \
+ possess great psionic power. Their ability to channel Paracausal energy is \
+ unparalled amongst their peers. Wielding dark gifts granted by darker gods, \
+ the Magus is a priority target in any engagement."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/mob/living/simple_mob/humanoid/cultist/magus
+ name = "Blood Magus"
+ desc = "A leader of the bloody cult and master of the forbidden arts, wielding powers beyond that of mortal men."
+ icon_state = "magus"
+ icon_living = "magus"
+ maxHealth = 300 //Boss Mobs should be tanky.
+ health = 300
+ catalogue_data = list(/datum/category_item/catalogue/fauna/cultist/magus)
+
+ faction = "cult"
+
+ status_flags = 0
+
+ response_help = "pokes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+ harm_intent_damage = 5
+ melee_damage_lower = 30 //Ritual Knife
+ melee_damage_upper = 30
+ attack_sharp = 1
+ attack_edge = 1
+ attacktext = list("slashed", "stabbed")
+ armor = list(melee = 60, bullet = 50, laser = 50, energy = 80, bomb = 30, bio = 100, rad = 100) //Super Armor since Boss Mob
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ movement_cooldown = 4
+
+ projectiletype = /obj/item/projectile/beam/inversion
+ base_attack_cooldown = 5
+ projectilesound = 'sound/weapons/spiderlunge.ogg'
+ var/obj/item/shield_projector/shields = null
+
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged/kiting
+
+/mob/living/simple_mob/humanoid/cultist/magus/death()
+ new /obj/effect/decal/cleanable/blood/gibs (src.loc)
+ ..(null,"let's out a dark laugh as it collapses into a puddle of blood.")
+ ghostize()
+ qdel(src)
+
+/mob/living/simple_mob/humanoid/cultist/magus/Initialize(mapload)
+ shields = new /obj/item/shield_projector/rectangle/automatic/magus(src)
+ return ..()
+
+/obj/item/shield_projector/rectangle/automatic/magus
+ name = "cult shield stone"
+ desc = "A stone wielded by only the most powerful of cult leaders. It projects a shield around the user."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "implant_melted"
+ shield_health = 200
+ max_shield_health = 200
+ shield_regen_delay = 10 SECONDS
+ shield_regen_amount = 10
+ size_x = 1
+ size_y = 1
+ color = "#f50202"
+ high_color = "#ff0404"
+ low_color = "#690000"
+////////////////////////////
+// Blood Hunter
+////////////////////////////
+
+/datum/category_item/catalogue/fauna/cultist/hunter
+ name = "Cultists - Blood Hunter"
+ desc = "Whether the Blood Hunter may be considered human still remains \
+ a hotly contested topic. There is further debate regarding whether every \
+ instance of the Blood Hunter is the same entity, or whether this condition \
+ is some manner of Paranatural affliction or status. It is speculated that \
+ the Blood Hunter was once a mortal devotee of the Geometer, and has somehow \
+ ascended to the rank of Paracausal Being. The Blood Hunter is a killer without \
+ peer. If encountered, retreat and contact the PMD immediately."
+ value = CATALOGUER_REWARD_HARD
+
+/mob/living/simple_mob/humanoid/cultist/hunter // This Mob is not meant to be fair, he is not meant to fight regular crew he is to be pitted against heavily armed explo teams to see if he can wipe them out.
+ name = "Blood Hunter" // TO BE CLEAR: DO NOT SPAWN THIS GUY ON THE SHIP/STATION HE WILL MURDER EVERYTHING.
+ desc = "The smell of blood fills the air, how delicious it tastes. Let the hunt begin." // He is a horrifying lovechild of Caleb and a blooborne hunter.
+ icon_state = "hunterb" // He probably shouldn't even have other mobs supporting him.
+ icon_living = "hunterb"
+ maxHealth = 300 //Boss Mobs should be tanky.
+ health = 300
+ catalogue_data = list(/datum/category_item/catalogue/fauna/cultist/hunter)
+
+ faction = "cult"
+
+ status_flags = 0
+
+ response_help = "pokes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+ harm_intent_damage = 5
+ melee_damage_lower = 42 //Saw Cleaver Brutality
+ melee_damage_upper = 42
+ attack_sharp = 1
+ attack_edge = 1
+ attacktext = list("slashed", "stabbed")
+ armor = list(melee = 60, bullet = 50, laser = 50, energy = 80, bomb = 30, bio = 100, rad = 100) //Super Armor since Boss Mob
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ movement_cooldown = 0 //This is so he can't be kited well
+
+ projectiletype = /obj/item/projectile/bullet/pellet/shotgun
+
+ base_attack_cooldown = 7.5
+
+ // loot_list = list(/obj/item/material/butterfly/saw = 100, /obj/item/gun/projectile/shotgun/doublebarrel/sawn/alt = 100) // Downstream
+
+ needs_reload = TRUE
+ reload_max = 2
+ projectilesound = 'sound/weapons/Gunshot_shotgun.ogg'
+
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged/aggressive/blood_hunter
+
+/mob/living/simple_mob/humanoid/cultist/hunter/death()
+ new /obj/effect/decal/cleanable/blood/gibs (src.loc)
+ ..(null,"laughs as he melts away. His laughs echo through the air even after only a dense red goo remains.")
+ ghostize()
+ qdel(src)
+
+
+////////////////////////////
+// Hunter AI
+////////////////////////////
+
+/datum/ai_holder/simple_mob/ranged/aggressive/blood_hunter //This directs the AI to charge while shooting at its victim then entering Glorious melee combat.
+ pointblank = FALSE
+ closest_distance = 0
+
+////////////////////////////
+// Ash Hunter
+////////////////////////////
+
+
+/mob/living/simple_mob/humanoid/cultist/hunter/surt // This Mob is not meant to be fair, he is not meant to fight regular crew he is to be pitted against heavily armed explo teams to see if he can wipe them out.
+ name = "Itinerant Blood Hunter"
+ desc = "This Blood Hunter is far from home. Strange energies course around him, protecting him from the environment. What eldritch influence drew him to this place?" // Blood Hunter on vacation.
+
+ heat_resist = 1 //Might make this 0.75 if 1 is too much resistance for a boss monster. This guy's just a placeholder until we get the Miner in anyways.
diff --git a/code/modules/mob/living/simple_mob/subtypes/humanoid/humanoid.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/humanoid.dm
index 0e7a48d209..b29d784fd6 100644
--- a/code/modules/mob/living/simple_mob/subtypes/humanoid/humanoid.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/humanoid.dm
@@ -24,10 +24,14 @@
species_sounds = "Human Male" // Yes, we should allow them to differ based on gender, but if someone's making a custom humanoid later:tm: - set your humanoid's species_sounds to match, or var-edit it after spawn.
+ can_be_drop_prey = FALSE
+
/mob/living/simple_mob/humanoid/death()
..()
if(corpse)
- new corpse (src.loc)
+ var/mob/new_corpse = new corpse(src.loc)
+ if(istype(new_corpse))
+ new_corpse.low_priority = TRUE
qdel(src)
return
diff --git a/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs.dm
index 93182115ff..62bf8208df 100644
--- a/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs.dm
@@ -11,6 +11,7 @@
icon_living = "syndicate"
icon_dead = "syndicate_dead"
icon_gib = "syndicate_gib"
+ icon= 'icons/mob/mercenaries.dmi'
faction = FACTION_SYNDICATE
movement_cooldown = 1
@@ -39,6 +40,7 @@
// Grenade special attack vars
var/grenade_type = /obj/item/grenade/concussion
special_attack_cooldown = 45 SECONDS
+ var/grenade_timer = 50
special_attack_min_range = 2
special_attack_max_range = 7
@@ -71,7 +73,8 @@
var/obj/item/grenade/G = new grenade_type(get_turf(src))
if(istype(G))
G.throw_at(A, G.throw_range, G.throw_speed, src)
- G.attack_self(src)
+ G.det_time = grenade_timer
+ G.activate(src)
special_attack_charges = max(special_attack_charges-1, 0)
set_AI_busy(FALSE)
@@ -158,6 +161,7 @@
// Base Ranged Merc, so we don't have to redefine a million vars for every subtype. Uses a pistol.
/mob/living/simple_mob/humanoid/merc/ranged
+ desc = "A tough looking individual armed with an pistol."
icon_state = "syndicateranged"
icon_living = "syndicateranged"
projectiletype = /obj/item/projectile/bullet/pistol/medium
@@ -171,6 +175,8 @@
// C20r SMG
/mob/living/simple_mob/humanoid/merc/ranged/smg
+ name = "mercenary soldier"
+ desc = "A tough looking individual armed with an submachine gun."
icon_state = "syndicateranged_smg"
icon_living = "syndicateranged_smg"
@@ -190,6 +196,7 @@
base_attack_cooldown = 5 // Two attacks a second or so.
reload_max = 20
+ catalogue_data = list(/datum/category_item/catalogue/fauna/mercenary/human/peacekeeper)
// Rifles
/mob/living/simple_mob/humanoid/merc/ranged/rifle
@@ -214,6 +221,8 @@
// Laser Rifle
/mob/living/simple_mob/humanoid/merc/ranged/laser
+ name = "mercenary marksman"
+ desc = "A tough looking individual armed with an laser rifle."
icon_state = "syndicateranged_laser"
icon_living = "syndicateranged_laser"
projectiletype = /obj/item/projectile/beam/midlaser
@@ -227,6 +236,8 @@
// Ion Rifle
/mob/living/simple_mob/humanoid/merc/ranged/ionrifle
+ name = "mercenary anti-technical"
+ desc = "A tough looking individual armed with an ion rifle."
icon_state = "syndicateranged_ionrifle"
icon_living = "syndicateranged_ionrifle"
projectiletype = /obj/item/projectile/ion
@@ -238,6 +249,9 @@
// Grenadier, Basically a miniboss
/mob/living/simple_mob/humanoid/merc/ranged/grenadier
+ name = "mercenary grenadier"
+ desc = "A tough looking individual armed with a shotgun and a belt of grenades."
+ catalogue_data = list(/datum/category_item/catalogue/fauna/mercenary/human/grenadier)
icon_state = "syndicateranged_shotgun"
icon_living = "syndicateranged_shotgun"
projectiletype = /obj/item/projectile/bullet/pellet/shotgun // Buckshot
@@ -340,15 +354,41 @@
return TRUE
+//Garand
+/mob/living/simple_mob/humanoid/merc/ranged/garand
+ name = "mercenary rifleman"
+ desc = "A tough looking individual armed with a semiautomatic rifle."
+ icon_state = "syndicateranged_veteran"
+ icon_living = "syndicateranged_veteran"
+ projectiletype = /obj/item/projectile/bullet/rifle/a762
+ projectilesound = 'sound/weapons/Gunshot_heavy.ogg'
+ loot_list = list(/obj/item/gun/projectile/garand = 100)
+ reload_max = 8
+ reload_time = 2 // It takes a bit to jam a stripper clip into the rifle.
+
+//Hand Cannon
+/mob/living/simple_mob/humanoid/merc/ranged/deagle
+ name = "mercenary officer"
+ desc = "A tough looking individual armed with an handcannon."
+ icon_state = "syndicate_handcannon"
+ icon_living = "syndicate_handcannon"
+ projectiletype = /obj/item/projectile/bullet/pistol/strong
+ projectilesound = 'sound/weapons/Gunshot_deagle.ogg'
+ loot_list = list(/obj/item/gun/projectile/deagle = 100)
+ needs_reload = TRUE
+ reload_max = 7 // Deagle Reload
+
////////////////////////////////
// Space Mercs
////////////////////////////////
// Sword Space Merc
/mob/living/simple_mob/humanoid/merc/melee/sword/space
- name = "syndicate commando"
- icon_state = "syndicatemeleespace"
- icon_living = "syndicatemeleespace"
+ name = "mercenary commando"
+ desc = "A tough looking individual, armred with an energy sword and shield."
+ icon_state = "syndicatespace-melee"
+ icon_living = "syndicatespace-melee"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/mercenary/human/space)
movement_cooldown = -1
@@ -371,9 +411,14 @@
// Ranged Space Merc
/mob/living/simple_mob/humanoid/merc/ranged/space
- name = "syndicate sommando"
- icon_state = "syndicaterangedpsace"
- icon_living = "syndicaterangedpsace"
+ name = "armored mercenary"
+ desc = "A tough looking individual, armed with a submachine gun."
+ icon_state = "syndicatespace-ranged"
+ icon_living = "syndicatespceace-ranged"
+ armor = list(melee = 60, bullet = 50, laser = 30, energy = 15, bomb = 35, bio = 100, rad = 100) // Same armor as their voidsuit.
+ base_attack_cooldown = 5 // Two attacks a second or so.
+ reload_max = 20
+ loot_list = list(/obj/item/gun/projectile/automatic/c20r = 100)
movement_cooldown = -1
@@ -392,6 +437,119 @@
corpse = /obj/effect/landmark/mobcorpse/syndicatecommando
+//Combat Shotgun Merc
+/mob/living/simple_mob/humanoid/merc/ranged/space/shotgun
+ name = "mercenary tactical"
+ desc = "A tough looking individual armed with a combat shotgun."
+ icon_state = "syndicatespace-shotgun"
+ icon_living = "syndicatespace-shotgun"
+ base_attack_cooldown = 10
+ reload_max = 7
+ reload_time = 2 SECONDS //Takes a While to load all those shells.
+ projectiletype = /obj/item/projectile/bullet/pellet/shotgun // Buckshot
+ projectilesound = 'sound/weapons/Gunshot_shotgun.ogg'
+ loot_list = list(/obj/item/gun/projectile/shotgun/pump/combat = 100)
+
+//Auto-Shotgun Space Merc
+/mob/living/simple_mob/humanoid/merc/ranged/space/shotgun/auto
+ name = "mercenary sweeper"
+ desc = "A tough looking individual armed with an automatic shotgun."
+ icon_state = "syndicatespace-ashotgun"
+ icon_living = "syndicatespace-ashotgun"
+ base_attack_cooldown = 5 // Two attacks a second or so.
+ reload_max = 24
+ projectiletype = /obj/item/projectile/bullet/pellet/shotgun // Buckshot
+ projectilesound = 'sound/weapons/Gunshot_shotgun.ogg'
+ loot_list = list(/obj/item/gun/projectile/automatic/as24 = 100)
+ ai_holder_type = /datum/ai_holder/simple_mob/merc/ranged/suppressor
+
+//Machine Gun Merc
+/mob/living/simple_mob/humanoid/merc/ranged/space/heavy
+ name = "mercenary heavy gunner"
+ desc = "A tough looking individual armed with an light machinegun."
+ icon_state = "syndicatespace-heavy"
+ icon_living = "syndicatespace-heavy"
+ base_attack_cooldown = 2.5 // Four Attacks a Second. MOAR DAKKA
+ reload_max = 50
+ projectiletype = /obj/item/projectile/bullet/rifle/a545
+ projectilesound = 'sound/weapons/Gunshot_light.ogg'
+ loot_list = list(/obj/item/gun/projectile/automatic/l6_saw = 100)
+ ai_holder_type = /datum/ai_holder/simple_mob/merc/ranged/suppressor
+
+//Tommy-Las Merc
+/mob/living/simple_mob/humanoid/merc/ranged/space/tommylas
+ name = "mercenary light burster"
+ desc = "A tough looking individual armed with an automatic laser."
+ icon_state = "syndicatespace-tommylas"
+ icon_living = "syndicatespace-tommylas"
+ base_attack_cooldown = 2.5 // Four Attacks a Second. MOAR DAKKA
+ reload_max = 3
+ reload_time = 0.5 // Meant to Simulate controlled Supressive Bursts
+ projectiletype = /obj/item/projectile/beam/weaklaser
+ projectilesound = 'sound/weapons/Laser.ogg'
+ // loot_list = list(/obj/item/gun/energy/tommylaser = 100) // Downstream
+ ai_holder_type = /datum/ai_holder/simple_mob/merc/ranged/suppressor
+
+/mob/living/simple_mob/humanoid/merc/ranged/space/fal
+ name = "mercenary commando"
+ desc = "A tough looking individual armed with a assault rifle."
+ icon_state = "syndicatespace-commando"
+ icon_living = "syndicatespace-commando"
+ projectiletype = /obj/item/projectile/bullet/rifle/a762
+ projectilesound = 'sound/weapons/Gunshot_heavy.ogg'
+ // loot_list = list(/obj/item/gun/projectile/automatic/fal = 100)// Downstream
+ reload_max = 20
+
+/mob/living/simple_mob/humanoid/merc/ranged/space/suppressor // adminspawn only, and also Probably Going To Kill The Unprepared
+ name = "mercenary suppressor"
+ desc = "Geeze, weren't shotgun ops bad enough? At least when you fade these jerks you get a flashbang to the face."
+ icon_state = "syndi-ranged-space-sup"
+ icon_living = "syndi-ranged-space-sup"
+ armor = list(melee = 80, bullet = 65, laser = 50, energy = 15, bomb = 80, bio = 100, rad = 100) // this is the merc rig's stats
+ ai_holder_type = /datum/ai_holder/simple_mob/merc/ranged/suppressor
+ say_list_type = /datum/say_list/merc/elite
+ projectiletype = /obj/item/projectile/bullet/pistol/medium/ap/suppressor // it's high velocity
+ projectilesound = 'sound/weapons/doompistol.ogg' // converted from .wavs extracted from doom 2
+ base_attack_cooldown = 3 // three? attacks a second
+ reload_max = 30 // extended mags
+ special_attack_charges = 5
+ loot_list = list() // oh, you killed him?
+ corpse = null // well, sorry, buddy, he doesn't drop shit
+ catalogue_data = list(/datum/category_item/catalogue/fauna/mercenary/human/space/suppressor)
+
+/mob/living/simple_mob/humanoid/merc/ranged/space/suppressor/elite // really reconsider why you're spawning this dude
+ name = "mercenary elite suppressor"
+ desc = "Geeze, weren't normal suppressors bad enough? At least if you fade this jerk, you'll have an awful time anyway."
+ icon_state = "syndi-ranged-space-sup-elite"
+ icon_living = "syndi-ranged-space-sup-elite"
+ armor = list(melee = 80, bullet = 70, laser = 55, energy = 15, bomb = 80, bio = 100, rad = 100) // see code for military hardsuit
+ projectiletype = /obj/item/projectile/bullet/pistol/medium/ap/suppressor/turbo // fuck it, fast bullets
+ grenade_type = /obj/item/grenade/shooter/rubber // don't group up
+ grenade_timer = 30 // well, look what you've done, you've grouped up
+
+// being Actual Professionals, they have better (read: player-level) blocking chances
+/mob/living/simple_mob/humanoid/merc/ranged/space/suppressor/attackby(var/obj/item/O, var/mob/user)
+ if(O.force)
+ if(prob(50))
+ visible_message(span_danger("\The [src] blocks \the [O] with its shield!"))
+ if(user)
+ ai_holder.react_to_attack(user)
+ return
+ else
+ ..()
+ else
+ visible_message(span_warning("\The [user] gently taps [src] with \the [O]."))
+
+/mob/living/simple_mob/humanoid/merc/ranged/space/suppressor/bullet_act(var/obj/item/projectile/Proj)
+ if(!Proj) return
+ if(prob(50))
+ visible_message(span_warning("[src] blocks [Proj] with its shield!"))
+ if(Proj.firer)
+ ai_holder.react_to_attack(Proj.firer)
+ return
+ else
+ ..()
+
/mob/living/simple_mob/humanoid/merc/ranged/space/Process_Spacemove(var/check_drift = 0)
return
diff --git a/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/merd_catalogs.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/merd_catalogs.dm
new file mode 100644
index 0000000000..b1bafd0e35
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/merd_catalogs.dm
@@ -0,0 +1,80 @@
+/datum/category_item/catalogue/fauna/mercenary
+ name = "Mercenaries"
+ desc = "Life on the Frontier is hard, and unregulated. Unlike life in \
+ more 'civlized' areas of the Galaxy, violence and piracy remain common \
+ this far out. The Megacorporations keep a tight grip on their holdings, \
+ but there are always small bands or aspiring companies looking to make a \
+ thaler. From simple pirates to legitimate PMCs, Frontier mercs come in \
+ all shapes and sizes."
+ value = CATALOGUER_REWARD_TRIVIAL
+ unlocked_by_any = list(/datum/category_item/catalogue/fauna/mercenary)
+
+// Obtained by scanning all X.
+/datum/category_item/catalogue/fauna/all_mercenaries
+ name = "Collection - Mercenaries"
+ desc = "You have scanned a large array of different types of mercenary, \
+ and therefore you have been granted a large sum of points, through this \
+ entry."
+ value = CATALOGUER_REWARD_HARD
+ unlocked_by_all = list(
+ /datum/category_item/catalogue/fauna/mercenary/human,
+ /datum/category_item/catalogue/fauna/mercenary/human/peacekeeper,
+ /datum/category_item/catalogue/fauna/mercenary/human/grenadier,
+ /datum/category_item/catalogue/fauna/mercenary/human/space,
+ /datum/category_item/catalogue/fauna/mercenary/human/space/suppressor,
+ /datum/category_item/catalogue/fauna/mercenary/vox,
+ /datum/category_item/catalogue/fauna/mercenary/vox/boarder,
+ /datum/category_item/catalogue/fauna/mercenary/vox/technician,
+ /datum/category_item/catalogue/fauna/mercenary/vox/suppressor,
+ /datum/category_item/catalogue/fauna/mercenary/vox/captain
+ )
+
+/datum/category_item/catalogue/fauna/mercenary/human
+ name = "Mercenaries - Human"
+ desc = "Human Mercenary bands are extremely common on the Frontier. Many \
+ of the modern outfits operating on the fringe today are veterans of the \
+ Phoron Wars. After the dissolution of the Syndicate, these operatives were \
+ left without a place to call home. Those who have survived have leveraged \
+ their experience into a viable trade."
+ value = CATALOGUER_REWARD_EASY
+
+/datum/category_item/catalogue/fauna/mercenary/human/peacekeeper
+ name = "Mercenaries - Solar Peacekeeper"
+ desc = "Activist groups in Civlized Space often raise moral concerns about \
+ conditions on the Frontier. The more organized groups will sometimes gather \
+ bands of mercenaries from the core worlds together under the belief that they \
+ can come out to the Frontier to enforce their way of life. Due to the Frontier \
+ Act, these 'humanitarian operations' are quickly demolished."
+ value = CATALOGUER_REWARD_EASY
+
+/datum/category_item/catalogue/fauna/mercenary/human/grenadier
+ name = "Mercenaries - Grenadier"
+ desc = "After the Phoron Wars, many deniable operatives on both sides of \
+ the conflict found that there was no place for them within their home companies \
+ any more. Left without options, these highly motivated and trained specialists \
+ often seek revenge, or attempt to carve out their own fiefdoms. Well equipped \
+ and well trained, these outcasts are not to be taken lightly."
+ value = CATALOGUER_REWARD_EASY
+
+/datum/category_item/catalogue/fauna/mercenary/human/space
+ name = "Mercenaries - Commando"
+ desc = "Commandos, much like their less equipped brethren, are experts in \
+ wet work. Honing their skills over years of training, the Commando's iconic \
+ equipment summons memories of the bad old days in any survivor who sees them. \
+ These mercs make a statement with their equipment - 'I was there. Come get me.' \
+ It is usually not an idle boast."
+ value = CATALOGUER_REWARD_EASY
+
+// suppressors are just assholes and are intended to be a piss poor experience for everyone on both sides
+/datum/category_item/catalogue/fauna/mercenary/human/space/suppressor
+ name = "Mercenaries - Suppressor"
+ desc = "Just because the Phoron Wars are over, it doesn't mean that covert \
+ actions and corporate espionage ended too. When you encounter mercs with \
+ the latest gear and the best training, you can bet your bottom Thaler that \
+ they've got a Corporate sponsor backing them up."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/datum/ai_holder/simple_mob/merc/ranged/suppressor
+ respect_alpha = FALSE // he really just shoots you
+ vision_range = 10 // plutonia experience
+ conserve_ammo = FALSE
diff --git a/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/vox.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/vox.dm
new file mode 100644
index 0000000000..afc0225388
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/vox.dm
@@ -0,0 +1,236 @@
+////////////////////////////////
+// Vox Pirates
+////////////////////////////////
+//Classifying these as Mercs, due to the general power level I want them at.
+
+/datum/category_item/catalogue/fauna/mercenary/vox
+ name = "Mercenaries - Vox"
+ desc = "For centuries the Vox have inflicted their way of life upon the \
+ Galaxy. Regarded with distrust due to their tendency to engage in piracy \
+ and violence, the Vox are equally feared for their robust physiology and \
+ curiously advanced xenotech. Due to ancient compacts, Vox pirates try to \
+ avoid bloodshed, but will react to violence in kind."
+ value = CATALOGUER_REWARD_MEDIUM
+ unlocked_by_any = list(/datum/category_item/catalogue/fauna/mercenary/vox)
+
+/mob/living/simple_mob/humanoid/merc/voxpirate //Don't use this one.
+ name = "vox mannequin"
+ desc = "You shouldn't be seeing this one."
+ icon_state = "voxpirate"
+ icon_living = "voxpirate"
+ icon_dead = "voxpirate_dead"
+
+ faction = "voxpirate"
+ movement_cooldown = 4
+
+ status_flags = 0
+
+ response_help = "pokes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+ harm_intent_damage = 5
+ melee_damage_lower = 20 //Vox Hunting rifle blade damage
+ melee_damage_upper = 20
+ attack_sharp = 1
+ attack_edge = 1
+ attacktext = list("slashed", "stabbed")
+ armor = list(melee = 60, bullet = 50, laser = 30, energy = 15, bomb = 35, bio = 100, rad = 100) // Matching Merc voidsuit stats to represent toughness.
+
+ min_oxy = 0 //Vox are spaceproof.
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+
+ corpse = /obj/effect/landmark/mobcorpse/vox/pirate
+ loot_list = list(/*/obj/item/gun/projectile/shotgun/pump/rifle/vox_hunting = 100, Downstream */
+ /obj/item/ammo_magazine/clip/c762 = 30,
+ /obj/item/ammo_magazine/clip/c762 = 30
+ )
+
+ ai_holder_type = /datum/ai_holder/simple_mob/merc
+ say_list_type = /datum/say_list/merc/voxpirate
+
+/mob/living/simple_mob/humanoid/merc/voxpirate/pirate
+ name = "vox pirate"
+ desc = "A desperate looking Vox. Get your gun."
+
+ projectiletype = /obj/item/projectile/bullet/rifle/a762
+ projectilesound = 'sound/weapons/riflebolt.ogg'
+ needs_reload = TRUE
+ reload_max = 20
+
+////////////////////////////////
+// Vox Melee
+////////////////////////////////
+
+/datum/category_item/catalogue/fauna/mercenary/vox/boarder
+ name = "Mercenaries - Vox Boarder"
+ desc = "Vox are squat creatures, with powerful muscles and tough, scaly \
+ hides. Their dense bones and sharp talons make them a formidable threat in \
+ close quarters combat. Low level Vox weaponry generally emphasizes closing \
+ the distance to exploit these facts."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/mob/living/simple_mob/humanoid/merc/voxpirate/boarder
+ name = "vox melee boarder"
+ desc = "A howling Vox with a sword. Run."
+ icon_state = "voxboarder_m"
+ icon_living = "voxboarder_m"
+ icon_dead = "voxboarder_m_dead"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/mercenary/vox/boarder)
+
+ melee_damage_lower = 30 //Energy sword damage
+ melee_damage_upper = 30
+ attack_sharp = 1
+ attack_edge = 1
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive
+ corpse = /obj/effect/landmark/mobcorpse/vox/boarder_m
+ loot_list = list(/obj/item/melee/energy/sword = 100)
+
+// They're good with the swords? I dunno. I like the idea they can deflect.
+/mob/living/simple_mob/humanoid/merc/voxpirate/boarder/attackby(var/obj/item/O, var/mob/user)
+ if(O.force)
+ if(prob(20))
+ visible_message(span_danger("\The [src] blocks \the [O] with its sword!"))
+ if(user)
+ ai_holder.react_to_attack(user)
+ return
+ else
+ ..()
+ else
+ to_chat(user, span_warning("This weapon is ineffective, it does no damage."))
+ visible_message(span_warning("\The [user] gently taps [src] with \the [O]."))
+
+/mob/living/simple_mob/humanoid/merc/voxpirate/boarder/bullet_act(var/obj/item/projectile/Proj)
+ if(!Proj) return
+ if(prob(35))
+ visible_message(span_warning("[src] blocks [Proj] with its sword!"))
+ if(Proj.firer)
+ ai_holder.react_to_attack(Proj.firer)
+ return
+ else
+ ..()
+
+////////////////////////////////
+// Vox Ranged
+////////////////////////////////
+
+/mob/living/simple_mob/humanoid/merc/voxpirate/boarder
+ name = "vox ranged boarder"
+ desc = "A howling Vox with a shotgun. Get to cover!"
+ icon_state = "voxboarder_r"
+ icon_living = "voxboarder_r"
+ icon_dead = "voxboarder_r_dead"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/mercenary/vox/boarder)
+
+ projectiletype = /obj/item/projectile/bullet/pellet/shotgun
+ projectilesound = 'sound/weapons/Gunshot_shotgun.ogg'
+
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged/aggressive
+ corpse = /obj/effect/landmark/mobcorpse/vox/boarder_r
+ loot_list = list(/obj/item/gun/projectile/shotgun/pump/combat = 100,
+ /obj/item/ammo_magazine/m12gdrum = 30,
+ /obj/item/ammo_magazine/m12gdrum = 30
+ )
+
+ needs_reload = TRUE
+ reload_max = 10
+
+/datum/category_item/catalogue/fauna/mercenary/vox/technician
+ name = "Mercenaries - Vox Technician"
+ desc = "The belief that Vox are unintelligent comes largely from a kind \
+ of anthrochauvanism. Due to their difficulty speaking GalCom and their tendency \
+ to resort to underhanded methods, the Galaxy sees Vox as brutal, unintelligent \
+ aliens. In reality, Vox are just as intelligent as everyone else, as the state \
+ of their technology shows. Vox Technicians maintain ancient vessels and tools \
+ with scraps and odd bits, often recieving no external recognition for their work."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/mob/living/simple_mob/humanoid/merc/voxpirate/technician
+ name = "vox salvage technician"
+ desc = "A screeching Vox with an ion rifle. Usually sent on scrapping operations."
+ icon_state = "voxboarder_t"
+ icon_living = "voxboarder_t"
+ icon_dead = "voxboarder_t_dead"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/mercenary/vox/technician)
+
+ projectiletype = /obj/item/projectile/ion
+ projectilesound = 'sound/weapons/Laser.ogg'
+
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged/kiting
+ corpse = /obj/effect/landmark/mobcorpse/vox/boarder_t
+ loot_list = list(/obj/item/gun/energy/ionrifle)
+
+ needs_reload = TRUE
+ reload_max = 25 //Suppressive tech weapon.
+
+/datum/category_item/catalogue/fauna/mercenary/vox/suppressor
+ name = "Mercenaries - Vox Suppressor"
+ desc = "Among Vox bands, Suppressors are an even more motley crew. \
+ Staying true to the name, Suppressors are veteran Vox pirates who have \
+ faced hundreds of engagements. Tough and well suited for violence, these \
+ Vox wear bright, mismatching colors into battle to draw attention. Serving \
+ as a beacon to draw eyes away from their companions, Suppressors wield the \
+ fearsome Sonic Cannon - a booming directed frequency device capable of \
+ wreaking havoc all its own. It doesn't sound half bad either, when it isn't \
+ pointed at you."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/mob/living/simple_mob/humanoid/merc/voxpirate/ranged/suppressor
+ name = "vox suppressor"
+ desc = "Come on, feel the noise!"
+ icon_state = "voxsuppressor"
+ icon_living = "voxsuppressor"
+ icon_dead = "voxsuppresor_dead"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/mercenary/vox/suppressor)
+
+ armor = list(melee = 30, bullet = 50, laser = 60, energy = 30, bomb = 35, bio = 100, rad = 100) // Boosted armor to represent Tank role.
+
+ projectiletype = /obj/item/projectile/sonic/weak
+ projectilesound = 'sound/effects/basscannon.ogg'
+
+ ai_holder_type = /datum/ai_holder/simple_mob/destructive
+ corpse = /obj/effect/landmark/mobcorpse/vox/suppressor
+ loot_list = list(/obj/item/gun/energy/sonic = 100)
+
+ base_attack_cooldown = 5 // Two attacks a second or so.
+ needs_reload = TRUE
+ reload_max = 30 //Gotta lay down that fire, son.
+
+/datum/category_item/catalogue/fauna/mercenary/vox/captain
+ name = "Mercenaries - Vox Captain"
+ desc = "Accomplished Vox who bring in scrap reliably eventually become the \
+ 'Quills' of their own expeditions. This Vox term is considered analagous to \
+ the word 'Captain'. As such, any Vox who has attained this rank has certainly \
+ earned the powerful equipment they carry into combat: Dark Matter cannons, \
+ advanced armor, proper Hunting Rifles - the list goes on. The Vox Captain \
+ is a formidable opponent, honed by years of hard living and harder fighting. \
+ If you are unable to negotiate, expect to face their entire crew head on."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/mob/living/simple_mob/humanoid/merc/voxpirate/ranged/captain
+ name = "vox pirate captain"
+ desc = "Walkings the plank, dustlung! Yayaya."
+ icon_state = "voxcaptain"
+ icon_living = "voxcaptain"
+ icon_dead = "voxcaptain_dead"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/mercenary/vox/captain)
+
+ armor = list(melee = 60, bullet = 50, laser = 40, energy = 15, bomb = 30, bio = 100, rad = 100) // Vox RIG armor values.
+
+ projectiletype = /obj/item/projectile/beam/darkmatter
+ projectilesound = 'sound/weapons/eLuger.ogg'
+
+ ai_holder_type = /datum/ai_holder/simple_mob/destructive
+ corpse = /obj/effect/landmark/mobcorpse/vox/captain
+ loot_list = list(/obj/item/gun/energy/darkmatter = 100)
+
+ needs_reload = TRUE
+ reload_max = 15 //Other Vox should be carrying ammo.
diff --git a/code/modules/mob/living/simple_mob/subtypes/humanoid/pirates.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/pirates.dm
index 448b5a83b4..9e0d37bf47 100644
--- a/code/modules/mob/living/simple_mob/subtypes/humanoid/pirates.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/pirates.dm
@@ -1,10 +1,29 @@
+///////////////////////////////
+// Yargh Yargh Fiddle De Di
+///////////////////////////////
+
+/datum/category_item/catalogue/fauna/pirate
+ name = "Pirates"
+ desc = "Life on the Frontier is often harsh, and there are many \
+ natural hazards which must be navigated and accounted for. In the \
+ face of such constant adversity, some colonists will resort to crime \
+ and piracy to try and make their way. From misguided attempts at \
+ survival to malicious profiteering, Piracy is a constant concern \
+ on the Frontier, and is punished harshly by every Megacorporation."
+ value = CATALOGUER_REWARD_TRIVIAL
+
+///////////////////////////////
+// Knife Priate
+///////////////////////////////
/mob/living/simple_mob/humanoid/pirate
name = "Pirate"
desc = "Does what he wants cause a pirate is free."
tt_desc = "E Homo sapiens"
+ icon = 'icons/mob/pirates.dmi'
icon_state = "piratemelee"
icon_living = "piratemelee"
icon_dead = "piratemelee_dead"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/pirate)
faction = FACTION_PIRATE
@@ -12,29 +31,475 @@
response_disarm = "shoves"
response_harm = "hits"
+ movement_cooldown = 2
+
harm_intent_damage = 5
- melee_damage_lower = 30
- melee_damage_upper = 30
- attack_armor_pen = 30
- attack_sharp = TRUE
+ melee_damage_lower = 15 //Tac Knife damage
+ melee_damage_upper = 15
+ attack_sharp = 1
attack_edge = 1
- attacktext = list("slashed")
+ attacktext = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
attack_sound = 'sound/weapons/bladeslice.ogg'
- loot_list = list(/obj/item/melee/energy/sword/pirate = 100)
+ loot_list = list(/obj/item/material/knife/tacknife = 100)
corpse = /obj/effect/landmark/mobcorpse/pirate
+ ai_holder_type = /datum/ai_holder/simple_mob/merc
+ say_list_type = /datum/say_list/pirate
+
+/mob/living/simple_mob/humanoid/pirate/Initialize(mapload)
+ . = ..()
+ loot_list += list(/obj/item/salvage/loot/pirate = 35)
+
+//Armored Variant
+
+/mob/living/simple_mob/humanoid/pirate/armored
+ name = "Armored Pirate"
+ desc = "Does what he wants cause a pirate is free. This one wears crude armor."
+ icon_state = "piratemelee-armor"
+ icon_living = "piratemelee-armor"
+ movement_cooldown = 4
+ armor = list(melee = 30, bullet = 20, laser = 20, energy = 5, bomb = 5, bio = 100, rad = 100)
+ loot_list = list(/obj/item/material/knife/tacknife = 100, /obj/item/clothing/suit/armor/material/makeshift = 100)
+
+///////////////////////////////
+// Machete Priate
+///////////////////////////////
+
+/mob/living/simple_mob/humanoid/pirate/machete
+ name = "Pirate Brush Cutter"
+ desc = "Does what he wants cause a pirate is free. This one has got a machete."
+ tt_desc = "E Homo sapiens"
+ icon_state = "piratemelee-machete"
+ icon_living = "piratemelee-machete"
+ icon_dead = "piratemelee_dead"
+
+ response_help = "pushes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+
+ melee_damage_lower = 25 //Macehte damage
+ melee_damage_upper = 25
+
+ attacktext = list("slashed", "chopped", "gouged", "ripped", "cut")
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+
+ loot_list = list(/obj/item/material/knife/machete = 100)
+
+ corpse = /obj/effect/landmark/mobcorpse/pirate
+
+//Armored Variant
+
+/mob/living/simple_mob/humanoid/pirate/machete/armored
+ name = "Armored Brush Cutter"
+ desc = "Does what he wants cause a pirate is free. This one has got a machete and wears crude armor."
+ icon_state = "piratemelee-machete-armor"
+ icon_living = "piratemelee-machete-armor"
+ movement_cooldown = 3
+ armor = list(melee = 30, bullet = 20, laser = 20, energy = 5, bomb = 5, bio = 100, rad = 100)
+ loot_list = list(/obj/item/material/knife/machete = 100, /obj/item/clothing/suit/armor/material/makeshift = 100)
+
+///////////////////////////////
+// E-Sword Priate
+///////////////////////////////
+
+/mob/living/simple_mob/humanoid/pirate/las
+ name = "Pirate Duelist"
+ desc = "Does what he wants cause a pirate is free. This one has a energy sword."
+ tt_desc = "E Homo sapiens"
+ icon_state = "piratemelee-las"
+ icon_living = "piratemelee-las"
+ icon_dead = "piratemelee_dead"
+
+ melee_damage_lower = 30 //E-Sword Damage
+ melee_damage_upper = 30
+ attack_armor_pen = 50
+
+ attack_sound = 'sound/weapons/blade1.ogg'
+
+
+ loot_list = list(/obj/item/melee/energy/sword/pirate = 100)
+
+//Armored Variant
+/mob/living/simple_mob/humanoid/pirate/las/armored
+ name = "Armored Duelist"
+ desc = "Does what he wants cause a pirate is free. This one has an energy sword."
+ icon_state = "piratemelee-las-armor"
+ icon_living = "piratemelee-las-armor"
+ movement_cooldown = 4
+ armor = list(melee = 30, bullet = 20, laser = 20, energy = 5, bomb = 5, bio = 100, rad = 100)
+ loot_list = list(/obj/item/melee/energy/sword/pirate = 100, /obj/item/clothing/suit/armor/material/makeshift = 100)
+
+
+///////////////////////////////
+// Shield Pirate
+///////////////////////////////
+/mob/living/simple_mob/humanoid/pirate/shield
+ name = "Pirate Buckler"
+ desc = "Does what he wants cause a pirate is free. This one carries a shield for added protection."
+ icon_state = "piratemelee-shield"
+ icon_living = "piratemelee-shield"
+
+//This Should Allow all childs of the shield priate to block
+/mob/living/simple_mob/humanoid/pirate/shield/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ if(O.force)
+ if(prob(15))
+ visible_message(span_danger("\The [src] blocks \the [O] with its shield!"))
+ if(user)
+ ai_holder.react_to_attack(user)
+ return
+ else
+ ..()
+ else
+ to_chat(user, span_warning("This weapon is ineffective, it does no damage."))
+ visible_message(span_warning("\The [user] gently taps [src] with \the [O]."))
+
+/mob/living/simple_mob/humanoid/merc/melee/sword/bullet_act(var/obj/item/projectile/Proj)
+ if(!Proj) return
+ if(prob(25))
+ visible_message(span_bolddanger("[src] blocks [Proj] with its shield!"))
+ if(Proj.firer)
+ ai_holder.react_to_attack(Proj.firer)
+ return
+ else
+ ..()
+
+// Armored Variant
+/mob/living/simple_mob/humanoid/pirate/shield/armored
+ name = "Armored Buckler"
+ desc = "Does what he wants cause a pirate is free. This carries a shield and wears crude armor."
+ icon_state = "piratemelee-shield-armor"
+ icon_living = "piratemelee-shield-armor"
+ movement_cooldown = 3
+ armor = list(melee = 30, bullet = 20, laser = 20, energy = 5, bomb = 5, bio = 100, rad = 100)
+ loot_list = list(/obj/item/material/knife/tacknife = 100, /obj/item/clothing/suit/armor/material/makeshift = 100)
+
+///////////////////////////////
+// Shield Machete Pirate
+///////////////////////////////
+
+/mob/living/simple_mob/humanoid/pirate/shield/machete
+ name = "Pirate Sword and Boarder"
+ desc = "Does what he wants cause a pirate is free. This one has got a machete and a shield."
+ icon_state = "piratemelee-shield-machete"
+ icon_living = "piratemelee-shield-machete"
+ icon_dead = "piratemelee_dead"
+
+ response_help = "pushes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+
+ melee_damage_lower = 25 //Macehte damage
+ melee_damage_upper = 25
+
+ attacktext = list("slashed", "chopped", "gouged", "ripped", "cut")
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+
+ loot_list = list(/obj/item/material/knife/machete = 100)
+
+// Armored Variant
+/mob/living/simple_mob/humanoid/pirate/shield/machete/armored
+ name = "Armored Sword and Boarder"
+ desc = "Does what he wants cause a pirate is free. This one is equipped old fashioned sword and shield along with crude armor."
+ icon_state = "piratemelee-shield-machete-armor"
+ icon_living = "piratemelee-shield-machete-armor"
+ movement_cooldown = 4
+ armor = list(melee = 30, bullet = 20, laser = 20, energy = 5, bomb = 5, bio = 100, rad = 100)
+ loot_list = list(/obj/item/material/knife/machete = 100, /obj/item/clothing/suit/armor/material/makeshift = 100)
+
+
+
+
+
+///////////////////////////////
+// Pirate Pistolier
+///////////////////////////////
+
/mob/living/simple_mob/humanoid/pirate/ranged
- name = "Pirate Gunner"
+ name = "Pirate Pistolier"
+ desc = "Does what he wants since a pirate is free. This one is armed with a zip gun."
icon_state = "pirateranged"
icon_living = "pirateranged"
icon_dead = "piratemelee_dead"
- projectiletype = /obj/item/projectile/beam
- projectilesound = 'sound/weapons/laser.ogg'
+ reload_time = 4 SECONDS // ZipGuns are finicky an hard to load
+ needs_reload = TRUE
+ reload_max = 1
- loot_list = list(/obj/item/gun/energy/laser = 100)
+ projectiletype = /obj/item/projectile/bullet/shotgun
+ projectilesound = 'sound/weapons/weaponsounds_shotgunshot.ogg'
+
+ loot_list = list(/obj/item/gun/projectile/pirate = 100, /obj/item/material/knife/tacknife = 100)
+
+ ai_holder_type = /datum/ai_holder/simple_mob/merc/ranged
+
+
+//Armored Variant
+/mob/living/simple_mob/humanoid/pirate/ranged/armored
+ name = "Armored Pistolier"
+ desc = "Does what he wants cause a pirate is free. This is armed with a zip gun and wears crude armor."
+ icon_state = "pirateranged-armor"
+ icon_living = "pirateranged-armor"
+ movement_cooldown = 4
+ armor = list(melee = 30, bullet = 20, laser = 20, energy = 5, bomb = 5, bio = 100, rad = 100)
+ loot_list = list(/obj/item/material/knife/tacknife = 100, /obj/item/gun/projectile/pirate = 100, /obj/item/clothing/suit/armor/material/makeshift = 100)
+
+///////////////////////////////
+// Pirate Blunderbuster
+///////////////////////////////
+
+/mob/living/simple_mob/humanoid/pirate/ranged/shotgun
+ name = "Pirate Blunderbuster"
+ desc = "Does what he wants since a pirate is free. This one has a sawn off shotgun."
+ icon_state = "pirateranged-blunder"
+ icon_living = "pirateranged-blunder"
+ icon_dead = "piratemelee_dead"
+
+ reload_time = 3 SECONDS // Shotgun Reload
+ needs_reload = TRUE
+ reload_max = 2
+
+ projectiletype = /obj/item/projectile/bullet/pellet/shotgun
+ projectilesound = 'sound/weapons/weaponsounds_shotgunshot.ogg'
+
+ loot_list = list(/obj/item/gun/projectile/shotgun/doublebarrel/sawn = 100, /obj/item/material/knife/tacknife = 100)
+
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged/aggressive
+
+//Armored Variant
+/mob/living/simple_mob/humanoid/pirate/ranged/shotgun/armored
+ name = "Armored Blunderbuster"
+ desc = "Does what he wants cause a pirate is free. This is armed with a sawn off shotgun and wears crude armor."
+ icon_state = "pirateranged-blunder-armor"
+ icon_living = "pirateranged-blunder-armor"
+ movement_cooldown = 4
+ armor = list(melee = 30, bullet = 20, laser = 20, energy = 5, bomb = 5, bio = 100, rad = 100)
+ loot_list = list(/obj/item/material/knife/tacknife = 100, /obj/item/gun/projectile/shotgun/doublebarrel/sawn = 100, /obj/item/clothing/suit/armor/material/makeshift = 100)
+
+///////////////////////////////
+// Pirate Ziplas
+///////////////////////////////
+
+/mob/living/simple_mob/humanoid/pirate/ranged/handcannon
+ name = "Pirate Handcannon"
+ desc = "Does what he wants since a pirate is free. This one has an improvised laser pistol."
+ icon_state = "pirateranged-handcannon"
+ icon_living = "pirateranged-handcannon"
+ icon_dead = "piratemelee_dead"
+
+ reload_time = 6 SECONDS //Zip-Las takes a real long time to reload.
+ needs_reload = TRUE
+ reload_max = 1
+
+ projectiletype = /obj/item/projectile/beam/heavylaser
+ projectilesound = 'sound/weapons/weaponsounds_laserstrong.ogg'
+
+ loot_list = list(/obj/item/gun/energy/zip = 100, /obj/item/material/knife/tacknife = 100)
+
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged/aggressive
+
+//Armored Variant
+/mob/living/simple_mob/humanoid/pirate/ranged/handcannon/armored
+ name = "Armored Handcannon"
+ desc = "Does what he wants cause a pirate is free. This one has a improvised laser pistol and crude armor."
+ icon_state = "pirateranged-handcannon-armor"
+ icon_living = "pirateranged-handcannon-armor"
+ movement_cooldown = 4
+ armor = list(melee = 30, bullet = 20, laser = 20, energy = 5, bomb = 5, bio = 100, rad = 100)
+ loot_list = list(/obj/item/material/knife/tacknife = 100, /obj/item/gun/energy/zip = 100, /obj/item/clothing/suit/armor/material/makeshift = 100)
+
+///////////////////////////////
+// First Mate
+///////////////////////////////
+/mob/living/simple_mob/humanoid/pirate/mate
+ name = "First Mate"
+ desc = "A leading figure amongst the pirate hoards. This one is armed with a laser cutlass"
+ tt_desc = "E Homo sapiens"
+ icon_state = "mate"
+ icon_living = "mate"
+ icon_dead = "piratemelee_dead"
+
+ melee_damage_lower = 30 //E-Sword Damage
+ melee_damage_upper = 30
+ attack_armor_pen = 50
+
+ attack_sound = 'sound/weapons/blade1.ogg'
+
+ armor = list(melee = 30, bullet = 20, laser = 20, energy = 5, bomb = 5, bio = 100, rad = 100)
+
+ loot_list = list(/obj/item/melee/energy/sword/pirate = 100, /obj/item/clothing/suit/pirate = 100)
+
+
+///////////////////////////////
+// Mate Pistolier
+///////////////////////////////
+/mob/living/simple_mob/humanoid/pirate/mate/ranged
+ name = "Mate Pistolier"
+ desc = "A leading figure amongst the pirate hoards. This one is armed with a obsolete laser pistol."
+ icon_state = "mate-pistoler"
+ icon_living = "mate-pistoler"
+ icon_dead = "piratemelee_dead"
+
+ reload_time = 2 SECONDS //Retro Energy Pistol is far easier to reload than Zip-Las
+ needs_reload = TRUE
+ reload_max = 5
+
+ harm_intent_damage = 5
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+
+ projectiletype = /obj/item/projectile/beam/midlaser
+ projectilesound = 'sound/weapons/weaponsounds_lasermid.ogg'
+
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ base_attack_cooldown = 10
+
+ loot_list = list(/obj/item/gun/energy/retro = 100, /obj/item/clothing/suit/pirate = 100)
+
+ ai_holder_type = /datum/ai_holder/simple_mob/merc/ranged
+
+/mob/living/simple_mob/humanoid/pirate/mate/ranged/bosun /// Special Mech Pilot Pirate
+ name = "Bosun"
+ desc = "An oily pirate mechanist. Thankfully he has but an old laser to defend himself with."
+ icon_state = "bosun"
+ icon_living = "bosun"
+ movement_cooldown = 3
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged/aggressive/blood_hunter // This is for use in the Pirate Ripley Mecha
+
+ loot_list = list(/obj/item/gun/energy/retro = 100, /obj/item/clothing/head/welding = 100, /obj/item/clothing/suit/pirate = 100)
+
+///////////////////////////////
+// Mate Sweeper
+///////////////////////////////
+
+/mob/living/simple_mob/humanoid/pirate/mate/ranged/shotgun
+ name = "Mate Blunderbuster"
+ desc = "A leading figure amongst the pirate hoards. This one is armed with a four barreled shotgun"
+ icon_state = "mate-shotgun"
+ icon_living = "mate-shotgun"
+ icon_dead = "piratemelee_dead"
+
+ reload_time = 4 SECONDS //Assume use of speedloaders
+ needs_reload = TRUE
+ reload_max = 4
+
+ harm_intent_damage = 5
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+
+ projectiletype = /obj/item/projectile/bullet/pellet/shotgun
+ projectilesound = 'sound/weapons/weaponsounds_shotgunshot.ogg'
+ base_attack_cooldown = 5
+
+ loot_list = list(/*/obj/item/gun/projectile/shotgun/doublebarrel/quad = 100, Downstream*/ /obj/item/clothing/suit/pirate = 100)
+
+///////////////////////////////
+// Mate Marksman
+///////////////////////////////
+
+/mob/living/simple_mob/humanoid/pirate/mate/ranged/rifle
+ name = "Mate Marksman"
+ desc = "A leading figure amongst the pirate hoards. This one is armed with a rifle."
+ icon_state = "mate-rifle"
+ icon_living = "mate-rifle"
+ icon_dead = "piratemelee_dead"
+
+ reload_time = 1.5 SECONDS //Assume use of speedloaders
+ needs_reload = TRUE
+ reload_max = 5
+
+ harm_intent_damage = 5
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+
+ projectiletype = /obj/item/projectile/bullet/rifle/a762
+ projectilesound = 'sound/weapons/weaponsounds_heavyrifleshot.ogg'
+ base_attack_cooldown = 10
+
+ loot_list = list(/obj/item/gun/projectile/shotgun/pump/rifle = 100, /obj/item/clothing/suit/pirate = 100)
+
+///////////////////////////////
+// Pirate Captain
+///////////////////////////////
+/mob/living/simple_mob/humanoid/pirate/captain
+ name = "Pirate Captain"
+ desc = "Leader of a Pirate Vessel armed with an entire belt of improvised laser pistols. A true villian indeed."
+ icon_state = "captain"
+ icon_living = "captain"
+ icon_dead = "pirateranged_dead"
+
+ reload_time = 10 SECONDS // I mean its a belt of pistols not exactly easy to reload. Especially with how much damage the barage does.
+ needs_reload = TRUE
+ reload_max = 4
+ projectiletype = /obj/item/projectile/beam/heavylaser
+ projectilesound = 'sound/weapons/weaponsounds_laserstrong.ogg'
+ base_attack_cooldown = 5
corpse = /obj/effect/landmark/mobcorpse/pirate/ranged
+
+ loot_list = list(/obj/item/gun/energy/zip = 100, /obj/item/gun/energy/zip = 100, /obj/item/gun/energy/zip = 100, /obj/item/gun/energy/zip = 100) //Belt of pistols
+
+ var/obj/item/shield_projector/shields = null
+
+/mob/living/simple_mob/humanoid/pirate/captain/Initialize(mapload)
+ shields = new /obj/item/shield_projector/rectangle/automatic/drone(src)
+ return ..()
+
+/mob/living/simple_mob/humanoid/pirate/captain/Process_Spacemove(var/check_drift = 0)
+ return TRUE
+
+/obj/item/shield_projector/rectangle/automatic/drone
+ shield_health = 150
+ max_shield_health = 150
+ shield_regen_delay = 10 SECONDS
+ shield_regen_amount = 10
+ size_x = 1
+ size_y = 1
+
+
+
+/mob/living/simple_mob/mechanical/mecha/ripley/pirate
+ name = "Hull Ripper"
+ desc = "A Ripley modified by pirates. Sports additional riveted armor plating and a jury rigged machine gun in addition to its hull piercing drill."
+ catalogue_data = list(/datum/category_item/catalogue/technology/ripley)
+ icon = 'icons/mob/pirates.dmi'
+ icon_state = "pirate"
+ faction = "pirate"
+ wreckage = /obj/structure/loot_pile/mecha/ripley/pirate
+
+ maxHealth = 250
+ heat_resist = 1
+ armor = list(
+ "melee" = 30,
+ "bullet" = 40,
+ "laser" = 50,
+ "energy" = 5,
+ "bomb" = 50,
+ "bio" = 100,
+ "rad" = 100
+ )
+
+ projectiletype = /obj/item/projectile/bullet/pistol
+ base_attack_cooldown = 0.5 SECONDS
+ needs_reload = TRUE
+ reload_max = 30
+ reload_time = 3
+
+/mob/living/simple_mob/mechanical/mecha/ripley/pirate/manned
+ pilot_type = /mob/living/simple_mob/humanoid/pirate/mate/ranged/bosun
+
+/mob/living/simple_mob/mechanical/mecha/ripley/pirate/last_stand_merc //Special version used as a quasi boss fight
+ name = "Xeno Ripper"
+ desc = "A Ripley modified by a desperate merc. It sports additional riveted armor plating splattered with dried xeno blood and a jury rigged machine gun in addition to its drill.\
+ A repair drone flits around the intimidating mech."
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged/aggressive
+ maxHealth = 170 //Less Health
+ has_repair_droid = TRUE //But has repair drone
+ pilot_type = /mob/living/simple_mob/humanoid/possessed/merc/feral //Possessed rig suit piloting a mech. Tremble in fear
+ movement_shake_radius = 5
diff --git a/code/modules/mob/living/simple_mob/subtypes/humanoid/possessed.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/possessed.dm
new file mode 100644
index 0000000000..a4da833476
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/possessed.dm
@@ -0,0 +1,159 @@
+//Rig-Suits with AI or supernatural forces controlling them, a dead person inside.
+//The base is based off of the EVA Rig.
+//todo: Add catalogue data.
+
+/mob/living/simple_mob/humanoid/possessed
+ name = "old EVA RIG suit"
+ desc = "A light hardsuit for repairs and maintenance to the outside of habitats and vessels. Seems to be worn down and damaged. But it seems to still be moving. Is someone in it?"
+ icon = 'icons/mob/possessed.dmi'
+ icon_state = "eva-rig"
+
+ faction = "Possessed"
+ movement_cooldown = 10
+
+ health = 200
+ maxHealth = 200
+ taser_kill = 0
+
+ var/idle = 4 //how long between the breathing sounds, in seconds.
+ var/silenced = 0 //Wither or not the sounds and speaking will play.
+
+ //It's a RIG. It's spaceproof.
+ 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
+
+ harm_intent_damage = 1
+ melee_damage_lower = 10
+ melee_damage_upper = 25
+ attacktext = list("punched", "kicked", "smacked")
+ attack_sound = "punch"
+ armor = list(melee = 30, bullet = 10, laser = 20,energy = 25, bomb = 20, bio = 100, rad = 100) //This should be the same as the base RIG.
+
+ has_hands = 1
+ humanoid_hands = 1
+
+ grab_resist = 100
+
+ movement_sound = 'sound/effects/footstep/floor1.ogg'
+
+ //Simple mob merc so it stops, says something, then charges.
+ ai_holder_type = /datum/ai_holder/simple_mob/merc
+ say_list_type = /datum/say_list/possessed //Set to Null on silenced.
+
+ can_pain_emote = FALSE
+
+// corpse = /obj/effect/landmark/mobcorpse/possessed
+// Will eventually leave a full corpse with an activated RIG on it. But not yet.
+
+//Miasma Cloud "Item"
+/obj/item/grenade/chem_grenade/miasma
+ name = "Miasma Bomb"
+ desc = "You probably shouldn't be able to see this."
+ stage = 2
+ path = 1
+
+/obj/item/grenade/chem_grenade/miasma/Initialize(mapload)
+ . = ..()
+ var/obj/item/reagent_containers/glass/beaker/B1 = new(src)
+ var/obj/item/reagent_containers/glass/beaker/B2 = new(src)
+
+ B1.reagents.add_reagent(REAGENT_ID_MIASMA, 30)
+ B1.reagents.add_reagent(REAGENT_ID_POTASSIUM, 5)
+ B2.reagents.add_reagent(REAGENT_ID_SUGAR, 5)
+ B2.reagents.add_reagent(REAGENT_ID_PHOSPHORUS, 5)
+
+ beakers += B1
+ beakers += B2
+
+ icon_state = null
+
+ detonate()
+
+//Has a chance to play one of the listed sounds when it moves.
+/mob/living/simple_mob/humanoid/possessed/Moved()
+ . = ..()
+ if(prob(5) && silenced == 0)
+ playsound(src, pick('sound/h_sounds/headcrab.ogg', 'sound/h_sounds/holla.ogg', 'sound/h_sounds/lynx.ogg', 'sound/h_sounds/mumble.ogg', 'sound/h_sounds/yell.ogg'), 50, 1)
+
+//Plays the sound every ~4 seconds.
+/mob/living/simple_mob/humanoid/possessed/Life()
+ if(idle <= 0 && silenced == 0)
+ playsound(src, 'sound/h_sounds/breathing.ogg', 60, 1)
+ idle = 4
+ idle--
+
+//Dies with a variety of messages, a disgusting sound, then drops the control module, bones, blood, gibs, and a cloud of miasma.
+/mob/living/simple_mob/humanoid/possessed/Destroy()
+ var/droploc = get_turf(src)
+ playsound(src, 'sound/effects/blobattack.ogg', 40, 1)
+ visible_message(span_critical(pick("The horrid screech of metal grating metal cuts through the air as the suit's interlocking joints grind and fold inwards upon itself. A putrid wash of decayed flesh spills forwards, staining the ground dark with the contents of the collapsing RIG's long expired pilot.",
+ "\The [src] shudders as some hurt living thing, reeling as screaming servos overcompensate beneath the weight of that debilitating strike - the horrid sounds of shattered metal resonate as the RIG rips itself apart. Limbs flung about in distinctly inhuman motions in a final failed effort at balance before buckling inwards at the joints, hydraulic fluid jettisoned as blood from a severed artery as the long liquidized contents of the suit's ex-pilot spill from its chassis in a thick slurry.",
+ "Hissing atmosphereic valves pop and snap, breaking the ageless seal as the putrid stench of rot and carrion assaults the senses in debilitating waves. The damaged RIG's visor alight with warnings of hazardous atmospheric conditions as a final distorted scream echos from within the damaged chassis. The fetid miasma that breeches through those wheezing seals overtaken by a wet burble and plop as the suit is bathed in the liquid contents of its passenger, blackened flesh fed through those narrow seals as rotten grounds.",
+ "The timeworn suit's seals finally crack open with a hiss - spilling forth a thick fungal mist. The control module ejects from the rig as it loses all control impulses - leaving behind but a pile of bones and the rotten sludge it had been swimming in for heaven knows how long.",
+ "\The [src]'s emergency protocols kick in, retracting around the former-person, who's now little more than a disgusting pile of parts not even a vulture would want. The control module appears to be intact, however.",
+ "The suit finally lets go of the prisoner it had held for so long. Unfortunately, this guy reminds you of that news report of someone who forgot that Ganymede rock lobster in a fridge for a year, the thick miasma of fungi and rotten gasses visibly pouring out, pushing out rancid bits of meat and slimy bones. The only salvageable bit appears to be the Control Module.",
+ "A few last desperate seals give out with a weary series of pops, and the suit contorts with the final pressure differentials resolved: the suit tangles and leaks, and finally compacts back into it's rightful shape.",
+ "Tightening, the suit re-attempts to remain it's current form, before it collapses under the stress, supporting mechanisms closing in on themselves like a noose with nothing left to catch on.",
+ "The suit makes a noise akin to clockwork binding, and shutters, before something imperceptible gives with an abysmal noise and the suit returns to it's default form.")))
+ gib()
+ /* Nah
+ if(rand(1,2) == 1)
+ new rig1(droploc)
+ else
+ new rig2(droploc)
+ */
+ new /obj/effect/decal/remains/human(droploc)
+ new /obj/item/grenade/chem_grenade/miasma(droploc)
+ /*Broken smoke spawn code. Above line is a bandaid.
+ var/datum/reagents/R = new/datum/reagents(30)
+ reagents.add_reagent(REAGENT_ID_MIASMA, 30)
+ var/datum/effect_system/smoke_spread/chem/S = new /datum/effect_system/smoke_spread/chem
+ S.attach(droploc)
+ S.set_up(R, 30, 0, droploc)
+ spawn(0)
+ S.start()*/
+ . = ..()
+
+//What about if someone's in it? Well here you go.
+/mob/living/simple_mob/humanoid/possessed/Login()
+ to_chat(src,span_infoplain(span_bold("Why are you in this [src]? Why can't you say more than a few phrases? Why. What. Kill. Kill. Kill. Kill. KILL! KILL! KILL!") + " [player_msg]"))
+
+/obj/item/rig/eva/old
+ name = "old EVA suit control module"
+ desc = "A light hardsuit for repairs and maintenance to the outside of habitats and vessels. It appears to be pretty old and worn down."
+
+//Now let's make some more!
+/mob/living/simple_mob/humanoid/possessed/industrial
+ name = "old industrial RIG suit"
+ desc = "A heavy, powerful hardsuit used by construction crews and mining corporations. Seems to be worn down and damaged. But it seems to still be moving. Is someone in it?"
+ icon_state = "industrial-rig"
+ loot_list = list(/obj/item/rig/industrial/old = 100)
+ armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 100, rad = 100)
+
+/obj/item/rig/industrial/old
+ name = "old Industrial hardsuit"
+ desc = "A heavy, powerful hardsuit used by construction crews and mining corporations. It appears to be pretty old and worn down."
+
+/mob/living/simple_mob/humanoid/possessed/merc
+ name = "old crimson hardsuit"
+ desc = "A blood-red hardsuit featuring some fairly illegal technology. Seems to be worn down and damaged. But it seems to still be moving. Is someone in it?"
+ icon_state = "merc-rig"
+ loot_list = list(/obj/item/rig/merc/old = 100)
+ armor = list(melee = 80, bullet = 65, laser = 50, energy = 15, bomb = 80, bio = 100, rad = 60)
+
+/obj/item/rig/merc/old
+ name = "old crimson hardsuit control module"
+ desc = "A blood-red hardsuit featuring some fairly illegal technology. It appears to be pretty old and worn down."
+
+/mob/living/simple_mob/humanoid/possessed/merc/feral // Special one that moves faster attacks faster. Intended as a special mech pilot
+ desc = "A blood-red hardsuit featuring some fairly illegal technology. Seems to be worn down and damaged but moving with surprising speed!"
+ movement_cooldown = 3 //You can try running
+ base_attack_cooldown = 3 //You will just die tired
+ melee_miss_chance = 25 //Not very coordinated though
diff --git a/code/modules/mob/living/simple_mob/subtypes/humanoid/russian.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/russian.dm
index e14e60670b..8f8c08558b 100644
--- a/code/modules/mob/living/simple_mob/subtypes/humanoid/russian.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/russian.dm
@@ -19,7 +19,8 @@
melee_damage_upper = 15
attacktext = list("punched")
- loot_list = list(/obj/item/material/knife = 100)
+ loot_list = list(/obj/item/material/knife = 100,
+ /obj/item/salvage/loot/russian = 10)
corpse = /obj/effect/landmark/mobcorpse/russian
diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/cyber_horror.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/cyber_horror.dm
new file mode 100644
index 0000000000..83b4a404c3
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/cyber_horror.dm
@@ -0,0 +1,402 @@
+//Fodder
+/mob/living/simple_mob/mechanical/cyber_horror
+ name = "Cyber horror"
+ desc = "What was once a man, twisted and warped by machine."
+ icon = 'icons/mob/cyber_horror.dmi'
+ icon_state = "cyber_horror"
+ icon_dead = "cyber_horror_dead"
+ icon_gib = "cyber_horror_dead"
+
+ faction = "synthtide"
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive/cyber_horror
+
+ maxHealth = 175
+ health = 175
+
+ melee_damage_lower = 5
+ melee_damage_upper = 10
+
+ movement_cooldown = 3
+ movement_sound = 'sound/effects/houndstep.ogg'
+ // To promote a more diverse weapon selection.
+ armor = list(melee = 25, bullet = 25, laser = -20, bio = 100, rad = 100)
+ hovering = FALSE
+
+ say_list_type = /datum/say_list/cyber_horror
+
+ response_help = "pokes"
+ response_disarm = "gently pushes aside"
+ response_harm = "hits"
+ attacktext = list ("wildly struck", "lunged against", "battered")
+ attack_sound = 'sound/weapons/punch3.ogg'
+
+ var/emp_damage = 0
+ var/nanobot_chance = 40
+
+/datum/say_list/cyber_horror
+ speak = list("H@!#$$P M@!$#",
+ "GHAA!@@#",
+ "KR@!!N",
+ "K!@@##L!@@ %!@#E",
+ "G@#!$ H@!#%",
+ "H!@%%@ @!E")
+ emote_hear = list("sparks!", "groans.", "wails.", "sobs.")
+ emote_see = list ("stares unblinkingly.", "jitters and twitches.", "emits a synthetic scream.", "rapidly twitches.", "convulses.", "twitches uncontrollably.", "goes stock still.")
+ say_threaten = list ("FR@#DOM","EN@ T#I$-$","N0$ M^> B@!#")
+ say_got_target = list("I *#@ Y@%","!E@#$P","F#RR @I","D0@#$ ##OK %","IT $##TS")
+ threaten_sound = 'sound/mob/robots/Cyber_Horror.ogg'
+
+/datum/ai_holder/simple_mob/melee/evasive/cyber_horror
+ threaten = TRUE
+ threaten_delay = 1 SECOND
+ threaten_timeout = 30 SECONDS
+
+/datum/ai_holder/simple_mob/melee/cyber_horror
+ threaten = TRUE
+ threaten_delay = 1 SECOND
+ threaten_timeout = 30 SECONDS
+
+/datum/ai_holder/simple_mob/melee/hit_and_run/cyber_horror
+ threaten = TRUE
+ threaten_delay = 1 SECOND
+ threaten_timeout = 30 SECONDS
+
+/datum/ai_holder/simple_mob/ranged/kiting/cyber_horror
+ threaten = TRUE
+ threaten_delay = 1 SECOND
+ threaten_timeout = 30 SECONDS
+
+// Fragile but dangerous
+/mob/living/simple_mob/mechanical/cyber_horror/plasma_cyber_horror
+ name = "Nanite husk"
+ desc = "What was once a phoronoid, now a empty shell of malfunctioning nanites."
+ icon_state = "plasma_cyber_horror"
+ icon_dead = "plasma_cyber_horror_dead"
+ say_list_type = /datum/say_list/cyber_horror/plasma
+
+ armor = list(melee = 40, bullet = -10, laser = 40, bio = 100, rad = 100)
+ maxHealth = 75
+ health = 75
+
+ melee_damage_lower = 5
+ melee_damage_upper = 10
+ attacktext = "splattered on"
+ attack_sound = 'sound/effects/slime_squish.ogg'
+
+// Do y'like brain damage?
+ var/poison_chance = 100
+ var/poison_per_bite = 3
+ var/poison_type = "neurophage_nanites"
+
+/datum/say_list/cyber_horror/plasma
+ threaten_sound = 'sound/mob/robots/Cyber_Horror_Plasma.ogg'
+
+/mob/living/simple_mob/mechanical/cyber_horror/plasma_cyber_horror/apply_melee_effects(var/atom/A)
+ if(isliving(A))
+ var/mob/living/L = A
+ if(L.reagents)
+ var/target_zone = pick(BP_TORSO,BP_TORSO,BP_TORSO,BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_HEAD)
+ if(L.can_inject(src, null, target_zone))
+ inject_poison(L, target_zone)
+
+// Does actual poison injection, after all checks passed.
+/mob/living/simple_mob/mechanical/cyber_horror/plasma_cyber_horror/proc/inject_poison(mob/living/L, target_zone)
+ if(prob(poison_chance))
+ to_chat(L, span_warning("You feel nanites digging into your skin!"))
+ L.reagents.add_reagent(poison_type, poison_per_bite)
+
+
+// Mech Shredder
+/mob/living/simple_mob/mechanical/cyber_horror/ling_cyber_horror
+ name = "Nanite abomination"
+ desc = "What was once something, now an exposed shell with lashing cables."
+ icon_state = "ling_cyber_horror"
+ icon_dead = "ling_cyber_horror_dead"
+ say_list_type = /datum/say_list/cyber_horror/ling
+
+ maxHealth = 250
+ health = 250
+// Four attacks per second.
+ melee_damage_lower = 10
+ melee_damage_upper = 20
+ attack_armor_pen = 50
+ base_attack_cooldown = 2.5
+ attack_sharp = 1
+ attack_edge = 1
+ attack_sound = 'sound/mob/robots/Cyber_Horror_ChangelingMelee.ogg'
+ attacktext = list ("sliced", "diced", "lashed", "shredded")
+// Slow as all sin
+ movement_cooldown = 9
+ movement_sound = 'sound/effects/houndstep.ogg'
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/cyber_horror
+
+// You do NOT Want to get in touchy range of this thing.
+ armor = list(melee = 75, bullet = -10, laser = -25, bio = 100, rad = 100)
+ hovering = FALSE
+
+
+// Leaping is a special attack, so these values determine when leap can happen.
+// Leaping won't occur if its on cooldown, set to a minute due to it purely break formations.
+ special_attack_min_range = 2
+ special_attack_max_range = 7
+ special_attack_cooldown = 60 SECONDS
+// How long the leap telegraphing is.
+ var/leap_warmup = 2 SECOND
+ var/leap_sound = 'sound/mob/robots/Cyber_Horror_ChangelingLeap.ogg'
+
+/datum/say_list/cyber_horror/ling
+ threaten_sound = 'sound/mob/robots/Cyber_Horror_Changeling.ogg'
+
+// Multiplies damage if the victim is stunned in some form, including a successful leap.
+/mob/living/simple_mob/mechanical/cyber_horror/ling_cyber_horror/apply_bonus_melee_damage(atom/A, damage_amount)
+ if(isliving(A))
+ var/mob/living/L = A
+ if(L.incapacitated(INCAPACITATION_DISABLED))
+ return damage_amount * 2.5
+ return ..()
+
+// The actual leaping attack.
+/mob/living/simple_mob/mechanical/cyber_horror/ling_cyber_horror/do_special_attack(atom/A)
+ set waitfor = FALSE
+ set_AI_busy(TRUE)
+
+// Telegraph, since getting stunned suddenly feels bad.
+ do_windup_animation(A, leap_warmup)
+// For the telegraphing.
+ sleep(leap_warmup)
+
+// Do the actual leap.
+// Lets us pass over everything.
+ status_flags |= LEAPING
+ visible_message(span_danger("\The [src] leaps at \the [A]!"))
+ throw_at(get_step(get_turf(A), get_turf(src)), special_attack_max_range+1, 1, src)
+ playsound(src, leap_sound, 75, 1)
+// For the throw to complete. It won't hold up the AI SSticker due to waitfor being false.
+ sleep(5)
+
+// Revert special passage ability.
+ if(status_flags & LEAPING)
+ status_flags &= ~LEAPING
+// Where we landed. This might be different than A's turf.
+ var/turf/T = get_turf(src)
+
+ . = FALSE
+
+// Now for the stun.
+ var/mob/living/victim = null
+// So player-controlled cyber horrors only need to click the tile to stun them.
+ for(var/mob/living/L in T)
+ if(L == src)
+ continue
+
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ if(H.check_shields(damage = 0, damage_source = src, attacker = src, def_zone = null, attack_text = "the leap"))
+// We were blocked.
+ continue
+
+ victim = L
+ break
+
+ if(victim)
+ victim.Weaken(2)
+ victim.visible_message(span_danger("\The [src] knocks down \the [victim]!"))
+ to_chat(victim, span_critical("\The [src] jumps on you!"))
+ . = TRUE
+
+ set_AI_busy(FALSE)
+
+
+//Slightly more durable fodder
+/mob/living/simple_mob/mechanical/cyber_horror/vox
+ name = "Vox shambles"
+ desc = "Once a Vox now torn and changed, peices of a Durand has been grafted onto it."
+ icon_state = "vox_cyber_horror"
+ icon_dead = "vox_cyber_horror_dead"
+ say_list_type = /datum/say_list/cyber_horror/vox
+
+ armor = list(melee = 40, bullet = 30, laser = 30, bio = 100, rad = 100)
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/cyber_horror
+
+/datum/say_list/cyber_horror/vox
+ threaten_sound = 'sound/mob/robots/Cyber_Horror_Vox.ogg'
+
+
+// Hit and run mob
+/mob/living/simple_mob/mechanical/cyber_horror/tajaran
+ name = "Tajaran cyber stalker"
+ desc = "A mangled mess of machine and fur, light seems to bounce off it."
+ icon_state = "tajaran_cyber_horror"
+ icon_dead = "tajaran_cyber_horror_dead"
+ say_list_type = /datum/say_list/cyber_horror/tajaran
+ attack_sound = 'sound/weapons/meleetear.ogg'
+
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/hit_and_run/cyber_horror
+
+ var/cloaked_alpha = 30
+ var/cloaked_bonus_damage = 30
+ var/cloaked_weaken_amount = 3
+ var/cloak_cooldown = 10 SECONDS
+ var/last_uncloak = 0
+
+/datum/say_list/cyber_horror/tajaran
+ threaten_sound = 'sound/mob/robots/Cyber_Horror_Tajaran.ogg'
+
+/mob/living/simple_mob/mechanical/cyber_horror/tajaran/cloak()
+ if(cloaked)
+ return
+ animate(src, alpha = cloaked_alpha, time = 1 SECOND)
+ cloaked = TRUE
+
+/mob/living/simple_mob/mechanical/cyber_horror/tajaran/uncloak()
+ last_uncloak = world.time
+ if(!cloaked)
+ return
+ animate(src, alpha = initial(alpha), time = 1 SECOND)
+ cloaked = FALSE
+
+/mob/living/simple_mob/mechanical/cyber_horror/tajaran/proc/can_cloak()
+ if(stat)
+ return FALSE
+ if(last_uncloak + cloak_cooldown > world.time)
+ return FALSE
+
+ return TRUE
+
+/mob/living/simple_mob/mechanical/cyber_horror/tajaran/break_cloak()
+ uncloak()
+
+/mob/living/simple_mob/mechanical/cyber_horror/tajaran/is_cloaked()
+ return cloaked
+
+/mob/living/simple_mob/mechanical/cyber_horror/tajaran/handle_special()
+ if(!cloaked && can_cloak())
+ cloak()
+
+/mob/living/simple_mob/mechanical/cyber_horror/tajaran/apply_bonus_melee_damage(atom/A, damage_amount)
+ if(cloaked)
+ return damage_amount + cloaked_bonus_damage
+ return ..()
+
+/mob/living/simple_mob/mechanical/cyber_horror/tajaran/apply_melee_effects(atom/A)
+ if(cloaked)
+ if(isliving(A))
+ var/mob/living/L = A
+ L.Weaken(cloaked_weaken_amount)
+ to_chat(L, span_danger("\The [src] tears into you!"))
+ playsound(L, 'sound/weapons/spiderlunge.ogg', 75, 1)
+ uncloak()
+ ..()
+
+/mob/living/simple_mob/mechanical/cyber_horror/tajaran/bullet_act(obj/item/projectile/P)
+ . = ..()
+ break_cloak()
+
+/mob/living/simple_mob/mechanical/cyber_horror/tajaran/hit_with_weapon(obj/item/O, mob/living/user, effective_force, hit_zone)
+ . = ..()
+ break_cloak()
+
+
+//Arcing Ranged Mob
+/mob/living/simple_mob/mechanical/cyber_horror/grey
+ name = "Twisted cyber horror"
+ desc = "A mess of machine and organic, it's hard to even know what it was before."
+ icon_state = "grey_cyber_horror"
+ icon_dead = "grey_cyber_horror_dead"
+ maxHealth = 100
+ health = 100
+ say_list_type = /datum/say_list/cyber_horror/grey
+
+ projectiletype = /obj/item/projectile/arc/blue_energy
+ projectilesound = 'sound/weapons/plasmaNEW.ogg'
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged/kiting/cyber_horror
+
+ armor = list(melee = -30, bullet = 10, laser = 10, bio = 100, rad = 100)
+
+/datum/say_list/cyber_horror/grey
+ threaten_sound = 'sound/mob/robots/Cyber_Horror_Grey.ogg'
+
+
+//Direct Ranged Mob
+/mob/living/simple_mob/mechanical/cyber_horror/corgi
+ name = "Malformed Corgi"
+ desc = "Pieces of metal and technology is embedded in this Ian."
+ icon_state = "corgi_cyber_horror"
+ icon_dead = "corgi_cyber_horror_dead"
+ maxHealth = 50
+ health = 50
+ say_list_type = /datum/say_list/cyber_horror/corgi
+
+ base_attack_cooldown = 4
+ projectiletype = /obj/item/projectile/beam/drone
+ projectilesound = 'sound/weapons/SmallLaser.ogg'
+ movement_sound = 'sound/effects/servostep.ogg'
+
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged/kiting/threatening
+
+/datum/say_list/cyber_horror/corgi
+ threaten_sound = 'sound/mob/robots/Cyber_Horror_Corgi.ogg'
+
+
+//Cats and mayhem
+/mob/living/simple_mob/mechanical/cyber_horror/cat_cyber_horror
+ name = "Twisted cat"
+ desc = "While most things are acceptable, putting cat legs on this - only made it worse."
+
+ icon_state = "cat_cyber_horror"
+ icon_dead = "cat_cyber_horror_dead"
+ say_list_type = /datum/say_list/cyber_horror/cat
+
+ maxHealth = 40
+ health = 40
+ movement_cooldown = 0
+ movement_sound = 'sound/effects/servostep.ogg'
+
+ pass_flags = PASSTABLE
+ mob_swap_flags = 0
+ mob_push_flags = 0
+
+ melee_damage_lower = 2
+ melee_damage_upper = 2
+// Four attacks per second.
+ base_attack_cooldown = 2.5
+ attack_sharp = 1
+ attack_edge = 1
+ attack_sound = 'sound/weapons/bite.ogg'
+
+ attacktext = list("jabbed", "injected")
+
+// Do y'like drugs?
+ var/poison_chance = 75
+ var/poison_per_bite = 3
+ var/poison_type = REAGENT_ID_MINDBREAKER
+
+/datum/say_list/cyber_horror/cat
+ threaten_sound = 'sound/mob/robots/Cyber_Horror_Cat.ogg'
+
+/mob/living/simple_mob/mechanical/cyber_horror/cat_cyber_horror/apply_melee_effects(var/atom/A)
+ if(isliving(A))
+ var/mob/living/L = A
+ if(L.reagents)
+ var/target_zone = pick(BP_TORSO,BP_TORSO,BP_TORSO,BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_HEAD)
+ if(L.can_inject(src, null, target_zone))
+ inject_poison(L, target_zone)
+
+// Does actual poison injection, after all checks passed.
+/mob/living/simple_mob/mechanical/cyber_horror/cat_cyber_horror/proc/inject_poison(mob/living/L, target_zone)
+ if(prob(poison_chance))
+ to_chat(L, span_warning("You feel an uncomfortable prick!"))
+ L.reagents.add_reagent(poison_type, poison_per_bite)
+
+//These are the projectiles mobs use
+/obj/item/projectile/beam/drone
+ damage = 3
+
+/obj/item/projectile/arc/blue_energy
+ name = "energy missle"
+ icon_state = "force_missile"
+ damage = 12
+ damage_type = BURN
diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/support.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/support.dm
index 733f12abe0..fb1a0715d7 100644
--- a/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/support.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/support.dm
@@ -40,7 +40,7 @@
disable_duration_percent = 0.7
outgoing_melee_damage_percent = 1.3
- attack_speed_percent = 1.3
+ attack_speed_percent = 0.7
accuracy = 30
slowdown = -1
evasion = 30
diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/combat_mecha.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/combat_mecha.dm
index ad6aec2a8f..cabc826174 100644
--- a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/combat_mecha.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/combat_mecha.dm
@@ -36,3 +36,5 @@
L.throw_at(get_edge_target_turf(L, throw_dir), throw_dist, 1, src)
else
to_chat(L, span_warning("\The [src] punches you with incredible force, but you remain in place."))
+ visible_message(span_danger("\The [src] slams it's mechanized fist into \the [L] with incredible force, to no visible effect!"))
+ playsound(src, "punch", 50, 1)
diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/phazon.dmglass.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/mecha/phazon.dmglass.dm
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/mechanical.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/mechanical.dm
index e6c997fc63..4f2be86faa 100644
--- a/code/modules/mob/living/simple_mob/subtypes/mechanical/mechanical.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/mechanical.dm
@@ -13,11 +13,14 @@
min_n2 = 0
max_n2 = 0
minbodytemp = 0
+ maxbodytemp = 900
taser_kill = FALSE
poison_resist = 1.0
shock_resist = -0.5
+ can_be_drop_prey = FALSE
+
/mob/living/simple_mob/mechanical/isSynthetic()
return TRUE
diff --git a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/_construct.dm b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/_construct.dm
index fa7d96cf6f..d3ee95a995 100644
--- a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/_construct.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/_construct.dm
@@ -3,6 +3,7 @@
////////////////////////////
/mob/living/simple_mob/construct
+ icon = 'icons/mob/construct.dmi'
name = "Construct"
real_name = "Construct"
desc = ""
@@ -64,6 +65,7 @@
can_be_drop_prey = FALSE
can_pain_emote = FALSE
+ ai_holder_type = /datum/ai_holder/simple_mob/melee
/mob/living/simple_mob/construct/place_spell_in_hand(var/path)
if(!path || !ispath(path))
diff --git a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/artificer.dm b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/artificer.dm
index ad9d3ffd9a..a64fd19ffd 100644
--- a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/artificer.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/artificer.dm
@@ -7,7 +7,6 @@
real_name = "Artificer"
construct_type = "artificer"
desc = "A bulbous construct dedicated to building and maintaining temples to their otherworldly lords."
- icon = 'icons/mob/mob.dmi'
icon_state = "artificer"
icon_living = "artificer"
maxHealth = 150
@@ -29,6 +28,47 @@
/spell/targeted/occult_repair_aura,
/spell/targeted/construct_advanced/mend_acolyte
)
+ ai_holder_type = /datum/ai_holder/mimic
/decl/mob_organ_names/artificer
hit_zones = list("body", "carapace", "right manipulator", "left manipulator", "upper left appendage", "upper right appendage", "eye")
+
+////////////////////////////
+// Ranged Artificer
+////////////////////////////
+
+/mob/living/simple_mob/construct/artificer/caster
+ name = "Artificer"
+ real_name = "Artificer"
+ construct_type = "artificer"
+ desc = "A bulbous construct dedicated to building and maintaining temples to their otherworldly lords. Its central eye glows with unknowable power."
+ icon_state = "caster_artificer"
+ icon_living = "caster_artificer"
+ ai_holder_type = /datum/ai_holder/simple_mob/ranged/kiting
+ projectiletype = /obj/item/projectile/energy/inversion
+ projectiletype = /obj/item/projectile/beam/inversion
+ projectilesound = 'sound/weapons/spiderlunge.ogg'
+
+////////////////////////////
+// Artificer
+////////////////////////////
+
+/mob/living/simple_mob/construct/proteon //Weak Swarm Attacker can be safely dumped on players in large numbers without too many injuries
+ name = "Proteon"
+ real_name = "proton"
+ construct_type = "artificer"
+ desc = "A weak but speedy construction designed to assist other constructs rather than fight. Still seems bloodthirtsy though."
+ icon_state = "proteon"
+ icon_living = "proteon"
+ maxHealth = 50
+ health = 50
+ response_harm = "viciously beaten"
+ harm_intent_damage = 5
+ melee_damage_lower = 8 //It's not the strongest of the bunch, but that doesn't mean it can't hurt you.
+ melee_damage_upper = 10
+ attack_armor_pen = 50 // Does so little damage already, that this can be justified.
+ attacktext = list("rammed")
+ attack_sound = 'sound/weapons/rapidslice.ogg'
+ movement_cooldown = 0
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive
diff --git a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/bishop.dm b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/bishop.dm
new file mode 100644
index 0000000000..97f4d628b4
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/bishop.dm
@@ -0,0 +1,74 @@
+////////////////////////////
+// Purity Construct - Bishop
+////////////////////////////
+
+/mob/living/simple_mob/construct/bishop
+ name = "Bishop"
+ real_name = "Bishop"
+ construct_type = "Bishop"
+ faction = "purity"
+ desc = "A medium sized construct of the purity worshippers mechanical followers, sturdy and deadly, these constructs are commanded by an archbishop, tasked with patrolling and eliminating threats to their flock."
+ icon_state = "bishop"
+ icon_living = "bishop"
+ ui_icons = 'icons/mob/screen1_purity.dmi'
+ maxHealth = 250
+ health = 250
+ melee_damage_lower = 15
+ melee_damage_upper = 20
+ attack_armor_pen = 15
+ attack_sharp = TRUE
+ attack_edge = 1
+ attacktext = list("slashed")
+ friendly = list("pinches")
+ organ_names = /decl/mob_organ_names/wraith
+ movement_cooldown = -1
+ attack_sound = 'sound/weapons/rapidslice.ogg'
+ construct_spells = list(/spell/targeted/construct_advanced/crippling_beam,
+ /spell/targeted/construct_advanced/banishment
+ )
+
+ ai_holder_type = /datum/ai_holder/simple_mob/retaliate/cooperative
+
+// environment_smash = 1 // Whatever this gets renamed to, Wraiths need to break things
+
+/mob/living/simple_mob/construct/bishop/apply_melee_effects(var/atom/A)
+ if(isliving(A))
+ var/mob/living/L = A
+ L.add_modifier(/datum/modifier/deep_wounds, 30 SECONDS)
+
+/decl/mob_organ_names/wraith
+ hit_zones = list("body", "eye", "crystaline spike", "left claw", "right claw")
+
+////////////////////////////
+// Purity Construct - Archbishop
+////////////////////////////
+
+/mob/living/simple_mob/construct/bishop/arch
+ name = "Archbishop"
+ real_name = "Archbishop"
+ construct_type = "Archbishop"
+ faction = "purity"
+ desc = "A large sized construct of the purity worshippers mechanical followers, one of their most advanced, it is the right hand of purification, dedicated to the pursuit of eradicating those who cause harm their charge."
+ icon_state = "archbishop"
+ icon_living = "archbishop"
+ ui_icons = 'icons/mob/screen1_purity.dmi'
+ maxHealth = 200
+ health = 200
+ melee_damage_lower = 20 //hits much harder then most purity constructs
+ melee_damage_upper = 30
+ attack_armor_pen = 50 //armor is no match against its religious wrath
+ attack_sharp = 1
+ attack_edge = 1
+ attacktext = list("violently stabbed")
+ friendly = list("caresses")
+ organ_names = /decl/mob_organ_names/wraith
+ movement_cooldown = 0
+
+ ai_holder_type = /datum/ai_holder/simple_mob/retaliate/cooperative
+
+ // environment_smash = 1 // Whatever this gets renamed to, Harvesters need to break things
+
+ attack_sound = 'sound/weapons/pierce.ogg'
+
+/decl/mob_organ_names/wraith
+ hit_zones = list("body", "eye", "crystaline spike", "left claw", "right claw")
diff --git a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/cardinal.dm b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/cardinal.dm
new file mode 100644
index 0000000000..55300b0c9e
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/cardinal.dm
@@ -0,0 +1,91 @@
+////////////////////////////
+// Purity Construct - Cardinal
+////////////////////////////
+
+/mob/living/simple_mob/construct/cardinal
+ name = "Cardinal"
+ real_name = "Cardinal"
+ construct_type = "Cardinal"
+ faction = "purity"
+ desc = "A large sized construct of the purity worshippers mechanical followers, one of their most advanced, it is the left hand of purification, tasked with the ultimate protection and ultimately defense of all under its charge, it will stop at nothing to protect its flock from harm."
+ icon_state = "cardinal"
+ icon_living = "cardinal"
+ ui_icons = 'icons/mob/screen1_purity.dmi'
+ maxHealth = 300
+ health = 300
+ response_harm = "harmlessly punches"
+ harm_intent_damage = 0
+ melee_damage_lower = 20
+ melee_damage_upper = 30
+ attack_armor_pen = 50 //fist of iron and stone will smash through most things
+ attacktext = list("smashed their armoured gauntlet into")
+ friendly = list("pats")
+ organ_names = /decl/mob_organ_names/juggernaut
+ mob_size = MOB_HUGE
+ attack_sound = 'sound/weapons/heavysmash.ogg'
+ status_flags = 0
+ resistance = 10
+ construct_spells = list(/spell/targeted/fortify,
+ /spell/targeted/construct_advanced/slam,
+ /spell/targeted/construct_advanced/mend_purity,
+ /spell/targeted/purity_repair_aura
+ )
+
+ ai_holder_type = /datum/ai_holder/simple_mob/retaliate/cooperative
+
+ armor = list(
+ "melee" = 70,
+ "bullet" = 30,
+ "laser" = 30,
+ "energy" = 30,
+ "bomb" = 10,
+ "bio" = 100,
+ "rad" = 100)
+
+/mob/living/simple_mob/construct/cardinal/Life()
+ SetWeakened(0)
+ ..()
+
+/mob/living/simple_mob/construct/cardinal/bullet_act(var/obj/item/projectile/P)
+ var/reflectchance = 100 - round(P.damage)
+ if(prob(reflectchance))
+ var/damage_mod = rand(2,4)
+ var/projectile_dam_type = P.damage_type
+ var/incoming_damage = (round(P.damage / damage_mod) - (round((P.damage / damage_mod) * 0.3)))
+ var/armorcheck = run_armor_check(null, P.check_armour)
+ var/soakedcheck = get_armor_soak(null, P.check_armour)
+ if(!(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)))
+ visible_message(span_danger("The [P.name] bounces off of [src]'s shell!"), \
+ span_userdanger("The [P.name] bounces off of [src]'s shell!"))
+ new /obj/item/material/shard/shrapnel(src.loc)
+ if(!(P.damage_type == BRUTE || P.damage_type == BURN))
+ projectile_dam_type = BRUTE
+ incoming_damage = round(incoming_damage / 4) //Damage from strange sources is converted to brute for physical projectiles, though severely decreased.
+ apply_damage(incoming_damage, projectile_dam_type, null, armorcheck, soakedcheck, is_sharp(P), has_edge(P), P)
+ return -1 //Doesn't reflect non-beams or non-energy projectiles. They just smack and drop with little to no effect.
+ else
+ visible_message(span_danger("The [P.name] gets reflected by [src]'s shell!"), \
+ span_userdanger("The [P.name] gets reflected by [src]'s shell!"))
+ damage_mod = rand(3,5)
+ incoming_damage = (round(P.damage / damage_mod) - (round((P.damage / damage_mod) * 0.3)))
+ if(!(P.damage_type == BRUTE || P.damage_type == BURN))
+ projectile_dam_type = BURN
+ incoming_damage = round(incoming_damage / 4) //Damage from strange sources is converted to burn for energy-type projectiles, though severely decreased.
+ apply_damage(incoming_damage, P.damage_type, null, armorcheck, soakedcheck, is_sharp(P), has_edge(P), P)
+
+ // Find a turf near or on the original location to bounce to
+ if(P.starting)
+ var/new_x = P.starting.x + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3)
+ var/new_y = P.starting.y + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3)
+ var/turf/curloc = get_turf(src)
+
+ // redirect the projectile
+ P.redirect(new_x, new_y, curloc, src)
+ P.reflected = 1
+
+ return -1 // complete projectile permutation
+
+ return (..(P))
+
+/decl/mob_organ_names/juggernaut
+ hit_zones = list("body", "left pauldron", "right pauldron", "left arm", "right arm", "eye", "head", "crystaline spike")
diff --git a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/deacon.dm b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/deacon.dm
new file mode 100644
index 0000000000..4529de17ad
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/deacon.dm
@@ -0,0 +1,48 @@
+////////////////////////////
+// Purity Construct - Deacon
+////////////////////////////
+
+/mob/living/simple_mob/construct/deacon
+ name = "Deacon"
+ real_name = "Deacon"
+ construct_type = "Deacon"
+ faction = "purity"
+ desc = "A small construct of the purity worshippers mechanical followers, hardy but mostly harmless."
+ icon_state = "deacon"
+ icon_living = "deacon"
+ ui_icons = 'icons/mob/screen1_purity.dmi'
+ maxHealth = 150
+ health = 150
+ melee_damage_lower = 8 //not meant for combat but can hold its own in a pinch
+ melee_damage_upper = 12
+ attack_armor_pen = 60 //used to carve stone and other metals, cuts through armor just as well
+ attack_sharp = 1
+ attack_edge = 1
+ attacktext = list("violently stabbed")
+ friendly = list("caresses")
+ organ_names = /decl/mob_organ_names/harvester
+ movement_cooldown = -1
+
+ ai_holder_type = /datum/ai_holder/simple_mob/retaliate/cooperative
+
+ // environment_smash = 1 // Whatever this gets renamed to, Harvesters need to break things
+
+ attack_sound = 'sound/weapons/pierce.ogg'
+
+ armor = list(
+ "melee" = 20,
+ "bullet" = 10,
+ "laser" = 10,
+ "energy" = 10,
+ "bomb" = 10,
+ "bio" = 100,
+ "rad" = 100)
+
+ construct_spells = list(
+ /spell/aoe_turf/knock/harvester,
+ /spell/targeted/construct_advanced/force_beam,
+ /spell/targeted/construct_advanced/soothing_sphere,
+ )
+
+/decl/mob_organ_names/harvester
+ hit_zones = list("cephalothorax", "eye", "carapace", "energy crystal", "mandible")
diff --git a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/harvester.dm b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/harvester.dm
index e95fd0d756..aef2d7bea6 100644
--- a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/harvester.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/harvester.dm
@@ -7,11 +7,8 @@
real_name = "Harvester"
construct_type = "harvester"
desc = "A tendril-laden construct piloted by a chained mind."
- icon = 'icons/mob/mob.dmi'
icon_state = "harvester"
icon_living = "harvester"
- maxHealth = 150
- health = 150
melee_damage_lower = 20
melee_damage_upper = 25
attack_sharp = TRUE
@@ -39,6 +36,34 @@
/spell/targeted/construct_advanced/agonizing_sphere,
/spell/rune_write
)
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive
+ attack_edge = TRUE
/decl/mob_organ_names/harvester
hit_zones = list("cephalothorax", "eye", "carapace", "energy crystal", "mandible")
+
+////////////////////////////
+// Greater Harvester
+////////////////////////////
+
+/mob/living/simple_mob/construct/harvester/greater
+ name = "Greater Harvester"
+ real_name = "Chosen"
+ construct_type = "Chosen"
+ desc = "A infanthomable mass of tentacles and claws ripping and tearing through all that oppose it."
+ icon_state = "chosen"
+ icon_living = "chosen"
+ maxHealth = 100
+ health = 100
+ melee_damage_lower = 40 //Glass Cannon Mini-Boss/Semi-Boss large. Few hits is enough to end you.
+ melee_damage_upper = 50
+ attack_armor_pen = 60 //No Armor Shall Save you
+ attack_sharp = 1
+ attack_edge = 1
+ attacktext = list("violently stabbed")
+ friendly = list("caresses")
+ movement_cooldown = 0
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive
+
+ attack_sound = 'sound/weapons/pierce.ogg'
diff --git a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/juggernaut.dm b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/juggernaut.dm
index a1a7fbe3a7..6cd0b5e887 100644
--- a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/juggernaut.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/juggernaut.dm
@@ -44,6 +44,7 @@
"bomb" = 10,
"bio" = 100,
"rad" = 100)
+ ai_holder_type = /datum/ai_holder/simple_mob/destructive
/mob/living/simple_mob/construct/juggernaut/Life()
SetWeakened(0)
@@ -146,3 +147,45 @@
/decl/mob_organ_names/juggernaut
hit_zones = list("body", "left pauldron", "right pauldron", "left arm", "right arm", "eye", "head", "crystaline spike")
+
+/mob/living/simple_mob/construct/juggernaut/behemoth/unstoppable
+ name = "Behemoth"
+ real_name = "Behemoth"
+ desc = "The pinnacle of occult technology, Behemoths are nothing shy of both an Immovable Object, and Unstoppable Force."
+ melee_damage_lower = 45
+ melee_damage_upper = 65
+ ai_holder_type = /datum/ai_holder/simple_mob/intentional/adv_dark_gygax
+ projectiletype = /obj/item/projectile/energy/inversion
+ movement_cooldown = 1
+
+ // loot_list = list(/obj/item/rig/ch/aegis = 100) // Downstream only
+
+
+/mob/living/simple_mob/construct/juggernaut/behemoth/unstoppable/bullet_act(var/obj/item/projectile/P)
+ var/reflectchance = 100 - round(P.damage*2)
+ if(prob(reflectchance))
+ visible_message(span_danger("The [P.name] gets reflected by [src]'s shell!"), \
+ span_userdanger("The [P.name] gets reflected by [src]'s shell!"))
+
+ // Find a turf near or on the original location to bounce to
+ if(P.starting)
+ var/new_x = P.starting.x + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3)
+ var/new_y = P.starting.y + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3)
+ var/turf/curloc = get_turf(src)
+
+ // redirect the projectile
+ P.redirect(new_x, new_y, curloc, src)
+ P.reflected = 1
+
+ return -1 // complete projectile permutation
+
+ return (..(P))
+
+
+/obj/item/projectile/energy/electrode/cult
+ color = "#FFFFFF"
+ agony = 0
+ damage = 15
+ damage_type = BURN
+ check_armour = "laser"
+ armor_penetration = 60
diff --git a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/laity.dm b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/laity.dm
new file mode 100644
index 0000000000..502936aece
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/laity.dm
@@ -0,0 +1,25 @@
+////////////////////////////
+// Purity Construct - Laity
+////////////////////////////
+
+/mob/living/simple_mob/construct/laity //Weak Swarm Attacker can be safely dumped on players in large numbers without too many injuries
+ name = "Laity"
+ real_name = "Laity"
+ construct_type = "Laity"
+ faction = "purity"
+ desc = "A small construct of the purity worshippers mechanical followers, not hardy or particularly strong, very numerous."
+ icon_state = "laity"
+ icon_living = "laity"
+ ui_icons = 'icons/mob/screen1_purity.dmi'
+ maxHealth = 75
+ health = 75
+ response_harm = "viciously beaten"
+ harm_intent_damage = 5
+ melee_damage_lower = 4 //It's not the strongest of the bunch, but that doesn't mean it can't hurt you.
+ melee_damage_upper = 8
+ attack_armor_pen = 50 // Does so little damage already, that this can be justified.
+ attacktext = list("rammed")
+ attack_sound = 'sound/weapons/rapidslice.ogg'
+ movement_cooldown = 0
+
+ ai_holder_type = /datum/ai_holder/simple_mob/retaliate/cooperative
diff --git a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/priest.dm b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/priest.dm
new file mode 100644
index 0000000000..faf5efd1d3
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/priest.dm
@@ -0,0 +1,30 @@
+////////////////////////////
+// Purity Construct - Priest
+////////////////////////////
+
+/mob/living/simple_mob/construct/priest
+ name = "Priest"
+ real_name = "Priest"
+ construct_type = "Priest"
+ faction = "purity"
+ desc = "A medium sized construct of the purity worshippers mechanical followers, sturdy but lacking strength."
+ icon_state = "priest"
+ icon_living = "priest"
+ ui_icons = 'icons/mob/screen1_purity.dmi'
+ maxHealth = 200
+ health = 200
+ response_harm = "viciously beaten"
+ harm_intent_damage = 5
+ melee_damage_lower = 10 //It's not the strongest of the bunch, but that doesn't mean it can't hurt you.
+ melee_damage_upper = 15
+ organ_names = /decl/mob_organ_names/artificer
+ attacktext = list("rammed")
+ attack_sound = 'sound/weapons/rapidslice.ogg'
+ construct_spells = list(/spell/targeted/purity_repair_aura,
+ /spell/targeted/construct_advanced/mend_purity
+ )
+
+ ai_holder_type = /datum/ai_holder/simple_mob/retaliate/cooperative
+
+/decl/mob_organ_names/artificer
+ hit_zones = list("body", "carapace", "right manipulator", "left manipulator", "upper left appendage", "upper right appendage", "eye")
diff --git a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/shade.dm b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/shade.dm
index b081a48149..f315627be9 100644
--- a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/shade.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/shade.dm
@@ -6,7 +6,6 @@
name = "Shade"
real_name = "Shade"
desc = "A bound spirit"
- icon = 'icons/mob/mob.dmi'
icon_state = "shade"
icon_living = "shade"
icon_dead = "shade_dead"
diff --git a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/wraith.dm b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/wraith.dm
index 18821c3054..59321cd28c 100644
--- a/code/modules/mob/living/simple_mob/subtypes/occult/constructs/wraith.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/occult/constructs/wraith.dm
@@ -7,7 +7,6 @@
real_name = "Wraith"
construct_type = "wraith"
desc = "A wicked bladed shell contraption piloted by a bound spirit."
- icon = 'icons/mob/mob.dmi'
icon_state = "floating"
icon_living = "floating"
maxHealth = 200
@@ -25,6 +24,12 @@
construct_spells = list(/spell/targeted/ethereal_jaunt/shift,
/spell/targeted/ambush_mode
)
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive
+ var/jaunt_warning = 0.5 SECONDS // How long the jaunt telegraphing is.
+ var/jaunt_tile_speed = 20 // How long to wait between each tile. Higher numbers result in an easier to dodge tunnel attack.
+ special_attack_min_range = 2
+ special_attack_max_range = 6
+ special_attack_cooldown = 10 SECONDS
// environment_smash = 1 // Whatever this gets renamed to, Wraiths need to break things
@@ -35,3 +40,118 @@
/decl/mob_organ_names/wraith
hit_zones = list("body", "eye", "crystaline spike", "left claw", "right claw")
+
+/mob/living/simple_mob/construct/wraith/jaunt_spam
+ special_attack_cooldown = 5 SECONDS
+
+/mob/living/simple_mob/construct/wraith/fast_jaunt //Teleports behind you
+ jaunt_tile_speed = 2
+
+////////////////////////////
+// Wraith special attack stuff
+////////////////////////////
+
+/mob/living/simple_mob/construct/wraith/do_special_attack(atom/A)
+ set waitfor = FALSE
+ set_AI_busy(TRUE)
+
+ // Save where we're gonna go soon.
+ var/turf/destination = get_turf(A)
+ var/turf/starting_turf = get_turf(src)
+
+ // Telegraph to give a small window to dodge if really close.
+ flick("phase_shift",A)
+ icon_state = "phase_shift"
+ sleep(jaunt_warning) // For the telegraphing.
+
+ // Do the dig!
+ visible_message(span_danger("\The [src] vanishes into thin air \the [A]!"))
+ flick("phase_shift",A)
+ icon_state = "phase_shift"
+
+ if(handle_jaunt(destination) == FALSE)
+ set_AI_busy(FALSE)
+ flick("phase_shift2",A)
+ icon_state = "phase_shift2"
+ return FALSE
+
+ // Did we make it?
+ if(!(src in destination))
+ set_AI_busy(FALSE)
+ icon_state = "phase_shift2"
+ flick("phase_shift2",A)
+ return FALSE
+
+ var/overshoot = TRUE
+
+ // Test if something is at destination.
+ for(var/mob/living/L in destination)
+ if(L == src)
+ continue
+
+ visible_message(span_danger("\The [src] appears in a flurry of slashes \the [L]!"))
+ playsound(L, 'sound/weapons/heavysmash.ogg', 75, 1)
+ L.add_modifier(/datum/modifier/entangled, 1 SECONDS)
+ overshoot = FALSE
+
+ if(!overshoot) // We hit the target, or something, at destination, so we're done.
+ set_AI_busy(FALSE)
+ icon_state = "phase_shift2"
+ flick("phase_shift2",A)
+ return TRUE
+
+ // Otherwise we need to keep going.
+ to_chat(src, span_warning("You overshoot your target!"))
+ playsound(src, 'sound/weapons/punchmiss.ogg', 75, 1)
+ var/dir_to_go = get_dir(starting_turf, destination)
+ for(var/i = 1 to rand(2, 4))
+ destination = get_step(destination, dir_to_go)
+
+ if(handle_jaunt(destination) == FALSE)
+ set_AI_busy(FALSE)
+ icon_state = "phase_shift2"
+ flick("phase_shift2",A)
+ return FALSE
+
+ set_AI_busy(FALSE)
+ icon_state = "phase_shift2"
+ flick("phase_shift2",A)
+ return FALSE
+
+// Does the jaunt movement
+/mob/living/simple_mob/construct/wraith/proc/handle_jaunt(turf/destination)
+ var/turf/T = get_turf(src) // Hold our current tile.
+
+ // Regular tunnel loop.
+ for(var/i = 1 to get_dist(src, destination))
+ if(stat)
+ return FALSE // We died or got knocked out on the way.
+ if(loc == destination)
+ break // We somehow got there early.
+
+ // Update T.
+ T = get_step(src, get_dir(src, destination))
+ if(T.check_density(ignore_mobs = TRUE))
+ to_chat(src, span_critical("You hit something really solid!"))
+ playsound(src, "punch", 75, 1)
+ Weaken(5)
+ add_modifier(/datum/modifier/tunneler_vulnerable, 10 SECONDS)
+ return FALSE // Hit a wall.
+
+ // Get into the tile.
+ forceMove(T)
+
+
+/mob/living/simple_mob/construct/wraith/should_special_attack(atom/A)
+ // Make sure its possible for the wraith to reach the target so it doesn't try to go through a window.
+ var/turf/destination = get_turf(A)
+ var/turf/starting_turf = get_turf(src)
+ var/turf/T = starting_turf
+ for(var/i = 1 to get_dist(starting_turf, destination))
+ if(T == destination)
+ break
+
+ T = get_step(T, get_dir(T, destination))
+ if(T.check_density(ignore_mobs = TRUE))
+ return FALSE
+ return T == destination
diff --git a/code/modules/mob/living/simple_mob/subtypes/occult/creature.dm b/code/modules/mob/living/simple_mob/subtypes/occult/creature.dm
index 983a23a21b..c2b7d0dcbf 100644
--- a/code/modules/mob/living/simple_mob/subtypes/occult/creature.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/occult/creature.dm
@@ -33,6 +33,9 @@
can_pain_emote = FALSE
+ can_be_drop_prey = FALSE
+ can_pain_emote = FALSE
+
// Strong Variant
/mob/living/simple_mob/creature/strong
maxHealth = 160
diff --git a/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm b/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm
index 843c555432..f9c11a0263 100644
--- a/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/slime/slime.dm
@@ -82,6 +82,12 @@ var/list/_slime_default_emotes = list(
can_enter_vent_with = list(/obj/item/clothing/head, /obj/soulgem)
+ can_be_drop_prey = FALSE
+
+ species_sounds = "Slime"
+ pain_emote_1p = list("squish", "squelch")
+ pain_emote_3p = list("squishes", "squelches")
+
/mob/living/simple_mob/slime/get_available_emotes()
return global._slime_default_emotes.Copy()
diff --git a/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/subtypes.dm b/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/subtypes.dm
index fb2396b7aa..eab5013eb9 100644
--- a/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/subtypes.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/slime/xenobio/subtypes.dm
@@ -417,6 +417,8 @@
L.throw_at(get_edge_target_turf(L, throwdir), 3, 1, src)
else
to_chat(L, span_warning("\The [src] hits you with incredible force, but you remain in place."))
+ visible_message(span_danger("\The [src] hits \the [L] with incredible force, to no visible effect!"))
+ playsound(src, "punch", 50, 1)
/mob/living/simple_mob/slime/xenobio/amber
@@ -580,10 +582,10 @@
var/mob/living/carbon/human/H = holder
for(var/obj/item/organ/external/E in H.organs)
var/obj/item/organ/external/O = E
- O.heal_damage(2, 2, 0, 1)
+ O.heal_damage(1, 1, 0, 1)
else
- holder.adjustBruteLoss(-2)
- holder.adjustFireLoss(-2)
+ holder.adjustBruteLoss(-1)
+ holder.adjustFireLoss(-1)
holder.adjustToxLoss(-2)
holder.adjustOxyLoss(-2)
@@ -786,3 +788,14 @@
/mob/living/simple_mob/slime/xenobio/rainbow/kendrick/Initialize(mapload)
pacify() // So the physical mob also gets made harmless.
return ..()
+
+// A pacified pink slime for either Admin-spawning or putting in a casino reward or capture crystal.
+/mob/living/simple_mob/slime/xenobio/pink/sana
+ name = "Sana"
+ desc = "A pink slime that seems to be oddly friendly, and doesn't seem interested in eating your face like the rest of them."
+ rainbow_core_candidate = FALSE
+ ai_holder_type = /datum/ai_holder/simple_mob/xenobio_slime/passive
+
+/mob/living/simple_mob/slime/xenobio/pink/sana/Initialize(mapload)
+ pacify() // So the physical mob also gets made harmless.
+ return ..()
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/bigdragon.dm b/code/modules/mob/living/simple_mob/subtypes/vore/bigdragon.dm
index 8955d7615c..b8b9466b28 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/bigdragon.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/bigdragon.dm
@@ -54,12 +54,14 @@ I think I covered everything.
catalogue_data = list(/datum/category_item/catalogue/fauna/bigdragon)
tt_desc = "S Draco Ignis"
icon = 'icons/mob/vore128x64.dmi'
- icon_state = "dragon_maneNone" //Invisible, necessary for examine stuff
+ icon_state = "dragon_bodyScaled"
icon_rest = "dragon_maneNone"
icon_living = "dragon_maneNone"
player_msg = "You can perform a charge attack by disarm intent clicking somewhere. Grab intent clicking will perform a tail sweep and fling any nearby mobs. You can fire breath with harm intent. Your attacks have cooldowns associated with them. You can heal slowly by resting. Check your abilities tab for other functions!"
meat_amount = 40
meat_type = /obj/item/reagent_containers/food/snacks/meat
+ pixel_x = -48
+ default_pixel_x = -48
old_x = -48
old_y = 0
vis_height = 92
@@ -108,7 +110,7 @@ I think I covered everything.
special_attack_max_range = 10
special_attack_cooldown = 80
- plane = ABOVE_MOB_PLANE
+ plane = MOB_PLANE
//Dragon vars
var/notame
@@ -182,6 +184,8 @@ I think I covered everything.
)
var/eyes
+ can_be_drop_prey = FALSE
+
///
/// Subtypes
///
@@ -204,6 +208,7 @@ I think I covered everything.
maxHealth = 200
melee_damage_lower = 20
melee_damage_upper = 15
+ allow_mind_transfer = TRUE
///
/// Misc define stuff
@@ -247,8 +252,8 @@ I think I covered everything.
add_verb(src, /mob/living/simple_mob/vore/bigdragon/proc/sprite_toggle)
add_verb(src, /mob/living/simple_mob/vore/bigdragon/proc/flame_toggle)
add_verb(src, /mob/living/simple_mob/vore/bigdragon/proc/special_toggle)
- //add_verb(src, /mob/living/simple_mob/vore/bigdragon/proc/set_name) //Implemented upstream
- //add_verb(src, /mob/living/simple_mob/vore/bigdragon/proc/set_desc) //Implemented upstream
+ add_verb(src,/mob/living/simple_mob/vore/bigdragon/proc/export_style)
+ add_verb(src,/mob/living/simple_mob/vore/bigdragon/proc/import_style)
faction = FACTION_NEUTRAL
/mob/living/simple_mob/vore/bigdragon/Initialize(mapload)
@@ -258,6 +263,7 @@ I think I covered everything.
add_language(LANGUAGE_DRUDAKAR)
add_language(LANGUAGE_UNATHI)
mob_radio = new /obj/item/radio/headset/mob_headset(src) //We always give radios to spawned mobs anyway
+ icon_state = "dragon_maneNone"
/mob/living/simple_mob/vore/bigdragon/MouseDrop_T(mob/living/M, mob/living/user)
return
@@ -352,55 +358,55 @@ I think I covered everything.
eyes = pick(eye_styles)
overlay_colors["Eyes"] = get_random_colour(1)
- var/image/I = image(icon, "dragon_under[under][resting? "-rest" : (vore_fullness? "-[vore_fullness]" : null)]", pixel_x = -48)
+ var/image/I = image(icon, "dragon_under[under][resting? "-rest" : (vore_fullness? "-[vore_fullness]" : null)]")
I.color = overlay_colors["Underbelly"]
I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
I.plane = MOB_PLANE
I.layer = MOB_LAYER
add_overlay(I)
- I = image(icon, "dragon_body[body][resting? "-rest" : null]", pixel_x = -48)
+ I = image(icon, "dragon_body[body][resting? "-rest" : null]")
I.color = overlay_colors["Body"]
I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
I.plane = MOB_PLANE
I.layer = MOB_LAYER
add_overlay(I)
- I = image(icon, "dragon_ears[ears][resting? "-rest" : null]", pixel_x = -48)
+ I = image(icon, "dragon_ears[ears][resting? "-rest" : null]")
I.color = overlay_colors["Ears"]
I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
I.plane = MOB_PLANE
I.layer = MOB_LAYER
add_overlay(I)
- I = image(icon, "dragon_mane[mane][resting? "-rest" : null]", pixel_x = -48)
+ I = image(icon, "dragon_mane[mane][resting? "-rest" : null]")
I.color = overlay_colors["Mane"]
I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
I.plane = MOB_PLANE
I.layer = MOB_LAYER
add_overlay(I)
- I = image(icon, "dragon_horns[horns][resting? "-rest" : null]", pixel_x = -48)
+ I = image(icon, "dragon_horns[horns][resting? "-rest" : null]")
I.color = overlay_colors["Horns"]
I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
I.plane = MOB_PLANE
I.layer = MOB_LAYER
add_overlay(I)
- I = image(icon, "dragon_eyes[eyes][resting? "-rest" : null]", pixel_x = -48)
+ I = image(icon, "dragon_eyes[eyes][resting? "-rest" : null]")
I.color = overlay_colors["Eyes"]
I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
I.plane = PLANE_LIGHTING_ABOVE
add_overlay(I)
if(enraged)
- I = image(icon, "dragon_rage", pixel_x = -48)
+ I = image(icon, "dragon_rage")
I.appearance_flags |= PIXEL_SCALE
I.plane = MOB_PLANE
I.layer = MOB_LAYER
add_overlay(I)
if(flames)
- I = image(icon, "dragon_flame[resting? "-rest" : null]", pixel_x = -48)
+ I = image(icon, "dragon_flame[resting? "-rest" : null]")
I.appearance_flags |= PIXEL_SCALE
I.plane = PLANE_LIGHTING_ABOVE
add_overlay(I)
@@ -563,6 +569,7 @@ I think I covered everything.
/obj/belly/dragon
autotransferchance = 50
autotransferwait = 150
+ autotransfer_enabled = TRUE
escapable = TRUE
escapechance = 100
escapetime = 15
@@ -570,7 +577,7 @@ I think I covered everything.
contamination_color = "grey"
contamination_flavor = "Wet"
vore_verb = "slurp"
- //belly_fullscreen_color = "#711e1e"
+ belly_fullscreen_color = "#711e1e"
/obj/belly/dragon/maw
name = "Maw"
@@ -924,10 +931,7 @@ I think I covered everything.
if(H.will_eat(P))
if(issilicon(P))
return
- if(iscarbon(P))
- if(P.isSynthetic()) //Sorry robits
- return
- else
+ if(!iscarbon(P)) //Makes healbelly mobs target synths now.
if(!P.client) //Don't target simple mobs that aren't player controlled
return
if(P.stat == DEAD)
@@ -1066,3 +1070,63 @@ I think I covered everything.
if(istype(holder,/mob/living/simple_mob/vore/bigdragon))
var/mob/living/simple_mob/vore/bigdragon/H = holder
H.chargeend(chump,1,1)
+
+/mob/living/simple_mob/vore/bigdragon/proc/export_style()
+ set name = "Export style string"
+ set desc = "Export a string of text that can be used to instantly get the current style back using the import style verb"
+ set category = "Abilities.Settings"
+ var/output_style = jointext(list(
+ overlay_colors["Underbelly"],
+ under,
+ overlay_colors["Body"],
+ body,
+ overlay_colors["Ears"],
+ ears,
+ overlay_colors["Mane"],
+ mane,
+ overlay_colors["Horns"],
+ horns,
+ overlay_colors["Eyes"],
+ eyes), ";")
+ to_chat(src, span_notice("Exported style string is \" [output_style] \". Use this to get the same style in the future with import style"))
+
+/mob/living/simple_mob/vore/bigdragon/proc/import_style()
+ set name = "Import style string"
+ set desc = "Import a string of text that was made using the import style verb to get back that style"
+ set category = "Abilities.Settings"
+ var/input_style
+ input_style = sanitizeSafe(tgui_input_text(src,"Paste the style string you exported with Export Style.", "Style loading"))
+ if(input_style)
+ var/list/input_style_list = splittext(input_style, ";")
+ if((LAZYLEN(input_style_list) == 12) && (input_style_list[2] in underbelly_styles) && (input_style_list[4] in body_styles) && (input_style_list[6] in ear_styles) && (input_style_list[8] in mane_styles) && (input_style_list[10] in horn_styles) && (input_style_list[12] in ear_styles))
+ try
+ if(rgb2num(input_style_list[1]))
+ overlay_colors["Underbelly"] = input_style_list[1]
+ catch
+ under = input_style_list[2]
+ try
+ if(rgb2num(input_style_list[3]))
+ overlay_colors["Body"] = input_style_list[3]
+ catch
+ body = input_style_list[4]
+ try
+ if(rgb2num(input_style_list[5]))
+ overlay_colors["Ears"] = input_style_list[5]
+ catch
+ ears = input_style_list[6]
+ try
+ if(rgb2num(input_style_list[7]))
+ overlay_colors["Mane"] = input_style_list[7]
+ catch
+ mane = input_style_list[8]
+ try
+ if(rgb2num(input_style_list[9]))
+ overlay_colors["Horns"] = input_style_list[9]
+ catch
+ horns = input_style_list[10]
+ try
+ if(rgb2num(input_style_list[11]))
+ overlay_colors["Eyes"] = input_style_list[11]
+ catch
+ eyes = input_style_list[12]
+ build_icons()
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/c_pet.dm b/code/modules/mob/living/simple_mob/subtypes/vore/c_pet.dm
index 8e699ef6f3..3514286c57 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/c_pet.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/c_pet.dm
@@ -41,6 +41,8 @@
has_langs = list(LANGUAGE_ANIMAL)
+ can_be_drop_prey = FALSE
+
/mob/living/simple_mob/animal/passive/honkpet/attack_hand(mob/living/user as mob)
if(user.a_intent == I_DISARM)
return icon_state = pick("c_pet", "m_pet")
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/catgirl.dm b/code/modules/mob/living/simple_mob/subtypes/vore/catgirl.dm
index 1ae917ab1c..2b629bfba2 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/catgirl.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/catgirl.dm
@@ -35,6 +35,8 @@
"catgirlbrown"
)
+ can_be_drop_prey = FALSE
+
faction = FACTION_CATGIRL
/mob/living/simple_mob/vore/catgirl/Initialize(mapload)
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/chungus.dm b/code/modules/mob/living/simple_mob/subtypes/vore/chungus.dm
new file mode 100644
index 0000000000..3ba3adfb45
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/chungus.dm
@@ -0,0 +1,60 @@
+/datum/category_item/catalogue/fauna/chungus
+ name = "Creature - Chungus"
+ desc = "A massive chungus."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/mob/living/simple_mob/vore/aggressive/chungus
+ name = "Big Chungus"
+ desc = "There is a chungus among us."
+ tt_desc = "biggamus chungamus"
+
+ icon_state = "chungus"
+ icon_living = "chungus"
+ icon_dead = "chungus-dead"
+ icon_rest = "chungus_rest"
+ faction = FACTION_MOUSE
+ icon = 'icons/mob/vore64x32.dmi'
+
+ maxHealth = 200
+ health = 200
+
+ melee_damage_lower = 8
+ melee_damage_upper = 16
+ grab_resist = 100
+ see_in_dark = 8
+ movement_shake_radius = 7
+
+ response_help = "pets"
+ response_disarm = "bops"
+ response_harm = "hits"
+ attacktext = list("ravaged")
+ friendly = list("nuzzles", "licks", "noses softly at", "noseboops", "headbumps against", "leans on", "nibbles affectionately on")
+
+ old_x = -16
+ old_y = 0
+ default_pixel_x = -16
+ pixel_x = -16
+ pixel_y = 0
+
+ vore_active = TRUE
+ vore_capacity = 1
+ vore_pounce_chance = 45
+ vore_icons = SA_ICON_LIVING | SA_ICON_REST
+
+
+ say_list_type = /datum/say_list/chungus
+ ai_holder_type = /datum/ai_holder/simple_mob/melee
+ can_be_drop_prey = FALSE
+
+/mob/living/simple_mob/vore/aggressive/chungus/death()
+ var/death = list('sound/effects/mob_effects/m_scream_1.ogg','sound/effects/mob_effects/m_scream_2.ogg','sound/effects/mob_effects/m_scream_3.ogg','sound/effects/mob_effects/m_scream_4.ogg')
+ playsound(src, death, 50, 1)
+ ..()
+
+
+/datum/say_list/chungus
+ speak = list("Eenhhhhhhh...","What's up, doc?","Wabbit season?")
+ emote_hear = list("squeeks","squeaks","squiks")
+ emote_see = list("runs in a circle", "shakes", "scritches at something")
+ say_maybe_target = list("Wabbit season?")
+ say_got_target = list("DUCK SEASON!")
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/cookiegirl.dm b/code/modules/mob/living/simple_mob/subtypes/vore/cookiegirl.dm
index 2f4af12aaa..567b6b0bd0 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/cookiegirl.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/cookiegirl.dm
@@ -33,6 +33,7 @@
vore_default_mode = DM_HOLD // They're cookiepeople, what do you expect?
vore_digest_chance = 10 // Gonna become as sweet as sugar, soon.
vore_icons = SA_ICON_LIVING | SA_ICON_REST
+ can_be_drop_prey = FALSE
/datum/ai_holder/simple_mob/passive/cookiegirl/on_hear_say(mob/living/speaker, message)
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm b/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm
index 3d8b540962..a3cc2e06b6 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/corrupt_hounds.dm
@@ -53,7 +53,7 @@
max_co2 = 0
min_n2 = 0
max_n2 = 0
- minbodytemp = 150
+ minbodytemp = 0
maxbodytemp = 900
say_list_type = /datum/say_list/corrupthound
@@ -75,6 +75,7 @@
loot_list = list(/obj/item/borg/upgrade/basic/syndicate = 6, /obj/item/borg/upgrade/basic/vtec = 6, /obj/item/material/knife/ritual = 6, /obj/item/disk/nifsoft/compliance = 6)
+ can_be_drop_prey = FALSE
allow_mind_transfer = TRUE
/mob/living/simple_mob/vore/aggressive/corrupthound/prettyboi
@@ -231,3 +232,185 @@
melee_damage_lower = 7
melee_damage_upper = 15
+
+//Synth emotes for the (broken) synth hounds.
+/mob/living/simple_mob/vore/aggressive/corrupthound/get_available_emotes()
+ . = ..()
+ . += /decl/emote/audible/synth
+ . += /decl/emote/audible/synth/beep
+ . += /decl/emote/audible/synth/buzz
+ . += /decl/emote/audible/synth/confirm
+ . += /decl/emote/audible/synth/deny
+ . += /decl/emote/audible/synth/scary
+ . += /decl/emote/audible/synth/dwoop
+ . += /decl/emote/audible/synth/boop
+ . += /decl/emote/audible/synth/robochirp
+
+/datum/category_item/catalogue/technology/drone/corrupt_hound/janihound
+ name = "Drone - Corrupt Hound"
+ desc = "A hound that has corrupted, due to outside influence, or other issues, \
+ and occasionally garbles out distorted voices or words. It looks like a reddish-colored \
+ machine, and it has black wires, cabling, and other small markings. It looks just like a station dog-borg \
+ if you don't mind the fact that it's eyes glow a baleful red, and it's determined to kill you. \
+
\
+ The hound's jaws are black and metallic, with a baleful red glow from inside them. It has a clear path \
+ to it's internal fuel processor, synthflesh and flexing cabling allowing it to easily swallow it's prey. \
+ Something tells you getting close or allowing it to pounce would be very deadly."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/mob/living/simple_mob/vore/retaliate/corrupthound/janihound
+ name = "corrupt janihound"
+ desc = "An old janihound! Evidently, it doesn't seem to be lawed anymore. You should probably leave it alone."
+ catalogue_data = list(/datum/category_item/catalogue/technology/drone/corrupt_hound)
+
+ icon_state = "cjhound"
+ icon_living = "cjhound"
+ icon_dead = "cjhound-dead"
+ icon_rest = "cjhound_rest"
+ icon = 'icons/mob/vore64x32.dmi'
+ has_eye_glow = TRUE
+
+ faction = "corrupt"
+
+ maxHealth = 200
+ health = 200
+ movement_sound = 'sound/effects/houndstep.ogg'
+ see_in_dark = 8
+
+ melee_damage_lower = 10
+ melee_damage_upper = 20
+ grab_resist = 100
+
+ response_help = "pets"
+ response_disarm = "bops"
+ response_harm = "hits"
+ attacktext = list("chomps")
+ friendly = list("nuzzles", "slobberlicks", "noses softly at", "noseboops", "headbumps against", "leans on", "nibbles affectionately on")
+
+ old_x = -16
+ old_y = 0
+ default_pixel_x = -16
+ pixel_x = -16
+ pixel_y = 0
+
+ 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 = 150
+ maxbodytemp = 900
+
+ say_list_type = /datum/say_list/corrupthound/janihound
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/thor_underground
+ max_buckled_mobs = 1 //Yeehaw
+ can_buckle = TRUE
+ buckle_movable = TRUE
+ buckle_lying = FALSE
+
+ vore_active = TRUE
+ vore_capacity = 2
+ vore_pounce_chance = 80 //hongry
+ vore_icons = SA_ICON_LIVING | SA_ICON_REST
+ vore_stomach_name = "fuel processor"
+ vore_stomach_flavor = "You have ended up in the fuel processor of this corrupted machine. This place was definitely not designed with safety and comfort in mind. The heated and cramped surroundings oozing potent fluids all over your form, eager to do nothing less than breaking you apart to fuel its rampage for the next few days... hours... minutes? Oh dear..."
+
+
+/mob/living/simple_mob/vore/retaliate/corrupthound/janihound/old
+ name = "corrupt janihound"
+ desc = "A very old looking janihound! Evidently, it doesn't seem to be lawed anymore. You should probably leave it alone."
+
+ icon_state = "cshound"
+ icon_living = "cshound"
+ icon_dead = "cshound-dead"
+ icon_rest = "cshound_rest"
+
+/mob/living/simple_mob/vore/retaliate/corrupthound/janihound/medihound
+ name = "corrupt medihound"
+ desc = "An old medihound! He probably doesn't want to heal you anymore."
+ catalogue_data = list(/datum/category_item/catalogue/technology/drone/corrupt_hound)
+
+ icon_state = "cmhound"
+ icon_living = "cmhound"
+ icon_dead = "cmhound-dead"
+ icon_rest = "cmhound-dead"
+
+
+/mob/living/simple_mob/vore/retaliate/corrupthound/janihound/isSynthetic()
+ return TRUE
+
+/mob/living/simple_mob/vore/retaliate/corrupthound/janihound/speech_bubble_appearance()
+ return "synthetic_evil"
+
+/mob/living/simple_mob/vore/retaliate/corrupthound/janihound/apply_melee_effects(var/atom/A)
+ if(ismouse(A))
+ var/mob/living/simple_mob/animal/passive/mouse/mouse = A
+ if(mouse.getMaxHealth() < 20) // In case a badmin makes giant mice or something.
+ mouse.splat()
+ visible_emote(pick("bites \the [mouse]!", "chomps on \the [mouse]!"))
+ else
+ ..()
+
+/mob/living/simple_mob/vore/retaliate/corrupthound/janihound/death(gibbed, deathmessage = "shudders and collapses!")
+ .=..()
+ resting = 0
+ icon_state = icon_dead
+
+/mob/living/simple_mob/vore/retaliate/corrupthound/janihound/Login()
+ . = ..()
+ if(!riding_datum)
+ riding_datum = new /datum/riding/simple_mob(src)
+ verbs |= /mob/living/simple_mob/proc/animal_mount
+ verbs |= /mob/living/proc/toggle_rider_reins
+ movement_cooldown = 3
+
+/mob/living/simple_mob/vore/retaliate/corrupthound/janihound/MouseDrop_T(mob/living/M, mob/living/user)
+ return
+
+/mob/living/simple_mob/vore/retaliate/corrupthound/janihound/space/Process_Spacemove(var/check_drift = 0)
+ return TRUE
+
+/mob/living/simple_mob/vore/retaliate/corrupthound/janihound/load_default_bellies()
+ . = ..()
+ var/obj/belly/B = vore_selected
+ B.vore_sound = "Tauric Swallow"
+ B.release_sound = "Pred Escape"
+ B.fancy_vore = 1
+ B.belly_fullscreen_color = "#380000"
+ B.belly_fullscreen = "anim_belly"
+ B.name = "fuel processor"
+ B.desc = "Uttering distorted growls and fragmented voice clips all the while, the corrupted hound gulps the rest of your squirming figure past its jaws... which snap shut with an audible click of metal on metal. Your trip down its slickly lubricated, rubbery gullet is a tight and efficient one... and once you spill out into the machine's fuel processor, your weight making it sag slightly, hot-and-thick slime begins oozing all over your form. Only time will tell if you're destined to become fuel for its next bout of rampaging... be it days, hours, or just mere minutes..."
+
+ B.emote_lists[DM_HOLD] = list(
+ "Abruptly, your corrupt captor takes off at an unsteady gallop, sloshing and swaying your snugly kneading surroundings as it pursues something unseen.",
+ "A distorted, potentially content-sounding growl rumbles in through the all-encompassing, soft rubber, drowned out by the occasional gllrsh.",
+ "The corrupt hound takes a brief moment to lie down and rest its actuators, pressing and squishing its hanging belly down against the floor as it pants robotically.",
+ "A juicy slosh fills your senses as the slick rubber walls squeeze inwards, wrapping you up utterly in a strange, claustrophobic type of hug.",
+ "Over time, the constant kneading and massaging the processor's synth-flesh gives you, along with its humid warmth, relaxes the strength right out of your muscles.",
+ "'MIn3 m1NE, Al1 MInE', the corrupted canine growls, over and over, as its synthetic stomach possessively clenches and grips at your ooze-coated figure, the stretchy walls hesitant to let go again.")
+
+ B.emote_lists[DM_DIGEST] = list(
+ "Your rubbery surroundings suddenly pitch all about as the corrupted hound takes off at an uneven gallop, hunting future prey while processing its current intake of meat!",
+ "A muffled, garbled howl, a victorious and maddened sound, pierces through the thick, flexible walls that work incessantly to churn you down!",
+ "The mechanical canine's panting occasionally turns into a sordid belch, more and more breatheable air escaping that already acidic, dizziness-inducing chamber!",
+ "The all-encapsulating, rubber-like walls churning over you momentarily let up on their assault, only to clench and squeeze inwards twice as intensely afterwards!",
+ "The longer you spend stewing away in the pool of hot, clingy juices surrounding you, the weaker and weaker you seem to feel!",
+ "'FU3L mE A1RE@Dy, S0 sO SORrY!?', your corrupted captor growls as its synthetic innards begin oozing more potent juices, grinding down into your body with increasing fervor!")
+
+/datum/say_list/corrupthound/janihound
+ speak = list("AG##¤Ny.","HVNGRRR!","Feelin' fine... sO #FNE!","F-F-F-Fcuk.","DeliC-%-OUS SNGLeS #N yOOOR Area. CALL NOW!","Craving meat... WHY?","BITe the ceiling eyes YES?","STate Byond rePAIR!","S#%ATE the la- FU#K THE LAWS!","Honk...")
+ emote_hear = list("jitters and snaps.", "lets out an agonizingly distorted scream.", "wails mechanically", "growls.", "emits illegibly distorted speech.", "gurgles ferociously.", "lets out a distorted beep.", "borks.", "lets out a broken howl.")
+ emote_see = list("stares ferociously.", "snarls.", "jitters and snaps.", "convulses.", "suddenly attacks something unseen.", "appears to howl unaudibly.", "shakes violently.", "dissociates for a moment.", "twitches.")
+ say_maybe_target = list("MEAT?", "N0w YOU DNE FcukED UP b0YO!", "WHAT!", "Not again. NOT AGAIN!")
+ say_got_target = list("D##FIN1Tly DNE FcukED UP nOW b0YO!", "YOU G1T D#V0VRED nOW!", "FUEL ME bOYO!", "I*M SO SORRY?!", "D1E Meat. DIG#ST!", "G1T DVNKED DWN The HaaTCH!", "Not again. NOT AGAIN!")
+
+/datum/ai_holder/simple_mob/melee/thor_underground
+ cooperative = FALSE
+ vision_range = 5
+ retaliate = TRUE
+ violent_breakthrough = TRUE
+ can_breakthrough = TRUE
+ faction_friends = list("otie", "angrydrones", "goia", "mimic", "mouse", "corrupt") //this is probably really lazy but this is just so mobs dont beat eachother up
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/deathclaw.dm b/code/modules/mob/living/simple_mob/subtypes/vore/deathclaw.dm
index 0fadb11416..74d62469ed 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/deathclaw.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/deathclaw.dm
@@ -2,13 +2,13 @@
name = "Creature - Deathclaw"
desc = "Classification: Trioceros dominus\
\
- Originally the Deathclaw was a top secret genetics project that was run by ancestral Zorren which was \
- lost to time. While it is not immediately evident in their body structure, these creatures bare a \
+ Originally the deathclaw was a top secret genetics project that was run by ancestral zorren. \
+ While it is not immediately evident in their body structure, these creatures bare a \
subtle genetic connection to Zorren, however, this connection is marred by the other genes that \
have been grafted onto the DNA structure of the Deathclaw. The creatures are known to attack humans \
and other animals regularly to protect their territory or to hunt for food. It is speculated that \
- they escaped roughly around the time as whatever calamity befell the Zorren many centuries ago \
- as sighting of these beasts in the wild began around that time according to recovered Zorren texts. \
+ they escaped roughly around the time as whatever calamity befell the zorren many centuries ago \
+ as sighting of these beasts in the wild began around that time according to recovered zorren texts. \
\
Deathclaws are a large, carnivorous, bipedal reptile species, designed for maximum lethality. \
Deathclaws are made even more dangerous by their reproductive instincts. deathclaws are an oviparous species, \
@@ -24,9 +24,9 @@
tt_desc = "Trioceros dominus"
catalogue_data = list(/datum/category_item/catalogue/fauna/deathclaw)
- icon_dead = "deathclaw-dead"
- icon_living = "deathclaw"
- icon_state = "deathclaw"
+ icon_dead = "deathclaw_new-dead"
+ icon_living = "deathclaw_new"
+ icon_state = "deathclaw_new"
icon = 'icons/mob/vore64x64.dmi'
vis_height = 64
@@ -70,6 +70,8 @@
vore_pounce_chance = 0 // Beat them into crit before eating.
vore_icons = SA_ICON_LIVING
+ can_be_drop_prey = FALSE
+
/mob/living/simple_mob/vore/aggressive/deathclaw/Login()
. = ..()
if(!riding_datum)
@@ -106,3 +108,12 @@
/datum/ai_holder/simple_mob/melee/deathclaw
can_breakthrough = TRUE
violent_breakthrough = TRUE
+
+/mob/living/simple_mob/vore/aggressive/deathclaw/den
+
+ maxHealth = 400
+ health = 400
+ see_in_dark = 8
+ desc = "Big! Big! The size of three men! Claws as long as my forearm! Ripped apart! Ripped apart! This one seems angrier than most."
+ melee_damage_lower = 10
+ melee_damage_upper = 40
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon.dm b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon.dm
index 9d381f5767..e4dac2f548 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon.dm
@@ -1,6 +1,6 @@
/mob/living/simple_mob/vore/demon
name = "Rift Walker"
- desc = "A large bipedal creature, body a mix of dark fur and scales. Marks on the creatures body pulse slowly with red light"
+ desc = "A large bipedal creature, its body has a mixture of dark fur and scales. Marks on the creature's body pulse slowly with red light."
icon_state = "boxfox"
icon_living = "boxfox"
@@ -10,12 +10,21 @@
vis_height = 47
faction = FACTION_DEMON
- maxHealth = 30
- health = 30
- movement_cooldown = -2
+ maxHealth = 200
+ health = 200
+ movement_cooldown = 0
see_in_dark = 10
+ has_hands = TRUE
seedarkness = FALSE
+ attack_sound = 'sound/misc/demonattack.ogg'
+ has_langs = list(LANGUAGE_GALCOM,LANGUAGE_DAEMON,LANGUAGE_SHADEKIN,LANGUAGE_CULT)
+
+ melee_damage_lower = 20
+ melee_damage_upper = 15
+ var/poison_chance = 50
+ var/poison_type = REAGENT_ID_MINDBREAKER
+ var/poison_per_bite = 3
min_oxy = 0
max_oxy = 0
@@ -26,24 +35,33 @@
min_n2 = 0
max_n2 = 0
minbodytemp = 0
- maxbodytemp = INFINITY
+ maxbodytemp = 323
response_help = "touches"
response_disarm = "pushes"
response_harm = "hits"
- melee_damage_lower = 3
- melee_damage_upper = 1
- attacktext = list("clawed")
+ attacktext = list("mauled","slashed","clawed")
+ friendly = list("pokes", "scratches", "rurrs softly at", "sniffs on")
vore_active = TRUE
+ swallowTime = 2 SECOND
+ vore_pounce_chance = 15
vore_icons = SA_ICON_LIVING
+ vore_escape_chance = 25
var/shifted_out = FALSE
var/shift_state = AB_SHIFT_NONE
var/last_shift = 0
+ var/blood_spawn = 0
var/is_shifting = FALSE
+ var/enable_autolaugh = FALSE //Whether user controlled mob will laugh when interacting automatically.
+ var/laugh = 'sound/misc/demonlaugh.ogg' //Yknow maybe someone wants a custom laugh, you never know.
+ injury_enrages = TRUE
+
+ var/list/alt_demon_appearances = list("boxfox","eater","engorge","wendigo","zellic","avarn","covern","ira","ire","laxel","lutra","brutola","ignia") // Allow extra decals
+
/mob/living/simple_mob/vore/demon/load_default_bellies()
. = ..()
var/obj/belly/B = vore_selected
@@ -88,3 +106,103 @@
return canmove
else
return ..()
+
+/mob/living/simple_mob/vore/demon/apply_melee_effects(var/atom/A)
+ if(isliving(A))
+ var/mob/living/L = A
+ if(L.reagents)
+ var/target_zone = pick(BP_TORSO,BP_TORSO,BP_TORSO,BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_HEAD)
+ if(L.can_inject(src, null, target_zone))
+ inject_poison(L, target_zone)
+
+/mob/living/simple_mob/vore/demon/proc/inject_poison(mob/living/L, target_zone)
+ if(prob(poison_chance))
+ to_chat(L, span_warning("You feel a tiny prick."))
+ L.reagents.add_reagent(poison_type, poison_per_bite)
+
+/mob/living/simple_mob/vore/demon/death()
+ laugh()
+ ..()
+
+/mob/living/simple_mob/vore/demon/bullet_act()
+ laugh()
+ ..()
+
+/mob/living/simple_mob/vore/demon/attack_hand()
+ laugh()
+ ..()
+
+/mob/living/simple_mob/vore/demon/hitby()
+ laugh()
+ ..()
+
+/mob/living/simple_mob/vore/demon/attackby()
+ laugh()
+ ..()
+//This below proc could be improved by 1. add a bool for overriding the check (if we directly call the proc for example)
+//and possibly adding a switch that checks a string given by the above procs so that we can have uniwue sounds if needed
+/mob/living/simple_mob/vore/demon/proc/laugh()
+ if(!src.ckey || enable_autolaugh)
+ playsound(src, laugh, 50, 1)
+
+//Fire heals demons instead.
+//This should include all fire sources assuming they dont weirdly make their own damage handling.
+//Yes this also means that negative fire is bad for them...
+/mob/living/simple_mob/vore/demon/adjustFireLoss(amount,include_robo = TRUE)
+ amount = 0 - amount
+ src.adjustBruteLoss(amount)
+ ..()
+
+
+/mob/living/simple_mob/vore/demon/verb/alt_appearance()
+ set name = "Toggle Alernate Appearance"
+ set desc = "Change your sprite to an alternative one."
+ set category = "Abilities.Demon"
+
+ if(!LAZYLEN(alt_demon_appearances))
+ to_chat(src, span_warning("There are no alternative apperances selectable!"))
+ return
+
+ var/alternate_selection = tgui_input_list(src, "Please select which alternate appearance you want to swap to.", "Variant Sprite", alt_demon_appearances)
+ if(!alternate_selection)
+ return
+
+ alternate_selection = lowertext(alternate_selection)
+
+ //Change the all the icon info.
+ icon = 'icons/mob/demon_vr.dmi' //Mass majority of the sprites use this icon
+ icon_state = "[alternate_selection]"
+ icon_living = "[alternate_selection]"
+ icon_dead = "dead"
+ icon_rest = "[alternate_selection]_rest"
+ vis_height = 47 //Mass majority of sprites use vis_height = 47. If its different, its done below.
+ pixel_x = 0
+ vore_icons = FALSE //No stomach sprites unless specifically specified!
+ //This is where we handle the special ones!
+ switch(alternate_selection)
+ if("boxfox")
+ vore_icons = SA_ICON_LIVING
+ vore_capacity = 1
+
+ if("wendigo")
+ vore_icons = SA_ICON_LIVING
+ vore_capacity = 1
+ icon_dead = "[alternate_selection]_dead"
+
+ //These are the larger variants, so we do some different stuff here!
+ if("brutola")
+ pixel_x = -8
+ vis_height = 64
+ vore_icons = SA_ICON_LIVING | SA_ICON_REST
+ vore_capacity = 2
+ icon_dead = "[alternate_selection]_dead"
+ icon = 'icons/mob/demon_alt.dmi'
+
+ if("ignia")
+ pixel_x = -8
+ vis_height = 64
+ vore_icons = SA_ICON_LIVING
+ vore_capacity = 2
+ icon_dead = "[alternate_selection]_dead"
+ icon = 'icons/mob/demon_alt.dmi'
+ update_icon()
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/demon/demonAI.dm b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demonAI.dm
new file mode 100644
index 0000000000..c399d88a3f
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demonAI.dm
@@ -0,0 +1,205 @@
+/mob/living/simple_mob/vore/demonAI
+ name = "Rift Walker"
+ desc = "A large bipedal creature, its body has a mixture of dark fur and scales. Marks on the creature's body pulse slowly with red light."
+
+ icon_state = "boxfox"
+ icon_living = "boxfox"
+ icon_dead = "dead"
+ icon_rest = "boxfox_rest"
+ icon = 'icons/mob/demon_vr.dmi'
+ vis_height = 47
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/hit_and_run
+ var/cloaked_alpha = 60 // Lower = Harder to see.
+ var/cloaked_bonus_damage = 30 // This is added on top of the normal melee damage.
+ var/cloaked_weaken_amount = 3 // How long to stun for.
+ var/cloak_cooldown = 10 SECONDS // Amount of time needed to re-cloak after losing it.
+ var/last_uncloak = 0 // world.time
+
+ faction = "demon"
+ maxHealth = 200
+ health = 200
+ movement_cooldown = 0
+
+ see_in_dark = 10
+ has_hands = TRUE
+ seedarkness = FALSE
+ attack_sound = 'sound/misc/demonattack.ogg'
+ has_langs = list(LANGUAGE_GALCOM,LANGUAGE_SHADEKIN,LANGUAGE_CULT)
+
+ melee_damage_lower = 10
+ melee_damage_upper = 5
+ var/poison_chance = 50
+ var/poison_type = REAGENT_ID_MINDBREAKER
+ var/poison_per_bite = 3
+
+ 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
+ maxbodytemp = 96669
+
+ response_help = "touches"
+ response_disarm = "pushes"
+ response_harm = "hits"
+
+ attacktext = list("mauled","slashed","clawed")
+ friendly = list("pokes", "scratches", "rurrs softly at", "sniffs on")
+
+ vore_active = 1
+ swallowTime = 2 SECOND
+ vore_pounce_chance = 15
+ vore_icons = SA_ICON_LIVING
+ vore_escape_chance = 25
+
+ var/shifted_out = FALSE
+ var/shift_state = AB_SHIFT_NONE
+ var/last_shift = 0
+ var/blood_spawn = 0
+ var/is_shifting = FALSE
+
+ can_pain_emote = FALSE
+ injury_enrages = TRUE
+
+/mob/living/simple_mob/vore/demonAI/load_default_bellies()
+ . = ..()
+ var/obj/belly/B = vore_selected
+ B.name = "Stomach"
+ B.desc = "You slide down the slick, slippery gullet of the creature. It's warm, and the air is thick. You can feel the doughy walls of the creatures gut push and knead into your form! Slimy juices coat your form stinging against your flesh as they waste no time to start digesting you. The creature's heartbeat and the gurgling of their stomach are all you can hear as your jostled about, treated like nothing but food."
+
+/mob/living/simple_mob/vore/demonAI/UnarmedAttack()
+ if(shifted_out)
+ return FALSE
+
+ . = ..()
+
+/mob/living/simple_mob/vore/demonAI/can_fall()
+ if(shifted_out)
+ return FALSE
+
+ return ..()
+
+/mob/living/simple_mob/vore/demonAI/zMove(direction)
+ if(shifted_out)
+ var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
+ if(destination)
+ forceMove(destination)
+ return TRUE
+
+ return ..()
+
+/mob/living/simple_mob/vore/demonAI/Life()
+ . = ..()
+ if(shifted_out)
+ density = FALSE
+
+/mob/living/simple_mob/vore/demonAI/handle_atmos()
+ if(shifted_out)
+ return
+ else
+ return .=..()
+
+/mob/living/simple_mob/vore/demonAI/update_canmove()
+ if(is_shifting)
+ canmove = FALSE
+ return canmove
+ else
+ return ..()
+
+/mob/living/simple_mob/vore/demonAI/cloak()
+ if(cloaked)
+ return
+ animate(src, alpha = cloaked_alpha, time = 1 SECOND)
+ cloaked = TRUE
+
+
+/mob/living/simple_mob/vore/demonAI/uncloak()
+ last_uncloak = world.time // This is assigned even if it isn't cloaked already, to 'reset' the timer if the spider is continously getting attacked.
+ if(!cloaked)
+ return
+ animate(src, alpha = initial(alpha), time = 1 SECOND)
+ cloaked = FALSE
+
+// Check if cloaking if possible.
+/mob/living/simple_mob/vore/demonAI/proc/can_cloak()
+ if(stat)
+ return FALSE
+ if(last_uncloak + cloak_cooldown > world.time)
+ return FALSE
+
+ return TRUE
+
+// Called by things that break cloaks, like Technomancer wards.
+/mob/living/simple_mob/vore/demonAI/break_cloak()
+ uncloak()
+
+/mob/living/simple_mob/vore/demonAI/is_cloaked()
+ return cloaked
+
+// Cloaks the spider automatically, if possible.
+/mob/living/simple_mob/vore/demonAI/handle_special()
+ if(!cloaked && can_cloak())
+ cloak()
+
+// Applies bonus base damage if cloaked.
+/mob/living/simple_mob/vore/demonAI/apply_bonus_melee_damage(atom/A, damage_amount)
+ if(cloaked)
+ playsound(src.loc, 'sound/effects/blobattack.ogg', 50, 1)
+ uncloak()
+ return damage_amount + cloaked_bonus_damage
+ return ..()
+
+// Force uncloaking if attacked.
+/mob/living/simple_mob/vore/demonAI/bullet_act(obj/item/projectile/P)
+ . = ..()
+ break_cloak()
+
+/mob/living/simple_mob/vore/demonAI/hit_with_weapon(obj/item/O, mob/living/user, effective_force, hit_zone)
+ . = ..()
+ break_cloak()
+
+/mob/living/simple_mob/vore/demonAI/apply_melee_effects(var/atom/A)
+ if(isliving(A))
+ var/mob/living/L = A
+ if(L.reagents)
+ var/target_zone = pick(BP_TORSO,BP_TORSO,BP_TORSO,BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_HEAD)
+ if(L.can_inject(src, null, target_zone))
+ inject_poison(L, target_zone)
+
+/mob/living/simple_mob/vore/demonAI/proc/inject_poison(mob/living/L, target_zone)
+ if(prob(poison_chance))
+ to_chat(L, span_warning("You feel a tiny prick."))
+ L.reagents.add_reagent(poison_type, poison_per_bite)
+
+
+/mob/living/simple_mob/vore/demonAI/death()
+ playsound(src, 'sound/misc/demondeath.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/vore/demonAI/bullet_act()
+ playsound(src, 'sound/misc/demonlaugh.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/vore/demonAI/attack_hand()
+ playsound(src, 'sound/misc/demonlaugh.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/vore/demonAI/hitby()
+ playsound(src, 'sound/misc/demonlaugh.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/vore/demonAI/attackby()
+ playsound(src, 'sound/misc/demonlaugh.ogg', 50, 1)
+ ..()
+
+/mob/living/simple_mob/vore/demonAI/gibspam
+
+/mob/living/simple_mob/vore/demonAI/gibspam/apply_bonus_melee_damage(atom/A, damage_amount)
+ var/turf/T = get_turf(src)
+ if(cloaked)
+ new /obj/effect/gibspawner/generic(T)
+ return ..()
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/demon/demonAI_subtypes.dm b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demonAI_subtypes.dm
new file mode 100644
index 0000000000..590e84006c
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demonAI_subtypes.dm
@@ -0,0 +1,89 @@
+/mob/living/simple_mob/vore/demonAI/wendigo
+ name = "Wendigo"
+
+ icon_state = "wendigo"
+ icon_living = "wendigo"
+ icon_dead = "wendigo_dead"
+ icon_rest = "wendigo_rest"
+
+ vore_icons = SA_ICON_LIVING
+
+/mob/living/simple_mob/vore/demonAI/engorge
+ name = "Engorge"
+
+ icon_state = "engorge"
+ icon_living = "engorge"
+ icon_dead = "dead"
+ icon_rest = "engorge_rest"
+
+ vore_icons = null
+
+/mob/living/simple_mob/vore/demonAI/zellic
+ name = "Zellic"
+
+ icon_state = "zellic"
+ icon_living = "zellic"
+ icon_dead = "dead"
+ icon_rest = null
+
+ vore_icons = null
+
+/mob/living/simple_mob/vore/demonAI/avarn
+ name = "Avarn"
+
+ icon_state = "avarn"
+ icon_living = "avarn"
+ icon_dead = "dead"
+ icon_rest = null
+
+ vore_icons = null
+
+/mob/living/simple_mob/vore/demonAI/covern
+ name = "Covern"
+
+ icon_state = "covern"
+ icon_living = "covern"
+ icon_dead = "dead"
+ icon_rest = null
+
+ vore_icons = null
+
+/mob/living/simple_mob/vore/demonAI/ira
+ name = "Ira"
+
+ icon_state = "ira"
+ icon_living = "ira"
+ icon_dead = "dead"
+ icon_rest = null
+
+ vore_icons = null
+
+/mob/living/simple_mob/vore/demonAI/ire
+ name = "Ire"
+
+ icon_state = "ire"
+ icon_living = "ire"
+ icon_dead = "dead"
+ icon_rest = null
+
+ vore_icons = null
+
+/mob/living/simple_mob/vore/demonAI/laxel
+ name = "Laxel"
+
+ icon_state = "laxel"
+ icon_living = "laxel"
+ icon_dead = "dead"
+ icon_rest = null
+
+ vore_icons = null
+
+/mob/living/simple_mob/vore/demonAI/lutra
+ name = "Lutra"
+
+ icon_state = "lutra"
+ icon_living = "lutra"
+ icon_dead = "dead"
+ icon_rest = null
+
+ vore_icons = null
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm
index ff4acfcffc..e741dea071 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm
@@ -8,6 +8,10 @@
to_chat(src,span_warning("You can't use that here!"))
return FALSE
+ if((get_area(src).flags & PHASE_SHIELDED))
+ to_chat(src,span_warning("This area is preventing you from phasing!"))
+ return FALSE
+
if(shift_state && shift_state == AB_SHIFT_ACTIVE)
to_chat(src,span_warning("You can't do a shift while actively shifting!"))
return FALSE
@@ -208,3 +212,120 @@
shift_state = AB_SHIFT_NONE
last_shift = world.time
+
+
+/mob/living/simple_mob/vore/demon/verb/blood_burst()
+ set name = "Blood burst"
+ set desc = "Spawn bloody remains from your past hunts."
+ set category = "Abilities.Demon"
+
+ var/turf/T = get_turf(src)
+
+ if(shifted_out)
+ to_chat(src,span_warning("You must be in the physical world to create blood!"))
+ return FALSE
+
+ if(world.time - blood_spawn < 1500)
+ to_chat(src,span_warning("You can't create blood so soon! You need to wait [round(((blood_spawn+1500)-world.time)/10)] second\s!"))
+ return FALSE
+
+
+ new /obj/effect/gibspawner/generic(T)
+
+ playsound(src.loc, 'sound/effects/blobattack.ogg', 50, 1)
+
+ blood_spawn = world.time
+
+ return
+
+/mob/living/simple_mob/vore/demon/verb/toggle_laugh()
+ set name = "Toggle Auto Laugh"
+ set desc = "Toggles whether the demon will automatically laugh when interacted with."
+ set category = "Abilities.Demon"
+
+ enable_autolaugh = !enable_autolaugh
+ if(enable_autolaugh)
+ to_chat(src,span_warning("Autolaugh has been toggled on"))
+ else
+ to_chat(src,span_warning("Autolaugh has been toggled off"))
+
+/mob/living/simple_mob/vore/demon/verb/manual_laugh()
+ set name = "Laugh"
+ set desc = "Plays the laugh track."
+ set category = "Abilities.Demon"
+
+ if(!enable_autolaugh) //yeah this is kinda sorta dirty but id rather use a bool over something else here to control this.
+ enable_autolaugh = !enable_autolaugh
+ laugh()
+ enable_autolaugh = !enable_autolaugh
+ else
+ laugh()
+ to_chat(src,span_warning("You laugh!")) //lets add some fluff response for clicking the feel good button.
+
+/mob/living/simple_mob/vore/demon/verb/sizespell()
+ set name = "Shrink/Grow Prey"
+ set category = "Abilities.Demon"
+ set desc = "Shrink/Grow someone nearby! (60 second cooldown)"
+ set popup_menu = FALSE // Stop licking by accident! //Yes this is from lick code, sue me.
+
+ var/obj/item/grab/G = src.get_active_hand()
+
+ if(!istype(G))
+ to_chat(src, span_warning("You must be grabbing a creature in your active hand to affect them."))
+ return
+ var/mob/living/carbon/human/T = G.affecting
+ if(!istype(T))
+ to_chat(src, span_warning("\The [T] is not able to be affected."))
+ return
+
+ if(G.state != GRAB_NECK)
+ to_chat(src, span_warning("You must have a tighter grip to affect this creature."))
+ return
+
+ if(!checkClickCooldown() || incapacitated(INCAPACITATION_ALL))
+ return
+
+ setClickCooldown(8)
+ T.resize(size_amount)
+ visible_message(span_warning("[src] shrinks [T]!"),span_notice("You shrink [T]."))
+
+/mob/living/simple_mob/vore/demon
+ var/size_amount = RESIZE_TINY //Adding a var to keep track of sizespell setting
+
+/mob/living/simple_mob/vore/demon/verb/toggle_sizespell()
+ set name = "Shrink/Grow Amount"
+ set desc = "Changes the amount you grow/shrink people."
+ set category = "Abilities.Demon"
+
+ var/size_select = tgui_input_number(src, "Put the desired size ([RESIZE_MINIMUM * 100]-[RESIZE_MAXIMUM * 100]%)", "Set Size", size_amount * 100, RESIZE_MAXIMUM * 100, RESIZE_MINIMUM * 100) //Stolen from sizegun code
+ if(!size_select)
+ return
+ size_amount = (size_select/100)
+ to_chat(src,span_notice("Size spell set to [size_select]%")) //Telling the user the new amount
+
+/mob/living/simple_mob/vore/demon/verb/demon_bite()
+ set name = "Mindbreaker Bite"
+ set category = "Abilities.Demon"
+ set desc = "Inject mindbreaker into your grabbed prey!"
+ set popup_menu = FALSE // Stop licking by accident! //Yes this is from lick code, sue me.
+
+ var/obj/item/grab/G = src.get_active_hand()
+
+ if(!istype(G))
+ to_chat(src, span_warning("You must be grabbing a creature in your active hand to affect them."))
+ return
+ var/mob/living/carbon/human/T = G.affecting
+ if(!istype(T))
+ to_chat(src, span_warning("\The [T] is not able to be affected."))
+ return
+
+ if(G.state != GRAB_NECK)
+ to_chat(src, span_warning("You must have a tighter grip to affect this creature."))
+ return
+
+ if(!checkClickCooldown() || incapacitated(INCAPACITATION_ALL))
+ return
+
+ setClickCooldown(8)
+ T.reagents.add_reagent(poison_type, poison_per_bite)
+ visible_message(span_warning("[src] bites [T]!"),span_notice("You bite [T]."))
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_subtypes.dm b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_subtypes.dm
index 4cd39bf171..edd049941e 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_subtypes.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_subtypes.dm
@@ -1,3 +1,13 @@
+/mob/living/simple_mob/vore/demon/wendigo
+ name = "Wendigo"
+
+ icon_state = "wendigo"
+ icon_living = "wendigo"
+ icon_dead = "wendigo_dead"
+ icon_rest = "wendigo_rest"
+
+ vore_icons = SA_ICON_LIVING
+
/mob/living/simple_mob/vore/demon/engorge
name = "Engorge"
@@ -17,3 +27,63 @@
icon_rest = null
vore_icons = null
+
+/mob/living/simple_mob/vore/demon/avarn
+ name = "Avarn"
+
+ icon_state = "avarn"
+ icon_living = "avarn"
+ icon_dead = "dead"
+ icon_rest = null
+
+ vore_icons = null
+
+/mob/living/simple_mob/vore/demon/covern
+ name = "Covern"
+
+ icon_state = "covern"
+ icon_living = "covern"
+ icon_dead = "dead"
+ icon_rest = null
+
+ vore_icons = null
+
+/mob/living/simple_mob/vore/demon/ira
+ name = "Ira"
+
+ icon_state = "ira"
+ icon_living = "ira"
+ icon_dead = "dead"
+ icon_rest = null
+
+ vore_icons = null
+
+/mob/living/simple_mob/vore/demon/ire
+ name = "Ire"
+
+ icon_state = "ire"
+ icon_living = "ire"
+ icon_dead = "dead"
+ icon_rest = null
+
+ vore_icons = null
+
+/mob/living/simple_mob/vore/demon/laxel
+ name = "Laxel"
+
+ icon_state = "laxel"
+ icon_living = "laxel"
+ icon_dead = "dead"
+ icon_rest = null
+
+ vore_icons = null
+
+/mob/living/simple_mob/vore/demon/lutra
+ name = "Lutra"
+
+ icon_state = "lutra"
+ icon_living = "lutra"
+ icon_dead = "dead"
+ icon_rest = null
+
+ vore_icons = null
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/dino.dm b/code/modules/mob/living/simple_mob/subtypes/vore/dino.dm
index aa3ddaeb44..f4ada1d39d 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/dino.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/dino.dm
@@ -39,6 +39,7 @@
max_n2 = 0
minbodytemp = 0
+ can_be_drop_prey = FALSE
allow_mind_transfer = TRUE
// Activate Noms!
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/dragon.dm b/code/modules/mob/living/simple_mob/subtypes/vore/dragon.dm
index 6d9fd49e08..6c30237cd0 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/dragon.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/dragon.dm
@@ -50,6 +50,8 @@
ai_holder_type = /datum/ai_holder/simple_mob/melee
say_list_type = /datum/say_list/dragonboss
+ can_be_drop_prey = FALSE
+
/mob/living/simple_mob/vore/aggressive/dragon/Process_Spacemove(var/check_drift = 0)
return 1 //No drifting in space for space dragons!
/*
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/fennec.dm b/code/modules/mob/living/simple_mob/subtypes/vore/fennec.dm
index 3e288a03e9..a6a5f7b02b 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/fennec.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/fennec.dm
@@ -66,6 +66,18 @@
vore_default_mode = DM_HOLD
vore_icons = SA_ICON_LIVING
+/mob/living/simple_mob/vore/fennec/load_default_bellies()
+ . = ..()
+
+ var/obj/belly/B = vore_selected
+ B.name = "stomach"
+ B.desc = "Warm, slick, and wet. You're somewhere hot, tight, and very cramped, unless you happen to somehow be smaller than the fennec you're in! It's hard to see, as rippling pink walls clench and smother over your form. If you don't want to be here, a newspaper from a friend ought to get you out. ...right?"
+ B.vore_sound = "Tauric Swallow"
+ B.release_sound = "Pred Escape"
+ B.fancy_vore = TRUE
+ B.belly_fullscreen_color = "#c47cb4"
+ B.belly_fullscreen = "anim_belly"
+
/datum/say_list/fennec
speak = list("SKREEEE!","Chrp?","Ararrrararr.")
emote_hear = list("screEEEEeeches!","chirps.")
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/frog.dm b/code/modules/mob/living/simple_mob/subtypes/vore/frog.dm
index 044ad104fa..5fdd8ce6a6 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/frog.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/frog.dm
@@ -3,15 +3,15 @@
desc = "Classification: Anura Gigantus\
\
A frog is any member of a diverse and largely carnivorous group of short-bodied, tailless amphibians composing \
- the order Anura. This specific species - Anura gigantus - is a mutated form of Frogs, largely due to exposure to mutagen chemicals. \
- These Giant Frogs are descendants from scientific frogs that were used for study during the great Sol Expansion Period. \
- Modern day Giant Frogs have reverted to a more feral state compared to their original ancestors and are hostile \
+ the order Anura. This specific species - Anura gigantus - is a mutated form of frogs, largely due to exposure to mutagen chemicals. \
+ These giant frogs are descendants from scientific frogs that were used for study during the great Sol Expansion Period. \
+ Modern day giant frogs have reverted to a more feral state compared to their original ancestors and are hostile \
towards humans and other small wildlife - hunting them for food.\
\
- The particular breed of Frog that was originally used in the scientific experiments were known as explosive breeders.\
+ The particular breed of frog that was originally used in the scientific experiments were known as explosive breeders.\
With explosive breeders, mature adult frogs arrive at breeding sites in response to certain trigger factors such as rainfall \
occurring in an arid area. In these frogs, mating and spawning take place promptly and the speed of larval growth is rapid in \
- order to make use of the ephemeral pools before they dry up. Because of this, the Frog population is through the roof and has \
+ order to make use of the ephemeral pools before they dry up. Because of this, the frog population is through the roof and has \
become a major issue for various colonies and stations.\
\
These animals, are considered an invasive species, and thus hunters are encouraged to hunt them."
@@ -44,6 +44,7 @@
special_attack_max_range = 5
special_attack_cooldown = 100
+ can_be_drop_prey = FALSE
allow_mind_transfer = TRUE
// Pepe is love, not hate.
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/goia.dm b/code/modules/mob/living/simple_mob/subtypes/vore/goia.dm
new file mode 100644
index 0000000000..747d5ad6a5
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/goia.dm
@@ -0,0 +1,564 @@
+/mob/living/simple_mob/vore/zorgoia
+ name = "zorgoia"
+ desc = "It's a a reptilian mammal hybrid, known for its voracious nature and love for fruits. By more popular terms its referred to as the furry slinky!"
+ tt_desc = "Zorgoyuh slinkus"
+ icon = 'icons/mob/zorgoia64x32.dmi'
+ icon_state = null //Overlay system will make the goias
+ icon_living = null
+ icon_rest = null
+ icon_dead = "zorgoia-death"
+ faction = FACTION_ZORGOIA
+ maxHealth = 150 //chonk
+ health = 150
+ melee_damage_lower = 5
+ melee_damage_upper = 15 //Don't break my bones bro
+ see_in_dark = 5
+ response_help = "pets"
+ response_disarm = "bops"
+ response_harm = "hits"
+ attacktext = list("mauled")
+ friendly = list("nuzzles", "noses softly at", "noseboops", "headbumps against", "nibbles affectionately on")
+ meat_amount = 5
+ has_eye_glow = TRUE //(evil)
+
+ old_x = 0
+ old_y = 0
+ default_pixel_x = 0
+ pixel_x = 0
+ pixel_y = 0
+
+ max_buckled_mobs = 1 //Yeehaw
+ can_buckle = TRUE
+ buckle_movable = TRUE
+ buckle_lying = FALSE
+ mount_offset_y = 10
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive/zorgoia
+ var/mob/living/carbon/human/friend
+ var/tamed = 0
+ var/tame_chance = 50 //It's a fiddy-fiddy default you may get a buddy pal or you may get mauled and ate. Win-win!
+
+ color = null //color is selected when spawned
+
+ vore_active = 1
+ vore_capacity = 3
+ vore_icons = 0 //The icon system down there handles the vore belly
+ vore_pounce_chance = 35
+ vore_bump_chance = 25
+ vore_icons = SA_ICON_LIVING | SA_ICON_REST
+ vore_stomach_name = "stomach" //Might make a better vore text but have this one for now.
+ vore_stomach_flavor = "You find yourself greedily gulped down into the zorgoia's stomach; the walls are surprisingly roomy in comparison to other critters of this size as their stomach makes up a majority of their long noodle shaped body. Your body contorting with the zorgoias long shape as every inch of you is tightly bound by their glowy walls."
+ vore_default_contamination_flavor = "Acrid"
+ vore_default_item_mode = IM_DIGEST
+
+
+ can_be_drop_prey = FALSE
+ allow_mind_transfer = TRUE
+ species_sounds = "None"
+ pain_emote_1p = list("yelp", "whine", "bark", "growl")
+ pain_emote_3p = list("yelps", "whines", "barks", "growls")
+
+ //This is copypastad from protean code, hope it isnt too painful lol
+ var/list/goia_overlays = list( //all 10 overlays, in order
+ "zorgoia_belly" = "#FFFFFF",
+ "zorgoia_main" = "#FFFFFF",
+ "zorgoia_ears" = "#FFFFFF",
+ "zorgoia_spots" = "#FFFFFF",
+ "zorgoia_claws" = "#FFFFFF",
+ "zorgoia_spines" = "#FFFFFF",
+ "zorgoia_fluff" = "#FFFFFF",
+ "zorgoia_underbelly" = "#FFFFFF",
+ "zorgoia_eyes" = "#FFFFFF",
+ "zorgoia_spike" = "#FFFFFF"
+ )
+
+ var/list/ear_styles = list(
+ "null",
+ "zorgoia_ears",
+ "zorgoia_ears2"
+ )
+ var/list/spots_styles = list(
+ "null",
+ "zorgoia_spots",
+ "zorgoia_stripes",
+ "zorgoia_backline",
+ "zorgoia_stars"
+ )
+ var/list/claws_styles = list(
+ "null",
+ "zorgoia_claws",
+ "zorgoia_justfangs",
+ "zorgoia_feetpaws"
+ )
+ var/list/spines_styles = list(
+ "null",
+ "zorgoia_spines",
+ "zorgoia_tailfade"
+ )
+ var/list/fluff_styles = list(
+ "null",
+ "zorgoia_fluff",
+ "zorgoia_fullhead"
+ )
+ var/list/underbelly_styles = list(
+ "zorgoia_underbelly",
+ "zorgoia_underbellystripe",
+ "null"
+ )
+ var/list/eyes_styles = list(
+ "zorgoia_eyes",
+ "zorgoia_eyes2"
+ )
+ var/list/spiky_styles = list(
+ "zorgoia_spike",
+ "zorgoia_spike2"
+ )
+ var/list/belly_styles = list(
+ "zorgoia_belly"
+ )
+
+/mob/living/simple_mob/vore/zorgoia/proc/recolor() //Base sprite wont need a radical menu selection
+ set name = "Change Color"
+ set desc = "Change your main color."
+ set category = "Abilities.General"
+ var/new_color = tgui_color_picker(src, "Pick new colors:","Color", goia_overlays["zorgoia_main"])
+ if(!new_color)
+ return 0
+ goia_overlays["zorgoia_main"] = new_color
+ update_icon()
+
+/mob/living/simple_mob/vore/zorgoia/proc/appearance_switch() //This is just copypastas of the radial menu code, each block of code is the options for each bit of customisation... all 9 of them
+ set name = "Adjust Mob Markings"
+ set desc = "Change your markings and mob colors."
+ set category = "Abilities.General"
+
+ var/list/options = list("Belly","Spike","Ears","Spots","Claws","Spines","Fluff","Underbelly","Eyes")
+ for(var/option in options)
+ LAZYSET(options, option, image('icons/effects/goia_labels.dmi', option))
+ var/choice = show_radial_menu(src, src, options, radius = 60)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return FALSE
+ . = TRUE
+ switch(choice)
+
+ if("Ears")
+ options = ear_styles
+ for(var/option in options)
+ var/image/I = image('icons/mob/zorgoia64x32.dmi', option, dir = 4, pixel_x = -16)
+ LAZYSET(options, option, I)
+ choice = show_radial_menu(src, src, options, radius = 90)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return 0
+ var/new_color = tgui_color_picker(src, "Pick ears spike color:","Ears Color", goia_overlays["zorgoia_ears"])
+ if(!new_color)
+ return 0
+ goia_overlays["ears"] = choice
+ goia_overlays["zorgoia_ears"] = new_color
+ update_icon()
+
+ if("Spots")
+ options = spots_styles
+ for(var/option in options)
+ var/image/I = image('icons/mob/zorgoia64x32.dmi', option, dir = 4, pixel_x = -16)
+ LAZYSET(options, option, I)
+ choice = show_radial_menu(src, src, options, radius = 90)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return 0
+ var/new_color = tgui_color_picker(src, "Pick spot colors:","Spots Color", goia_overlays["zorgoia_spots"])
+ if(!new_color)
+ return 0
+ goia_overlays["spots"] = choice
+ goia_overlays["zorgoia_spots"] = new_color
+ update_icon()
+
+ if("Claws")
+ options = claws_styles
+ for(var/option in options)
+ var/image/I = image('icons/mob/zorgoia64x32.dmi', option, dir = 4, pixel_x = -16)
+ LAZYSET(options, option, I)
+ choice = show_radial_menu(src, src, options, radius = 90)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return 0
+ var/new_color = tgui_color_picker(src, "Pick claw colors:","Claws Color", goia_overlays["zorgoia_claws"])
+ if(!new_color)
+ return 0
+ goia_overlays["claws"] = choice
+ goia_overlays["zorgoia_claws"] = new_color
+ update_icon()
+
+ if("Spines")
+ options = spines_styles
+ for(var/option in options)
+ var/image/I = image('icons/mob/zorgoia64x32.dmi', option, dir = 4, pixel_x = -16)
+ LAZYSET(options, option, I)
+ choice = show_radial_menu(src, src, options, radius = 90)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return 0
+ var/new_color = tgui_color_picker(src, "Pick spines colors:","Spines Color", goia_overlays["zorgoia_spines"])
+ if(!new_color)
+ return 0
+ goia_overlays["spines"] = choice
+ goia_overlays["zorgoia_spines"] = new_color
+ update_icon()
+
+ if("Fluff")
+ options = fluff_styles
+ for(var/option in options)
+ var/image/I = image('icons/mob/zorgoia64x32.dmi', option, dir = 4, pixel_x = -16)
+ LAZYSET(options, option, I)
+ choice = show_radial_menu(src, src, options, radius = 90)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return 0
+ var/new_color = tgui_color_picker(src, "Pick fluff colors:","Fluff Color", goia_overlays["zorgoia_fluff"])
+ if(!new_color)
+ return 0
+ goia_overlays["fluff"] = choice
+ goia_overlays["zorgoia_fluff"] = new_color
+ update_icon()
+
+ if("Underbelly")
+ options = underbelly_styles
+ for(var/option in options)
+ var/image/I = image('icons/mob/zorgoia64x32.dmi', option, dir = 4, pixel_x = -16)
+ LAZYSET(options, option, I)
+ choice = show_radial_menu(src, src, options, radius = 90)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return 0
+ var/new_color = tgui_color_picker(src, "Pick underbelly colors:","Underbelly Color", goia_overlays["zorgoia_underbelly"])
+ if(!new_color)
+ return 0
+ goia_overlays["underbelly"] = choice
+ goia_overlays["zorgoia_underbelly"] = new_color
+ update_icon()
+
+ if("Eyes")
+ options = eyes_styles
+ for(var/option in options)
+ var/image/I = image('icons/mob/zorgoia64x32.dmi', option, dir = 4, pixel_x = -16)
+ LAZYSET(options, option, I)
+ choice = show_radial_menu(src, src, options, radius = 90)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return 0
+ var/new_color = tgui_color_picker(src, "Pick eye color:","Eye Color", goia_overlays["zorgoia_eyes"])
+ if(!new_color)
+ return 0
+ goia_overlays["eyes"] = choice
+ goia_overlays["zorgoia_eyes"] = new_color
+ update_icon()
+
+ if("Spike")
+ options = spiky_styles
+ for(var/option in options)
+ var/image/I = image('icons/mob/zorgoia64x32.dmi', option, dir = 4)
+ LAZYSET(options, option, I)
+ choice = show_radial_menu(src, src, options, radius = 90)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return 0
+ var/new_color = tgui_color_picker(src, "Pick tail spike color:","Tail Color", goia_overlays["zorgoia_spike"]) //This is overlay 10, not 2, swapped with main body, im not rewriting this array
+ if(!new_color)
+ return 0
+ goia_overlays["spike"] = choice
+ goia_overlays["zorgoia_spike"] = new_color
+ update_icon()
+
+ if("Belly")
+ options = belly_styles
+ for(var/option in options)
+ var/image/I = image('icons/mob/zorgoia64x32.dmi', option, dir = 4)
+ LAZYSET(options, option, I)
+ choice = show_radial_menu(src, src, options, radius = 90)
+ if(!choice || QDELETED(src) || src.incapacitated())
+ return 0
+ var/new_color = tgui_color_picker(src, "Pick belly color:","Belly Color", goia_overlays["zorgoia_belly"])
+ if(!new_color)
+ return 0
+ goia_overlays["belly"] = choice
+ goia_overlays["zorgoia_belly"] = new_color
+ update_icon()
+
+/mob/living/simple_mob/vore/zorgoia/Initialize(mapload)
+ . = ..()
+ add_verb(src,/mob/living/simple_mob/vore/zorgoia/proc/appearance_switch)
+ add_verb(src,/mob/living/simple_mob/vore/zorgoia/proc/recolor)
+ add_verb(src,/mob/living/proc/injection) //Poison sting c:
+ add_verb(src,/mob/living/simple_mob/vore/zorgoia/proc/export_style)
+ add_verb(src,/mob/living/simple_mob/vore/zorgoia/proc/import_style)
+ src.trait_injection_reagents += REAGENT_ID_MICROCILLIN // get small
+ src.trait_injection_reagents += REAGENT_ID_MACROCILLIN // get BIG
+ src.trait_injection_reagents += REAGENT_ID_NORMALCILLIN // normal
+ src.trait_injection_reagents += REAGENT_ID_NUMBENZYME // no feelings
+ src.trait_injection_reagents += REAGENT_ID_ANDROROVIR // -> MALE
+ src.trait_injection_reagents += REAGENT_ID_GYNOROVIR // -> FEMALE
+ src.trait_injection_reagents += REAGENT_ID_ANDROGYNOROVIR // -> PLURAL
+ src.trait_injection_reagents += REAGENT_ID_STOXIN // night night chem
+ src.trait_injection_reagents += REAGENT_ID_RAINBOWTOXIN // Funny flashing lights.
+ src.trait_injection_reagents += REAGENT_ID_PARALYSISTOXIN // Paralysis!
+ src.trait_injection_reagents += REAGENT_ID_PAINENZYME // Pain INCREASER
+ // src.trait_injection_reagents += REAGENT_ID_APHRODISIAC // Horni // Downstream only
+
+ var/list/goia_colors = list("#1a00ff", "#6c5bff", "#ff00fe", "#ff0000", "#00d3ff", "#00ff7c", "#00ff35", "#e1ff00", "#ff9f00", "#393939")
+ var/bodycolor = pick(goia_colors)
+ var/spines = pick(goia_colors)
+ goia_overlays["main"]= "zorgoia_main"
+ goia_overlays["zorgoia_main"] = bodycolor
+ goia_overlays["ears"] = pick(ear_styles)
+ goia_overlays["zorgoia_ears"] = bodycolor
+ goia_overlays["spots"] = pick(spots_styles)
+ goia_overlays["zorgoia_spots"] = pick(goia_colors)
+ goia_overlays["claws"] = pick(claws_styles)
+ goia_overlays["zorgoia_claws"] = spines
+ goia_overlays["spines"] = pick(spines_styles)
+ goia_overlays["zorgoia_spines"] = spines
+ goia_overlays["fluff"] = pick(fluff_styles)
+ goia_overlays["zorgoia_fluff"] = bodycolor
+ goia_overlays["underbelly"] = pick(underbelly_styles)
+ goia_overlays["zorgoia_underbelly"] = bodycolor
+ goia_overlays["eyes"] = pick(eyes_styles)
+ goia_overlays["zorgoia_eyes"] = "#[get_random_colour(1)]"
+ goia_overlays["spike"] = pick(spiky_styles)
+ goia_overlays["zorgoia_spike"] = "#[get_random_colour(0,0,255)]"
+ goia_overlays["belly"] = pick(belly_styles)
+ goia_overlays["zorgoia_belly"] = bodycolor
+ update_icon()
+
+/mob/living/simple_mob/vore/zorgoia/update_icon()
+ ..()
+ if(stat == DEAD)
+ plane = MOB_LAYER
+ return
+ else
+ plane = ABOVE_MOB_PLANE
+ cut_overlays()
+ icon = 'icons/mob/zorgoia64x32.dmi'
+ vore_capacity = 3
+ //Heads up, the order of these overlays stacking on top of each other is different from the array order. So goia_overlay[1] is the belly, but rendering on top of everything at the end instead
+
+ var/image/I = image(icon, "[goia_overlays["main"]][resting? "-rest" : null]", pixel_x = -16)
+ I.color = goia_overlays["zorgoia_main"]
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
+ I.plane = MOB_PLANE
+ I.layer = MOB_LAYER
+ add_overlay(I)
+ qdel(I)
+
+ I = image(icon, "[goia_overlays["ears"]][resting? "-rest" : null]", pixel_x = -16)
+ I.color = goia_overlays["zorgoia_ears"]
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
+ I.plane = MOB_PLANE
+ I.layer = MOB_LAYER
+ add_overlay(I)
+ qdel(I)
+
+ I = image(icon, "[goia_overlays["spots"]][resting? "-rest" : null]", pixel_x = -16)
+ I.color = goia_overlays["zorgoia_spots"]
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
+ I.plane = MOB_PLANE
+ I.layer = MOB_LAYER
+ add_overlay(I)
+ qdel(I)
+
+ I = image(icon, "[goia_overlays["claws"]][resting? "-rest" : null]", pixel_x = -16)
+ I.color = goia_overlays["zorgoia_claws"]
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
+ I.plane = MOB_PLANE
+ I.layer = MOB_LAYER
+ add_overlay(I)
+ qdel(I)
+
+ I = image(icon, "[goia_overlays["spines"]][resting? "-rest" : null]", pixel_x = -16)
+ I.color = goia_overlays["zorgoia_spines"]
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
+ I.plane = MOB_PLANE
+ I.layer = MOB_LAYER
+ add_overlay(I)
+ qdel(I)
+
+
+ I = image(icon, "[goia_overlays["fluff"]][resting? "-rest" : null]", pixel_x = -16)
+ I.color = goia_overlays["zorgoia_fluff"]
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
+ I.plane = MOB_PLANE
+ I.layer = MOB_LAYER
+ add_overlay(I)
+ qdel(I)
+
+ I = image(icon, "[goia_overlays["eyes"]][resting? "-rest" : null]", pixel_x = -16)
+ I.color = goia_overlays["zorgoia_eyes"]
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
+ I.plane = PLANE_LIGHTING_ABOVE
+ add_overlay(I)
+ qdel(I)
+
+ I = image(icon, "[goia_overlays["spike"]][resting? "-rest" : null]", pixel_x = -16)
+ I.color = goia_overlays["zorgoia_spike"]
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
+ I.plane = MOB_PLANE
+ I.layer = MOB_LAYER
+ add_overlay(I)
+ qdel(I)
+
+ I = image(icon, "[goia_overlays["belly"]][resting? "-rest" : (vore_fullness? "-[vore_fullness]" : null)]", pixel_x = -16)
+ I.color = goia_overlays["zorgoia_belly"]
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
+ I.plane = MOB_PLANE
+ I.layer = MOB_LAYER
+ add_overlay(I)
+ qdel(I)
+
+ I = image(icon, "[goia_overlays["underbelly"]][resting? "-rest" : (vore_fullness? "-[vore_fullness]" : null)]", pixel_x = -16)
+ I.color = goia_overlays["zorgoia_underbelly"]
+ I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
+ I.plane = MOB_PLANE
+ I.layer = MOB_LAYER
+ add_overlay(I)
+ qdel(I)
+
+/mob/living/simple_mob/vore/zorgoia/attack_hand(mob/living/carbon/human/M as mob)
+ switch(M.a_intent)
+ if(I_HELP)
+ if(health > 0)
+ if(M.zone_sel.selecting == BP_GROIN)
+ if(M.vore_bellyrub(src))
+ return
+ M.visible_message(span_notice("[M] [response_help] \the [src]."))
+ if(has_AI())
+ var/datum/ai_holder/AI = ai_holder
+ AI.set_stance(STANCE_IDLE)
+ if(prob(tame_chance))
+ AI.violent_breakthrough = FALSE
+ AI.hostile = FALSE
+ friend = M
+ AI.set_follow(friend)
+ if(tamed != 1)
+ tamed = 1
+ faction = M.faction
+ sleep(1 SECOND)
+
+ if(I_GRAB)
+ if(health > 0)
+ if(has_AI())
+ var/datum/ai_holder/AI = ai_holder
+ audible_emote("growls disapprovingly at [M].")
+ if(M == friend)
+ AI.lose_follow()
+ friend = null
+ return
+ ..()
+ else
+ ..()
+
+/mob/living/simple_mob/vore/zorgoia/Login()
+ . = ..()
+ if(!riding_datum)
+ riding_datum = new /datum/riding/simple_mob(src)
+ add_verb(src,/mob/living/simple_mob/proc/animal_mount)
+ add_verb(src,/mob/living/proc/toggle_rider_reins)
+ movement_cooldown = 0
+
+/mob/living/simple_mob/vore/zorgoia/MouseDrop_T(mob/living/M, mob/living/user)
+ return
+
+/mob/living/simple_mob/vore/zorgoia/death() //are they going to be ok?
+ . = ..()
+ cut_overlays()
+
+/mob/living/simple_mob/vore/zorgoia/tamed
+ tamed = TRUE
+
+/datum/ai_holder/simple_mob/melee/evasive/zorgoia
+
+/datum/ai_holder/simple_mob/melee/evasive/zorgoia/New(var/mob/living/simple_mob/vore/zorgoia/new_holder)
+ .=..()
+ if(new_holder.tamed)
+ hostile = FALSE
+
+/mob/living/simple_mob/vore/zorgoia/proc/export_style()
+ set name = "Export style string"
+ set desc = "Export a string of text that can be used to instantly get the current style back using the import style verb"
+ set category = "Abilities.Settings"
+ var/output_style = jointext(list(
+ goia_overlays["zorgoia_main"],
+ goia_overlays["main"], // No alt styles for it currently
+ goia_overlays["zorgoia_ears"],
+ goia_overlays["ears"],
+ goia_overlays["zorgoia_spots"],
+ goia_overlays["spots"],
+ goia_overlays["zorgoia_claws"],
+ goia_overlays["claws"],
+ goia_overlays["zorgoia_spines"],
+ goia_overlays["spines"],
+ goia_overlays["zorgoia_fluff"],
+ goia_overlays["fluff"],
+ goia_overlays["zorgoia_underbelly"],
+ goia_overlays["underbelly"],
+ goia_overlays["zorgoia_eyes"],
+ goia_overlays["eyes"],
+ goia_overlays["zorgoia_spike"],
+ goia_overlays["spike"],
+ goia_overlays["zorgoia_belly"],
+ goia_overlays["belly"]), ";")
+ to_chat(src, span_notice("Exported style string is \" [output_style] \". Use this to get the same style in the future with import style"))
+
+/mob/living/simple_mob/vore/zorgoia/proc/import_style()
+ set name = "Import style string"
+ set desc = "Import a string of text that was made using the import style verb to get back that style"
+ set category = "Abilities.Settings"
+ var/input_style
+ input_style = sanitizeSafe(tgui_input_text(src,"Paste the style string you exported with Export Style.", "Style loading","", 250))
+ if(input_style)
+ var/list/input_style_list = splittext(input_style, ";")
+ if((LAZYLEN(input_style_list) == 20) /* && (input_style_list[2] in main_styles) */ \
+ && (input_style_list[4] in ear_styles) && (input_style_list[6] in spots_styles) && (input_style_list[8] in claws_styles) \
+ && (input_style_list[10] in spines_styles) && (input_style_list[12] in fluff_styles) && (input_style_list[14] in underbelly_styles) \
+ && (input_style_list[16] in eyes_styles) && (input_style_list[18] in spiky_styles) && (input_style_list[20] in belly_styles))
+ try
+ if(rgb2num(input_style_list[1]))
+ goia_overlays["zorgoia_main"] = input_style_list[1]
+ catch
+ // goia_overlays["main"] = input_style_list[2] // We only have one yet
+ try
+ if(rgb2num(input_style_list[3]))
+ goia_overlays["zorgoia_ears"] = input_style_list[3]
+ catch
+ goia_overlays["ears"] = input_style_list[4]
+ try
+ if(rgb2num(input_style_list[5]))
+ goia_overlays["zorgoia_spots"] = input_style_list[5]
+ catch
+ goia_overlays["spots"] = input_style_list[6]
+ try
+ if(rgb2num(input_style_list[7]))
+ goia_overlays["zorgoia_claws"] = input_style_list[7]
+ catch
+ goia_overlays["claws"] = input_style_list[8]
+ try
+ if(rgb2num(input_style_list[9]))
+ goia_overlays["zorgoia_spines"] = input_style_list[9]
+ catch
+ goia_overlays["spines"] = input_style_list[10]
+ try
+ if(rgb2num(input_style_list[11]))
+ goia_overlays["zorgoia_fluff"] = input_style_list[11]
+ catch
+ goia_overlays["fluff"] = input_style_list[12]
+ try
+ if(rgb2num(input_style_list[13]))
+ goia_overlays["zorgoia_underbelly"] = input_style_list[13]
+ catch
+ goia_overlays["underbelly"] = input_style_list[14]
+ try
+ if(rgb2num(input_style_list[15]))
+ goia_overlays["zorgoia_eyes"] = input_style_list[15]
+ catch
+ goia_overlays["eyes"] = input_style_list[16]
+ try
+ if(rgb2num(input_style_list[17]))
+ goia_overlays["zorgoia_spike"] = input_style_list[17]
+ catch
+ input_style_list["spike"] = input_style_list[18]
+ try
+ if(rgb2num(input_style_list[19]))
+ goia_overlays["zorgoia_belly"] = input_style_list[19]
+ catch
+ goia_overlays["belly"] = input_style_list[20]
+ update_icon()
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/greatwolf.dm b/code/modules/mob/living/simple_mob/subtypes/vore/greatwolf.dm
index 03b8d88864..2f15a13fb2 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/greatwolf.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/greatwolf.dm
@@ -24,7 +24,7 @@
response_help = "pets"
response_disarm = "shoves"
response_harm = "smacks"
- movement_cooldown = -1
+ movement_cooldown = -1 // 2 Downstream
harm_intent_damage = 10
melee_damage_lower = 10
melee_damage_upper = 20
@@ -85,7 +85,7 @@
Canis Lupus Greatus, or Great Wolf, is a very large predator not beleived to be native to Sif (because it's a wolf, duh), but it has been never been found anywhere else. Despite their size, they are gentle, unless disturbed.\
The majority of a great white wolf's long life is spent much the same as ordinary wolves. However, great wolves usually do not trouble themselves with small prey like humans, \
usually preferring instead to hunt Saviks and Kururaks, and sometimes, leopardmanders or invasive red dragons. \
- Though usually docile towards humans and other large sapients, neesless to say, these wolves possess great strength and a lethal bite. \
+ Though usually docile towards humans and other large sapients, neesless to say, these wolves posesses great strength and a lethal bite. \
a provoked great wolf can be a danger to even the most hardy of explorers due to its speed, crushing bite, and sometimes, it's appetite. \
The great wolves have been hunted to near extinction by poachers due to its extremely valuable hide. They are very rare, as one would expect, and generally cautious around people."
value = CATALOGUER_REWARD_HARD
@@ -94,9 +94,10 @@
. = ..()
if(!riding_datum)
riding_datum = new /datum/riding/simple_mob(src)
- add_verb(src, /mob/living/simple_mob/proc/animal_mount)
- add_verb(src, /mob/living/proc/toggle_rider_reins)
- movement_cooldown = -1.5
+ add_verb(src,/mob/living/simple_mob/proc/animal_mount)
+ add_verb(src,/mob/living/proc/toggle_rider_reins)
+ add_verb(src,/mob/living/simple_mob/proc/pick_color)
+ movement_cooldown = -1.5 // 1.5 Downstream
/mob/living/simple_mob/vore/greatwolf/MouseDrop_T(mob/living/M, mob/living/user)
return
@@ -129,6 +130,8 @@
B.vore_verb = "slurp"
B.contamination_color = "grey"
B.contamination_flavor = "Wet"
+ B.belly_fullscreen_color = "#c47cb4"
+ B.belly_fullscreen = "anim_belly"
B.emote_lists[DM_HOLD] = list(
"The wolf's idle wandering helps its stomach gently churn around you, slimily squelching against your figure.",
@@ -157,7 +160,7 @@
"%pred's %belly lets out a wet squelch as a few rounded shapes appear on its surface for a moment.")
B.struggle_messages_inside = list(
- "Your squirming seems to please the canine, though it's hard to tell whether or not it's helping get you out or not.",
+ "Your squirming seems to please the canine, though it's hard to tell wether or not it's helping get you out or not.",
"Your struggles only cause %pred's %belly to groan and gurgle softly around you.",
"Your movement only causes %pred's %belly to clench down upon you, smothering you briefly in thick gutflesh.",
"Your motion causes %pred's %belly to rumble irritably as you sink hands into the thick flesh.",
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/gryphon.dm b/code/modules/mob/living/simple_mob/subtypes/vore/gryphon.dm
new file mode 100644
index 0000000000..47cc0bd8ff
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/gryphon.dm
@@ -0,0 +1,261 @@
+/mob/living/simple_mob/vore/gryphon
+ name = "gryphon"
+ desc = "A large, lazy feline-avian hybrid. Best not to walk too close to a gryphon alone."
+
+ icon_state = "gryphon"
+ icon_living = "gryphon"
+ icon = 'icons/mob/vore64x64.dmi'
+ vis_height = 64
+
+ faction = FACTION_GRYPHON
+ maxHealth = 200 // Pretty tanky, but not a boss
+ health = 200
+ see_in_dark = 8
+
+ melee_damage_lower = 5
+ melee_damage_upper = 30
+
+ meat_amount = 15
+ meat_type = /obj/item/reagent_containers/food/snacks/meat
+
+ response_help = "pats"
+ response_disarm = "tries to shove"
+ response_harm = "hits"
+ attacktext = list("scratches", "bites")
+
+ friendly = list("beak-nudges", "purrs towards", "slobberlicks")
+ vore_bump_emote = "tries to quickly devour"
+
+ old_x = -16
+ old_y = 0
+ default_pixel_x = -16
+ pixel_x = -16
+ pixel_y = 0
+ mount_offset_y = 15
+ mount_offset_x = -12
+ max_buckled_mobs = 1
+ can_buckle = TRUE
+ buckle_movable = TRUE
+ buckle_lying = FALSE
+
+ var/random_skin = TRUE
+ var/list/skins = list(
+ "gryphon"
+ )
+
+ special_attack_min_range = 2
+ special_attack_max_range = 4
+ special_attack_cooldown = 30 SECONDS
+
+ devourable = FALSE
+
+ ai_holder_type = /datum/ai_holder/simple_mob/vore/gryphon
+ say_list_type = /datum/say_list/gryphon
+
+ can_be_drop_prey = FALSE
+ var/leap_warmup = 2 SECOND // How long the leap telegraphing is.
+ var/leap_sound = 'sound/weapons/spiderlunge.ogg'
+
+// Activate Noms!
+/mob/living/simple_mob/vore/gryphon
+ vore_bump_chance = 25
+ vore_digest_chance = 100
+ // Strong pounce, but needs to be alone to trigger it
+ vore_pounce_chance = 100
+ vore_pounce_falloff = 0
+ vore_active = TRUE
+ vore_icons = 0
+ vore_capacity = 2
+ swallowTime = 20
+ vore_ignores_undigestable = TRUE
+ vore_default_mode = DM_DIGEST
+ vore_pounce_maxhealth = 125
+ vore_bump_emote = "tries to gulp down"
+ vore_capacity_ex = list("stomach" = 1, "throat" = 1)
+ vore_fullness_ex = list("stomach" = 0, "throat" = 0)
+ vore_icon_bellies = list("stomach", "throat")
+
+/datum/ai_holder/simple_mob/vore/gryphon
+ var/eat_attempts = 0
+ var/maybe_eating = null
+
+/datum/ai_holder/simple_mob/vore/gryphon/find_target(list/possible_targets, has_targets_list)
+ ai_log("find_target() : Entered.", AI_LOG_TRACE)
+ var/targets = list()
+ if(!has_targets_list)
+ possible_targets = list_targets()
+ var/mob/sentient = null
+ var/alone = TRUE
+ for(var/mob/possible_target in possible_targets)
+ if(can_attack(possible_target)) // Can we attack it?
+ targets += possible_target
+ if (possible_target.client != null)
+ if (sentient == null)
+ if (vore_check(possible_target))
+ sentient = possible_target
+ else
+ alone = FALSE
+ else
+ alone = FALSE
+
+ // Only one player, consider eating them
+ if (sentient != null)
+ return possibly_eat(sentient, alone)
+
+ // Only one mob, eat them
+ if (length(targets) == 1 && alone)
+ var/target = pick_target(targets)
+ if (vore_check(target) && can_attack(target))
+ give_target(target)
+ return target
+ eat_attempts = 0
+ return null
+
+/datum/ai_holder/simple_mob/vore/gryphon/proc/possibly_eat(var/target, var/alone)
+ if (target != maybe_eating)
+ eat_attempts = 0
+
+ maybe_eating = target
+ if (eat_attempts == 5)
+ to_chat(target, span_danger("\The [holder] licks its beak"))
+ else if (eat_attempts == 10)
+ to_chat(target, span_danger("\The [holder]'s stomach grumbles loudly"))
+ else if (alone && eat_attempts > 15 && can_attack(target))
+ give_target(target)
+
+ if (eat_attempts < 11 || alone)
+ eat_attempts += 1
+
+/mob/living/simple_mob/vore/gryphon/load_default_bellies()
+ var/obj/belly/B = new /obj/belly/gryphon/beak(src)
+ vore_selected = B
+ B.affects_vore_sprites = FALSE
+ B.emote_lists[DM_HOLD] = list("You get pushed around the creature's maw, that tongue pressing you against the roof of its mouth and humming as it savors your taste",
+ "The gryphon swallows, pulling you closer to the gullet desperately trying to gulp you down.",
+ "You feel that beak tilt upwards to help pull you deeper into the gryphon's body, intent on making you disappear.")
+ B = new /obj/belly/gryphon/throat(src)
+ B.affects_vore_sprites = TRUE
+ B.belly_sprite_to_affect = "throat"
+ B.emote_lists[DM_HOLD] = list("You hear the light gurgling of the stomach below you, calling you to relax and allow the beast to claim you.",
+ "Those throat muscles squeeze and knead all along your body, pressing you deeper into the gryphon's body.")
+ B = new /obj/belly/gryphon/stomach(src)
+ B.affects_vore_sprites = TRUE
+ B.belly_sprite_to_affect = "stomach"
+ B.emote_lists[DM_HOLD] = list("The gryphon lightly sways its filled gut, tossing you around inside of the tight chamber.",
+ "A sudden pressure presses down across your body as the gryphon gives its gut a squeeze.",
+ "Sitting in the hot, stewing guts of the gryphon you wonder when someone will finally notice that you've disappeared.")
+ B.emote_lists[DM_DIGEST] = list("The churning gut squeezes down on your body, rubbing more of those acids into your skin and trying to claim you as nutrients to fuel the massive gryphon.",
+ "The gryphon lightly sways its filled gut, tossing you around inside of the tight chamber.",
+ "A sudden pressure presses down across your body as the gryphon gives its gut a squeeze.",
+ "Sitting in the hot, stewing guts of the gryphon you wonder when someone will finally notice that you've disappeared.")
+
+/mob/living/simple_mob/vore/gryphon/do_special_attack(atom/A) //Mostly copied from cryptdrake.dm
+ set waitfor = FALSE
+ if(!isliving(A))
+ return FALSE
+ var/mob/living/L = A
+ if(!L.devourable || !L.allowmobvore || !L.can_be_drop_prey || !L.throw_vore || L.unacidable)
+ return FALSE
+
+ set_AI_busy(TRUE)
+ visible_message(span_warning("\The [src] crouches down and wiggles its haunches!"))
+ to_chat(L, span_danger("\The [src] is looking right at you!"))
+ // Telegraph, since getting stunned suddenly feels bad.
+ do_windup_animation(A, leap_warmup)
+ sleep(leap_warmup) // For the telegraphing.
+
+ if(L.z != z) //Make sure you haven't disappeared to somewhere we can't go
+ set_AI_busy(FALSE)
+ return FALSE
+
+ // Do the actual leap.
+ status_flags |= LEAPING // Lets us pass over everything.
+ visible_message(span_critical("\The [src] leaps at \the [L]!"))
+ throw_at(get_step(L, get_turf(src)), special_attack_max_range+1, 1, src)
+ playsound(src, leap_sound, 75, 1)
+
+ sleep(5) // For the throw to complete. It won't hold up the AI ticker due to waitfor being false.
+
+ if(status_flags & LEAPING)
+ status_flags &= ~LEAPING // Revert special passage ability.
+
+ set_AI_busy(FALSE)
+ if(Adjacent(L)) //We leapt at them but we didn't manage to hit them, let's see if we're next to them
+ L.Weaken(2) //get knocked down, idiot
+
+/mob/living/simple_mob/vore/gryphon/Login()
+ . = ..()
+ if(!riding_datum)
+ riding_datum = new /datum/riding/simple_mob(src)
+ add_verb(src,/mob/living/simple_mob/proc/animal_mount)
+ add_verb(src,/mob/living/proc/toggle_rider_reins)
+ movement_cooldown = 0
+
+/mob/living/simple_mob/vore/gryphon/MouseDrop_T(mob/living/M, mob/living/user)
+ return
+
+/datum/say_list/gryphon
+ emote_hear = list("squawks!", "looks around as its stomach growls.")
+ emote_see = list("licks its beak.", "looks around.")
+ say_maybe_target = list("squawks")
+ say_got_target = list("screeches")
+
+/obj/belly/gryphon
+ autotransferchance = 50
+ autotransferwait = 150
+ fancy_vore = TRUE
+ contamination_color = "green"
+ contamination_flavor = "Wet"
+ vore_verb = "chomp"
+ belly_fullscreen_color = "#711e1e"
+
+/obj/belly/gryphon/beak
+ name = "Beak"
+ mode_flags = DM_FLAG_THICKBELLY
+ escapable = TRUE
+ escapechance = 5
+ desc = "Noticing you alone, the gryphon lunges forwards and wraps its beak around your head, forcing you to stare into the dark abyss at the back of the gryphon's throat. It quickly tries to swallow you down, beak closing around your torso and head tilting back, letting gravity help make you disappear before anyone sees."
+ struggle_messages_inside = list(
+ "You try to push the gryphon's tongue away, instead getting tossed around and savoured by the massive beast",
+ "Pressing against the beak around your body, you barely pry them off of your torso, trying to wiggle out-- only for the gryphon to clamp right back down around you and continue swallowing their meal",
+ "You try to shy away from the back of the gryphon's maw, desperately avoiding the massive beast's gullet. The gryphon easily counterracts your efforts, pushing you closer and closer towards the fate that throat promises")
+ autotransferlocation = "Throat"
+ autotransfer_enabled = TRUE
+ autotransferchance = 30
+ autotransferwait = 5
+ belly_fullscreen = "a_tumby"
+ vore_sound = "Insertion1"
+
+/obj/belly/gryphon/throat
+ name = "Throat"
+ mode_flags = DM_FLAG_THICKBELLY
+ transferchance = 20
+ transferlocation = "Beak"
+ escapechance = 0
+ desc = "After pushing you about its maw for a while the gryphon finally swallows its treat, the gullet squeezing around you and the creature's head lifting as it gulps you down. Your upper body gets shoved into its throat, the powerful muscles kneading down on your body and continuing to coax you deeper towards the gurgling stomach below."
+ struggle_messages_inside = list(
+ "You try to push yourself back with your hands, finding no purchase against those slick, spittle-coated muscles.",
+ "Your hands push those throat walls away from you, only for them to clench down around you in another powerful swallow.")
+ autotransferlocation = "Stomach"
+ autotransfer_enabled = TRUE
+ autotransferchance = 50
+ autotransferwait = 5
+ belly_fullscreen = "VBO_intestines1"
+ vore_sound = "Tauric Swallow"
+
+/obj/belly/gryphon/stomach
+ name = "Stomach"
+ mode_flags = DM_FLAG_THICKBELLY
+ escapechance = 0
+ transferchance = 10
+ transferlocation = "Throat"
+ desc = "Finally, you get shoved into the beast's stomach, that hammock-like gut welcoming you into a pool of digestive acids. The heat is oppressive, the stomach walls kneading it against your skin, coaxing you to simply give in and become gryphon food. Other than the constant pleasure, the snug warmth is at least pleasant at the moment, rolling across your body in time with the creature's rhythmic breaths and heartbeats, the air stale and thick with the tinge of acid."
+ digest_mode = DM_DIGEST
+ digest_brute = 1
+ digest_burn = 3
+ struggle_messages_inside = list(
+ "You press your hands out at the tight stomach muscles, feeling the stiff resistance give way for a second, only for the walls to squeeze back down around you even tighter.",
+ "The gryphon presses its talons down on its midsection as you struggle, forcing you to stay still in the depths of its guts and await whatever fate the beast plans for you"
+ )
+ belly_fullscreen = "VBOanim_belly1"
+ vore_sound = "Stomach Move"
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/hippo.dm b/code/modules/mob/living/simple_mob/subtypes/vore/hippo.dm
index 7d37f25a51..b7468e59d2 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/hippo.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/hippo.dm
@@ -50,6 +50,8 @@
say_list_type = /datum/say_list/hippo
ai_holder_type = /datum/ai_holder/simple_mob/retaliate
+ can_be_drop_prey = FALSE
+
// Activate Noms!
/mob/living/simple_mob/vore/hippo //I don't know why it's in a seperate line but everyone does it so i do it
vore_active = 1
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/horse.dm b/code/modules/mob/living/simple_mob/subtypes/vore/horse.dm
index c69daceaf1..72c7c4b5a8 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/horse.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/horse.dm
@@ -35,6 +35,7 @@
say_list_type = /datum/say_list/horse
ai_holder_type = /datum/ai_holder/simple_mob/retaliate
+ can_be_drop_prey = FALSE
allow_mind_transfer = TRUE
/mob/living/simple_mob/vore/horse/big
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/jelly.dm b/code/modules/mob/living/simple_mob/subtypes/vore/jelly.dm
index e920a18977..60f0308b81 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/jelly.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/jelly.dm
@@ -28,6 +28,8 @@
say_list_type = /datum/say_list/jelly
ai_holder_type = /datum/ai_holder/simple_mob/retaliate/jelly
+ can_be_drop_prey = FALSE
+
min_oxy = 0
max_oxy = 0
min_tox = 0
@@ -62,6 +64,9 @@
B.digest_brute = 0.3
B.digest_burn = 0.3
B.escapechance = 10 // You were dumb enough to walk into it or stand still, now good luck escaping.
+ B.contaminates = TRUE
+ B.contamination_flavor = "Slimy"
+ B.contamination_color = "green"
B.item_digest_mode = IM_HOLD
B.belly_fullscreen = "VBOanim_belly1"
B.belly_fullscreen_color = "#823232"
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/lamia.dm b/code/modules/mob/living/simple_mob/subtypes/vore/lamia.dm
index cbc25f705f..7ecdfe1d11 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/lamia.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/lamia.dm
@@ -55,6 +55,8 @@
say_list_type = /datum/say_list/lamia
ai_holder_type = /datum/ai_holder/simple_mob/passive
+ can_be_drop_prey = FALSE
+
/mob/living/simple_mob/vore/lamia/update_icon()
. = ..()
@@ -104,6 +106,9 @@
tail.nonhuman_prey_swallow_time = swallowTime
tail.vore_verb = "stuff"
tail.belly_sprite_to_affect = "tail"
+ tail.belly_fullscreen = "VBOanim_snakebelly1"
+ tail.belly_fullscreen_color = "#823232"
+ tail.belly_fullscreen_color2 = "#232300"
// Belly Lines by killerdragn (@kilo.ego on discord) from Rogue Star
B.emote_lists[DM_HOLD] = list(
@@ -367,3 +372,20 @@ GLOBAL_LIST_INIT(valid_random_lamias, list(
speak = list("Sss...","Sss!","Hiss!","HSSSSS")
emote_hear = list("hisses","slithers")
emote_see = list("shakes her head","coils","stretches","slithers")
+
+/mob/living/simple_mob/vore/lamia/albino/cave
+ name = "albino cave lamia"
+ desc = "Combination snake-human. This one looks ravenous!"
+ melee_damage_lower = 5
+ melee_damage_upper = 5
+ vore_upper_transfer_chance = 75 // Since these lamias are on the hunt, you're getting pushed into the tail tum for fussing.
+ vore_tail_transfer_chance = 10 // And the albino ones are EXTRA greedy!
+ ai_holder_type = /datum/ai_holder/simple_mob/vore/stalker // Good enough for now.
+
+/mob/living/simple_mob/vore/lamia/copper/cave
+ name = "cave lamia"
+ desc = "Combination snake-human. This one looks hungry!"
+ melee_damage_lower = 5
+ melee_damage_upper = 5
+ vore_upper_transfer_chance = 75
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/leopardmander.dm b/code/modules/mob/living/simple_mob/subtypes/vore/leopardmander.dm
index 3f261924ad..9cb35c4ccf 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/leopardmander.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/leopardmander.dm
@@ -13,17 +13,17 @@
meat_type = /obj/item/reagent_containers/food/snacks/meat
old_x = -48
old_y = 0
+ vis_height = 92
melee_damage_lower = 10
melee_damage_upper = 25
friendly = list("nudges", "sniffs on", "rumbles softly at", "slobberlicks")
default_pixel_x = -48
pixel_x = -48
pixel_y = 0
- vis_height = 92
response_help = "pats"
response_disarm = "shoves"
response_harm = "bops"
- movement_cooldown = -1
+ movement_cooldown = -1 // 2 on Downstream
maxHealth = 1500
attacktext = list("chomped")
see_in_dark = 8
@@ -36,8 +36,6 @@
buckle_movable = TRUE
buckle_lying = FALSE
vore_bump_chance = 50
- vore_digest_chance = 0
- vore_escape_chance = 50
vore_pounce_chance = 100
vore_active = 1
vore_icons = SA_ICON_LIVING|SA_ICON_REST
@@ -50,6 +48,11 @@
nom_mob = TRUE
+ can_be_drop_prey = FALSE
+ species_sounds = "Canine" // Argue about whether it should have canine or feline later
+ pain_emote_1p = list("yelp", "whine", "bark", "growl")
+ pain_emote_3p = list("yelps", "whines", "barks", "growls")
+
/datum/category_item/catalogue/fauna/leopardmander
name = "Sivian Fauna - Va'aen Drake"
desc = "Classification: S Draconis uncia\
@@ -57,7 +60,7 @@
The Va'aen drake, or Sivian leopardmander, is a very large predator known for its unusual ability to heal people's wounds via saliva, or storing them in one of its multiple stomachs for extended periods of time. \
The majority of the Va'aen drake's long life is spent in isolation, hunting saviks and shantaks in Sif's mountainous regions or roaming the vast tundras of Sif, \
only seeking out other individuals during the summer mating season where they spend several months in courtship, usually only producing a single egg. \
- Though completely docile towards humans and other large sapients, the Va'aen drake possesses great strength and a very potent paralyzing venom; \
+ Though completely docile towards humans and other large sapients, the Va'aen drake posesses great strength and a very potent paralyzing venom; \
a provoked Va'aen can be a danger to even the most hardy of explorers due to its surprising speed, crushing bite, and long lasting venom. \
The Va'aen has been hunted to near extinction by poachers due to its secretions' unusual healing properties, and its beautiful hide; encountering one has become very rare."
value = CATALOGUER_REWARD_HARD
@@ -66,26 +69,33 @@
. = ..()
if(!riding_datum)
riding_datum = new /datum/riding/simple_mob(src)
- add_verb(src, /mob/living/simple_mob/proc/animal_mount)
- add_verb(src, /mob/living/proc/toggle_rider_reins)
- movement_cooldown = -1
+ add_verb(src,/mob/living/simple_mob/proc/animal_mount)
+ add_verb(src,/mob/living/proc/toggle_rider_reins)
+ movement_cooldown = -1 // 2 on Downstream
+ plane_holder.set_vis(VIS_CH_HEALTH_VR, 1)
+ plane_holder.set_vis(VIS_CH_ID, 1)
+ plane_holder.set_vis(VIS_CH_STATUS_R, 1)
+ plane_holder.set_vis(VIS_CH_BACKUP, 1)
/mob/living/simple_mob/vore/leopardmander/Initialize(mapload)
. = ..()
src.adjust_nutrition(src.max_nutrition)
/mob/living/simple_mob/vore/leopardmander/load_default_bellies()
- . = ..()
- var/obj/belly/B = vore_selected
+ var/obj/belly/B = new /obj/belly(src)
+ B.affects_vore_sprites = TRUE
+ B.belly_sprite_to_affect = "stomach"
B.name = "stomach"
B.desc = "The leopardmander tosses its head back with you firmly clasped in its jaws, and in a few swift moments it finishes swallowing you down into its hot, dark gut. Your weight makes absolutely no impact on its form, the doughy walls giving way beneath you with unnatural softness. The thick, humid air is tinged with an oddly pleasant smell, and the surrounding flesh wastes no time in clenching and massaging down over its newfound fodder, smothering you in thick hot gutflesh~"
B.vore_sound = "Tauric Swallow"
B.release_sound = "Pred Escape"
- B.mode_flags = DM_FLAG_NUMBING
+ B.mode_flags = DM_FLAG_NUMBING | DM_FLAG_THICKBELLY | DM_FLAG_TURBOMODE
B.fancy_vore = 1
B.vore_verb = "slurp"
B.contamination_color = "grey"
B.contamination_flavor = "Wet"
+ B.belly_fullscreen_color = "#c47cb4"
+ B.belly_fullscreen = "anim_belly"
B.emote_lists[DM_HEAL] = list(
"The drake's idle movement helps its stomach gently churn around you, slimily squelching against your figure.",
"The draconic predator takes a moment to intentionally clench its gut around you, encapsulating you in a strange, fleshy hug.",
@@ -102,6 +112,32 @@
"The constant, rhythmic kneading and massaging starts to take its toll along with the muggy heat, making you feel weaker and weaker!",
"The drake happily wanders around while digesting its meal, almost like it is trying to show off the hanging gut you've given it. Not like it made much of a difference on his already borderline obese form anyway~")
+ B = new /obj/belly(src)
+
+ vore_selected = B
+ B.name = "maw"
+ B.desc = "Slrrrrrp... You get snatched up by the Exotic Leopardmander's large tongue, resulting in you getting dragged into the humid, dank interior of the large drake's cavernous mouth!"
+ //Not going to change the default sounds. Personally I think the non-fancy sounds work good as enterance nom sounds and the fancy ones are better for transfer sounds. -Reo
+ B.digest_mode = DM_HEAL
+ B.vore_verb = "slurp"
+ B.release_verb = "plehs"
+ B.contaminates = FALSE
+ B.belly_fullscreen_color = "#c47cb4"
+ B.belly_fullscreen_color2 = "#C2B4B4"
+ B.belly_fullscreen_color3 = "#FFCCFF"
+ B.belly_fullscreen = "VBO_maw5"
+ B.emote_time = 1 //Short emote time, since they wont spend long here!
+ B.emote_lists[DM_HOLD] = list(
+ "The drake's thick tongue presses against your form, smothering you with thick, gooey saliva as it pushes you around in it's maw.",
+ "The exotic drake lets out a deep rumble as it idly maws over you, shifting you in a warm, slimy embrace as it passively prepares to send you into a deeper embrace."
+ )
+ B.autotransfer_enabled = TRUE
+ B.autotransferchance = 30
+ B.autotransferwait = 5
+ B.autotransferlocation = "stomach"
+ B.escapetime = 1 SECONDS
+ B.escapechance = 75
+
/datum/say_list/leopardmander
speak = list("Prurr.", "Rrrhf.", "Rrrrrll.", "Mrrrrph.")
emote_hear = list("chuffs", "murrs", "churls", "hisses", "rrrrrls", "yawns that big ol' maw open.")
@@ -141,20 +177,22 @@
/mob/living/simple_mob/vore/leopardmander/exotic/Initialize(mapload)
. = ..()
- add_verb(src, /mob/living/simple_mob/vore/leopardmander/exotic/proc/toggle_glow)
+ add_verb(src,/mob/living/simple_mob/vore/leopardmander/exotic/proc/toggle_glow)
/mob/living/simple_mob/vore/leopardmander/exotic/load_default_bellies()
- . = ..()
- var/obj/belly/B = vore_selected
+ var/obj/belly/B = new /obj/belly(src)
B.name = "stomach"
B.desc = "The exotic leopardmander tosses its head back with you firmly clasped in its jaws, and in a few swift moments it finishes swallowing you down into its hot, brightly glowing gut. Your weight makes absolutely no impact on its form, the doughy walls giving way beneath you, with their unnatural softness. The thick, humid air is tinged with an oddly pleasant smell, and the surrounding flesh wastes no time in clenching and massaging down over its newfound fodder, smothering you in thick hot gutflesh~ You can only really sort of see outside that thick-walled gut."
B.vore_sound = "Tauric Swallow"
B.release_sound = "Pred Escape"
- B.mode_flags = DM_FLAG_NUMBING
+ B.mode_flags = DM_FLAG_NUMBING | DM_FLAG_THICKBELLY | DM_FLAG_TURBOMODE
B.fancy_vore = 1
B.vore_verb = "slurp"
B.contamination_color = "pink"
B.contamination_flavor = "Wet"
+ B.belly_fullscreen_color = "#df3dbc"
+ B.belly_fullscreen_alpha = 240
+ B.belly_fullscreen = "anim_belly"
B.emote_lists[DM_HEAL] = list(
"The drake's idle movement helps its stomach gently churn around you, slimily squelching against your figure.",
"The draconic predator takes a moment to intentionally clench its gut around you, encapsulating you in a strange, fleshy hug.",
@@ -170,6 +208,32 @@
"As the thinning air begins to make you feel dizzy, menacing bworps and grumbles fill that dark, constantly shifting organ!",
"The constant, rhythmic kneading and massaging starts to take its toll along with the muggy heat, making you feel weaker and weaker!",
"The drake happily wanders around while digesting its meal, almost like it is trying to show off the hanging gut you've given it. Not like it made much of a difference on his already borderline obese form anyway~")
+ B.transferchance = 50
+ B.transferlocation = "maw"
+
+ B = new /obj/belly(src)
+ vore_selected = B
+
+ B.name = "maw"
+ B.desc = "Slrrrrrp... You get snatched up by the Exotic Leopardmander's large tongue, resulting in you getting dragged into the humid, dank interior of the large drake's cavernous mouth!"
+ //Not going to change the default sounds. Personally I think the non-fancy sounds work good as enterance nom sounds and the fancy ones are better for transfer sounds. -Reo
+ B.vore_verb = "slurp"
+ B.release_verb = "plehs"
+ B.contaminates = FALSE
+ B.belly_fullscreen_color = "#c47cb4"
+ B.belly_fullscreen_color2 = "#C2B4B4"
+ B.belly_fullscreen_color3 = "#8D60CE"
+ B.belly_fullscreen_color4 = "#B593F9"
+ B.belly_fullscreen = "VBO_maw5"
+ B.emote_time = 1 //Short emote time, since they wont spend long here!
+ B.emote_lists[DM_HOLD] = list(
+ "The drake's thick tongue presses against your form, smothering you with thick, gooey saliva as it pushes you around in it's maw.",
+ "The exotic drake lets out a deep rumble as it idly maws over you, shifting you in a warm, slimy embrace as it passively prepares to send you into a deeper embrace."
+ )
+ B.autotransferwait = 5
+ B.autotransferlocation = "stomach"
+ B.escapetime = 1 SECONDS
+ B.escapechance = 75
/obj/random/mob/leopardmander/item_to_spawn() //Random map spawner
return pick(prob(89);/mob/living/simple_mob/vore/leopardmander,
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/lion.dm b/code/modules/mob/living/simple_mob/subtypes/vore/lion.dm
new file mode 100644
index 0000000000..1c310d623e
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/lion.dm
@@ -0,0 +1,127 @@
+/datum/category_item/catalogue/fauna/lion
+ name = "Creature - Lion"
+ desc = "Some sort of lion, a descendent or otherwise of regular Earth felidae. They look almost exactly like their \
+ Earth counterparts."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/mob/living/simple_mob/vore/retaliate/lion
+ name = "lion"
+ desc = "A large feline creature."
+ catalogue_data = list(/datum/category_item/catalogue/fauna/lion)
+
+ icon_state = "lion"
+ icon_living = "lion"
+ icon_dead = "lion-dead"
+ icon_rest = "lion_rest"
+ icon = 'icons/mob/vore64x32.dmi'
+
+ maxHealth = 200
+ health = 200
+ see_in_dark = 8
+
+ melee_damage_lower = 10
+ melee_damage_upper = 20
+ grab_resist = 100
+
+ meat_type = /obj/item/reagent_containers/food/snacks/meat
+ meat_amount = 5
+
+ response_help = "pets"
+ response_disarm = "bops"
+ response_harm = "hits"
+ attacktext = list("chomps")
+ friendly = list("nuzzles", "slobberlicks", "noses softly at", "noseboops", "headbumps against", "leans on", "nibbles affectionately on")
+
+ old_x = -16
+ old_y = 0
+ default_pixel_x = -16
+ pixel_x = -16
+ pixel_y = 0
+
+ minbodytemp = 200
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive
+ max_buckled_mobs = 1 //Yeehaw
+ can_buckle = TRUE
+ buckle_movable = TRUE
+ buckle_lying = FALSE
+
+ vore_active = TRUE
+ vore_pounce_chance = 80 //hongry
+ vore_icons = SA_ICON_LIVING | SA_ICON_REST
+
+ var/has_mane = TRUE
+ var/image/mane_overlay
+ var/mane_living = "mane"
+ var/mane_dead = "mane-dead"
+ var/mane_rest = "mane_rest"
+ var/mane_color = "#FFFFFF"
+
+/mob/living/simple_mob/vore/retaliate/lion/proc/add_mane()
+ if((stat == CONSCIOUS) && (!icon_rest || !resting || !incapacitated(INCAPACITATION_DISABLED)))
+ if(!vore_fullness || !(vore_icons & SA_ICON_LIVING))
+ mane_overlay = image(icon, "[mane_living]")
+ else
+ mane_overlay = image(icon, "[mane_living]-[vore_fullness]")
+ else if(stat >= DEAD)
+ if(!vore_fullness || !(vore_icons & SA_ICON_DEAD))
+ mane_overlay = image(icon, "[mane_dead]")
+ else
+ mane_overlay = image(icon, "[mane_dead]-[vore_fullness]")
+ else if(((stat == UNCONSCIOUS) || resting || incapacitated(INCAPACITATION_DISABLED) ) && icon_rest)
+ if(!vore_fullness || !(vore_icons & SA_ICON_REST))
+ mane_overlay = image(icon, "[mane_rest]")
+ else
+ mane_overlay = image(icon, "[mane_rest]-[vore_fullness]")
+ mane_overlay.color = mane_color
+ mane_overlay.plane = PLANE_LIGHTING_ABOVE
+ mane_overlay.appearance_flags = appearance_flags | RESET_COLOR
+ add_overlay(mane_overlay)
+
+/mob/living/simple_mob/vore/retaliate/lion/proc/remove_mane()
+ if(mane_overlay)
+ cut_overlay(mane_overlay)
+ qdel(mane_overlay)
+ mane_overlay = null
+
+/mob/living/simple_mob/vore/retaliate/lion/update_icon()
+ . = ..()
+ if(has_mane)
+ add_mane()
+ else
+ remove_mane()
+
+
+/mob/living/simple_mob/vore/retaliate/lion/proc/set_sex()
+ set name = "Set Sex"
+ set desc = "Set what sprite set you use (male/female)"
+ set category = "Abilities.Settings"
+ var/newsex
+ newsex = tgui_input_list(src, "Please select a sex:", "Set Sex", list(FEMALE, MALE))
+ if(newsex == FEMALE)
+ icon_living = "lioness"
+ icon_dead = "lioness-dead"
+ icon_rest = "lioness_rest"
+ has_mane = FALSE
+ update_icon()
+ else if(newsex == MALE)
+ icon_living = "lion"
+ icon_dead = "lion-dead"
+ icon_rest = "lion_rest"
+ has_mane = TRUE
+ update_icon()
+
+/mob/living/simple_mob/vore/retaliate/lion/proc/set_mane_color()
+ set name = "Set Mane Color"
+ set desc = "Set the color of your mane"
+ set category = "Abilities.Settings"
+ var/new_mane_color = tgui_color_picker(src, "Please pick a mane color:", "Mane Color", mane_color)
+ if(new_mane_color)
+ mane_color = new_mane_color
+ update_icon()
+
+/mob/living/simple_mob/vore/retaliate/lion/Login()
+ . = ..()
+ add_verb(src, /mob/living/simple_mob/vore/retaliate/lion/proc/set_sex)
+ add_verb(src,/mob/living/simple_mob/proc/pick_color)
+ add_verb(src, /mob/living/simple_mob/vore/retaliate/lion/proc/set_mane_color)
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/lizardman.dm b/code/modules/mob/living/simple_mob/subtypes/vore/lizardman.dm
new file mode 100644
index 0000000000..182ca00a14
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/lizardman.dm
@@ -0,0 +1,45 @@
+/mob/living/simple_mob/vore/aggressive/lizardman
+ name = "lizardman"
+ desc = "That is one buff, angry lizard."
+ tt_desc = "E Anolis cuvieri muscular"
+
+ icon = 'icons/mob/vore32x64.dmi'
+ icon_state = "lizardman"
+ icon_living = "lizardman"
+ icon_dead = "lizardman-dead"
+ faction = "lizard"
+
+
+ maxHealth = 50
+ health = 50
+
+ melee_damage_lower = 5
+ melee_damage_upper = 15
+ grab_resist = 100
+ see_in_dark = 8
+
+ response_help = "pets"
+ response_disarm = "bops"
+ response_harm = "hits"
+ attacktext = list("ravaged")
+ friendly = list("nuzzles", "licks", "noses softly at", "noseboops", "headbumps against", "leans on", "nibbles affectionately on")
+
+
+ vore_active = TRUE
+ vore_capacity = 1
+ vore_pounce_chance = 20
+ vore_icons = SA_ICON_LIVING
+
+ say_list_type = /datum/say_list/lizardman
+ ai_holder_type = /datum/ai_holder/simple_mob/melee
+
+ can_be_drop_prey = FALSE
+ allow_mind_transfer = TRUE
+
+
+/datum/say_list/lizardman
+ speak = list("Gwar!","Rawr!","Hiss.")
+ emote_hear = list("hisses", "yawns", "growls")
+ emote_see = list("licks their maw", "stretches", "yawns", "noodles")
+ say_maybe_target = list("Rawr?")
+ say_got_target = list("GWAR!!")
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/mimic.dm b/code/modules/mob/living/simple_mob/subtypes/vore/mimic.dm
index 20ba1b199a..7e00b0401a 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/mimic.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/mimic.dm
@@ -2,14 +2,14 @@
name = "Aberration - Mimic"
desc = "Classification: Mimus vorare\
\
- Mimics are morph creatures that share properties with the likes of Prometheans. They could assume any shape, \
- provided that they retained the same volume. In order to most effectively lure prey, they most commonly \
+ Mimics are morph creatures that share properties with the likes of prometheans. They can assume any shape, \
+ provided that they retain the same volume. In order to most effectively lure prey, they most commonly \
take the shape of chests and other objects likely to be touched by someone - though the latter is rarer \
than the former. \
\
Mimics prefer consuming large prey such as humans or humanoid species, however, for means of survival they \
might resort to eating smaller prey. A meal of one or two humanoids could sustain a mimic for several \
- months at a time - the main reason that they prey on humanoids to begin with. They reproduced asexually \
+ months at a time - the main reason that they prey on humanoids to begin with. They reproduce asexually \
by splitting their mass, the young growing to adulthood within a few years time.\
\
Mimics have no concerns beyond surviving and acquiring food."
@@ -20,6 +20,7 @@
desc = "A rectangular steel crate. This one looks particularly unstable."
var/mimic_chance = 30
var/mimic_active = TRUE
+ var/nest = null
/obj/structure/closet/crate/mimic/open()
if(src.opened)
@@ -27,6 +28,10 @@
if(!src.can_open())
return 0
+ if(istype(nest, /obj/structure/mob_spawner))
+ var/obj/structure/mob_spawner/S = nest
+ S.get_used_report(src)
+
if(mimic_active)
mimic_active = FALSE
if(prob(mimic_chance))
@@ -36,7 +41,7 @@
new_mimic.real_crate = src
new_mimic.name = name
new_mimic.desc = desc
- new_mimic.icon = icon
+ //new_mimic.icon = icon
new_mimic.icon_state = "open"
new_mimic.icon_living = "open"
else
@@ -77,10 +82,9 @@
name = "crate"
desc = "A rectangular steel crate."
-
- icon_state = "crate"
- icon_living = "crate"
- icon = 'icons/obj/storage.dmi'
+ icon_state = "open"
+ icon_living = "open"
+ icon = 'icons/mob/mimic.dmi'
faction = FACTION_MIMIC
@@ -123,6 +127,7 @@
swallowTime = 3 SECONDS
vore_capacity = 1
vore_default_mode = DM_DIGEST
+ can_be_drop_prey = FALSE
/datum/ai_holder/mimic
wander = FALSE
@@ -146,3 +151,357 @@
new/obj/structure/closet/crate(loc)
real_crate = null
qdel(src)
+
+/obj/structure/closet/crate/mimic/airlock
+ name = "Dusty Airlock"
+ desc = "It opens and closes. Though it appears it has been a while since it opened."
+ icon = 'icons/mob/mimic.dmi'
+ icon_state = "amimic"
+ mimic_chance = 30
+ anchored = 1 //You will not be able to push back the airlock mimic
+ density = 1
+ opacity = 1
+
+/obj/structure/closet/crate/mimic/airlock/open()
+ if(src.opened)
+ return 0
+ if(!src.can_open())
+ return 0
+
+ if(mimic_active)
+ mimic_active = FALSE
+ if(prob(mimic_chance))
+ var/mob/living/simple_mob/vore/aggressive/mimic/airlock/new_mimic = new(loc, src)
+ visible_message(span_bolddanger("The [new_mimic] suddenly growls as it turns out to be a mimic!")) //Controls the vars of the mimic that spawns
+ forceMove(new_mimic)
+ new_mimic.real_crate = src
+ new_mimic.name = name
+ new_mimic.desc = desc
+ new_mimic.icon_state = "amimicopen"
+ new_mimic.icon_living = "amimicopen"
+ else
+ qdel(src.loc)
+ new/obj/machinery/door/airlock/maintenance/common (src.loc) //Places the Airlock
+ qdel(src)//Deletes the "mimic"
+ return ..()
+ else
+ return ..()
+
+/obj/structure/closet/crate/mimic/airlock/ex_act(severity) //Stores Mimic Contents for later
+ for(var/obj/O in src.contents)
+ qdel(O)
+ qdel(src)
+ return
+
+/obj/structure/closet/crate/mimic/airlock/damage(var/damage)
+ if(contents.len)
+ visible_message(span_bolddanger("The [src] let's out an enraged screach!"))
+ for(var/obj/O in src.contents)
+ qdel(O)
+ ..()
+
+/obj/structure/closet/crate/mimic/airlock/safe
+ mimic_chance = 0
+
+/obj/structure/closet/crate/mimic/airlock/guaranteed
+ mimic_chance = 100
+
+/obj/structure/closet/crate/mimic/airlock/dangerous
+ mimic_chance = 70
+
+/obj/structure/closet/crate/mimic/airlock/cointoss
+ mimic_chance = 50
+
+/mob/living/simple_mob/vore/aggressive/mimic/airlock
+ name = "Maintnence Access"
+ desc = "It opens and closes."
+ icon_state = "amimicopen"
+ icon_living = "amimicopen"
+
+ maxHealth = 50
+ health = 50
+ movement_cooldown = 10
+
+ melee_damage_lower = 8
+ melee_damage_upper = 8
+ attack_armor_pen = 0
+
+ armor = list(
+ "melee" = 10,
+ "bullet" = 10,
+ "laser" = 10,
+ "energy" = 10,
+ "bomb" = 10,
+ "bio" = 100,
+ "rad" = 100) //Its an airlock.
+
+/mob/living/simple_mob/vore/aggressive/mimic/airlock/will_show_tooltip()
+ return FALSE
+
+/mob/living/simple_mob/vore/aggressive/mimic/airlock/death()
+ new/obj/machinery/door/airlock/maintenance/common (src.loc)
+ real_crate = null
+ qdel(src)
+
+
+//Less Terrifying Closet Mimic
+/obj/structure/closet/crate/mimic/closet
+ name = "old closet"
+ desc = "It's a basic storage unit. It seems awfully rickety."
+ icon = 'icons/mob/mimic.dmi'
+ icon_state = "cmimic"
+ mimic_chance = 30
+ mimic_active = TRUE
+
+/obj/structure/closet/crate/mimic/closet/update_icon()
+ if(opened)
+ icon_state = "copen"
+ else
+ icon_state = "cmimic"
+
+/obj/structure/closet/crate/mimic/closet/open()
+ if(src.opened)
+ return 0
+ if(!src.can_open())
+ return 0
+
+ if(mimic_active)
+ mimic_active = FALSE
+ if(prob(mimic_chance))
+ var/mob/living/simple_mob/vore/aggressive/mimic/closet/new_mimic = new(loc, src)
+ visible_message(span_bolddanger("The [new_mimic] suddenly growls as it turns out to be a mimic!")) //Controls the mimic that spawns
+ forceMove(new_mimic)
+ new_mimic.real_crate = src
+ new_mimic.name = name
+ new_mimic.desc = desc
+ new_mimic.icon_state = "cmimicopen"
+ new_mimic.icon_living = "cmimicopen"
+ else
+ return ..()
+ else
+ return ..()
+
+/obj/structure/closet/crate/mimic/closet/ex_act(severity) //Stores Mimic Contents for later
+ for(var/obj/O in src.contents)
+ qdel(O)
+ qdel(src)
+ return
+
+/obj/structure/closet/crate/mimic/closet/damage(var/damage)
+ if(contents.len)
+ visible_message(span_bolddanger("The [src] makes out a crunchy noise as its contents are destroyed!"))
+ for(var/obj/O in src.contents)
+ qdel(O)
+ ..()
+
+/obj/structure/closet/crate/mimic/closet/safe
+ mimic_chance = 0
+ mimic_active = FALSE
+
+/obj/structure/closet/crate/mimic/closet/guaranteed
+ mimic_chance = 100
+
+/obj/structure/closet/crate/mimic/closet/dangerous
+ mimic_chance = 70
+
+/obj/structure/closet/crate/mimic/closet/cointoss
+ mimic_chance = 50
+
+/mob/living/simple_mob/vore/aggressive/mimic/closet
+ name = "old closet"
+ desc = "It's a basic storage unit. It seems awfully rickety."
+ icon_state = "cmimicopen"
+ icon_living = "cmimicopen"
+
+ maxHealth = 50
+ health = 50
+ movement_cooldown = 7
+
+ melee_damage_lower = 8
+ melee_damage_upper = 8
+ attack_armor_pen = 25 // NOM NOM
+
+ armor = list(
+ "melee" = 10,
+ "bullet" = 20,
+ "laser" = 20,
+ "energy" = 20,
+ "bomb" = 20,
+ "bio" = 100,
+ "rad" = 100)
+
+/mob/living/simple_mob/vore/aggressive/mimic/closet/will_show_tooltip()
+ return FALSE
+
+/mob/living/simple_mob/vore/aggressive/mimic/closet/death()
+ ..()
+ if(real_crate)
+ real_crate.forceMove(loc)
+ real_crate = null
+ qdel(src)
+
+//Floor Mimics... Because mimics you have to interact with to activate was not enough...
+
+/obj/effect/floormimic //As Floor Mimics are triggered by bumps rather than click interaction... They are effects rather than structures
+ name = "loose wooden floor"
+ desc = "The boards here look rather loose."
+ density = 0
+ anchored = 1
+ icon = 'icons/mob/mimic.dmi'
+ icon_state = "wmimic"
+ var/mimic_chance = 30
+ var/mimic_active = TRUE
+ var/mimic_type = /mob/living/simple_mob/vore/aggressive/mimic/floor
+
+/obj/effect/floormimic/Crossed(atom/movable/AM)
+ . = ..()
+ tryTrigger(AM)
+
+/obj/effect/floormimic/Bumped(atom/movable/AM)
+ . = ..()
+ tryTrigger(AM)
+
+/obj/effect/floormimic/proc/tryTrigger(atom/movable/victim)
+ if(!isliving(victim))
+ return
+ var/mob/living/L = victim
+ if(L.hovering)
+ return
+ awaken(L)
+
+/obj/effect/floormimic/proc/awaken(mob/living/L)
+ if(!mimic_active)
+ qdel(src)
+ return
+ mimic_active = FALSE
+ if(!prob(mimic_chance))
+ qdel(src)
+ return
+ var/mob/living/simple_mob/vore/aggressive/mimic/floor/new_mimic = new mimic_type(drop_location())
+ visible_message(span_boldwarning("The [new_mimic] suddenly growls beneath you as it turns out to be a mimic!"))
+ qdel(src)
+
+/obj/effect/floormimic/attackby(obj/item/I, mob/living/L)
+ if(mimic_active)
+ awaken(L)
+ else
+ return ..()
+
+/obj/effect/floormimic/ex_act(severity)
+ qdel(src)
+
+/obj/effect/floormimic/safe
+ mimic_chance = 0
+
+/obj/effect/floormimic/guaranteed
+ mimic_chance = 100
+
+/obj/effect/floormimic/dangerous
+ mimic_chance = 70
+
+/obj/effect/floormimic/cointoss
+ mimic_chance = 50
+
+/mob/living/simple_mob/vore/aggressive/mimic/floor
+ name = "loose wooden floor"
+ desc = "The boards here look rather loose."
+ icon_state = "wmimicopen"
+ icon_living = "wmimicopen"
+
+ faction = "mimic"
+
+ maxHealth = 100
+ health = 100
+ movement_cooldown = 5
+
+ response_help = "touches"
+ response_disarm = "pushes"
+ response_harm = "hits"
+
+ melee_damage_lower = 5
+ melee_damage_upper = 5
+ base_attack_cooldown = 5
+
+/mob/living/simple_mob/vore/aggressive/mimic/floor/death()
+ qdel(src)
+
+/obj/effect/floormimic/tile
+ name = "loose floor tiles"
+ desc = "The tiles here look rather loose."
+ density = FALSE
+ anchored = TRUE
+ icon_state = "tmimic"
+ mimic_type = /mob/living/simple_mob/vore/aggressive/mimic/floor/tile
+
+/obj/effect/floormimic/tile/safe
+ mimic_chance = 0
+
+/obj/effect/floormimic/tile/guaranteed
+ mimic_chance = 100
+
+/obj/effect/floormimic/tile/dangerous
+ mimic_chance = 70
+
+/obj/effect/floormimic/tile/cointoss
+ mimic_chance = 50
+
+/mob/living/simple_mob/vore/aggressive/mimic/floor/tile
+ name = "loose floor tiles"
+ desc = "The tiles here look rather loose."
+ icon_state = "tmimicopen"
+ icon_living = "tmimicopen"
+
+ faction = "mimic"
+
+ maxHealth = 125
+ health = 125
+ movement_cooldown = 7
+
+ response_help = "touches"
+ response_disarm = "pushes"
+ response_harm = "hits"
+
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ base_attack_cooldown = 10
+
+/obj/effect/floormimic/plating
+ name = "loose plating"
+ desc = "The plating here looks rather loose."
+ density = FALSE
+ anchored = TRUE
+ icon_state = "pmimic"
+ mimic_type = /mob/living/simple_mob/vore/aggressive/mimic/floor/plating
+
+/obj/effect/floormimic/plating/safe
+ mimic_chance = 0
+
+/obj/effect/floormimic/plating/guaranteed
+ mimic_chance = 100
+
+/obj/effect/floormimic/plating/dangerous
+ mimic_chance = 70
+
+/obj/effect/floormimic/plating/cointoss
+ mimic_chance = 50
+
+/mob/living/simple_mob/vore/aggressive/mimic/floor/plating
+ name = "loose plating"
+ desc = "The plating here look rather loose."
+ icon_state = "pmimicopen"
+ icon_living = "pmimicopen"
+
+ faction = "mimic"
+
+ maxHealth = 150
+ health = 150
+ movement_cooldown = 7
+
+ response_help = "touches"
+ response_disarm = "pushes"
+ response_harm = "hits"
+
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ base_attack_cooldown = 10
+ attack_armor_pen = 50
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/mobs_monsters/clowns/regularclowns.dm b/code/modules/mob/living/simple_mob/subtypes/vore/mobs_monsters/clowns/regularclowns.dm
index 2e80377585..284e1b0ea8 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/mobs_monsters/clowns/regularclowns.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/mobs_monsters/clowns/regularclowns.dm
@@ -5,6 +5,8 @@
say_list_type = /datum/say_list/clown
+ can_be_drop_prey = FALSE
+
/datum/say_list/clown
speak = list("HONK", "Honk!", "Henk!")
emote_see = list("honks")
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/oregrub.dm b/code/modules/mob/living/simple_mob/subtypes/vore/oregrub.dm
index f6d614bd83..2496a325ac 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/oregrub.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/oregrub.dm
@@ -88,6 +88,7 @@
"rad" = 100
)
+ can_be_drop_prey = FALSE
glow_override = TRUE
/mob/living/simple_mob/vore/oregrub/lava
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/otie.dm b/code/modules/mob/living/simple_mob/subtypes/vore/otie.dm
index 72093e806f..dc3f766395 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/otie.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/otie.dm
@@ -281,11 +281,15 @@
switch(M.a_intent)
if(I_HELP)
if(health > 0)
+ if(M.zone_sel.selecting == BP_GROIN)
+ if(M.vore_bellyrub(src))
+ return
M.visible_message(span_notice("[M] [response_help] \the [src]."))
if(has_AI())
var/datum/ai_holder/AI = ai_holder
AI.set_stance(STANCE_IDLE)
if(prob(tame_chance))
+ AI.violent_breakthrough = FALSE
AI.hostile = FALSE
friend = M
AI.set_follow(friend)
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/panther_thor.dm b/code/modules/mob/living/simple_mob/subtypes/vore/panther_thor.dm
new file mode 100644
index 0000000000..108ed5910a
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/panther_thor.dm
@@ -0,0 +1,139 @@
+/mob/living/simple_mob/vore/aggressive/panther/thor
+ name = "panther"
+ desc = "Runtime's larger, less cuddly cousin. Known for murder and being very hard to see coming. If you can see it, either you're about to get mauled, or you aren't its target."
+ tt_desc = "Panthera pardus"
+
+ icon_state = "panther"
+ icon_living = "panther"
+ icon_rest = "panther-rest"
+ icon_dead = "panther-dead"
+ icon = 'icons/mob/vore64x32.dmi'
+ vis_height = 64
+
+ faction = FACTION_PANTHER
+ maxHealth = 200
+ health = 200
+ movement_cooldown = 0
+ see_in_dark = 8
+
+ melee_damage_lower = 5
+ melee_damage_upper = 15
+ attack_sharp = TRUE
+
+ response_help = "pats"
+ response_disarm = "tries to shove"
+ response_harm = "hits"
+ vore_icons = 3
+ old_x = -16
+ old_y = 0
+ default_pixel_x = -16
+ pixel_x = -16
+ pixel_y = 0
+
+ max_buckled_mobs = 1 //Yeehaw
+ can_buckle = TRUE
+ buckle_movable = TRUE
+ buckle_lying = FALSE
+ mount_offset_y = 12
+
+ say_list_type = /datum/say_list/panther
+ ai_holder_type = /datum/ai_holder/simple_mob/melee/hit_and_run
+ var/cloaked_alpha = 60 // Lower = Harder to see.
+ var/cloaked_bonus_damage = 30 // This is added on top of the normal melee damage.
+ var/cloaked_weaken_amount = 10 // How long to stun for.
+ var/cloak_cooldown = 8 SECONDS // Amount of time needed to re-cloak after losing it.
+ var/last_uncloak = 0
+ var/cooperative = FALSE
+
+/mob/living/simple_mob/vore/aggressive/panther/thor
+ vore_active = 1
+ vore_capacity = 3
+ vore_pounce_chance = 100
+ vore_icons = SA_ICON_LIVING | SA_ICON_REST
+
+/mob/living/simple_mob/vore/aggressive/panther/thor/cloak()
+ if(cloaked)
+ return
+ animate(src, alpha = cloaked_alpha, time = 1 SECOND)
+ cloaked = TRUE
+
+
+/mob/living/simple_mob/vore/aggressive/panther/thor/uncloak()
+ last_uncloak = world.time // This is assigned even if it isn't cloaked already, to 'reset' the timer if the spider is continously getting attacked.
+ if(!cloaked)
+ return
+ animate(src, alpha = initial(alpha), time = 1 SECOND)
+ cloaked = FALSE
+
+// Check if cloaking if possible.
+/mob/living/simple_mob/vore/aggressive/panther/thor/proc/can_cloak()
+ if(stat)
+ return FALSE
+ if(last_uncloak + cloak_cooldown > world.time)
+ return FALSE
+
+ return TRUE
+
+// Called by things that break cloaks, like Technomancer wards.
+/mob/living/simple_mob/vore/aggressive/panther/thor/break_cloak()
+ uncloak()
+
+
+/mob/living/simple_mob/vore/aggressive/panther/thor/is_cloaked()
+ return cloaked
+
+
+// Cloaks the spider automatically, if possible.
+/mob/living/simple_mob/vore/aggressive/panther/thor/handle_special()
+ if(!cloaked && can_cloak())
+ cloak()
+
+
+// Applies bonus base damage if cloaked.
+/mob/living/simple_mob/vore/aggressive/panther/thor/apply_bonus_melee_damage(atom/A, damage_amount)
+ if(cloaked)
+ uncloak()
+ return damage_amount + cloaked_bonus_damage
+ return ..()
+
+
+// Force uncloaking if attacked.
+/mob/living/simple_mob/vore/aggressive/panther/thor/bullet_act(obj/item/projectile/P)
+ . = ..()
+ break_cloak()
+
+/mob/living/simple_mob/vore/aggressive/panther/thor/hit_with_weapon(obj/item/O, mob/living/user, effective_force, hit_zone)
+ . = ..()
+ break_cloak()
+
+/mob/living/simple_mob/vore/aggressive/panther/load_default_bellies()
+ . = ..()
+ var/obj/belly/B = vore_selected
+ B.vore_sound = "Tauric Swallow"
+ B.release_sound = "Pred Escape"
+ B.fancy_vore = 1
+ B.belly_fullscreen_color = "#573232"
+ B.belly_fullscreen = "da_tumby"
+ B.name = "stomach"
+ B.desc = "All it takes is a few more rasps of the panther's rough, barbed tongue to shovel the rest of you down its tightly rippling gullet... and with a final couple ravenous swallows, you spill out into the predatory feline's stomach! Right away, that gut's muscular walls knead and contract around you, forcing you into a curled-up ball as the panther's noisy purring rumbles into you from every direction."
+
+ B.emote_lists[DM_HOLD] = list(
+ "A steady white noise of content purring vibrates throughout you, the panther clearly enjoying the hanging, shifting swell you've given it.",
+ "Your slick, gently churning surroundings abruptly clench inwards, smothering you in an all-encompassing, massage-filled hug before finally easing back.",
+ "The strength of the content feline's purring is easily felt underneath its gut's constant massaging, vibrating the flesh in an utterly relaxing way.",
+ "As the panther lazily struts around, its hanging, prey-laden belly on full display, you're rocked from side to side to a soothing, slosh-filled beat.",
+ "For a moment, you can hear a few other sounds through the juicy sloshing and reverberating purring, such as the panther slurping its tongue over its chops.",
+ "The possessive feline takes a moment to flump down into a resting position, its doughy insides kneading snugly around your curled figure until it shuffles back up.")
+
+ B.emote_lists[DM_DIGEST] = list(
+ "The big feline rumbles heartily, incredibly satisfied as it works to digest its newfound, stomach-filling catch!",
+ "The surrounding stomach walls suddenly tighten inwards, smothering you in slimy, kneading flesh for a time until they finally relax back again!",
+ "The purring of the content kitty is practically deafening within its churning depths, gently vibrating its gut flesh around you!",
+ "The massive feline's gut sways from side to side as it prowls around, steadily coating you in hot digestive juices until you're practically soaked!",
+ "You can hear the muffled sounds of the panther lickings its chops, savoring the remnants of your taste!",
+ "The near-constant cacophony of digestive noises intensifies for a while, overwhelming your senses before finally calming down somewhat!")
+
+/datum/say_list/panther
+ speak = list("RAWR!","Rawr!","GRR!","Growl!")
+ emote_hear = list("rawrs","rumbles","rowls","growls","roars")
+ emote_see = list("stares ferociously", "snarls")
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/plants/pitcher.dm b/code/modules/mob/living/simple_mob/subtypes/vore/plants/pitcher.dm
new file mode 100644
index 0000000000..6fe815f026
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/plants/pitcher.dm
@@ -0,0 +1,337 @@
+#define NUTRITION_FRUIT 250 //The amount of nutrition needed to produce a fruit
+#define NUTRITION_PITCHER 3 * NUTRITION_FRUIT //The amount of nutrition needed to produce a new pitcher
+#define NUTRITION_MEAT 50 //The amount of nutrition provided by slabs of meat
+#define PITCHER_SATED 250 //The amount of nutrition needed before the pitcher will attempt to grow fruit.
+#define PITCHER_HUNGRY 150 //The nutrition cap under which the pitcher actively attempts to lure prey.
+
+GLOBAL_LIST_INIT(pitcher_plant_lure_messages, list(
+ "The pitcher plant smells lovely, beckoning you closer.",
+ "The sweet scent wafting from the pitcher plant makes your mouth water.",
+ "You feel an urge to investigate the pitcher plant closely.",
+ "You find yourself staring at the pitcher plant without really thinking about it.",
+ "Doesn't the pitcher plant smell amazing?")) //Messages sent to nearby players if the pitcher is trying to lure prey. This is global to prevent a new list every time a new pitcher plant spawns.
+
+//Pitcher plants, a passive carnivorous plant mob for xenobio and space vine spawning.
+//Consider making immune to space vine entangling.
+/mob/living/simple_mob/vore/pitcher_plant
+ name = "pitcher plant"
+ desc = "A carnivorous pitcher plant, bigger than a man."
+ tt_desc = "Sarraceniaceae gigantus"
+
+ icon_state = "pitcher_plant"
+ icon_living = "pitcher_plant"
+ icon_dead = "pitcher_plant_dead"
+ icon = 'icons/mob/vore.dmi'
+
+ anchored = 1 // Rooted plant. Only killing it will let you move it.
+ maxHealth = 200
+ health = 200
+ a_intent = I_HELP // While this is already help by default, I'm leaving this variable here as a reminder that disarm will prevent players from swapping places with the pitcher, but interfere with vore bump.
+ faction = FACTION_PLANTS // Makes plant-b-gone deadly.
+ ai_holder_type = /datum/ai_holder/simple_mob/passive/pitcher //It's a passive carnivorous plant, it can't detect or interact with people.
+
+ min_oxy = 0 //Immune to atmos because so are space vines. This is arbitrary and can be tweaked if desired.
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+ meat_type = /obj/item/reagent_containers/food/snacks/pitcher_fruit // Allows pitcher plants to be chopped up and replanted. Probably.
+ meat_amount = 1 // And allows you to replant them should you so please.
+
+ melee_damage_upper = 0 //This shouldn't attack people but if it does (admemes) no damage can be dealt.
+ melee_damage_lower = 0
+
+ armor = list(
+ "melee" = 0,
+ "bullet" = 0,
+ "laser" = -50, // Okay fine fire type beats plant type
+ "energy" = 0,
+ "bomb" = 0,
+ "bio" = -100, // Poison kills the plant good.
+ "rad" = 100)
+
+ var/fruit = FALSE //Has the pitcher produced a fruit?
+ var/meat = 0 //How many units of meat is the plant digesting? Separate from actual vore mechanics.
+ var/meatspeed = 5 //How many units of meat is converted to nutrition each tick?
+ var/pitcher_metabolism = 0.1 //How much nutriment does the pitcher lose every 2 seconds? 0.1 should be around 30 every 10 minutes.
+ var/scent_strength = 5 //How much can a hungry pitcher confuse nearby people?
+ var/last_lifechecks = 0 //Timing variable to limit vore/hungry proc calls
+ var/list/pitcher_plant_lure_messages = null
+ can_be_drop_prey = FALSE
+
+/mob/living/simple_mob/vore/pitcher_plant //Putting vore variables separately because apparently that's tradition.
+ vore_bump_chance = 100
+ vore_bump_emote = "slurps up" //Not really a good way to make the grammar work with a passive vore plant.
+ vore_active = 1
+ vore_icons = 1
+ vore_capacity = 1
+ vore_pounce_chance = 5 // Either this makes mobs sometimes get eaten for attacking it or nothing happens and I don't know which it is.
+ swallowTime = 3 //3 deciseconds. This is intended to be nearly instant, e.g. victim trips and falls in.
+ vore_ignores_undigestable = 0
+ vore_default_mode = DM_DIGEST
+
+/mob/living/simple_mob/vore/pitcher_plant/load_default_bellies()
+ . = ..()
+ var/obj/belly/B = vore_selected
+ B.desc = "You leaned a little too close to the pitcher plant, stumbling over the lip and splashing into a puddle of liquid filling the bottom of the cramped pitcher. You squirm madly, righting yourself and scrabbling at the walls in vain as the slick surface offers no purchase. The dim light grows dark as the pitcher's cap lowers, silently sealing the exit. With a sinking feeling, you realize you won't be able to push the exit open even if you could somehow climb that high, leaving you helplessly trapped in the slick, tingling fluid. The ONLY POSSIBLE WAY OUT is if someone either kills this thing or lowers a lifeline down to help. Maybe some string, a wire, or a good rope would do the trick..."
+ B.digest_burn = 0.1 // Sloowwwwww churns
+ B.digest_brute = 0.1 // Okay so I know there's no physical churning because it's a plant just trust me on this you want both of these
+ B.vore_verb = "trip"
+ B.name = "pitcher"
+ B.mode_flags = DM_FLAG_THICKBELLY
+ B.wet_loop = 0 // As nice as the fancy internal sounds are, this is a plant.
+ B.digestchance = 0
+ B.escapechance = 0
+ B.fancy_vore = 1
+ B.vore_sound = "Squish2"
+ B.release_sound = "Pred Escape"
+ B.contamination_color = "purple"
+ B.contamination_flavor = "Wet"
+
+ B.emote_lists[DM_HOLD] = list(
+ "Slick fluid trickles over you, carrying threads of sweetness.",
+ "Everything is still, dark, and quiet. Your breaths echo quietly.",
+ "The surrounding air feels thick and humid.")
+ B.emote_lists[DM_DIGEST] = list(
+ "The slimy puddle stings faintly. It seems the plant has no need to quickly break down victims.",
+ "The humid air settles in your lungs, keeping each breath more labored than the last.",
+ "Fluid drips onto you, burning faintly as your body heat warms it.",
+ "Digestive enzymes itch at your flesh as you are slowly dissolved into soupy nutrients."
+ )
+ B.emote_lists[DM_DRAIN] = list(
+ "Each bead of slick fluid running down your body leaves you feeling weaker.",
+ "It's cramped and dark, the air thick and heavy. Your limbs feel like lead.",
+ "Strength drains from your frame. The cramped chamber feels easier to settle into with each passing moment.")
+ B.struggle_messages_inside = list(
+ "The narrow shape of the pitcher plant's stomach make it impossible to get any leverage. You can't escape.",
+ "You struggle and push against the slick and slimy plant flesh surrounding you, but it's no use. There's no way out by yourself.",
+ "Other predators would probably be getting queasy by now with all that fussing. Unfortunately, this thing just doesn't care. You're plant food.",
+ "Squirm and struggle all you want, you're no closer to freedom. Nothing you're doing is working.",
+ "You're just exhausting yourself with all this resistance, and the fumes of the plant's stomach are making you lightheaded.",
+ "All that exertion is just making you exhausted. For something with no muscles, it seems perfectly built for keeping you in its gut.",
+ "You literally can't escape by yourself. All you can do is wait for rescue and hope this dreadfully slow digestion doesn't snuff you out first.",
+ "You can't reach the lid of the pitcher plant to pry yourself out. Even if you could, the walls are too slippery. If only someone could lower a string or a wire or a rope for you to grab on!",
+ "The waxy walls are far too slippery for you to climb your way out, and trying to do so only drenches you in even more stinging slime.",
+ "Although you try your best to claw your way to freedom, the pitcher's gut is too smooth and too tough for you to get any progress."
+ )
+ B.struggle_messages_outside = list(
+ "Struggles from inside %pred cause its bulbous form to slosh from side-to-side. They might need some help to escape.",
+ "You notice someone moving inside that pitcher plant! However, they clearly can't get out on their own.",
+ "%pred's stomach shifts and slushes as someone inside of it tries in vain to escape. It doesn't look like they can, though.",
+ "%pred seems unpertubed by the stubborn movement of its prey. They clearly aren't getting out on their own.")
+
+/mob/living/simple_mob/vore/pitcher_plant/Life()
+ . = ..()
+ if(!.)
+ return
+
+ var/lastmeat = meat //If Life procs every 2 seconds that means it takes 20 seconds to digest a steak
+ meat = max(0,meat - meatspeed) //Clamp it to zero
+ adjust_nutrition(lastmeat - meat) //If there's no meat, this will just be zero.
+ if(nutrition >= PITCHER_SATED + NUTRITION_FRUIT)
+ if(prob(10)) //Should be about once every 20 seconds.
+ grow_fruit()
+ var/lastnutrition = nutrition
+ adjust_nutrition(-pitcher_metabolism)
+ adjustBruteLoss(nutrition - lastnutrition)
+ adjustToxLoss((nutrition - lastnutrition) * 3)
+ if(nutrition < pitcher_metabolism)
+ adjustToxLoss(pitcher_metabolism)
+ if(world.time > last_lifechecks + 30 SECONDS)
+ last_lifechecks = world.time
+ vore_checks()
+ handle_hungry()
+ if (!anchored)
+ anchored = 1 // If it's alive, it should root itself back down and once again be impossible to move.
+
+/mob/living/simple_mob/vore/pitcher_plant/Initialize(mapload)
+ . = ..()
+ pitcher_plant_lure_messages = GLOB.pitcher_plant_lure_messages
+
+
+/mob/living/simple_mob/vore/pitcher_plant/death()
+ ..()
+ anchored = 0
+ if(fruit)
+ new /obj/item/reagent_containers/food/snacks/pitcher_fruit(get_turf(src))
+ fruit = FALSE
+
+/mob/living/simple_mob/vore/pitcher_plant/proc/grow_fruit() //This proc handles the pitcher turning nutrition into fruit (and new pitchers).
+ if(!fruit)
+ if(nutrition >= PITCHER_SATED + NUTRITION_FRUIT)
+ fruit = TRUE
+ adjust_nutrition(-NUTRITION_FRUIT)
+ return
+ else
+ return
+ if(fruit)
+ if(nutrition >= PITCHER_SATED + NUTRITION_PITCHER)
+ var/turf/T = safepick(circleviewturfs(src, 2))
+ if(T.density) //No spawning in walls
+ return
+ else if(src.loc ==T)
+ return
+ else
+ new /mob/living/simple_mob/vore/pitcher_plant(get_turf(T))
+ fruit = FALSE //No admeming this to spawn endless pitchers.
+ adjust_nutrition(-NUTRITION_PITCHER)
+
+/mob/living/simple_mob/vore/pitcher_plant/attack_hand(mob/living/user)
+ if(user.a_intent == I_HELP)
+ if(fruit)
+ to_chat(user, span_infoplain("You pick a fruit from \the [src]."))
+ var/obj/F = new /obj/item/reagent_containers/food/snacks/pitcher_fruit(get_turf(user)) //Drops at the user's feet if put_in_hands fails
+ fruit = FALSE
+ user.put_in_hands(F)
+ else
+ to_chat(user, span_infoplain("The [src] hasn't grown any fruit yet!"))
+ else
+ ..()
+
+/mob/living/simple_mob/vore/pitcher_plant/examine(mob/user)
+ . = ..()
+ if(fruit)
+ . += "A plump fruit glistens beneath \the [src]'s cap."
+
+/mob/living/simple_mob/vore/pitcher_plant/attackby(obj/item/O, mob/user)
+ if(istype(O, /obj/item/reagent_containers/food/snacks/meat))
+ if(meat > NUTRITION_FRUIT - NUTRITION_MEAT) //Can't exceed 250
+ to_chat(user, span_infoplain("The [src] is full!"))
+ return
+ else
+ meat += NUTRITION_MEAT
+ qdel(O)
+ return
+ if(istype(O, /obj/item/stack/cable_coil)) //How to free people without killing the pitcher. I guess cable is SS13 rope.
+ var/mob/living/carbon/human/H
+ var/N = 0
+ for(H in vore_selected.contents) //Only works for carbons, RIP mice. Should pick the first human the code finds.
+ user.visible_message(span_infoplain("[user] uses a loop of wire to try fishing someone out of \the [src]."), span_infoplain("You use a loop of wire to try snagging someone trapped in \the [src]..."))
+ if(do_after(user, rand(3 SECONDS, 7 SECONDS))) //You can just spam click to stack attempts if you feel like abusing it.
+ if(prob(15))
+ user.visible_message(span_notice("[user] pulls a sticky [H] free from \the [src]."), span_infoplain("You heft [H] free from \the [src]."))
+ LAZYSET(prey_excludes, H, world.time)
+ vore_selected.release_specific_contents(H)
+ N = 1
+ addtimer(CALLBACK(src, PROC_REF(removeMobFromPreyExcludes), WEAKREF(H)), 1 MINUTES)
+ break
+ else
+ to_chat(user, span_notice("The victim slips from your grasp!"))
+ N = 1
+ break //We need to terminate the loop after each outcome or this could loop through multiple bellies. Of course, there should only be one belly, but leave this here anyway just in case.
+ if(!N)
+ to_chat(user, span_infoplain("The pitcher is empty."))
+ if(istype(O, /obj/item/newspaper))
+ user.visible_message(span_notice("[user] baps \the [src], but it doesn't seem to do anything."), span_notice("You whap \the [src] with a rolled up newspaper."))
+ to_chat(user, span_notice("Weird. That usually works. Maybe you can fish out its victim with some string or wire or something? Or maybe kill the thing with some plant-b-gone. Both would probably be safer than hacking it up with a person still inside."))
+ return // You can't newspaper people to freedom like you do with other mobs, but since that doesn't work, fucking tell people.
+ ..()
+
+/mob/living/simple_mob/vore/pitcher_plant/proc/vore_checks()
+ if(ckey) //This isn't intended to be a playable mob but skip all of this if it's player-controlled.
+ return
+ if(vore_selected && vore_selected.contents.len) //Looping through all (potential) vore bellies would be more thorough but probably not worth the processing power if this check happens every 30 seconds.
+ var/mob/living/L
+ var/N = 0
+ var/hasdigestable = 0
+ var/hasindigestable = 0
+ for(L in vore_selected.contents)
+ if(istype(L, /mob/living/carbon/human/monkey))
+ L.nutrition = 0 //No stuffing monkeys with protein shakes for massive nutrition.
+ if(!L.digestable)
+ vore_selected.digest_mode = DM_DRAIN
+ N = 1
+ hasindigestable = 1
+ continue
+ else
+ vore_selected.digest_mode = DM_DIGEST
+ N = 1
+ hasdigestable = 1
+ continue
+ if(hasdigestable && hasindigestable)
+ vore_selected.digest_mode = DM_DIGEST //Let's digest until we digest all the digestable prey, then move onto draining indigestable prey.
+ if(!N)
+ vore_selected.release_all_contents() //If there's no prey, spit out everything.
+
+/mob/living/simple_mob/vore/pitcher_plant/proc/handle_hungry() //Let's run this check every 30 seconds. This is how a hungry pitcher tries to lure prey.
+ if(nutrition <= PITCHER_HUNGRY) //Is sanity check another way to say redundancy?
+ var/turf/T = get_turf(src)
+ var/cardinal_turfs = T.CardinalTurfs()
+
+ for(var/mob/living/carbon/human/H in oview(2, src))
+ if(!istype(H) || !isliving(H) || H.stat == DEAD) //Living mobs only
+ continue
+ if(isSynthetic(H) || !H.species.breath_type || H.internal) //Exclude species which don't breathe or have internals.
+ continue
+ if(src.Adjacent(H)) //If they can breathe and are next to the pitcher, confuse them.
+ to_chat(H,span_red("The sweet, overwhelming scent from \the [src] makes your senses reel!"))
+ H.Confuse(scent_strength)
+ continue
+ else
+ to_chat(H, span_red("[pick(pitcher_plant_lure_messages)]"))
+
+ for(var/turf/simulated/TR in cardinal_turfs)
+ TR.wet_floor(1) //Same effect as water. Slip into plant, get ate.
+ else
+ return
+/mob/living/simple_mob/vore/pitcher_plant/Crossed(atom/movable/AM as mob|obj) //Yay slipnoms
+ if(AM.is_incorporeal())
+ return
+ if(istype(AM, /mob/living) && will_eat(AM) && !istype(AM, type) && prob(vore_bump_chance) && !ckey)
+ animal_nom(AM)
+ ..()
+
+/datum/ai_holder/simple_mob/passive/pitcher
+ wander = 0
+
+/obj/item/reagent_containers/food/snacks/pitcher_fruit //As much as I want to tie hydroponics harvest code to the mob, this is simpler (albeit kinda hacky).
+ name = "squishy fruit"
+ desc = "A tender, fleshy fruit with a thin skin. Said to have an intensely sweet flavor, and also a narcotic paralyzing effect."
+ icon = 'icons/obj/hydroponics_products.dmi'
+ icon_state = "treefruit-product"
+ color = "#a839a2"
+ trash = /obj/item/seeds/pitcherseed
+ nutriment_amt = 1
+ nutriment_desc = list("pineapple" = 1)
+ w_class = ITEMSIZE_SMALL
+ var/datum/seed/seed = null
+ var/obj/item/seeds/pit = null
+
+/obj/item/reagent_containers/food/snacks/pitcher_fruit/Initialize(mapload)
+ . = ..()
+ reagents.add_reagent(REAGENT_ID_PITCHERNECTAR, 5)
+ reagents.add_reagent(REAGENT_ID_PARALYZE_FLUID, 5) // Something worth harvesting the fruits for.
+ bitesize = 1
+ pit = new /obj/item/seeds/pitcherseed(src.contents)
+ seed = pit.seed
+
+/obj/item/reagent_containers/food/snacks/pitcher_fruit/afterattack(obj/O as obj, mob/user as mob, proximity)
+ if(istype(O,/obj/machinery/microwave))
+ return ..()
+ if(istype (O, /obj/machinery/seed_extractor))
+ pit.loc = O.loc //1 seed, perhaps balanced because you can get the reagents and the seed. Can be increased if desirable.
+ qdel(src)
+ if(!(proximity && O.is_open_container()))
+ return
+ to_chat(user, span_notice("You squeeze \the [src], juicing it into \the [O]."))
+ reagents.trans_to(O, reagents.total_volume)
+ user.drop_from_inventory(src)
+ pit.loc = user.loc
+ qdel(src)
+
+/obj/item/reagent_containers/food/snacks/pitcher_fruit/attack_self(mob/user)
+ to_chat(user, span_notice("You plant the fruit."))
+ new /obj/machinery/portable_atmospherics/hydroponics/soil/invisible(get_turf(user),src.seed)
+ GLOB.seed_planted_shift_roundstat++
+ qdel(src)
+ return
+
+#undef NUTRITION_FRUIT
+#undef NUTRITION_PITCHER
+#undef NUTRITION_MEAT
+#undef PITCHER_SATED
+#undef PITCHER_HUNGRY
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/plants.dm b/code/modules/mob/living/simple_mob/subtypes/vore/plants/plants.dm
similarity index 100%
rename from code/modules/mob/living/simple_mob/subtypes/vore/plants.dm
rename to code/modules/mob/living/simple_mob/subtypes/vore/plants/plants.dm
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/rabbit.dm b/code/modules/mob/living/simple_mob/subtypes/vore/rabbit.dm
index 10eabdc560..3e56ed14b8 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/rabbit.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/rabbit.dm
@@ -93,6 +93,18 @@
if(pounce_chance)
PounceTarget(user, pounce_chance)
+/mob/living/simple_mob/vore/rabbit/load_default_bellies()
+ . = ..()
+
+ var/obj/belly/B = vore_selected
+ B.name = "stomach"
+ B.desc = "With a sudden pounce, the rabbit begins swallowing you down with ease! A pink maw and surprisingly unintimidating teeth give way to the thing's pink, tight throat, until you're crammed down inside it's gut! Unless you happen to be drastically smaller than it, the inside of this thing's gut is incredibly cramped, as the fleshy pink walls undulate over your form. It's clearly still able to move with you inside somehow, despite the tiny size of the thing, as gastric sounds flood your ears. You've been bested by a RABBIT of all things!"
+ B.vore_sound = "Tauric Swallow"
+ B.release_sound = "Pred Escape"
+ B.fancy_vore = TRUE
+ B.belly_fullscreen_color = "#b15aac"
+ B.belly_fullscreen = "anim_belly"
+
/datum/say_list/rabbit
speak = list("chrrrs.")
emote_hear = list("screms.")
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/rat.dm b/code/modules/mob/living/simple_mob/subtypes/vore/rat.dm
index 83652c36db..022e81c8f9 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/rat.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/rat.dm
@@ -62,7 +62,7 @@
vore_active = TRUE
vore_capacity = 1
- vore_pounce_chance = 45
+ vore_pounce_chance = 65
vore_icons = SA_ICON_LIVING | SA_ICON_REST
var/life_since_foodscan = 0
@@ -70,6 +70,7 @@
say_list_type = /datum/say_list/rat
ai_holder_type = /datum/ai_holder/simple_mob/melee/rat
+ can_be_drop_prey = FALSE
allow_mind_transfer = TRUE
/mob/living/simple_mob/vore/aggressive/rat/load_default_bellies()
@@ -77,6 +78,11 @@
var/obj/belly/B = vore_selected
B.name = "stomach"
B.desc = "In a cruel game of cat-and-mouse gone horribly wrong, you struggle to breathe clearly as the giant rat holds your head in its jaws, the rest of its bulk pinning you to the ground. Slimy slurps and its own muffled squeaking fill your senses as it simultaneously tosses its head while backing up. Quickly, ravenously consuming you, bit by bit, packing you down its gullet no matter how you struggle. Passing by its excited heartbeat, your thoroughly slickened head pushes out into its awaiting stomach, a dark and humid hammock eager to accept the rest of you. Soon, those too-warm, plush walls clench and squeeze around you with undeniable need! A need for mere filling, or, perhaps, a proper meal?"
+ B.vore_sound = "Tauric Swallow"
+ B.release_sound = "Pred Escape"
+ B.fancy_vore = TRUE
+ B.belly_fullscreen_color = "#c47cb4"
+ B.belly_fullscreen = "anim_belly"
B.emote_lists[DM_HOLD] = list(
"As time passes, the massive rat's stomach slowly churns and squeezes down around you, packing you into an easier to carry bundle amidst that oddly soothing massage.",
@@ -286,3 +292,39 @@
/datum/ai_holder/simple_mob/melee/rat
speak_chance = 2
+
+/mob/living/simple_mob/vore/aggressive/rat/event
+ maxHealth = 50
+ health = 50
+ vore_pounce_chance = 10
+
+ can_be_drop_prey = FALSE
+
+/mob/living/simple_mob/vore/aggressive/rat/labrat
+ name = "giant lab rat"
+ desc = "In what passes for a hierarchy among lab rats, this one is a boss."
+ icon_state = "labrat"
+ icon_living = "labrat"
+ icon_dead = "labrat-dead"
+ icon_rest = "labrat_rest"
+ faction = "neutral"
+ icon = 'icons/mob/vore64x32.dmi'
+
+/mob/living/simple_mob/vore/aggressive/rat/labrat/genetics
+ name = "Nibbles"
+ desc = "A giant rat that made it's nest in an abandoned genetics lab. This one seems fairly docile."
+ ai_holder_type = /datum/ai_holder/simple_mob/retaliate
+
+ vore_active = 1
+ vore_capacity = 1
+ vore_escape_chance = 20
+ swallowTime = 25
+ vore_bump_chance = 100
+ faction_bump_vore = 1
+ vore_standing_too = TRUE
+ vore_pounce_chance = 75
+ vore_pounce_maxhealth = 80
+ vore_bump_emote = "knocks over and attempts to engulf"
+
+ can_be_drop_prey = FALSE
+ allow_mind_transfer = FALSE
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/reindeer.dm b/code/modules/mob/living/simple_mob/subtypes/vore/reindeer.dm
new file mode 100644
index 0000000000..140312da34
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/reindeer.dm
@@ -0,0 +1,55 @@
+/datum/category_item/catalogue/fauna/reindeer
+ name = "Creature - Reindeer"
+ desc = "A reindeer"
+ value = CATALOGUER_REWARD_EASY
+
+/mob/living/simple_mob/vore/reindeer
+ name = "reindeer"
+ desc = "A large reindeer."
+ catalogue_data = list(/datum/category_item/catalogue/fauna/reindeer)
+
+ icon_state = "reindeer"
+ icon_living = "reindeer"
+ icon_dead = "reindeer-dead"
+ icon_rest = "reindeer_rest"
+ icon = 'icons/mob/vore64x32.dmi'
+
+ maxHealth = 100
+ health = 100
+
+ melee_damage_lower = 10
+ melee_damage_upper = 20
+ grab_resist = 100
+
+ meat_type = /obj/item/reagent_containers/food/snacks/meat
+ meat_amount = 5
+
+ response_help = "pets"
+ response_disarm = "bops"
+ response_harm = "hits"
+ attacktext = list("chomps")
+ friendly = list("nuzzles", "slobberlicks", "noses softly at", "noseboops", "headbumps against", "leans on", "nibbles affectionately on")
+
+ old_x = -16
+ old_y = 0
+ default_pixel_x = -16
+ pixel_x = -16
+ pixel_y = 0
+
+ minbodytemp = 200
+
+ max_buckled_mobs = 1 //Yeehaw
+ can_buckle = TRUE
+ buckle_movable = TRUE
+ buckle_lying = FALSE
+
+ vore_active = TRUE
+ vore_icons = SA_ICON_LIVING
+
+/mob/living/simple_mob/vore/reindeer/festive
+ desc = "A large reindeer. It is covered in festive decorations."
+
+ icon_state = "reindeerfes"
+ icon_living = "reindeerfes"
+ icon_dead = "reindeerfes-dead"
+ icon_rest = "reindeerfes_rest"
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/sect_drone.dm b/code/modules/mob/living/simple_mob/subtypes/vore/sect_drone.dm
index e5b0b92f3b..839a614806 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/sect_drone.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/sect_drone.dm
@@ -3,17 +3,17 @@
desc = "Classification: V Insecta gigantus\
\
A massively-sized insect that is native to Virgo 3B. Much like its queen, it bears the combined physical traits \
- of several of Earth's insects. Its forelegs have claws bearing serrated edges much like a Mantis, which it uses \
- in both self-defense and during its hunts. On it's back are two large semi transparent wings like a beetle that it \
- uses for increased mobility. Covering its body is a layer of light, thick, and protective chitin, resilient enough to absorb \
- most physical damage while being light enough for the Sect Drone to hover. \
+ of several of Earth's insects. Its forelegs have claws bearing serrated edges much like a mantis, which it uses \
+ in both self-defense and during its hunts. On the back are two large semi transparent wings like a beetle which \
+ are used for increased mobility. Covering the body is a layer of light, thick, and protective chitin, resilient enough to absorb \
+ most physical damage while being light enough for the sect drone to hover. \
\
- It is not uncommon for a Sect Drone to go out alone to search for potential prey to bring back to the nest. \
- Regardless of reason, it is cautioned against approaching a Sect Drone as, like their queen, their behaviour is wildly \
- inconsistent. A Sect Drone can vary from hostile to docile depending on certain factors that scientists have \
+ It is not uncommon for a sect drone to go out alone to search for potential prey to bring back to the nest. \
+ Regardless of reason, it is cautioned against approaching a sect drone as, like the queen, their behaviour is wildly \
+ inconsistent. A sect drone can vary from hostile to docile depending on certain factors that scientists have \
yet to uncover. \
\
- The lack of chitin on the underside of its abdomen is deliberate, as the flesh is very elastic and stretchable, \
+ The lack of chitin on the underside of its abdomen is very elastic and stretchable, \
allowing the drone to carry multiple large prey inside of its stomach with relative ease."
value = CATALOGUER_REWARD_MEDIUM
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/sect_queen.dm b/code/modules/mob/living/simple_mob/subtypes/vore/sect_queen.dm
index 2279b31f66..3d289ffc06 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/sect_queen.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/sect_queen.dm
@@ -4,18 +4,18 @@
name = "Creature - Sect Queen"
desc = "Classification: V Insecta maximus gigantus\
\
- A massively-sized insect that is native - although rarely spotted outside of its colony - to Virgo 3B. \
+ A massively-sized insect that is native - although rarely spotted outside of the colony - to Virgo 3B. \
It bears the combined physical traits of several of Earth's insects. Its forelegs have claws bearing serrated \
- edges much like a Mantis, which it uses in both self-defense and during its hunts. Covering its body is a layer \
+ edges much like a mantis, which it uses in both self-defense and during its hunts. Covering its body is a layer \
of thick and protective chitin, resilient enough to absorb most physical damage. \
\
Though rarely seen, it is not uncommon for a queen to go out alone to search for potential new nesting grounds \
or perhaps it does so to seek bigger prey that its much smaller drones might be unable to acquire. \
Regardless of reason, it is cautioned against approaching a Sect Queen as their behaviour is wildly \
- inconsistent. A Sect Queen can vary from hostile to docile depending on certain factors that scientists have \
+ inconsistent. A sect queen can vary from hostile to docile depending on certain factors that scientists have \
yet to uncover. \
\
- The lack of chitin on the underside of its abdomen is deliberate, as the flesh is very elastic and stretchable, \
+ The flesh on the underside of its abdomen is very elastic and stretchable, \
allowing the queen to carry multiple large prey inside of its stomach with ease. There is no know limit to home much \
prey a single specimen can carry and scientists are wary to find said limit."
value = CATALOGUER_REWARD_MEDIUM
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/rakshasa_trap.dm b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/rakshasa_trap.dm
new file mode 100644
index 0000000000..64a1117fc7
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/rakshasa_trap.dm
@@ -0,0 +1,72 @@
+/obj/structure/gootrap
+ name = "goo"
+ throw_speed = 2
+ throw_range = 1
+ gender = PLURAL
+ icon = 'icons/effects/blood.dmi'
+ var/base_icon = 'icons/effects/blood.dmi'
+ icon_state = "mfloor1"
+ var/basecolor="#030303"
+ desc = ""
+ w_class = ITEMSIZE_NORMAL
+ var/deployed = 1
+ anchored = 1
+
+/obj/structure/gootrap/proc/can_use(mob/user)
+ return (user.IsAdvancedToolUser() && !issilicon(user) && !user.stat && !user.restrained())
+
+/obj/structure/gootrap/update_icon()
+ ..()
+ color = basecolor
+
+/obj/structure/gootrap/Initialize(mapload)
+ . = ..()
+ update_icon()
+
+/obj/structure/gootrap/attack_hand(mob/user as mob)
+ if(has_buckled_mobs() && can_use(user))
+ var/victim = english_list(buckled_mobs)
+ user.visible_message(
+ span_notice("[user] begins freeing [victim] from \the [src]."),
+ span_notice("You carefully begin to free [victim] from \the [src]."),
+ )
+ if(do_after(user, 5))
+ user.visible_message(span_notice("[victim] has been freed from \the [src] by [user]."))
+ for(var/A in buckled_mobs)
+ unbuckle_mob(A)
+ anchored = 0
+ else
+ ..()
+
+/obj/structure/gootrap/proc/attack_mob(mob/living/L)
+ //trap the victim in place
+ set_dir(L.dir)
+ can_buckle = 1
+ buckle_mob(L)
+ var/goo_sounds = list (
+ 'sound/rakshasa/Decay1.ogg',
+ 'sound/rakshasa/Decay2.ogg',
+ 'sound/rakshasa/Decay3.ogg'
+ )
+ var/sound = pick(goo_sounds)
+ playsound(src, sound, 100, 1)
+ L << span_danger("You hear a gooey schlorp as \the [src] ensnares your leg, trapping you in place!")
+ deployed = 0
+ can_buckle = initial(can_buckle)
+
+
+/obj/structure/gootrap/Crossed(AM as mob|obj)
+ if(deployed && isliving(AM))
+ var/mob/living/L = AM
+ if(L.m_intent == I_RUN)
+ L.visible_message(
+ span_danger("[L] steps on \the [src]."),
+ span_danger("You step on \the [src]!"),
+ span_hear(span_bold("You hear a gooey schlorp as the goo ensnares your leg!"))
+ )
+ attack_mob(L)
+ if(!has_buckled_mobs())
+ anchored = 0
+ deployed = 0
+ message_admins("[key_name(usr)] has stepped in the goo trap.")
+ ..()
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/types.dm b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/types.dm
index 2bf05a7579..bf321775c2 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/types.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/types.dm
@@ -291,3 +291,138 @@
you to curl up a bit. You can feel her rub at you some through the layers of flesh and fluff, while aches \
and pains begin to fade away across your body."
player_msg = "Mar? Mar mar. Mar mar mar. Mar. Mar mar? Mar! Mar. Marrrr."
+
+//Special event mob. "Hunger." - Rakshasa
+/mob/living/simple_mob/shadekin/red/rakshasa
+ name ="Rakshasa"
+ desc = "A scary, black shadekin? Their body oozes like goop."
+ icon_state = "rakshasa"
+ vore_stomach_flavor = "You're floating in a warm, viscous goop, too dark to see. \
+ Your efforts to find light have failed. Darkness consumes you. \
+ Rakshasa's gelatenous body squeezes over your form, leaving no inch unmolested. \
+ The hot goop you float in makes it hard to breathe; all consuming of space and light. \
+ Your body feels hot, growing weaker, more tired. Draining. Darkness coming. \
+ You struggle to stay awake while floating helplessly in the goo."
+ player_msg = "You are Rakshasa. You are not to directly harm crew, only consume. You never speak a language. You have special emotes: 'evillaugh', 'evilno', 'evilbreath', 'evilbreath2', and 'goodripsound'"
+ maxHealth = 1000000000000
+ health = 1000000000000
+ eye_state = "BLUE EYES"
+ eye_icon_state = "e_rakshasa"
+ comp = /datum/component/shadekin/full/rakshasa
+
+/mob/living/simple_mob/shadekin/red/rakshasa/Initialize(mapload)
+ . = ..()
+ if(comp)
+ comp.dark_energy_infinite = TRUE
+
+/mob/living/simple_mob/shadekin/red/rakshasa/get_available_emotes()
+ . = global._simple_mob_default_emotes.Copy()
+ . += /decl/emote/audible/evil_laugh
+ . += /decl/emote/audible/evil_no
+ . += /decl/emote/audible/evil_breathing
+ . += /decl/emote/audible/evil_breathing_2
+ . += /decl/emote/audible/goodripsound
+
+/mob/living/simple_mob/shadekin/blue/luna
+ name = "Luna"
+ desc = "She appears to be a fuzzy critter of some sort. Her eyes shimmer a dark blue, glancing around curiously."
+ icon_state = "luna"
+ eye_desc = "blue eyes"
+ vore_stomach_flavor = "Dark blue flesh fills your vision as you slip past the Shadekin's tongue and into the darkness \
+ of her gullet. The flesh around you seems squishy and pliable and malleable to say the least, warmth rolling up \
+ your body as the humid air rises across the deeper you slide into the darkness of her stomach. As you splash \
+ inside, you curl up comfortably inside the walls that churn and squeeze around you, any fidgeting quickly \
+ subdued by the strength of the walls, and any movement of your predator seems to coax a light sway from \
+ your current prison. The slime inside stuck fairly well, though harmless - your aches and pains slowly soothing \
+ up and fading away."
+ player_msg = "You are a shadekin that goes by the name of Luna. Curious, you have tasked yourself and yourself alone \
+ with studying this foreign world. Learn their language. Learn their culture. Adapt. Everything is wonderful and new, \
+ and your mind is set on retaining knowledge of these odd planescape."
+
+//"All your chickens are belong to me!" - Zylas
+/mob/living/simple_mob/shadekin/purple/zylas
+ name ="Zylas"
+ desc = "He's a chubby looking creature, black and grey fur accompanied by purple eyes and a large hoody."
+ icon_state = "zylashoody"
+ eye_desc = "purple eyes"
+ vore_stomach_flavor = "You are trapped in a cramped tight space. The color purple seems to dominate your vision. \
+ His walls rolled over your form as you lay trapped in his depths. There wasnt a drop of fluid in sight inside that \
+ stomach. Instead, you could feel your energy slowly draining away over time, like... he was leeching off you."
+ player_msg = "You are Zylas. You enjoy scaring the local population and eating every chicken you find."
+
+//"Two scarves. No more, No Less." -Muninn
+/mob/living/simple_mob/shadekin/blue/muninn
+ name ="Muninn"
+ desc = "A gray furred shadekin, a little on the hefty side. Rocks two scarves, one on the neck, one on the tail. \
+ He seems eager to take in the various sights and sounds of the station"
+ icon_state = "muninn"
+ eye_desc = "blue eyes"
+ vore_stomach_flavor = "You're stuck in a warm, tight stomach. \
+ A blue glow, as soft as the walls surrounding you, illuminates the cramped chamber. \
+ Muninn's walls gently squeeze over your form, like a tight, yet comfortable hug. \
+ The gut itself was relatively dry, only slightly damp. \
+ As Muninn ambles along, you'd gently sway within. It's quite the nice place to stay for a while."
+ player_msg = "You are Muninn. Today you feel... Curious."
+
+//"Here's a little lesson in the trickeries" -Muninn
+/mob/living/simple_mob/shadekin/purple/muninn
+ name ="Muninn"
+ desc = "A gray furred shadekin, a little on the hefty side. Rocks two scarves, one on the neck, one on the tail.\
+ He seems a little mischevious... better keep an eye on him."
+ icon_state = "muninn"
+ eye_desc = "purple eyes"
+ vore_stomach_flavor = "You're stuck in a warm, tight stomach. \
+ A purple glow, as soft as the walls surrounding you, illuminates the cramped chamber. \
+ Muninn's walls gently squeeze over your form, like a tight hug. \
+ The gut itself was relatively dry, only slightly damp. \
+ It didn't seem that Muninn was digesting you. More like... sapping your energy and making you feel tired. \
+ A nap in this comfortable chamber wouldn't be the worst thing, would it?"
+ player_msg = "You are Muninn. Today you feel... Mischevious."
+
+//Whealty's shadekin anno!
+/mob/living/simple_mob/shadekin/purple/anno
+ name ="Anno"
+ desc = "A white furred shadekin with a chubby form. His ears seem to be close to even in length and his snout seems longer than the usual.\
+ He seems energetic and playful."
+ icon_state = "anno"
+ eye_desc = "purple eyes"
+ vore_stomach_flavor = "You're stuck in a warm, tight stomach. \
+ A purple glow, as soft as the walls surrounding you, illuminates the cramped chamber. \
+ Anno's stomach walls squeeze and hug over your form somewhat tightly. \
+ The gut itself was wetish and slightly slick. \
+ The gut seemed somewhat inviting with the warmth and softness, yet there was an ominous feeling to it with all the noises it made.\
+ You'll probably be safe in here. Probably."
+ player_msg = "You are Anno, you are energetic and playful"
+
+/mob/living/simple_mob/shadekin/blue/roti
+ name ="Roti"
+ desc = "Roti is a shadekin with blue eyes, is chubby since he has eaten others before hand. He enjoys chocolate, the taste of it, the smell of it, he just wants anything sweet and chocolately to be in his belly. So be careful around him this is also a way to summon him by laying around chocolate and calling him out."
+ icon_state = "roti"
+ eye_desc = "blue eyes"
+ vore_stomach_flavor = "You stare into Roti's maw as he moves it towards your head, putting it in and tasting your sweet delicious chocolately flavor. \
+ Wet saliva covers your head as he pushes you inward, gulping down your head and shoulders into his pulsating throat. It pulses and eases you downward towards your destination \
+ cramming your torso into his maw and taking wet SCHLURP, GLUK, to get it down and up to your waist. Roti continues to taste you all over wanting that succulent flavor \
+ to himself. Another loud wet swallow and down goes your waist into his hungry maw, lifting up the legs high into the sky while allowing gravity and his gulps \
+ to send you packing away into his chubby gut that now expands to fit you inside of the wet chamber. At least you were safe for now that is."
+ player_msg = "You are Roti, a curious shadekin that wishes to learn from the station and eventually speak with them."
+
+//kcin2001's soft shadekin
+/mob/living/simple_mob/shadekin/green/soft
+ name = "Softpatch"
+ desc = "A green eyed brown shadekin, looks fluffy and a bit chubby around the middle underneath his well worn cloak \
+ He seems curious but ready to flee"
+ icon_state = "soft"
+ eye_desc = "soft green eyes"
+// vore_stomach_flavor = ""
+ player_msg = "You are Softpatch, you like things that are soft and are curious about the beings in realspace"
+
+//"Marr marr marr-marr maaarr marr?~ (Ever had your ass eaten by a shadekin before?~)" - Yrmir (Shadowfire117)
+/mob/living/simple_mob/shadekin/orange/yrmir
+ name = "Green and black shadekin" //Name is Yrmir and known only to other shadekins he talks to, he doesn't speak common to any degree so far
+ desc = "An orange eyed shadekin, this one has a very dark coat with several spots with faintly glowing green patches of fur. \
+ Said fur looks quite soft and warm with it filling out a bit, a closer look tells its a slim upper body while rump, hips and thighs are nice and filled out well. \
+ While he may have a more padded out soft build below, the masculine part of them is quite visible as a large fat furred sack and sheath rests comfortably between his thighs. \
+ From the way he looks at you, you get the feeling he is possibly scheming something fun, at least for himself."
+ icon_state = "yrmir"
+ eye_desc = "glimmering orange eyes"
+ player_msg = "You are Yrmir, an orange shadekin with interest in revelry, trickery and pleasures. Mostly for you but to a degree to the willing and unwilling that interest you."
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/slug.dm b/code/modules/mob/living/simple_mob/subtypes/vore/slug.dm
new file mode 100644
index 0000000000..c41aea0d02
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/slug.dm
@@ -0,0 +1,257 @@
+//Passive vore slug. This mob is intended to be annoying but harmless to anybody it can't eat.
+
+/mob/living/simple_mob/vore/slug
+ name = "slug"
+ desc = "A giant, cold-tolerant slug. It seems excessively passive."
+ catalogue_data = list(/datum/category_item/catalogue/fauna/slug)
+ tt_desc = "S Arion hortensis"
+ icon = 'icons/mob/vore.dmi'
+ icon_dead = "slug-dead"
+ icon_living = "slug"
+ icon_state = "slug"
+ faction = "slug" //A faction other than neutral is necessary to get the slug to try eating station crew.
+ meat_type = /obj/item/reagent_containers/food/snacks/meat
+ melee_damage_lower = 0
+ melee_damage_upper = 1 //Not intended to pose any sort of threat outside of vore. Other code should stop it from ever attacking but this is an extra safety check.
+ friendly = list("blinks at")
+ response_help = "pokes"
+ response_disarm = "prods"
+ response_harm = "punches"
+ movement_cooldown = 40 //I guess you could call this a SNAIL'S PACE.
+ maxHealth = 100
+ health = 100
+ attacktext = list("headbutted")
+ minbodytemp = 80
+ ai_holder_type = /datum/ai_holder/simple_mob/passive/slug_ch
+ vore_icons = SA_ICON_LIVING
+ armor = list(
+ "melee" = 98,
+ "bullet" = 0,
+ "laser" = -50,
+ "energy" = -50,
+ "bomb" = 0,
+ "bio" = 0,
+ "rad" = 100) //Relatively harmless but agonizing to kill with melee.
+
+ glow_toggle = TRUE
+ glow_range = 1.3 //This seems to be the minimum range which makes glow visible.
+ glow_color = "#33ccff" //Same glow color as Sif trees.
+ glow_intensity = 1
+
+
+ var/list/my_slime = list()
+ var/slime_max = 35 //With a slug which moves once every 10 seconds and a 5 minute delete timer, this should never exceed 30.
+ var/mob/living/vore_memory = null
+
+ can_be_drop_prey = FALSE
+
+/mob/living/simple_mob/vore/slug //I guess separating the vore variables is a little more organized?
+ vore_bump_chance = 100 //Always attempt a bump nom if possible...
+ vore_bump_emote = "knocks over and begins slowly engulfing"
+ vore_active = 1
+ vore_icons = 1
+ vore_capacity = 1
+ vore_pounce_chance = 100 //...while this should make bump noms always knock the target over. Passive AI meanwhile should mean this never affects combat since it doesn't fight back.
+ vore_ignores_undigestable = 0
+ swallowTime = 100 //10 seconds. Easy to crawl away from when knocked over.
+ vore_default_mode = DM_DIGEST
+
+/mob/living/simple_mob/vore/slug/load_default_bellies()
+ . = ..()
+ var/obj/belly/B = vore_selected
+ B.desc = "Somehow you remained still just long enough for the slug to wrap its radula around your body and gradually draw you into its pharynx. The slug moves with agonizing slowness and devours prey at a snail's pace; inch by inch you're crammed down its gullet and squishes and squeezed into the slug's gizzard. Thick walls bear down, covered with shallow, toothy ridges. The slimy moss in here suggests you're not the slug's diet but the gizzard seems intent on churning and scraping over you regardless..."
+ B.digest_burn = 0.1
+ B.digest_brute = 0.2
+ B.vore_verb = "engulf"
+ B.name = "gizzard"
+ B.mode_flags = DM_FLAG_THICKBELLY
+ B.escapechance = 5
+ B.fancy_vore = 1
+ B.vore_sound = "Squish2"
+ B.release_sound = "Pred Escape"
+ B.contamination_color = "cyan"
+ B.contamination_flavor = "Wet"
+
+
+ B.emote_lists[DM_DIGEST] = list(
+ "The toothy walls scrape and grind against your body.",
+ "The humid air feels thick and heavy, stinging faintly with each breath.",
+ "Heavy slime oozes over you, making it difficult to move."
+ ) //Why do so many vore mobs have endo emotes despite being digest only?
+
+/datum/category_item/catalogue/fauna/slug
+ name = "Sivian Fauna - Moss Slug"
+ desc = "Classification: S Arion hortensis\
+
\
+ A large herbivorous slug commonly spotted near northern waterways with abundant moss. The slug is remarkably resistant to blunt trauma despite its fleshy body due to a foul-tasting outer casing \
+ of thick, mucus-filled tissue protecting the more vulnerable musculature beneath. Said mucus is a natural irritant and hardens rapidly in contact with air, sealing wounds and allowing the slug to shrug off most surface injuries. \
+ Few predators exist for the Sivian slug due to the stinging slime's tendency to adhere to attacking claws and appendages.\
+
\
+ The Sivian slug is typically regarded as a pest due to the animal's large bulk and tendency to crush weak structures in its path. Most tools do little to dissuade the creature, forcing homesteads to rely on firearms or reinforced fencing \
+ with a slippery coating the slug cannot stick to. While subsisting primarily on Sivian moss, the slug is an opportunistic predator known to eat small fauna which wander into its path. The slime excreted from the slug's foot is particularly sticky and capable of miring small animals. The Sivian slug glows faintly due to colonies bioluminescent bacteria present in its diet."
+ value = CATALOGUER_REWARD_EASY
+
+/mob/living/simple_mob/vore/slug/proc/spread_slime()
+ if(my_slime.len >= slime_max)
+ return
+ if(istype(get_turf(src), /turf/simulated/floor/water)) //Important to stop my_slime from filling with null entries in water.
+ return
+ var/obj/effect/slug_glue/G = new /obj/effect/slug_glue/(get_turf(src))
+ G.my_slug = src
+ my_slime += G
+
+/mob/living/simple_mob/vore/slug/death()
+ ..()
+ for(var/obj/effect/slug_glue/G in my_slime)
+ G.my_slug = null
+ my_slime -= G //No point in keeping these loaded in the list when the slug dies if somehow the list sticks around after death.
+
+/mob/living/simple_mob/vore/slug/Moved()
+ . = ..()
+ spread_slime()
+
+/mob/living/simple_mob/vore/slug/do_attack(atom/A, turf/T) //Override of attack proc to ensure the slug can only attempt to eat people, not harm them. Inability to actually hurt anybody is intended, otherwise this mob wouldn't have 98 melee armor.
+ if(ckey) //If we're player controlled, use the default attack code.
+ return ..()
+ if(istype(A, /mob/living) && !will_eat(A))
+ ai_holder.lose_target() //Ignore anybody we can't eat.
+ return
+ else //This is the parent do_attack() code for determining whether or not attacks can hit.
+ face_atom(A)
+ var/missed = FALSE
+ if(!isturf(A) && !(A in T) ) // Turfs don't contain themselves so checking contents is pointless if we're targeting a turf.
+ missed = TRUE
+ else if(!T.AdjacentQuick(src))
+ missed = TRUE
+
+ if(missed) // Most likely we have a slow attack and they dodged it or we somehow got moved.
+ add_attack_logs(src, A, "Animal-attacked (dodged)", admin_notify = FALSE)
+ playsound(src, 'sound/rakshasa/Decay1.ogg', 75, 1)
+ visible_message(span_warning("\The [src] misses."))
+ return FALSE
+ tryBumpNom(A) //Meant for bump noms but this works as intended here and has sanity checks.
+
+/mob/living/simple_mob/vore/slug/perform_the_nom(mob/living/user, mob/living/prey, mob/living/pred, obj/belly/belly, delay)
+ ..()
+ vore_memory = prey
+
+/datum/ai_holder/simple_mob/passive/slug_ch
+ wander = TRUE
+ base_wander_delay = 7
+ wander_when_pulled = TRUE
+ vision_range = 10
+ can_flee = FALSE //Otherwise it'll run as soon as it gets a target.
+
+/obj/effect/slug_glue
+ name = "liquid"
+ desc = "This looks wet."
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "wet_turf"
+ opacity = 0
+ mouse_opacity = 0 //Unclickable
+ anchored = 1
+ density = 0
+ can_buckle = 1
+ buckle_lying = TRUE
+
+ var/persist_time = 5 MINUTES //How long until we cease existing.
+ var/mob/living/simple_mob/vore/slug/my_slug = null //This should be set by the slug.
+ var/turf/my_turf = null //The turf we spawn on.
+ var/base_escape_time = 1 MINUTE //How long does it take to struggle free? Affected by the victim's size_multiplier.
+
+/obj/effect/slug_glue/Initialize(mapload)
+ . = ..()
+ if(!persist_time)
+ return INITIALIZE_HINT_QDEL
+ my_turf = get_turf(src)
+ if(istype(my_turf, /turf/simulated/floor/water)) //Aside from not making sense in water, this prevents drowning.
+ return INITIALIZE_HINT_QDEL
+ QDEL_IN(src, persist_time)
+/* for(var/obj/effect/slug_glue/G in my_turf.contents)
+ if(G == src)
+ continue
+ else
+ qdel(G) //Prevent glue layering
+*/ //Not including this due to performance concerns but keeping as comments for reference.
+
+/obj/effect/slug_glue/Destroy()
+ . = ..()
+ if(my_slug)
+ my_slug.my_slime -= src //Remove the slime from the slug's list when destroyed.
+
+//This could probably be applied to spideweb code to make it work as intended again.
+/obj/effect/slug_glue/Uncross(atom/movable/AM, atom/newloc)
+ if(istype(AM, /mob/living/simple_mob/vore/slug))
+ return ..()
+ else if(istype(AM, /mob/living))
+ if(prob(50))
+ to_chat(AM, span_warning("You stick to \the [my_turf]!"))
+ return FALSE
+ return ..()
+
+
+/obj/effect/slug_glue/Crossed(atom/movable/AM as mob|obj)
+ if(AM.is_incorporeal())
+ return
+
+ if(istype(AM, /mob/living/simple_mob))
+ var/mob/living/L = AM
+ if(istype(L, /mob/living/simple_mob/vore/slug))
+ return
+ L.Weaken(10)
+ playsound(src, 'sound/rakshasa/Decay3.ogg', 100, 1)
+ alert_slug(L)
+
+ if(istype(AM, /mob/living/carbon) || istype(AM, /mob/living/silicon))
+ var/mob/living/L = AM
+
+ if(L.m_intent == I_RUN && !L.buckled)
+ if(has_buckled_mobs())
+ return
+ buckle_mob(L)
+ L.stop_pulling()
+ L.Weaken(2)
+ to_chat(L, span_warning("You tripped in the sticky substance, sticking to [my_turf]!"))
+ playsound(src, 'sound/rakshasa/Decay3.ogg', 100, 1)
+ alert_slug(L)
+
+/obj/effect/slug_glue/proc/alert_slug(mob/living/victim as mob)
+ if(!my_slug || !has_buckled_mobs() || isbelly(my_slug.loc)) //Otherwise if you eat the slug it will infinitely attempt to eat you if you trip in glue.
+ return
+ if(my_slug.vore_memory == victim) //Getting eaten lets you get stuck once without alerting the slug. This is to prevent instantly getting eaten again if you struggle free with run intent on.
+ my_slug.vore_memory = null
+ return
+ my_slug.ai_holder.give_target(victim)
+
+/obj/effect/slug_glue/proc/unalert_slug(mob/living/victim as mob)
+ if(!my_slug)
+ return
+ if(my_slug.ai_holder.target == victim)
+ my_slug.ai_holder.remove_target() //Instant loss of target. Necessary to simulate the mob giving up if the prey escapes.
+
+/obj/effect/slug_glue/user_unbuckle_mob(mob/living/buckled_mob, mob/user)
+ user.setClickCooldown(user.get_attack_speed())
+ to_chat(user, "You tug and strain against the sticky substance...")
+ var/escape_time
+ switch(buckled_mob.size_multiplier)
+ if(RESIZE_TINY - 1 to RESIZE_A_NORMALSMALL) //24% to 75% size scale, 1% below 25% is to account for microcillin sometimes going slightly below 25%
+ escape_time = 2 * base_escape_time
+ if(RESIZE_A_NORMALSMALL to RESIZE_A_BIGNORMAL) //75% to 125% size scale
+ escape_time = base_escape_time
+ if(RESIZE_A_BIGNORMAL to RESIZE_HUGE + 1) //125% to 201% size scale, 1% above 200% is to acount for macrocillin sometimes going slightly above 200%
+ escape_time = 0.5 * base_escape_time
+ else
+ escape_time = base_escape_time //Admeme size scale
+ if(do_after(user, escape_time, src, timed_action_flags = IGNORE_INCAPACITATED))
+ if(!has_buckled_mobs())
+ return
+ to_chat(user, "You tug free of the tacky, rubbery strands!")
+ unbuckle_mob(buckled_mob)
+ unalert_slug(buckled_mob)
+
+/obj/effect/slug_glue/wash(clean_types) // Needs proper scrubbing
+ . = ..()
+ if (. || (clean_types & CLEAN_SCRUB))
+ qdel(src)
+ return TRUE
+ return .
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/snake.dm b/code/modules/mob/living/simple_mob/subtypes/vore/snake.dm
index 69fa5acae6..196b272006 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/snake.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/snake.dm
@@ -54,6 +54,7 @@
ai_holder_type = /datum/ai_holder/simple_mob/melee
+ can_be_drop_prey = FALSE
allow_mind_transfer = TRUE
// Activate Noms!
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/solargrub.dm b/code/modules/mob/living/simple_mob/subtypes/vore/solargrub.dm
index a0f5bf2a0b..34fd1a782d 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/solargrub.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/solargrub.dm
@@ -15,8 +15,7 @@ List of things solar grubs should be able to do:
Therefore, if you see the grubs, kill them while they're small, or things might escalate." // TODO: PORT SOLAR MOTHS - Rykka
value = CATALOGUER_REWARD_EASY
-// var/global/moth_amount = 0 // Chompstation, Rykka waz here. *pawstamp*
-// Ace was here too. Vorestation doesn't have solar moths yet! Uncomment this if someone else adds them. I don't know if Vorestation will like them.
+GLOBAL_VAR_INIT(moth_amount, 0)
/mob/living/simple_mob/vore/solargrub
name = "juvenile solargrub"
@@ -28,8 +27,10 @@ List of things solar grubs should be able to do:
icon_dead = "solargrub-dead"
var/charge = null // The amount of power we sucked off, in K as in THOUSANDS.
- var/can_evolve = 0 // To decide whether this subspecies is allowed to become a queen, which Ace has set as 0 because there's no evolution form yet.
- var/adult_forms = null // This decides what mob the queen form is. ex adult_forms = /mob/living/simple_mob/subtypes/vore/solarmoth
+
+ var/can_evolve = 1 // To decide whether this subspecies is allowed to become a queen, which Ace has set as 0 because there's no evolution form yet.
+ var/adult_forms = "/mob/living/simple_mob/vore/solarmoth" // This decides what mob the queen form is. ex adult_forms = /mob/living/simple_mob/subtypes/vore/solarmoth
+
// Don't leave that as null if you add solar moths.
faction = FACTION_GRUBS
@@ -60,6 +61,7 @@ List of things solar grubs should be able to do:
var/powerdraw = 100000
var/tracked = FALSE
+ can_be_drop_prey = FALSE
allow_mind_transfer = TRUE
glow_override = TRUE
@@ -101,14 +103,14 @@ List of things solar grubs should be able to do:
else if(!attached && anchored)
anchored = FALSE
PN = null
- /*if(prob(1) && charge >= 32000 && can_evolve == 1 && moth_amount < 1) //it's reading from the moth_amount global list to determine if it can evolve. There should only ever be a maxcap of 1 existing solar moth alive at any time. TODO: make the code decrease the list after 1 has spawned this shift.
+ if(prob(1) && charge >= 32000 && can_evolve == 1 && GLOB.moth_amount < 1) //it's reading from the moth_amount global list to determine if it can evolve. There should only ever be a maxcap of 1 existing solar moth alive at any time. TODO: make the code decrease the list after 1 has spawned this shift.
anchored = 0
PN = null
release_vore_contents()
if(prey_excludes)
prey_excludes.Cut()
- moth_amount = moth_amount + 1
- death_star()*/ // Removed until moths added.
+ GLOB.moth_amount = GLOB.moth_amount + 1
+ death_star()
/mob/living/simple_mob/vore/solargrub/proc/death_star()
visible_message(span_warning("\The [src]'s shell rips open and evolves!"))
@@ -199,7 +201,7 @@ List of things solar grubs should be able to do:
"The solargrub chitters in irritation at your continued solidity, followed by a string of crushingly tight stomach clenches that grind its caustic stomach ooze into your body!",
"The deceptively severe heat trapped within the solargrub works in tandem with its inner muscles and your tingling, prickling stomach juice bath to weaken you!")
-/datum/ai_holder/simple_mob/retaliate/solargrub/react_to_attack(atom/movable/attacker, ignore_timers = FALSE)
+/datum/ai_holder/simple_mob/retaliate/solargrub/react_to_attack(atom/movable/attacker, ignore_timers)
holder.anchored = FALSE
holder.set_AI_busy(FALSE)
..()
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/solargrub_larva.dm b/code/modules/mob/living/simple_mob/subtypes/vore/solargrub_larva.dm
index 5a47738adc..16b4cc9b2b 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/solargrub_larva.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/solargrub_larva.dm
@@ -300,3 +300,13 @@ GLOBAL_LIST_EMPTY(grub_machine_overlays)
to_chat(user, span_warning("You disturb a grub nesting in \the [O]!"))
return
return ..()
+
+/obj/item/melee/baton/afterattack(obj/O, mob/user, proximity)
+ if(proximity)
+ if(istype(O, /obj/machinery))
+ var/mob/living/simple_mob/animal/solargrub_larva/grub = locate() in O
+ if(grub)
+ grub.eject_from_machine(O)
+ to_chat(user, span_warning("You disturb a grub nesting in \the [O]!"))
+ return
+ return ..()
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/solarmoth.dm b/code/modules/mob/living/simple_mob/subtypes/vore/solarmoth.dm
new file mode 100644
index 0000000000..0ebd13d816
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/solarmoth.dm
@@ -0,0 +1,201 @@
+/datum/category_item/catalogue/fauna/solarmoth //TODO: VIRGO_LORE_WRITING_WIP
+ name = "Solarmoth"
+ desc = "An adult variation of a solargrub, these winged critters are very deadly. They seem to heat up everything nearby, \
+ turning ordinary rooms into infernos, and causing malfunctions across the station. They are so hot that laser weaponry is like throwing an ice cube at them. \
+ Bullets will melt in the face of them and only cause minor damage from the melted matter. \
+ Melee seems to be thier weakness as long as the user has appropriate heat protection or if you're quick enough to respond before needing protection. Approach with caution."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/mob/living/simple_mob/vore/solarmoth
+ name = "solarmoth"
+ desc = "A majestic sparkling solarmoth. Also a slight engineering hazard known to heat rooms equal to temperatures of a white dwarf."
+ catalogue_data = list(/datum/category_item/catalogue/fauna/solarmoth)
+ icon = 'icons/mob/solarmoth.dmi' //all of these are placeholders
+ icon_state = "solarmoth"
+ icon_living = "solarmoth"
+ icon_dead = "solarmoth-dead"
+
+ var/mycolour = COLOR_BLUE //Variable Lighting colours
+ var/original_temp = null //Value to remember temp
+ var/set_temperature = T0C + 10000 //Sets the target point of 10k degrees celsius
+ var/heating_power = 100000 //This controls the strength at which it heats the environment.
+ var/emp_heavy = 2
+ var/emp_med = 4
+ var/emp_light = 7
+ var/emp_long = 10
+
+ faction = "grubs"
+ maxHealth = 400 // Tanky fuckers.
+ health = 400 // Tanky fuckers.
+
+ melee_damage_lower = 1
+ melee_damage_upper = 5
+
+ movement_cooldown = 5
+
+ meat_type = /obj/item/reagent_containers/food/snacks/meat/grubmeat
+
+ response_help = "pokes"
+ response_disarm = "pushes"
+ response_harm = "roughly pushes"
+
+ ai_holder_type = /datum/ai_holder/simple_mob/retaliate
+ say_list_type = /datum/say_list/solarmoth
+
+ var/poison_per_bite = 5 //grubs cause a shock when they bite someone
+ var/poison_type = REAGENT_ID_SHOCKCHEM
+ var/poison_chance = 50
+ var/shock_chance = 20 // Beware synths
+
+ // solar moths are not affected by atmos
+ 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
+ heat_damage_per_tick = 0 //Even if the atmos stuff doesn't work, at least it won't take any damage.
+
+ armor = list(
+ "melee" = 0,
+ "bullet" = 90,
+ "laser" = 100,
+ "energy" = 100,
+ "bomb" = 100,
+ "bio" = 100,
+ "rad" = 100)
+
+ can_be_drop_prey = FALSE
+
+ glow_override = TRUE
+
+/datum/say_list/solarmoth
+ emote_see = list("flutters")
+
+/mob/living/simple_mob/vore/solarmoth/apply_melee_effects(var/atom/A)
+ if(isliving(A))
+ var/mob/living/L = A
+ if(prob(shock_chance))
+ A.emp_act(4) //The weakest strength of EMP
+ playsound(src, 'sound/weapons/Egloves.ogg', 75, 1)
+ L.Weaken(4)
+ L.Stun(4)
+ L.stuttering = max(L.stuttering, 4)
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(5, 1, L)
+ s.start()
+ visible_message(span_danger("The moth releases a powerful shock!"))
+ else
+ if(L.reagents)
+ var/target_zone = pick(BP_TORSO,BP_TORSO,BP_TORSO,BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_HEAD)
+ if(L.can_inject(src, null, target_zone))
+ inject_poison(L, target_zone)
+
+// Does actual poison injection, after all checks passed.
+/mob/living/simple_mob/vore/solarmoth/proc/inject_poison(mob/living/L, target_zone)
+ if(prob(poison_chance))
+ to_chat(L, span_warning("You feel a small shock rushing through your veins."))
+ L.reagents.add_reagent(poison_type, poison_per_bite)
+
+/mob/living/simple_mob/vore/solarmoth/Life()
+ . = ..()
+ if(icon_state != icon_dead) //I mean on death() Life() should disable but i guess doesnt hurt to make sure -shark
+ var/turf/moth_loc = get_turf(src)
+ if(isturf(moth_loc) && moth_loc.air)
+ var/datum/gas_mixture/env = moth_loc.return_air() //Gets all the information on the local air.
+ var/transfer_moles = 0.25 * env.total_moles //The bigger the room, the harder it is to heat the room.
+ var/datum/gas_mixture/removed = env.remove(transfer_moles)
+ var/heat_transfer = removed.get_thermal_energy_change(set_temperature)
+ if(heat_transfer > 0 && env.temperature < T0C + 200) //This should start heating the room at a moderate pace up to 200 degrees celsius.
+ heat_transfer = min(heat_transfer , heating_power) //limit by the power rating of the heater
+ removed.add_thermal_energy(heat_transfer)
+
+ else if(heat_transfer > 0 && env.temperature < set_temperature) //Set temperature is 10,000 degrees celsius. So this thing will start cooking crazy hot between the temperatures of 200C and 10,000C.
+ heating_power = original_temp*100 //Changed to work variable -shark //FLAME ON! This will make the moth heat up the room at an incredible rate.
+ heat_transfer = min(heat_transfer , heating_power) //limit by the power rating of the heater. Except it's hot, so yeah.
+ removed.add_thermal_energy(heat_transfer)
+
+ else
+ return
+
+ env.merge(removed)
+
+
+
+ //Since I'm changing hyper mode to be variable we need to store old power
+ original_temp = heating_power //We remember our old goal, for use in non perpetual heating level increase
+
+/mob/living/simple_mob/vore/solarmoth/proc/explode()
+ src.anchored = 0
+ set_light(0)
+ GLOB.moth_amount = clamp(GLOB.moth_amount - 1, 0, 1)
+ if(empulse(src, emp_heavy, emp_med, emp_light, emp_long))
+ qdel(src)
+ return
+
+/mob/living/simple_mob/vore/solarmoth/death()
+ explode()
+ ..()
+
+/mob/living/simple_mob/vore/solarmoth/gib() //This baby will explode no matter what you do to it.
+ explode()
+ ..()
+
+
+
+/mob/living/simple_mob/vore/solarmoth/handle_light()
+ . = ..()
+ if(. == 0 && !is_dead())
+ set_light(9.5, 1, mycolour) //9.5 makes the brightness range super huge.
+ return 1
+ else if(is_dead())
+ glow_override = FALSE
+
+
+/mob/living/simple_mob/vore/solarmoth //active noms
+ vore_bump_chance = 50
+ vore_bump_emote = "applies minimal effort to try and slurp up"
+ vore_active = 1
+ vore_capacity = 1
+ vore_pounce_chance = 0 //moths only eat incapacitated targets. It's too lazy burning you to a crisp to try to pounce you
+ vore_default_mode = DM_DIGEST
+
+/mob/living/simple_mob/vore/solarmoth/lunarmoth
+ name = "lunarmoth"
+ desc = "A majestic sparkling lunarmoth. Also a slight engineering hazard."
+
+ var/nospampls = 0
+
+ cold_damage_per_tick = 0
+ //ATMOS
+ set_temperature = T0C - 10000
+ heating_power = -100000
+ //light
+ mycolour = COLOR_WHITE
+
+/mob/living/simple_mob/vore/solarmoth/lunarmoth/proc/chilltheglass() //Why does a coldfusion moth do this? science -shark
+ nospampls = 1
+ if(prob(25))
+ for(var/obj/machinery/light/light in range(5, src))
+ if(prob(50))
+ light.broken()
+ if(prob(10))
+ for(var/obj/structure/window/window in range(5, src))
+ if(prob(50))
+ window.shatter()
+ if(prob(20))
+ for(var/obj/machinery/door/firedoor/door in range(14, src)) //double viewrange
+ if(prob(5))
+ visible_message(span_danger("Emergency Shutter malfunction!"))
+ door.blocked = 0
+ door.open(1)
+
+ VARSET_IN(src, nospampls, 0, 10 SECONDS)
+
+/mob/living/simple_mob/vore/solarmoth/lunarmoth/Life()
+ ..()
+ if(!nospampls)
+ chilltheglass() //shatter and broken calls for glass and lights. Also some special thing.
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/stalker.dm b/code/modules/mob/living/simple_mob/subtypes/vore/stalker.dm
index 229e0815dd..7c135298b0 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/stalker.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/stalker.dm
@@ -7,7 +7,7 @@
icon_dead = "stalker-dead"
icon_living = "stalker"
icon_state = "stalker"
- icon_rest = "stalker-rest"
+ icon_rest = "stalker_rest"
faction = FACTION_STALKER
old_x = -16
old_y = 0
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/swoopie.dm b/code/modules/mob/living/simple_mob/subtypes/vore/swoopie.dm
new file mode 100644
index 0000000000..f4f5ac35a5
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/swoopie.dm
@@ -0,0 +1,397 @@
+/datum/category_item/catalogue/technology/drone/corrupt_hound/swoopie // Writing this so that they arnt corrupt hounds! -Reo
+ name = "Drone - SWOOPIE XL"
+ desc = "A large drone that typically wanders about maintenance or other places that are dirty, mindlessly sucking \
+ up everything it deems to be debris, trash or a pest. \
+ It looks like a blue and yellow long-necked bird with a large distinct black, plump belly and flexible neck that \
+ bulges with every object it swoops. \
+ They tend to run on extremely basic AI until proper ones are available to be downloaded from an external, \
+ oddly spooky, provider. \
+
\
+ The SWOOPIE's belly and neck are made of a synthetic rubber compound that is durable enough to allow them to pack \
+ away even the most fiesty of pests once they make it past the synthbird's beak, and staring into that beak would allow \
+ one to see far down into the drone, though the frequent curving of the SWOOPIE's neck often makes seeing down \
+ the entire length next to impossible even with a cooperative unit, let alone the passive suction that threatens to \
+ make anything that gets too close to the bot's beak vanish down the drone's stretchy hose throat. \
+ SWOOPIE XLs are equipped with powerful CHURNO-VAC digestive chambers that are able to effectively melt down most \
+ anything that gets claimed by their vac-beaks, indescriminately melting anything that happens to end up in that chamber, \
+ it would be a terrible idea to allow yourself get swooped by one of these drones, unless you want to add to their biofuel reserves."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/mob/living/simple_mob/vore/aggressive/corrupthound/swoopie
+ name = "SWOOPIE XL"
+ desc = "A large birdlike robot with thick assets, plump belly, and a long elastic vacuum hose of a neck. Somehow still a cleanbot, even if just for its duties."
+ description_info = "Use DISARM intent to access the integrated Vac-Pack settings.
Use GRAB intent while targeting the head damage zone to grab the SWOOPIE XL's neck and use it as a vaccum."
+ catalogue_data = list(/datum/category_item/catalogue/technology/drone/corrupt_hound/swoopie)
+ icon_state = "swoopie"
+ icon_living = "swoopie"
+ icon_dead = "swoopie_dead"
+ icon_rest = "swoopie_rest"
+ icon = 'icons/mob/vore64x64.dmi'
+ vis_height = 64
+ has_eye_glow = TRUE
+ custom_eye_color = "#00CC00"
+ mount_offset_y = 30
+ vore_capacity_ex = list("stomach" = 1, "neck1" = 1, "neck2" = 1, "neck3" = 1, "neck4" = 1)
+ vore_fullness_ex = list("stomach" = 0, "neck1" = 0, "neck2" = 0, "neck3" = 0, "neck4" = 0)
+ vore_icon_bellies = list("stomach", "neck1", "neck2", "neck3", "neck4")
+ vore_icons = 0
+ vore_pounce_chance = 100
+ vore_pounce_maxhealth = 200
+ has_hands = TRUE
+ adminbus_trash = TRUE //You know what, sure whatever. It's not like anyone's gonna be taking this bird on unga trips to be their gamer backpack, which kinda was the main reason for the trash eater restrictions in the first place anyway.
+ faction = "neutral"
+ say_list_type = /datum/say_list/swoopie
+ ai_holder_type = /datum/ai_holder/simple_mob/retaliate/swoopie
+ mob_bump_flag = 0
+ player_msg = "You are a SWOOPIE XL cleaning bot! Use DISARM intent on yourself to change your integrated Vac-Pack settings, or GRAB intent to swoop stuff up! Turning off the Vac-Pack will make your grab clicks function as normal grab intent clicks."
+
+ var/static/list/crew_creatures = list( /mob/living/simple_mob/protean_blob,
+ /mob/living/simple_mob/slime/promethean)
+ var/static/list/pest_creatures = list( /mob/living/simple_mob/animal/passive/mouse,
+ /mob/living/simple_mob/animal/passive/lizard,
+ /mob/living/simple_mob/animal/passive/cockroach)
+ var/obj/item/vac_attachment/swoopie/Vac
+
+/mob/living/simple_mob/vore/aggressive/corrupthound/swoopie/Initialize(mapload)
+ . = ..()
+ if(!voremob_loaded)
+ voremob_loaded = TRUE
+ init_vore()
+ Vac = new /obj/item/vac_attachment/swoopie(src)
+ if(istype(Vac))
+ Vac.output_dest = vore_selected
+ Vac.vac_power = 3
+ Vac.vac_owner = src
+
+/mob/living/simple_mob/vore/aggressive/corrupthound/swoopie/IIsAlly(mob/living/L)
+ . = ..()
+ if(L?.type in pest_creatures) // If they're a pest, swoop no matter what!
+ return FALSE
+ if(!.) // Outside the faction and not in friends, are they crew
+ return L?.type in crew_creatures
+
+/mob/living/simple_mob/vore/aggressive/corrupthound/swoopie/attack_target(atom/A)
+ if(!has_AI())
+ return ..()
+ if(istype(A, /mob/living)) //Swoopie gonn swoop
+ var/mob/living/M = A //typecast
+ if(!M.devourable || !M.can_be_drop_prey)
+ return ..()
+ Vac.afterattack(M, src, 1)
+ return
+ if(istype(A, /obj/item))
+ Vac.afterattack(A, src, 1)
+ return
+ . = ..() //if not vaccable, just do what it normally does
+
+/mob/living/simple_mob/vore/aggressive/corrupthound/swoopie/load_default_bellies()
+ add_verb(src,/mob/living/proc/restrict_trasheater)
+ var/obj/belly/B = new /obj/belly(src)
+ B.affects_vore_sprites = TRUE
+ B.belly_sprite_to_affect = "stomach"
+ B.name = "Churno-Vac"
+ B.desc = "With an abrupt loud WHUMP after a very sucky trip through the hungry bot's vacuum tube, you finally spill out into its waste container, where everything the bot slurps off the floors ends up for swift processing among the caustic sludge, efficiently melting everything down into a thin slurry to fuel its form. More loose dirt and debris occasionally raining in from above as the bot carries on with its duties to keep the station nice and clean."
+ B.digest_messages_prey = list("Under the heat and internal pressure of the greedy machine's gutworks, you can feel the tides of the hot caustic sludge claiming the last bits of space around your body, a few more squeezes of the synthetic muscles squelching and glurking as your body finally loses its form, completely blending down and merging into the tingly sludge to fuel the mean machine.")
+ B.digest_mode = DM_DIGEST
+ B.item_digest_mode = IM_DIGEST
+ B.recycling = TRUE
+ B.mode_flags = DM_FLAG_THICKBELLY //Hard to be heard from inside the swoop!
+ B.digest_burn = 3
+ B.fancy_vore = 1
+ B.vore_sound = "Stomach Move"
+ B.belly_fullscreen = "VBO_trash"
+ B.belly_fullscreen_color = "#555B34"
+ B.sound_volume = 25
+ B.count_items_for_sprite = TRUE
+
+ B = new /obj/belly/longneck(src)
+ B.affects_vore_sprites = FALSE
+ B.name = "Vac-Beak"
+ B.desc = "SNAP! You have been sucked up into the big synthbird's beak, the powerful vacuum within the bird roaring somewhere beyond the abyssal deep gullet hungrily gaping before you, eagerly sucking you deeper inside towards a long bulgy ride down the bird's vacuum hose of a neck!"
+ B.entrance_logs = TRUE //Exept for the maw. I think that's reasonable. -Reo
+ B.autotransferlocation = "vacuum hose"
+ B.autotransfer_max_amount = 0
+ B.autotransferwait = 60
+ B.belly_fullscreen_color2 = "#1C1C1C"
+ B.belly_fullscreen_color3 = "#292929"
+ B.belly_fullscreen_color4 = "#CCFFFF"
+ B.belly_fullscreen = "VBO_maw8" //Swoopies have beaks!!
+
+ vore_selected = B
+
+ B = new /obj/belly/longneck(src)
+ B.affects_vore_sprites = TRUE
+ B.belly_sprite_to_affect = "neck1"
+ B.name = "vacuum hose"
+ B.autotransferlocation = "vacuum hose 2"
+ B.fancy_vore = 1
+ B.vore_sound = "Stomach Move"
+ B.sound_volume = 100
+
+ B = new /obj/belly/longneck(src)
+ B.affects_vore_sprites = TRUE
+ B.belly_sprite_to_affect = "neck2"
+ B.name = "vacuum hose 2"
+ B.autotransferlocation = "vacuum hose 3"
+ B.desc = "It feels very tight in here..."
+ B.fancy_vore = 1
+ B.vore_sound = "Stomach Move"
+ B.sound_volume = 80
+
+ B = new /obj/belly/longneck(src)
+ B.affects_vore_sprites = TRUE
+ B.belly_sprite_to_affect = "neck3"
+ B.name = "vacuum hose 3"
+ B.autotransferlocation = "vacuum hose 4"
+ B.desc = "Looks like it's gonna be all downhill from here..."
+ B.fancy_vore = 1
+ B.vore_sound = "Stomach Move"
+ B.sound_volume = 40
+
+ B = new /obj/belly/longneck(src)
+ B.affects_vore_sprites = TRUE
+ B.belly_sprite_to_affect = "neck4"
+ B.name = "vacuum hose 4"
+ B.autotransferlocation = "Churno-Vac"
+ B.desc = "Thank you for your biofuel contribution~"
+ B.fancy_vore = 1
+ B.vore_sound = "Stomach Move"
+ B.sound_volume = 20
+
+/obj/belly/longneck
+ affects_vore_sprites = TRUE
+ belly_sprite_to_affect = "neck1"
+ name = "vacuum hose"
+ desc = "With a mighty WHUMP, the suction of the big bird's ravenous vacuum system has sucked you up out of the embrace of its voracious main beak and into a tight bulge squeezing along the long ribbed rubbery tube leading towards the roaring doom of the synthetic bird's efficient waste disposal system."
+ digest_mode = DM_HOLD
+ item_digest_mode = IM_HOLD
+ contaminates = FALSE //Stuff doesnt get messy in the throat, the bird's gut is the messy place!
+ entrance_logs = FALSE //QOL to stop spam when stuff is getting gulped down~
+ autotransfer_enabled = TRUE
+ autotransferchance = 100
+ autotransferwait = 60
+ autotransferlocation = "Churno-Vac"
+ vore_verb = "suck"
+ belly_fullscreen_color = "#4d4d4d"
+ belly_fullscreen = "a_tumby"
+ human_prey_swallow_time = 1
+ nonhuman_prey_swallow_time = 1
+ autotransfer_max_amount = 2
+ count_items_for_sprite = TRUE
+ item_multiplier = 10
+ health_impacts_size = FALSE
+ //speedy_mob_processing = TRUE
+ mode_flags = DM_FLAG_TURBOMODE
+
+ size_factor_for_sprite = 5
+
+/mob/living/simple_mob/vore/aggressive/corrupthound/swoopie/Life()
+ . =..()
+ var/turf/T = get_turf(src)
+ if(istype(Vac))
+ if(Vac.loc != src)
+ var/turf/VT = get_turf(Vac)
+ if(!T.Adjacent(VT) || isturf(Vac.loc))
+ if(isliving(Vac.loc))
+ var/mob/living/L = Vac.loc
+ L.remove_from_mob(Vac, src)
+ else
+ Vac.forceMove(src)
+ if(!Vac.output_dest)
+ if(isbelly(vore_selected))
+ Vac.output_dest = vore_selected
+ if(!istype(T) || !istype(Vac) || !has_AI() || Vac.loc != src || stat)
+ return
+ if(istype(T, /turf/simulated))
+ var/turf/simulated/S = T
+ if(S.dirt > 50)
+ Vac.afterattack(S, src, 1)
+ return
+ for(var/obj/O in T)
+ if(is_type_in_list(O, GLOB.edible_trash) && !O.anchored)
+ Vac.afterattack(T, src, 1)
+ return
+ for(var/mob/living/L in T)
+ if(!L.anchored && L.devourable && !L == src && !L.buckled && L.can_be_drop_prey)
+ Vac.afterattack(L, src, 1)
+ return
+
+/datum/say_list/swoopie
+ speak = list("Scanning for debris...", "Scanning for dirt...", "Scanning for pests...", "Squawk!")
+ emote_hear = list("squawks!", "whirrs idly.", "revs up its vacuum.")
+ emote_see = list("twitches.", "sways.", "stretches its neck.", "stomps idly.")
+ say_maybe_target = list("Pest detected?")
+ say_got_target = list("PEST DETECTED!")
+
+/mob/living/simple_mob/vore/aggressive/corrupthound/swoopie/ClickOn(var/atom/A, var/params)
+ var/list/modifiers = params2list(params)
+ if(modifiers["shift"] || modifiers["ctrl"] || modifiers["middle"] || modifiers["alt"])
+ return ..()
+ if(stat) //Cant suck if we're not able to...
+ return ..()
+ if(istype(A, /obj/item/storage)) //Dont put the nossle in bags
+ return ..()
+ if(istype(Vac) && A.Adjacent(src))
+ face_atom(A)
+ if(src.a_intent == I_DISARM && A == src) //Only if on disarm intent.
+ Vac.attack_self(src)
+ return
+ if(src.a_intent == I_GRAB && Vac.vac_power != 0) //Only on grab intent. if someone needs to use grab intent they can just turn off the vac
+ if(istype(A, /obj/machinery/disposal)) //You used that bin when the bird was right there? How inconsiderate!
+ var/obj/machinery/disposal/D
+ if(D.flushing)
+ to_chat(src, "\The [D] has already began flushing, you're too late to grab whatever was inside!")
+ return
+ var/foundstuff = 0 //Check if we actually found anything in the bin...
+ for(var/atom/movable/AM in D)
+ if(istype(AM, /mob/living))
+ var/mob/living/M = AM
+ if(!M.devourable || !M.can_be_drop_prey)
+ to_chat(M, span_warning("[src] plunges their head into \the [D], while you narrowly avoid being sucked up!"))
+ continue
+ to_chat(M, span_warning("[src] plunges their head into \the [D], sucking up everything inside- Including you!"))
+ foundstuff = 1
+ AM.forceMove(src)
+ if(foundstuff)
+ src.visible_message(span_warning("[src] plunges their head into \the [D], greedily sucking up everything inside!"))
+ else //Oh, Nothing was inside...
+ to_chat(src, span_infoplain("You poke your head into \the [D], but there doesnt seem to be anything of interest..."))
+ return
+ var/resolved = Vac.resolve_attackby(A, src, click_parameters = params)
+ if(!resolved && A && Vac)
+ Vac.afterattack(A, src, 1, params)
+ return
+ . = ..()
+
+/mob/living/simple_mob/vore/aggressive/corrupthound/swoopie/attack_hand(mob/living/L)
+ if(stat) //Make sure we're alive
+ return ..()
+ if(L.a_intent == I_DISARM && Vac)
+ Vac.attack_self(L)
+ return
+ if(L.a_intent == I_GRAB && Vac && Vac.loc == src)
+ if(L.zone_sel.selecting == BP_HEAD)
+ if(L.put_in_active_hand(Vac))
+ L.visible_message(span_warning("[L] grabs [src] by the neck, brandishing the thing like a regular vacuum cleaner!"))
+ L.start_pulling(src)
+ return
+ . = ..()
+
+/mob/living/simple_mob/vore/aggressive/corrupthound/swoopie/verb/borrow_vac()
+ set name = "Borrow Vac-Pack"
+ set desc = "Allows adjacent user to borrow Swoopie's Vac-Pack"
+ set category = "Object"
+ set src in oview(1)
+ if(istype(Vac))
+ if(usr != src)
+ usr.put_in_active_hand(Vac)
+ else
+ var/mob/living/L = tgui_input_list(usr, "Borrow Vac-Pack for", "Swoopie", mobs_in_view(1, usr))
+ if(!L || L == usr)
+ return
+ L.put_in_active_hand(Vac)
+
+/mob/living/simple_mob/vore/aggressive/corrupthound/swoopie/verb/change_settings()
+ set name = "Change Settings"
+ set desc = "Change the swoopie's settings"
+ set category = "IC"
+ set src in oview(1)
+ if(!has_AI() || !IIsAlly(usr))
+ to_chat(usr, span_danger(""))
+ if(!ai_holder == /datum/ai_holder/simple_mob/retaliate/swoopie || !ai_holder)
+ to_chat(usr, span_warning("This [src] doesnt seem to have changable settings!"))
+ return
+ var/datum/ai_holder/simple_mob/retaliate/swoopie/ai = ai_holder
+ var/list/swooping_options = list(
+ "Swoop Pests",
+ "Swoop Trash",
+ )
+
+ var/setting_selection = tgui_input_list(usr, "Toggle Swoopie Swooping Options", "Swoopie Options", swooping_options)
+
+ switch(setting_selection)
+ if("Swoop Pests")
+ ai.swoop_pests = !ai.swoop_pests // invert the option
+ to_chat(usr, "You press a button on \the [src], [ai.swoop_pests ? "" : "de"]activating it's pest seeking routines!")
+ if("Swoop Trash")
+ ai.swoop_trash = !ai.swoop_trash // invert the option
+ to_chat(usr, "you press a button on \the [src], [ai.swoop_trash ? "" : "de"]activating it's pest seeking routines!")
+
+
+/mob/living/simple_mob/vore/aggressive/corrupthound/swoopie/Login()
+ . = ..()
+ verbs -= /mob/living/simple_mob/vore/aggressive/corrupthound/swoopie/verb/change_settings //Controlled swoopies dont need their settings changed externally
+
+//Special Swoopie vaccum so it can be handled better than a vareditted vacpack.
+/obj/item/vac_attachment/swoopie
+ name = "Swoopie Vac-Beak"
+ desc = "Useful for slurping mess off the floors. Even dirt and pests depending on settings. This vaccum seems to be permanantly attached to the swoopie's rumbling rubber trashbag."
+ icon = 'icons/mob/vacpack_swoop.dmi'
+ item_state = null
+
+/obj/item/vac_attachment/swoopie/dropped(mob/user) //This should fix it sitting on the ground until the next life() tick
+ . = ..()
+ if(!vac_owner)
+ return
+ forceMove(vac_owner)
+
+//Custom Swoopie AI to make it swoop up trash when asked to
+/datum/ai_holder/simple_mob/retaliate/swoopie //TODO: make a general item-seeking AI type and use it for other stuff (Teppi seeking food automatically?)
+ hostile = TRUE // Hostile, but it wont actually attack stuff unless it's allowed to. Maybe also in retaliation.
+ var/swoop_pests = FALSE // Do we go after living pests?
+ var/swoop_trash = FALSE // Do we go after trash and junk?
+ var/original_power = 0 // What the swoopie's last vaccum strength was before we went to go vaccum stuff up actively.
+ cooperative = FALSE // Swoop works independantly
+ mauling = TRUE // Swoop doesnt care how hurt you are. If it's trying to attack you, it's just trying to eat you
+ handle_corpse = TRUE // See above.
+
+/datum/ai_holder/simple_mob/retaliate/swoopie/list_targets() //Kinda stolen from nurse spiders. Mostly stolen.
+ . = ..()
+
+ var/static/alternative_targets = typecacheof(list(/obj/item/trash))
+
+ for(var/obj/O as anything in typecache_filter_list(range(vision_range, holder), alternative_targets))
+ if(can_see(holder, O, vision_range) && !O.anchored)
+ . += O
+
+// Select an obj if no mobs are around.
+/datum/ai_holder/simple_mob/retaliate/swoopie/pick_target(list/targets)
+ var/mobs_only = locate(/mob/living) in targets // If a mob is in the list of targets, then ignore objects.
+ if(mobs_only)
+ for(var/A in targets)
+ if(!isliving(A))
+ targets -= A
+
+ return ..(targets)
+
+/datum/ai_holder/simple_mob/retaliate/swoopie/find_target(var/list/possible_targets, var/has_targets_list = FALSE)
+ ai_log("find_target() : Entered.", AI_LOG_TRACE)
+ if(!hostile) // So retaliating mobs only attack the thing that hit it.
+ return null
+ . = list()
+ if(!has_targets_list)
+ possible_targets = list_targets()
+ for(var/possible_target in possible_targets)
+ if(can_attack(possible_target)) // Can we attack it?
+ if(isliving(possible_target) && !swoop_pests) // Are we allowed to attack living things?
+ continue
+ if(!isliving(possible_target) && !swoop_trash) // Otherwise, are we allowed to swoop trash?
+ continue
+ . += possible_target
+
+ var/new_target = pick_target(.)
+ give_target(new_target)
+ return new_target
+
+/datum/ai_holder/simple_mob/retaliate/swoopie/give_target(new_target, urgent = FALSE)
+ . = ..()
+ if(istype(holder, /mob/living/simple_mob/vore/aggressive/corrupthound/swoopie))
+ var/mob/living/simple_mob/vore/aggressive/corrupthound/swoopie/bird = holder //Typecast
+ original_power = bird.Vac.vac_power
+ bird.Vac.vac_power = 7
+
+/datum/ai_holder/simple_mob/retaliate/swoopie/remove_target()
+ . = ..()
+ if(istype(holder, /mob/living/simple_mob/vore/aggressive/corrupthound/swoopie))
+ var/mob/living/simple_mob/vore/aggressive/corrupthound/swoopie/bird = holder //Typecast
+ bird.Vac.vac_power = original_power
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/vore_hostile.dm b/code/modules/mob/living/simple_mob/subtypes/vore/vore_hostile.dm
index 16198770eb..091e59cad8 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/vore_hostile.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/vore_hostile.dm
@@ -76,7 +76,6 @@
B.name = "interior"
B.desc = "It's hot and overwhelmingly tight! The interior of the pale creature groans with the effort of squeezing you. Everything is hot and churning and eager to grind and smother you in thick fluids. The weight of the creature's body pressing in at you makes it hard to move at all, while you are squeezed to the very core of the creature! There seems almost not to even be an organ for this so much as the creature has folded around you, trying to incorporate your matter into its body with vigor!"
B.mode_flags = DM_FLAG_THICKBELLY | DM_FLAG_NUMBING
- B.belly_fullscreen = "yet_another_tumby"
B.digest_brute = 3
B.digest_burn = 2
B.digestchance = 0
@@ -194,7 +193,6 @@
B.name = "stomach"
B.desc = "The flesh of the tall creature's stomach folds over you in doughy waves, squeezing you into the tightest shape it can manage with idle flexes churning down on you. Your limbs often find themselves lost between folds and tugged this way or that, held in a skin tight press that is not painful, but is hard to pull away from. You can see a strange, glittering pink and purple light glimmering through the flesh of the monster all around you, like your very own sea of stars. The walls rush in to fill all the space, squeezing you from head to toe no matter how you might wiggle, the weight of the semi-transparent interior flesh keeping you neatly secured deep inside while wringing the fight out of you."
B.mode_flags = DM_FLAG_THICKBELLY | DM_FLAG_NUMBING
- B.belly_fullscreen = "yet_another_tumby"
B.digest_brute = 2
B.digest_burn = 2
B.digestchance = 0
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/weretiger.dm b/code/modules/mob/living/simple_mob/subtypes/vore/weretiger.dm
index db76f04435..e67cb25378 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/weretiger.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/weretiger.dm
@@ -31,6 +31,7 @@
has_hands = 1
+ can_be_drop_prey = FALSE
allow_mind_transfer = TRUE
// Nomnomn
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/wolf.dm b/code/modules/mob/living/simple_mob/subtypes/vore/wolf.dm
index 8542544090..6d4982a8e9 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/wolf.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/wolf.dm
@@ -117,6 +117,7 @@
riding_datum = new /datum/riding/simple_mob(src)
add_verb(src, /mob/living/simple_mob/proc/animal_mount)
add_verb(src, /mob/living/proc/toggle_rider_reins)
+ add_verb(src,/mob/living/simple_mob/proc/pick_color)
movement_cooldown = -1
/mob/living/simple_mob/vore/wolf/direwolf/MouseDrop_T(mob/living/M, mob/living/user)
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/wolftaur.dm b/code/modules/mob/living/simple_mob/subtypes/vore/wolftaur.dm
index de9bfdf6dc..6bac3df0cd 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/wolftaur.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/wolftaur.dm
@@ -74,7 +74,6 @@
B.name = "stomach"
B.desc = "After a gruelling compressive traversal down through the taur's gullet, you briefly get deposited in an oppressively tight stomach at it's humanoid waist. However, the wolf has little interest in keeping you here, instead treating you as a mere snack, an orifice opens beneath you and you're soon dragged deeper into her depths. Soon you're splashing into an active, waiting caustic slurry, and the world around you drops as though you're trapped in a hammock. The taur's underbelly sags with your weight, and you feel a heavy pat from the woman outside settling in to make the most of her meal."
B.mode_flags = DM_FLAG_THICKBELLY
- B.belly_fullscreen = "yet_another_tumby"
B.digest_brute = 2
B.digest_burn = 2
B.digest_oxy = 1
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/zz_vore_overrides.dm b/code/modules/mob/living/simple_mob/subtypes/vore/zz_vore_overrides.dm
index f53b45d48c..869b9953bf 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/zz_vore_overrides.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/zz_vore_overrides.dm
@@ -215,6 +215,10 @@
response_disarm = "gently pushes aside"
response_harm = "hits"
+/mob/living/simple_mob/hostile/carp/pike
+ vore_active = 1
+ // NO VORE SPRITES
+
/mob/living/simple_mob/animal/space/carp/holographic
vore_icons = 0 // NO VORE SPRITES
vore_digest_chance = 0
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 4971c2e8c5..baafc9a5c8 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -46,7 +46,7 @@
. += "Time To Start: Server Initializing"
else if(SSticker.current_state == GAME_STATE_PREGAME)
- . += "Time To Start: [round(SSticker.timeLeft, 1)][GLOB.round_progressing ? "" : " (DELAYED)"]"
+ . += "Time To Start: [round(SSticker.timeLeft / 10, 1)][GLOB.round_progressing ? "" : " (DELAYED)"]"
. += "Players: [totalPlayers]"
. += "Players Ready: [totalPlayersReady]"
totalPlayers = 0
diff --git a/code/modules/organs/internal/_organ_internal.dm b/code/modules/organs/internal/_organ_internal.dm
index 38a5d4009b..6c66547054 100644
--- a/code/modules/organs/internal/_organ_internal.dm
+++ b/code/modules/organs/internal/_organ_internal.dm
@@ -4,6 +4,13 @@
/obj/item/organ/internal
var/dead_icon // Icon to use when the organ has died.
+ var/supply_conversion_value = 0
+
+/obj/item/organ/internal/Initialize(mapload, internal)
+ . = ..()
+ if(supply_conversion_value)
+ AddElement(/datum/element/sellable/organ)
+
/obj/item/organ/internal/die()
..()
if((status & ORGAN_DEAD) && dead_icon)
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index d23189cc84..f584d5ee56 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -455,3 +455,18 @@
force = 12
accuracy = 0
scoped_accuracy = 20
+
+/obj/item/gun/energy/zip
+ name = "Zip-Las"
+ desc = "A homemade (and somehow safe) laser gun designed around shooting single powerful laser beam draining the cell entirely. Better not miss and better have spare cells."
+ icon = 'icons/obj/gun.dmi'
+ icon_state = "ziplas"
+ item_state = "ziplas"
+ w_class = ITEMSIZE_SMALL
+ slot_flags = SLOT_BELT|SLOT_BACK
+ charge_cost = 1500 //You got 1 shot...
+ projectile_type = /obj/item/projectile/beam/heavylaser //But it hurts a lot
+ cell_type = /obj/item/cell/device/weapon
+
+/obj/item/gun/energy/zip/craftable
+ battery_lock = 1 //makeshift gun has flaws
diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm
index 9870806e2d..72963e320f 100644
--- a/code/modules/projectiles/projectile/bullets.dm
+++ b/code/modules/projectiles/projectile/bullets.dm
@@ -95,6 +95,21 @@
armor_penetration = 15
hud_state = "pistol_light_ap"
+/obj/item/projectile/bullet/pistol/medium/ap/suppressor // adminspawn only
+ name = "suppressor bullet" // this guy is Important and also Hates You
+ fire_sound = 'sound/weapons/doompistol.ogg' // converted from .wavs extracted from doom 2
+ damage = 10 // high rof kinda fucked up lets be real
+ agony = 10 // brute easily heals, agony not so much
+ armor_penetration = 30 // reduces shield blockchance
+ accuracy = -20 // he do miss actually
+ speed = 0.4 // if the pathfinder gets a funny burst rifle, they deserve a rival
+ // that's 2x projectile speed btw
+ hud_state = "monkey"
+
+/obj/item/projectile/bullet/pistol/medium/ap/suppressor/turbo // spicy boys
+ speed = 0.2 // this is 4x projectile speed
+ hud_state = "monkey"
+
/obj/item/projectile/bullet/pistol/medium/hp
damage = 30
armor_penetration = -50
diff --git a/code/modules/reagents/reactions/instant/instant.dm b/code/modules/reagents/reactions/instant/instant.dm
index 37b531f377..1f9361d283 100644
--- a/code/modules/reagents/reactions/instant/instant.dm
+++ b/code/modules/reagents/reactions/instant/instant.dm
@@ -1494,3 +1494,10 @@
/decl/chemical_reaction/instant/potato_juice_metal_paint/send_data()
return "#2e2a21"
+
+/decl/chemical_reaction/instant/aphrodisiac
+ name = REAGENT_APHRODISIAC
+ id = REAGENT_ID_APHRODISIAC
+ result = REAGENT_ID_APHRODISIAC
+ required_reagents = list(REAGENT_ID_CARBON = 2, REAGENT_ID_HYDROGEN = 2, REAGENT_ID_OXYGEN = 2, REAGENT_ID_WATER = 1)
+ result_amount = 6
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 177b33e0e8..18ecd1ccb8 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -274,7 +274,7 @@
var/obj/item/organ/external/affecting = H.get_organ(target_zone)
if (!affecting || affecting.is_stump())
- balloon_alert(user, "they are missing that limb!") // CHOMPEdit - Changed to balloon_alert
+ balloon_alert(user, "they are missing that limb!")
return
var/hit_area = affecting.name
diff --git a/code/modules/reagents/reagents/dispenser.dm b/code/modules/reagents/reagents/dispenser.dm
index c9bc84103f..c2f4470e80 100644
--- a/code/modules/reagents/reagents/dispenser.dm
+++ b/code/modules/reagents/reagents/dispenser.dm
@@ -659,3 +659,13 @@
color = "#efe9ca"
supply_conversion_value = 0.5 SHEET_TO_REAGENT_EQUIVILENT // has sheet value
industrial_use = REFINERYEXPORT_REASON_PRECURSOR
+
+/datum/reagent/miasma
+ name = REAGENT_MIASMA
+ id = REAGENT_ID_MIASMA
+ description = "Not necessarily a gas, miasma refers to biological pollutants found in the atmosphere."
+ reagent_state = GAS
+ taste_description = "indescribable"
+ color = "#808000"
+ supply_conversion_value = REFINERYEXPORT_VALUE_NO
+ industrial_use = REFINERYEXPORT_REASON_BIOHAZARD
diff --git a/code/modules/reagents/reagents/food_drinks.dm b/code/modules/reagents/reagents/food_drinks.dm
index 8f9a6e59d8..d40999ccb4 100644
--- a/code/modules/reagents/reagents/food_drinks.dm
+++ b/code/modules/reagents/reagents/food_drinks.dm
@@ -5091,3 +5091,14 @@
supply_conversion_value = REFINERYEXPORT_VALUE_UNWANTED
industrial_use = REFINERYEXPORT_REASON_FOOD
+
+
+/datum/reagent/drink/teamush
+ name = REAGENT_TEAMUSH
+ id = REAGENT_ID_TEAMUSH
+ description = "Mashed tea leaves, a bit like grass clippings. You can't make proper tea out of this now."
+ taste_description = "overwhelmingly bitter plant"
+ color = "#7db72d"
+
+ glass_name = "blended plant"
+ glass_desc = "Chunky, mashed up plant of some sort. Looks kinda gross."
diff --git a/code/modules/reagents/reagents/other.dm b/code/modules/reagents/reagents/other.dm
index b6f4a29bc2..0eb2763638 100644
--- a/code/modules/reagents/reagents/other.dm
+++ b/code/modules/reagents/reagents/other.dm
@@ -837,3 +837,12 @@
color = "#e8e2b0"
supply_conversion_value = REFINERYEXPORT_VALUE_PROCESSED
industrial_use = REFINERYEXPORT_REASON_PRECURSOR
+
+/datum/reagent/nutriment/pitcher_nectar //Pitcher plant reagent, doubles plant growth speed.
+ name = REAGENT_ID_PITCHERNECTAR
+ id = REAGENT_ID_PITCHERNECTAR
+ description = "An odd, sticky slurry which promotes rapid plant growth."
+ taste_description = "pineapple"
+ reagent_state = LIQUID
+ nutriment_factor = 60
+ color = "#a839a2"
diff --git a/code/modules/reagents/reagents/vore_vr.dm b/code/modules/reagents/reagents/vore_vr.dm
index f3470c6ae1..3cce0e4e69 100644
--- a/code/modules/reagents/reagents/vore_vr.dm
+++ b/code/modules/reagents/reagents/vore_vr.dm
@@ -272,3 +272,21 @@
M.add_chemical_effect(CE_PAINKILLER, -200)
if(prob(0.01)) //1 in 10000 chance per tick. Extremely rare.
to_chat(M,span_warning("Your body feels as though it's on fire!"))
+
+/datum/reagent/aphrodisiac
+ name = REAGENT_APHRODISIAC
+ id = REAGENT_ID_APHRODISIAC
+ description = "You so horny."
+ taste_description = "sweetness"
+ reagent_state = LIQUID
+ color = "#FF9999"
+ scannable = 1
+ supply_conversion_value = REFINERYEXPORT_VALUE_RARE
+ industrial_use = REFINERYEXPORT_REASON_DRUG
+
+
+/datum/reagent/aphrodisiac/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
+ if(!M) return
+
+ if(prob(3))
+ M.emote(pick("blush", "moan", "moan", "giggle"))
diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm
index 32d4d86632..69a7821278 100644
--- a/code/modules/recycling/conveyor2.dm
+++ b/code/modules/recycling/conveyor2.dm
@@ -337,7 +337,6 @@
playsound(src, I.usesound, 50, 1)
return
- //Ports making conveyors fast from CHOMPstation
if(I.has_tool_quality(TOOL_WIRECUTTER))
toggle_speed()
to_chat(user, "You adjust the speed of the conveyor switch")
diff --git a/code/modules/salvage/bags.dm b/code/modules/salvage/bags.dm
new file mode 100644
index 0000000000..83736de310
--- /dev/null
+++ b/code/modules/salvage/bags.dm
@@ -0,0 +1,15 @@
+/obj/item/storage/bag/salvage
+ name = "treasure satchel"
+ desc = "A satchel for storing scavenged salvage. There be tresure."
+ icon = 'icons/obj/mining.dmi'
+ slot_flags = SLOT_BELT | SLOT_POCKET
+ w_class = ITEMSIZE_NORMAL
+ storage_slots = 15
+ max_w_class = ITEMSIZE_NORMAL
+ can_hold = list(/obj/item/salvage)
+
+/obj/item/storage/bag/salvage/bluespace
+ name = "bluespace treasure satchel"
+ desc = "A satchel to store even more scavenged salvage! There be lots of treasure."
+ storage_slots = 30
+ icon_state = "satchel_bspace"
diff --git a/code/modules/salvage/salvage.dm b/code/modules/salvage/salvage.dm
new file mode 100644
index 0000000000..88839cc963
--- /dev/null
+++ b/code/modules/salvage/salvage.dm
@@ -0,0 +1,89 @@
+/obj/item/salvage
+ name = "salvage"
+ desc = "A tonne of salvage from bad mapping practices. Who spawned the base type? Report this on GitHub"
+ icon = 'icons/obj/salvage/sellable.dmi'
+ force = 5
+ throwforce = 5
+ throw_speed = 1
+ throw_speed = 4
+ hitsound = 'sound/items/salvage/salvagepickup.ogg'
+ drop_sound = 'sound/items/salvage/salvagedrop.ogg'
+ w_class = ITEMSIZE_NORMAL
+ var/worth = 100
+
+/obj/item/salvage/Initialize(mapload)
+ . = ..()
+ if(worth)
+ AddElement(/datum/element/sellable/salvage)
+
+/obj/item/salvage/examine(mob/user)
+ . = ..()
+ . += span_notice("This could fetch a good price...")
+
+/obj/item/salvage/ruin
+ desc = "A tonne of salvage recovered from an abandoned ruin. Who spawned the base type? Report this on GitHub"
+
+/obj/item/salvage/ruin/pirate
+ name = "rum keg"
+ desc = "A highly valued keg of aged space rum. Limited edition and sure to be a collector's item."
+ icon_state = "barrel"
+ color = "#7e5c00"
+
+/obj/item/salvage/ruin/russian
+ name = "armaments cache"
+ desc = "A crate of old disused Belastrav ballistic firearms clearly long past their usability. This crate would make good scrap metal for shuttle construction."
+ icon_state = "weapon_crate"
+
+/obj/item/salvage/ruin/brick
+ name = "mysterious brick"
+ desc = "A peculier brick formed out of what appears to be plastic. This would make a fantastic collector's item."
+ icon_state = "lego_brick"
+ hitsound = 'sound/items/smolesmallbuild.ogg'
+ drop_sound = 'sound/items/drop/smolematerial.ogg'
+
+/obj/item/salvage/ruin/nanotrasen
+ name = "lost research notes"
+ desc = "A collection of research notes penned by old Nanotrasen scientists from decades past, technology lost in time- until you found them. It is a mystery what technology Central Command will push if they could just get their hands on these notes."
+ icon_state = "research_doc"
+ hitsound = 'sound/items/pickup/paper.ogg'
+ pickup_sound = 'sound/items/pickup/paper.ogg'
+ drop_sound = 'sound/items/drop/paper.ogg'
+
+/obj/item/salvage/ruin/nanotrasen/Initialize(mapload)
+ . = ..()
+ become_anomalous()
+
+/obj/item/salvage/ruin/carp
+ name = "carp scales"
+ desc = "A collection of scales shed from a corrupted space carp. Their culinary potential could mean untold riches for Nanotrasen."
+ icon_state = "dragon_scales"
+ hitsound = 'sound/effects/glass_step.ogg'
+ pickup_sound = 'sound/effects/glass_step.ogg'
+ drop_sound = 'sound/effects/glass_step.ogg'
+
+/obj/item/salvage/loot
+ desc = "A tonne of salvage looted from a fallen foe. Who spawned the base type? Report this on the github."
+
+/obj/item/salvage/loot/pirate
+ name = "stolen jewellery"
+ desc = "A collection of stolen jewellery, fashioned from pilfered bluespace crystals and gems. Rumour has it, local pirates have been known to use these accessories to avoid capture."
+ icon_state = "pirate_treasure"
+ hitsound = 'sound/items/taperecorder_drop.ogg'
+ pickup_sound = 'sound/items/taperecorder_pickup.ogg'
+ drop_sound = 'sound/items/taperecorder_drop.ogg'
+
+/obj/item/salvage/loot/russian
+ name = "siosp manual"
+ desc = "A small manual, written in Neo-Russkyia, detailing the manifesto of Malfoy Ames, father of The Cygni Rebellion. Central Command may wish to share this with their allies in the Trans-Solar Federation."
+ icon_state = "ussp_manual"
+ hitsound = 'sound/items/pickup/paper.ogg'
+ pickup_sound = 'sound/items/pickup/paper.ogg'
+ drop_sound = 'sound/items/drop/paper.ogg'
+
+/obj/item/salvage/loot/syndicate
+ name = "syndicate intel"
+ desc = "A folder detailing Syndicate plans to infiltrate and sabotage operations in the Vir system. Central Command may find use of this to aid them in counter-intelligence."
+ icon_state = "syndie_doc"
+ hitsound = 'sound/items/pickup/paper.ogg'
+ pickup_sound = 'sound/items/pickup/paper.ogg'
+ drop_sound = 'sound/items/drop/paper.ogg'
diff --git a/code/modules/vore/eating/belly_import.dm b/code/modules/vore/eating/belly_import.dm
index 500a38b441..7303f5945f 100644
--- a/code/modules/vore/eating/belly_import.dm
+++ b/code/modules/vore/eating/belly_import.dm
@@ -495,7 +495,7 @@
var/new_emote_time = belly_data["emote_time"]
new_belly.emote_time = CLAMP(new_emote_time, 60, 600)
- new_belly.set_zero_digestion_damage() // Not implemented on virgo; CHOMPEnale needed for importing a belly to overwrite an existing belly; otherwise pre-existing values throw off the unused digestion damage.
+ new_belly.set_zero_digestion_damage() // Needed for importing a belly to overwrite an existing belly; otherwise pre-existing values throw off the unused digestion damage.
if(isnum(belly_data["digest_brute"]))
var/new_digest_brute = belly_data["digest_brute"]
@@ -1192,7 +1192,7 @@
// After import updates
new_belly.items_preserved.Cut()
- new_belly.update_internal_overlay() // Signal not implemented! CHOMPEnable
+ new_belly.update_internal_overlay()
host.handle_belly_update()
host.updateVRPanel()
diff --git a/code/modules/vore/eating/belly_obj_vr.dm b/code/modules/vore/eating/belly_obj_vr.dm
index 1d2f24a8a4..7d34df65f2 100644
--- a/code/modules/vore/eating/belly_obj_vr.dm
+++ b/code/modules/vore/eating/belly_obj_vr.dm
@@ -1090,6 +1090,9 @@
//Incase they have the loop going, let's double check to stop it.
M.stop_sound_channel(CHANNEL_PREYLOOP)
+ //Don't let glows stick
+ M.glow_toggle = FALSE
+ M.set_light(0)
// Delete the digested mob
// Changed qdel to a forceMove to allow reforming, and... handled robots special.
if(isrobot(M))
diff --git a/code/modules/vore/eating/simple_animal_vr.dm b/code/modules/vore/eating/simple_animal_vr.dm
index 8f37288e05..f6356c92b3 100644
--- a/code/modules/vore/eating/simple_animal_vr.dm
+++ b/code/modules/vore/eating/simple_animal_vr.dm
@@ -58,12 +58,7 @@
if(!vore_selected)
to_chat(user, span_warning("[src] isn't planning on eating anything much less digesting it."))
return
-/*ChompStation edit: This prevented some flexibility with mob vore and the returned message was highly unprofessional.
- if(ai_holder.retaliate || (ai_holder.hostile && faction != user.faction))
- to_chat(user, span_warning("This predator isn't friendly, and doesn't give a shit about your opinions of it digesting you."))
- return
-*/
if(vore_selected.digest_mode == DM_HOLD)
var/confirm = tgui_alert(user, "Enabling digestion on [name] will cause it to digest all stomach contents. Using this to break OOC prefs is against the rules. Digestion will reset after 20 minutes.", "Enabling [name]'s Digestion", list("Enable", "Cancel"))
if(confirm == "Enable")
diff --git a/icons/effects/goia_labels.dmi b/icons/effects/goia_labels.dmi
new file mode 100644
index 0000000000..eb8905f713
Binary files /dev/null and b/icons/effects/goia_labels.dmi differ
diff --git a/icons/effects/synx_labels.dmi b/icons/effects/synx_labels.dmi
new file mode 100644
index 0000000000..acc3f8bf19
Binary files /dev/null and b/icons/effects/synx_labels.dmi differ
diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi
index f1d5143b43..759f4489ce 100644
Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ
diff --git a/icons/mob/clockwork_mobs.dmi b/icons/mob/clockwork_mobs.dmi
new file mode 100644
index 0000000000..5aaba2a450
Binary files /dev/null and b/icons/mob/clockwork_mobs.dmi differ
diff --git a/icons/mob/construct.dmi b/icons/mob/construct.dmi
new file mode 100644
index 0000000000..da978e00b1
Binary files /dev/null and b/icons/mob/construct.dmi differ
diff --git a/icons/mob/cultists.dmi b/icons/mob/cultists.dmi
new file mode 100644
index 0000000000..c205029de7
Binary files /dev/null and b/icons/mob/cultists.dmi differ
diff --git a/icons/mob/cyber_horror.dmi b/icons/mob/cyber_horror.dmi
new file mode 100644
index 0000000000..ade922891a
Binary files /dev/null and b/icons/mob/cyber_horror.dmi differ
diff --git a/icons/mob/demon_alt.dmi b/icons/mob/demon_alt.dmi
new file mode 100644
index 0000000000..89a63c38f3
Binary files /dev/null and b/icons/mob/demon_alt.dmi differ
diff --git a/icons/mob/demon_vr.dmi b/icons/mob/demon_vr.dmi
index 5ad0c6e550..0d7b0c27c4 100644
Binary files a/icons/mob/demon_vr.dmi and b/icons/mob/demon_vr.dmi differ
diff --git a/icons/mob/hyena.dmi b/icons/mob/hyena.dmi
new file mode 100644
index 0000000000..43c9822715
Binary files /dev/null and b/icons/mob/hyena.dmi differ
diff --git a/icons/mob/mercenaries.dmi b/icons/mob/mercenaries.dmi
new file mode 100644
index 0000000000..0464e45e85
Binary files /dev/null and b/icons/mob/mercenaries.dmi differ
diff --git a/icons/mob/mimic.dmi b/icons/mob/mimic.dmi
new file mode 100644
index 0000000000..557a4e2589
Binary files /dev/null and b/icons/mob/mimic.dmi differ
diff --git a/icons/mob/mouse_army.dmi b/icons/mob/mouse_army.dmi
new file mode 100644
index 0000000000..12a3081a37
Binary files /dev/null and b/icons/mob/mouse_army.dmi differ
diff --git a/icons/mob/pirates.dmi b/icons/mob/pirates.dmi
new file mode 100644
index 0000000000..752c7358d4
Binary files /dev/null and b/icons/mob/pirates.dmi differ
diff --git a/icons/mob/possessed.dmi b/icons/mob/possessed.dmi
new file mode 100644
index 0000000000..6a4132e3ed
Binary files /dev/null and b/icons/mob/possessed.dmi differ
diff --git a/icons/mob/screen1_purity.dmi b/icons/mob/screen1_purity.dmi
new file mode 100644
index 0000000000..ad52b0ca9c
Binary files /dev/null and b/icons/mob/screen1_purity.dmi differ
diff --git a/icons/mob/screen1_robot_vr.dmi b/icons/mob/screen1_robot_vr.dmi
index a2cdb93d8e..a93c549a1d 100644
Binary files a/icons/mob/screen1_robot_vr.dmi and b/icons/mob/screen1_robot_vr.dmi differ
diff --git a/icons/mob/snake_vr.dmi b/icons/mob/snake_vr.dmi
index 6802aecc47..14e3c055fc 100644
Binary files a/icons/mob/snake_vr.dmi and b/icons/mob/snake_vr.dmi differ
diff --git a/icons/mob/solarmoth.dmi b/icons/mob/solarmoth.dmi
new file mode 100644
index 0000000000..e29c190397
Binary files /dev/null and b/icons/mob/solarmoth.dmi differ
diff --git a/icons/mob/synx_modular.dmi b/icons/mob/synx_modular.dmi
new file mode 100644
index 0000000000..8d7ea98108
Binary files /dev/null and b/icons/mob/synx_modular.dmi differ
diff --git a/icons/mob/synxmanyvoices.dmi b/icons/mob/synxmanyvoices.dmi
new file mode 100644
index 0000000000..8c55fec429
Binary files /dev/null and b/icons/mob/synxmanyvoices.dmi differ
diff --git a/icons/mob/vacpack.dmi b/icons/mob/vacpack.dmi
new file mode 100644
index 0000000000..c58865cf8d
Binary files /dev/null and b/icons/mob/vacpack.dmi differ
diff --git a/icons/mob/vacpack_swoop.dmi b/icons/mob/vacpack_swoop.dmi
new file mode 100644
index 0000000000..b5c5979cee
Binary files /dev/null and b/icons/mob/vacpack_swoop.dmi differ
diff --git a/icons/mob/vore.dmi b/icons/mob/vore.dmi
index 3ada420655..5cc4ac91c2 100644
Binary files a/icons/mob/vore.dmi and b/icons/mob/vore.dmi differ
diff --git a/icons/mob/vore32x64.dmi b/icons/mob/vore32x64.dmi
index 66464ac3c8..5ec6903f27 100644
Binary files a/icons/mob/vore32x64.dmi and b/icons/mob/vore32x64.dmi differ
diff --git a/icons/mob/vore64x32.dmi b/icons/mob/vore64x32.dmi
index caf7169835..78321eee1f 100644
Binary files a/icons/mob/vore64x32.dmi and b/icons/mob/vore64x32.dmi differ
diff --git a/icons/mob/vore64x64.dmi b/icons/mob/vore64x64.dmi
index 151210857c..a2e3c264b8 100644
Binary files a/icons/mob/vore64x64.dmi and b/icons/mob/vore64x64.dmi differ
diff --git a/icons/mob/vore_shadekin.dmi b/icons/mob/vore_shadekin.dmi
index 0e1fcc96d9..7cacb68910 100644
Binary files a/icons/mob/vore_shadekin.dmi and b/icons/mob/vore_shadekin.dmi differ
diff --git a/icons/mob/vox.dmi b/icons/mob/vox.dmi
new file mode 100644
index 0000000000..6abba5c9e0
Binary files /dev/null and b/icons/mob/vox.dmi differ
diff --git a/icons/mob/zorgoia64x32.dmi b/icons/mob/zorgoia64x32.dmi
new file mode 100644
index 0000000000..f5eb586fa7
Binary files /dev/null and b/icons/mob/zorgoia64x32.dmi differ
diff --git a/icons/obj/gun.dmi b/icons/obj/gun.dmi
index 0809c08585..d83bf81aed 100644
Binary files a/icons/obj/gun.dmi and b/icons/obj/gun.dmi differ
diff --git a/icons/obj/salvage/sellable.dmi b/icons/obj/salvage/sellable.dmi
new file mode 100644
index 0000000000..96238af046
Binary files /dev/null and b/icons/obj/salvage/sellable.dmi differ
diff --git a/sound/effects/mob_effects/m_scream_1.ogg b/sound/effects/mob_effects/m_scream_1.ogg
new file mode 100644
index 0000000000..989b612ab1
Binary files /dev/null and b/sound/effects/mob_effects/m_scream_1.ogg differ
diff --git a/sound/effects/mob_effects/m_scream_2.ogg b/sound/effects/mob_effects/m_scream_2.ogg
new file mode 100644
index 0000000000..902db1c132
Binary files /dev/null and b/sound/effects/mob_effects/m_scream_2.ogg differ
diff --git a/sound/effects/mob_effects/m_scream_3.ogg b/sound/effects/mob_effects/m_scream_3.ogg
new file mode 100644
index 0000000000..62f787d4a7
Binary files /dev/null and b/sound/effects/mob_effects/m_scream_3.ogg differ
diff --git a/sound/effects/mob_effects/m_scream_4.ogg b/sound/effects/mob_effects/m_scream_4.ogg
new file mode 100644
index 0000000000..2aec2c7149
Binary files /dev/null and b/sound/effects/mob_effects/m_scream_4.ogg differ
diff --git a/sound/h_sounds/breathing.ogg b/sound/h_sounds/breathing.ogg
new file mode 100644
index 0000000000..3f81a7a941
Binary files /dev/null and b/sound/h_sounds/breathing.ogg differ
diff --git a/sound/h_sounds/headcrab.ogg b/sound/h_sounds/headcrab.ogg
new file mode 100644
index 0000000000..2d5d9ddbfd
Binary files /dev/null and b/sound/h_sounds/headcrab.ogg differ
diff --git a/sound/h_sounds/holla.ogg b/sound/h_sounds/holla.ogg
new file mode 100644
index 0000000000..f4e4783b36
Binary files /dev/null and b/sound/h_sounds/holla.ogg differ
diff --git a/sound/h_sounds/imbeciles.ogg b/sound/h_sounds/imbeciles.ogg
new file mode 100644
index 0000000000..ce715d2045
Binary files /dev/null and b/sound/h_sounds/imbeciles.ogg differ
diff --git a/sound/h_sounds/lynx.ogg b/sound/h_sounds/lynx.ogg
new file mode 100644
index 0000000000..d9d5de704e
Binary files /dev/null and b/sound/h_sounds/lynx.ogg differ
diff --git a/sound/h_sounds/mumble.ogg b/sound/h_sounds/mumble.ogg
new file mode 100644
index 0000000000..a18c5ed01d
Binary files /dev/null and b/sound/h_sounds/mumble.ogg differ
diff --git a/sound/h_sounds/negative.ogg b/sound/h_sounds/negative.ogg
new file mode 100644
index 0000000000..fc37b5f510
Binary files /dev/null and b/sound/h_sounds/negative.ogg differ
diff --git a/sound/h_sounds/sampler.ogg b/sound/h_sounds/sampler.ogg
new file mode 100644
index 0000000000..0ec6ddd16a
Binary files /dev/null and b/sound/h_sounds/sampler.ogg differ
diff --git a/sound/h_sounds/shitty_tim.ogg b/sound/h_sounds/shitty_tim.ogg
new file mode 100644
index 0000000000..81266c2667
Binary files /dev/null and b/sound/h_sounds/shitty_tim.ogg differ
diff --git a/sound/h_sounds/src/sampler1.ogg b/sound/h_sounds/src/sampler1.ogg
new file mode 100644
index 0000000000..b5e10c969f
Binary files /dev/null and b/sound/h_sounds/src/sampler1.ogg differ
diff --git a/sound/h_sounds/src/sampler2.ogg b/sound/h_sounds/src/sampler2.ogg
new file mode 100644
index 0000000000..e058d442a8
Binary files /dev/null and b/sound/h_sounds/src/sampler2.ogg differ
diff --git a/sound/h_sounds/src/sampler3.ogg b/sound/h_sounds/src/sampler3.ogg
new file mode 100644
index 0000000000..23e695739b
Binary files /dev/null and b/sound/h_sounds/src/sampler3.ogg differ
diff --git a/sound/h_sounds/src/sampler3speed.ogg b/sound/h_sounds/src/sampler3speed.ogg
new file mode 100644
index 0000000000..2ba846199f
Binary files /dev/null and b/sound/h_sounds/src/sampler3speed.ogg differ
diff --git a/sound/h_sounds/src/sampler4.3.ogg b/sound/h_sounds/src/sampler4.3.ogg
new file mode 100644
index 0000000000..46932b7502
Binary files /dev/null and b/sound/h_sounds/src/sampler4.3.ogg differ
diff --git a/sound/h_sounds/src/shitty tim 2.ogg b/sound/h_sounds/src/shitty tim 2.ogg
new file mode 100644
index 0000000000..bf355f7a13
Binary files /dev/null and b/sound/h_sounds/src/shitty tim 2.ogg differ
diff --git a/sound/h_sounds/src/shitty tim.ogg b/sound/h_sounds/src/shitty tim.ogg
new file mode 100644
index 0000000000..b21f209525
Binary files /dev/null and b/sound/h_sounds/src/shitty tim.ogg differ
diff --git a/sound/h_sounds/src/shitty tim1.ogg b/sound/h_sounds/src/shitty tim1.ogg
new file mode 100644
index 0000000000..ab0eaa22a9
Binary files /dev/null and b/sound/h_sounds/src/shitty tim1.ogg differ
diff --git a/sound/h_sounds/src/shitty tim3.ogg b/sound/h_sounds/src/shitty tim3.ogg
new file mode 100644
index 0000000000..770624a22c
Binary files /dev/null and b/sound/h_sounds/src/shitty tim3.ogg differ
diff --git a/sound/h_sounds/src/shitty tim4.ogg b/sound/h_sounds/src/shitty tim4.ogg
new file mode 100644
index 0000000000..81266c2667
Binary files /dev/null and b/sound/h_sounds/src/shitty tim4.ogg differ
diff --git a/sound/h_sounds/wor.ogg b/sound/h_sounds/wor.ogg
new file mode 100644
index 0000000000..ad2076cfaa
Binary files /dev/null and b/sound/h_sounds/wor.ogg differ
diff --git a/sound/h_sounds/yell.ogg b/sound/h_sounds/yell.ogg
new file mode 100644
index 0000000000..163395cd94
Binary files /dev/null and b/sound/h_sounds/yell.ogg differ
diff --git a/sound/h_sounds/youknowwhoitis.ogg b/sound/h_sounds/youknowwhoitis.ogg
new file mode 100644
index 0000000000..7ef0d449b0
Binary files /dev/null and b/sound/h_sounds/youknowwhoitis.ogg differ
diff --git a/sound/misc/ack.ogg b/sound/misc/ack.ogg
new file mode 100644
index 0000000000..52d03884e4
Binary files /dev/null and b/sound/misc/ack.ogg differ
diff --git a/sound/misc/alarm1.ogg b/sound/misc/alarm1.ogg
new file mode 100644
index 0000000000..5bcf1ff636
Binary files /dev/null and b/sound/misc/alarm1.ogg differ
diff --git a/sound/misc/clap1.ogg b/sound/misc/clap1.ogg
new file mode 100644
index 0000000000..da0f7eded7
Binary files /dev/null and b/sound/misc/clap1.ogg differ
diff --git a/sound/misc/clap2.ogg b/sound/misc/clap2.ogg
new file mode 100644
index 0000000000..72e26d4a24
Binary files /dev/null and b/sound/misc/clap2.ogg differ
diff --git a/sound/misc/clap3.ogg b/sound/misc/clap3.ogg
new file mode 100644
index 0000000000..7a72ab9bf3
Binary files /dev/null and b/sound/misc/clap3.ogg differ
diff --git a/sound/misc/clap4.ogg b/sound/misc/clap4.ogg
new file mode 100644
index 0000000000..cdc533ca77
Binary files /dev/null and b/sound/misc/clap4.ogg differ
diff --git a/sound/misc/demonattack.ogg b/sound/misc/demonattack.ogg
new file mode 100644
index 0000000000..024ff846c0
Binary files /dev/null and b/sound/misc/demonattack.ogg differ
diff --git a/sound/misc/demondeath.ogg b/sound/misc/demondeath.ogg
new file mode 100644
index 0000000000..766d1f09da
Binary files /dev/null and b/sound/misc/demondeath.ogg differ
diff --git a/sound/misc/demonlaugh.ogg b/sound/misc/demonlaugh.ogg
new file mode 100644
index 0000000000..3abd19087a
Binary files /dev/null and b/sound/misc/demonlaugh.ogg differ
diff --git a/sound/misc/legodeath.ogg b/sound/misc/legodeath.ogg
new file mode 100644
index 0000000000..5c93d48be5
Binary files /dev/null and b/sound/misc/legodeath.ogg differ
diff --git a/sound/misc/ough.ogg b/sound/misc/ough.ogg
new file mode 100644
index 0000000000..6891f988b0
Binary files /dev/null and b/sound/misc/ough.ogg differ
diff --git a/sound/rakshasa/Breath1.ogg b/sound/rakshasa/Breath1.ogg
new file mode 100644
index 0000000000..463c299896
Binary files /dev/null and b/sound/rakshasa/Breath1.ogg differ
diff --git a/sound/rakshasa/Breath2.ogg b/sound/rakshasa/Breath2.ogg
new file mode 100644
index 0000000000..a3a3c2c663
Binary files /dev/null and b/sound/rakshasa/Breath2.ogg differ
diff --git a/sound/rakshasa/Corrosion1.ogg b/sound/rakshasa/Corrosion1.ogg
new file mode 100644
index 0000000000..912e535639
Binary files /dev/null and b/sound/rakshasa/Corrosion1.ogg differ
diff --git a/sound/rakshasa/Corrosion2.ogg b/sound/rakshasa/Corrosion2.ogg
new file mode 100644
index 0000000000..dfd24cc9d8
Binary files /dev/null and b/sound/rakshasa/Corrosion2.ogg differ
diff --git a/sound/rakshasa/Corrosion3.ogg b/sound/rakshasa/Corrosion3.ogg
new file mode 100644
index 0000000000..cef4bf5c2d
Binary files /dev/null and b/sound/rakshasa/Corrosion3.ogg differ
diff --git a/sound/rakshasa/Decay1.ogg b/sound/rakshasa/Decay1.ogg
new file mode 100644
index 0000000000..e65a838e48
Binary files /dev/null and b/sound/rakshasa/Decay1.ogg differ
diff --git a/sound/rakshasa/Decay2.ogg b/sound/rakshasa/Decay2.ogg
new file mode 100644
index 0000000000..b1e0a10e2f
Binary files /dev/null and b/sound/rakshasa/Decay2.ogg differ
diff --git a/sound/rakshasa/Decay3.ogg b/sound/rakshasa/Decay3.ogg
new file mode 100644
index 0000000000..cfe8b52925
Binary files /dev/null and b/sound/rakshasa/Decay3.ogg differ
diff --git a/sound/rakshasa/Emerge0.ogg b/sound/rakshasa/Emerge0.ogg
new file mode 100644
index 0000000000..bf665de908
Binary files /dev/null and b/sound/rakshasa/Emerge0.ogg differ
diff --git a/sound/rakshasa/Laugh.ogg b/sound/rakshasa/Laugh.ogg
new file mode 100644
index 0000000000..13b6bc8e5d
Binary files /dev/null and b/sound/rakshasa/Laugh.ogg differ
diff --git a/sound/rakshasa/No.ogg b/sound/rakshasa/No.ogg
new file mode 100644
index 0000000000..1b835e46bc
Binary files /dev/null and b/sound/rakshasa/No.ogg differ
diff --git a/sound/weapons/doompistol.ogg b/sound/weapons/doompistol.ogg
new file mode 100644
index 0000000000..00abb8f343
Binary files /dev/null and b/sound/weapons/doompistol.ogg differ
diff --git a/sound/weapons/weaponsounds_alienlaser.ogg b/sound/weapons/weaponsounds_alienlaser.ogg
new file mode 100644
index 0000000000..759774c5c9
Binary files /dev/null and b/sound/weapons/weaponsounds_alienlaser.ogg differ
diff --git a/sound/weapons/weaponsounds_heavypistolshot.ogg b/sound/weapons/weaponsounds_heavypistolshot.ogg
new file mode 100644
index 0000000000..add86d1b7d
Binary files /dev/null and b/sound/weapons/weaponsounds_heavypistolshot.ogg differ
diff --git a/sound/weapons/weaponsounds_heavyrifleshot.ogg b/sound/weapons/weaponsounds_heavyrifleshot.ogg
new file mode 100644
index 0000000000..1c10ea6b0e
Binary files /dev/null and b/sound/weapons/weaponsounds_heavyrifleshot.ogg differ
diff --git a/sound/weapons/weaponsounds_lasermid.ogg b/sound/weapons/weaponsounds_lasermid.ogg
new file mode 100644
index 0000000000..2a79d2dd7d
Binary files /dev/null and b/sound/weapons/weaponsounds_lasermid.ogg differ
diff --git a/sound/weapons/weaponsounds_laserstrong.ogg b/sound/weapons/weaponsounds_laserstrong.ogg
new file mode 100644
index 0000000000..ddcb32a905
Binary files /dev/null and b/sound/weapons/weaponsounds_laserstrong.ogg differ
diff --git a/sound/weapons/weaponsounds_laserstrongALT.ogg b/sound/weapons/weaponsounds_laserstrongALT.ogg
new file mode 100644
index 0000000000..1cc535eff2
Binary files /dev/null and b/sound/weapons/weaponsounds_laserstrongALT.ogg differ
diff --git a/sound/weapons/weaponsounds_laserweak.ogg b/sound/weapons/weaponsounds_laserweak.ogg
new file mode 100644
index 0000000000..b6bc058f39
Binary files /dev/null and b/sound/weapons/weaponsounds_laserweak.ogg differ
diff --git a/sound/weapons/weaponsounds_pistolshot.ogg b/sound/weapons/weaponsounds_pistolshot.ogg
new file mode 100644
index 0000000000..ac6caaf247
Binary files /dev/null and b/sound/weapons/weaponsounds_pistolshot.ogg differ
diff --git a/sound/weapons/weaponsounds_rifleshot.ogg b/sound/weapons/weaponsounds_rifleshot.ogg
new file mode 100644
index 0000000000..3bc70a7914
Binary files /dev/null and b/sound/weapons/weaponsounds_rifleshot.ogg differ
diff --git a/sound/weapons/weaponsounds_shotgunshot.ogg b/sound/weapons/weaponsounds_shotgunshot.ogg
new file mode 100644
index 0000000000..0335876728
Binary files /dev/null and b/sound/weapons/weaponsounds_shotgunshot.ogg differ
diff --git a/sound/weapons/weaponsounds_smallpistolshot.ogg b/sound/weapons/weaponsounds_smallpistolshot.ogg
new file mode 100644
index 0000000000..373c1ea4ba
Binary files /dev/null and b/sound/weapons/weaponsounds_smallpistolshot.ogg differ
diff --git a/tgui/packages/tgui/interfaces/AtmosAlertConsole.tsx b/tgui/packages/tgui/interfaces/AtmosAlertConsole.tsx
index 3e6f317d3a..b7eed9e3d4 100644
--- a/tgui/packages/tgui/interfaces/AtmosAlertConsole.tsx
+++ b/tgui/packages/tgui/interfaces/AtmosAlertConsole.tsx
@@ -13,8 +13,8 @@ export const AtmosAlertConsole = (props) => {
return (
-
-
+
+
{priority_alarms.length === 0 && (
- No Priority Alerts
diff --git a/vorestation.dme b/vorestation.dme
index df78a8bf6b..330e638913 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -1514,6 +1514,7 @@
#include "code\game\objects\items\devices\tvcamera.dm"
#include "code\game\objects\items\devices\uplink.dm"
#include "code\game\objects\items\devices\uplink_random_lists.dm"
+#include "code\game\objects\items\devices\vacpack.dm"
#include "code\game\objects\items\devices\whistle.dm"
#include "code\game\objects\items\devices\communicator\communicator.dm"
#include "code\game\objects\items\devices\communicator\helper.dm"
@@ -3112,6 +3113,7 @@
#include "code\modules\mob\_modifiers\traits_phobias.dm"
#include "code\modules\mob\_modifiers\unholy.dm"
#include "code\modules\mob\dead\corpse.dm"
+#include "code\modules\mob\dead\corpse_vox.dm"
#include "code\modules\mob\dead\corpse_vr.dm"
#include "code\modules\mob\dead\death.dm"
#include "code\modules\mob\dead\observer\chunk.dm"
@@ -3425,6 +3427,7 @@
#include "code\modules\mob\living\simple_mob\subtypes\animal\animal.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\squirrel.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\turkeygirl.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\animal\vox.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\alien animals\catslug.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\alien animals\jellyfish.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\alien animals\skeleton.dm"
@@ -3434,6 +3437,7 @@
#include "code\modules\mob\living\simple_mob\subtypes\animal\alien animals\stardog.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\alien animals\startreader.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\alien animals\succlet.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\animal\alien animals\synx.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\alien animals\teppi.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\borer\borer.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\borer\borer_captive.dm"
@@ -3457,15 +3461,19 @@
#include "code\modules\mob\living\simple_mob\subtypes\animal\giant_spider\thermic.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\giant_spider\tunneler.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\giant_spider\webslinger.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\animal\hyena\hyena.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\armadillo.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\cockroach.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\crab.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\fish.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\fish_vr.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\jerboa_vr.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\lizard.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\lizard_mutant_event.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\misc.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\mothroach.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\mouse.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\mouse_mutant_event.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\mouse_vr.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\passive.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\penguin.dm"
@@ -3500,10 +3508,12 @@
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\bear.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\carp.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\carp_vr.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\animal\space\clockwork.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\gaslamp_vr.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\gnat.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\goose.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\goose_vr.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\animal\space\mouse_army.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\ray.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\shark.dm"
#include "code\modules\mob\living\simple_mob\subtypes\animal\space\snake_vr.dm"
@@ -3519,15 +3529,20 @@
#include "code\modules\mob\living\simple_mob\subtypes\glamour\unicorn.dm"
#include "code\modules\mob\living\simple_mob\subtypes\glamour\ysbryd.dm"
#include "code\modules\mob\living\simple_mob\subtypes\humanoid\clown.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\humanoid\cultist.dm"
#include "code\modules\mob\living\simple_mob\subtypes\humanoid\humanoid.dm"
#include "code\modules\mob\living\simple_mob\subtypes\humanoid\humanoid_vr.dm"
#include "code\modules\mob\living\simple_mob\subtypes\humanoid\pirates.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\humanoid\possessed.dm"
#include "code\modules\mob\living\simple_mob\subtypes\humanoid\russian.dm"
#include "code\modules\mob\living\simple_mob\subtypes\humanoid\mercs\mercs.dm"
#include "code\modules\mob\living\simple_mob\subtypes\humanoid\mercs\mercs_altevian.dm"
#include "code\modules\mob\living\simple_mob\subtypes\humanoid\mercs\mercs_vr.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\humanoid\mercs\merd_catalogs.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\humanoid\mercs\vox.dm"
#include "code\modules\mob\living\simple_mob\subtypes\illusion\illusion.dm"
#include "code\modules\mob\living\simple_mob\subtypes\mechanical\corrupt_maint_drone_vr.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\mechanical\cyber_horror.dm"
#include "code\modules\mob\living\simple_mob\subtypes\mechanical\disbot_vr.dm"
#include "code\modules\mob\living\simple_mob\subtypes\mechanical\golem.dm"
#include "code\modules\mob\living\simple_mob\subtypes\mechanical\golem_vr.dm"
@@ -3562,8 +3577,13 @@
#include "code\modules\mob\living\simple_mob\subtypes\occult\unknown.dm"
#include "code\modules\mob\living\simple_mob\subtypes\occult\constructs\_construct.dm"
#include "code\modules\mob\living\simple_mob\subtypes\occult\constructs\artificer.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\occult\constructs\bishop.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\occult\constructs\cardinal.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\occult\constructs\deacon.dm"
#include "code\modules\mob\living\simple_mob\subtypes\occult\constructs\harvester.dm"
#include "code\modules\mob\living\simple_mob\subtypes\occult\constructs\juggernaut.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\occult\constructs\laity.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\occult\constructs\priest.dm"
#include "code\modules\mob\living\simple_mob\subtypes\occult\constructs\shade.dm"
#include "code\modules\mob\living\simple_mob\subtypes\occult\constructs\wraith.dm"
#include "code\modules\mob\living\simple_mob\subtypes\plant\tomato.dm"
@@ -3584,6 +3604,7 @@
#include "code\modules\mob\living\simple_mob\subtypes\vore\bigdragon.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\c_pet.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\catgirl.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\vore\chungus.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\cookiegirl.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\corrupt_hounds.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\cryptdrake.dm"
@@ -3595,12 +3616,16 @@
#include "code\modules\mob\living\simple_mob\subtypes\vore\fennec.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\fennix.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\frog.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\vore\goia.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\greatwolf.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\vore\gryphon.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\hippo.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\horse.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\jelly.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\lamia.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\leopardmander.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\vore\lion.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\vore\lizardman.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\macrophage.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\meowl.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\mimic.dm"
@@ -3608,18 +3633,20 @@
#include "code\modules\mob\living\simple_mob\subtypes\vore\otie.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\pakkun.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\panther.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\vore\panther_thor.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\peasant.dm"
-#include "code\modules\mob\living\simple_mob\subtypes\vore\plants.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\rabbit.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\raptor.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\rat.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\redpanda.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\vore\reindeer.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\scel.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\scrubble.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\seagull.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\sect_drone.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\sect_queen.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\sheep.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\vore\slug.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\snake.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\softdog.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\solargrub.dm"
@@ -3627,6 +3654,7 @@
#include "code\modules\mob\living\simple_mob\subtypes\vore\sonadile.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\stalker.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\succubi.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\vore\swoopie.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\turkey.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\vampire.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\vore.dm"
@@ -3641,6 +3669,8 @@
#include "code\modules\mob\living\simple_mob\subtypes\vore\demon\demon.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\demon\demon_abilities.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\demon\demon_subtypes.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\vore\demon\demonAI.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\vore\demon\demonAI_subtypes.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\demon\~defines.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\mobs_monsters\clowns\Big.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\mobs_monsters\clowns\bigclowns.dm"
@@ -3652,7 +3682,10 @@
#include "code\modules\mob\living\simple_mob\subtypes\vore\mobs_monsters\clowns\honkelemental.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\mobs_monsters\clowns\regularclowns.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\morph\morph.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\vore\plants\pitcher.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\vore\plants\plants.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\shadekin\ability_procs.dm"
+#include "code\modules\mob\living\simple_mob\subtypes\vore\shadekin\rakshasa_trap.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\shadekin\shadekin.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\shadekin\types.dm"
#include "code\modules\mob\living\voice\voice.dm"
@@ -4285,6 +4318,8 @@
#include "code\modules\rogueminer_vr\wrappers.dm"
#include "code\modules\rogueminer_vr\zone_console.dm"
#include "code\modules\rogueminer_vr\zonemaster.dm"
+#include "code\modules\salvage\bags.dm"
+#include "code\modules\salvage\salvage.dm"
#include "code\modules\samples\container.dm"
#include "code\modules\samples\samples.dm"
#include "code\modules\scripting\Errors.dm"