diff --git a/code/game/gamemodes/changeling/powers/headcrab.dm b/code/game/gamemodes/changeling/powers/headslug.dm
similarity index 88%
rename from code/game/gamemodes/changeling/powers/headcrab.dm
rename to code/game/gamemodes/changeling/powers/headslug.dm
index b39a2bba0d5..f29ec02db54 100644
--- a/code/game/gamemodes/changeling/powers/headcrab.dm
+++ b/code/game/gamemodes/changeling/powers/headslug.dm
@@ -1,4 +1,4 @@
-/datum/action/changeling/headcrab
+/datum/action/changeling/headslug
name = "Last Resort"
desc = "We sacrifice our current body in a moment of need, placing us in control of a vessel that can plant our likeness in a new host. Costs 20 chemicals."
helptext = "We will be placed in control of a small, fragile creature. We may attack a corpse like this to plant an egg which will slowly mature into a new form for us."
@@ -7,12 +7,12 @@
dna_cost = 1
req_human = 1
-/datum/action/changeling/headcrab/try_to_sting(mob/user, mob/target)
+/datum/action/changeling/headslug/try_to_sting(mob/user, mob/target)
if(alert("Are you sure you wish to do this? This action cannot be undone.",,"Yes","No")=="No")
return
..()
-/datum/action/changeling/headcrab/sting_action(mob/user)
+/datum/action/changeling/headslug/sting_action(mob/user)
var/datum/mind/M = user.mind
var/list/organs = user.get_organs_zone("head", 1)
@@ -33,7 +33,7 @@
S.Weaken(3)
var/new_location = user.drop_location()
spawn(5) // So it's not killed in explosion
- var/mob/living/simple_animal/hostile/headcrab/crab = new(new_location)
+ var/mob/living/simple_animal/hostile/headslug/crab = new(new_location)
for(var/obj/item/organ/internal/I in organs)
I.loc = crab
crab.origin = M
diff --git a/code/modules/events/headcrabs.dm b/code/modules/events/headcrabs.dm
new file mode 100644
index 00000000000..3c02212a40f
--- /dev/null
+++ b/code/modules/events/headcrabs.dm
@@ -0,0 +1,146 @@
+#define LOC_ATMOS_CONTROL 0
+#define LOC_FPMAINT 1
+#define LOC_FPMAINT2 2
+#define LOC_FSMAINT 3
+#define LOC_FSMAINT2 4
+#define LOC_ASMAINT 5
+#define LOC_ASMAINT2 6
+#define LOC_APMAINT 7
+#define LOC_MAINTCENTRAL 8
+#define LOC_FORE 9
+#define LOC_STARBOARD 10
+#define LOC_PORT 11
+#define LOC_AFT 12
+#define LOC_STORAGE 13
+#define LOC_DISPOSAL 14
+#define LOC_GENETICS 15
+#define LOC_ELECTRICAL 16
+#define LOC_ABANDONEDBAR 17
+#define LOC_ELECTRICAL_SHOP 18
+#define LOC_GAMBLING_DEN 19
+
+#define HEADCRAB_NORMAL 0
+/*#define HEADCRAB_SPECIAL 1
+#define HEADCRAB_CLOWN 2 */ //Planned for the future
+
+/datum/event/headcrabs
+ announceWhen = 10
+ endWhen = 11
+ var/location
+ var/locstring
+ var/headcrab
+
+/datum/event/headcrabs/start()
+
+ location = rand(0,19)
+ var/list/turf/simulated/floor/turfs = list()
+ var/spawn_area_type
+ switch(location)
+ if(LOC_ATMOS_CONTROL)
+ spawn_area_type = /area/maintenance/atmos_control
+ locstring = "Atmospherics Maintenance"
+ if(LOC_FPMAINT)
+ spawn_area_type = /area/maintenance/fpmaint
+ locstring = "EVA Maintenance"
+ if(LOC_FPMAINT2)
+ spawn_area_type = /area/maintenance/fpmaint2
+ locstring = "Arrivals North Maintenance"
+ if(LOC_FSMAINT)
+ spawn_area_type = /area/maintenance/fsmaint
+ locstring = "Dormitory Maintenance"
+ if(LOC_FSMAINT2)
+ spawn_area_type = /area/maintenance/fsmaint2
+ locstring = "Bar Maintenance"
+ if(LOC_ASMAINT)
+ spawn_area_type = /area/maintenance/asmaint
+ locstring = "Medbay Maintenance"
+ if(LOC_ASMAINT2)
+ spawn_area_type = /area/maintenance/asmaint2
+ locstring = "Science Maintenance"
+ if(LOC_APMAINT)
+ spawn_area_type = /area/maintenance/apmaint
+ locstring = "Cargo Maintenance"
+ if(LOC_MAINTCENTRAL)
+ spawn_area_type = /area/maintenance/maintcentral
+ locstring = "Bridge Maintenance"
+ if(LOC_FORE)
+ spawn_area_type = /area/maintenance/fore
+ locstring = "Fore Maintenance"
+ if(LOC_STARBOARD)
+ spawn_area_type = /area/maintenance/starboard
+ locstring = "Starboard Maintenance"
+ if(LOC_PORT)
+ spawn_area_type = /area/maintenance/port
+ locstring = "Locker Room Maintenance"
+ if(LOC_AFT)
+ spawn_area_type = /area/maintenance/aft
+ locstring = "Engineering Maintenance"
+ if(LOC_STORAGE)
+ spawn_area_type = /area/maintenance/storage
+ locstring = "Atmospherics Maintenance"
+ if(LOC_DISPOSAL)
+ spawn_area_type = /area/maintenance/disposal
+ locstring = "Waste Disposal"
+ if(LOC_GENETICS)
+ spawn_area_type = /area/maintenance/genetics
+ locstring = "Genetics Maintenance"
+ if(LOC_ELECTRICAL)
+ spawn_area_type = /area/maintenance/electrical
+ locstring = "Electrical Maintenance"
+ if(LOC_ABANDONEDBAR)
+ spawn_area_type = /area/maintenance/abandonedbar
+ locstring = "Maintenance Bar"
+ if(LOC_ELECTRICAL_SHOP)
+ spawn_area_type = /area/maintenance/electrical_shop
+ locstring ="Electronics Den"
+ if(LOC_GAMBLING_DEN)
+ spawn_area_type = /area/maintenance/gambling_den
+ locstring = "Gambling Den"
+ for(var/areapath in typesof(spawn_area_type))
+ var/area/A = locate(areapath)
+ for(var/turf/simulated/floor/F in A.contents)
+ if(turf_clear(F))
+ turfs += F
+
+ var/list/spawn_types = list()
+ var/max_number
+ headcrab = 0 //rand(0,x) for the future
+ switch(headcrab) //Switch is for the future
+ if(HEADCRAB_NORMAL)
+ spawn_types = list(/mob/living/simple_animal/hostile/headcrab)
+ max_number = 6
+
+ var/num = rand(2,max_number)
+ while(turfs.len > 0 && num > 0)
+ var/turf/simulated/floor/T = pick(turfs)
+ turfs.Remove(T)
+ num--
+ var/spawn_type = pick(spawn_types)
+ new spawn_type(T)
+
+
+/datum/event/headcrabs/announce()
+ event_announcement.Announce("Bioscans indicate that creatures have been breeding in [locstring]. Clear them out, before this starts to affect productivity", "Lifesign Alert")
+
+#undef LOC_ATMOS_CONTROL
+#undef LOC_FPMAINT
+#undef LOC_FPMAINT2
+#undef LOC_FSMAINT
+#undef LOC_FSMAINT2
+#undef LOC_ASMAINT
+#undef LOC_ASMAINT2
+#undef LOC_APMAINT
+#undef LOC_MAINTCENTRAL
+#undef LOC_FORE
+#undef LOC_STARBOARD
+#undef LOC_PORT
+#undef LOC_AFT
+#undef LOC_STORAGE
+#undef LOC_DISPOSAL
+#undef LOC_GENETICS
+#undef LOC_ELECTRICAL
+#undef LOC_ABANDONEDBAR
+#undef LOC_ELECTRICAL_SHOP
+#undef LOC_GAMBLING_DEN
+
+#undef HEADCRAB_NORMAL
diff --git a/code/modules/mob/living/simple_animal/hostile/headcrab.dm b/code/modules/mob/living/simple_animal/hostile/headcrab.dm
index c82a0ee7806..1ef6f06259f 100644
--- a/code/modules/mob/living/simple_animal/hostile/headcrab.dm
+++ b/code/modules/mob/living/simple_animal/hostile/headcrab.dm
@@ -1,100 +1,106 @@
-#define EGG_INCUBATION_TIME 120
-
/mob/living/simple_animal/hostile/headcrab
- name = "headslug"
- desc = "Absolutely not de-beaked or harmless. Keep away from corpses."
+ name = "headcrab"
+ desc = "A small parasitic creature that would like to connect with your brain stem."
+ icon = 'icons/mob/headcrab.dmi'
icon_state = "headcrab"
icon_living = "headcrab"
icon_dead = "headcrab_dead"
- icon = 'icons/mob/mob.dmi'
- health = 50
- maxHealth = 50
+ health = 40
+ maxHealth = 40
melee_damage_lower = 5
- melee_damage_upper = 5
- attacktext = "chomps"
- attack_sound = 'sound/weapons/bite.ogg'
- faction = list("creature")
- robust_searching = 1
- stat_attack = 2
- obj_damage = 0
- environment_smash = 0
- speak_emote = list("squeaks")
- ventcrawler = 2
- var/datum/mind/origin
- var/egg_lain = 0
+ melee_damage_upper = 10
+ ranged = 1
+ ranged_message = "leaps"
+ ranged_cooldown_time = 40
+ var/jumpdistance = 4
+ var/jumpspeed = 1
+ attacktext = "bites"
+ attack_sound = 'sound/creatures/headcrab_attack.ogg'
+ speak_emote = list("hisses")
+ var/is_zombie = 0
+ stat_attack = 1 //so they continue to attack when they are on the ground.
+ var/host_species = ""
+ var/list/human_overlays = list()
-/mob/living/simple_animal/hostile/headcrab/examine(mob/user)
+/mob/living/simple_animal/hostile/headcrab/Life(seconds, times_fired)
+ if(!is_zombie && isturf(src.loc) && stat != DEAD)
+ for(var/mob/living/carbon/human/H in oview(src, 1)) //Only for corpse right next to/on same tile
+ if(H.stat == DEAD || (!H.check_death_method() && H.health <= HEALTH_THRESHOLD_DEAD))
+ Zombify(H)
+ break
..()
- if(stat == DEAD)
- to_chat(desc = "It appears to be dead.")
-/mob/living/simple_animal/hostile/headcrab/proc/Infect(mob/living/carbon/victim)
- var/obj/item/organ/internal/body_egg/changeling_egg/egg = new(victim)
- egg.insert(victim)
- if(origin)
- egg.origin = origin
- else if(mind) // Let's make this a feature
- egg.origin = mind
- for(var/obj/item/organ/internal/I in src)
- I.loc = egg
- visible_message("[src] plants something in [victim]'s flesh!", \
- "We inject our egg into [victim]'s body!")
- egg_lain = 1
+/mob/living/simple_animal/hostile/headcrab/OpenFire(atom/A)
+ if(check_friendly_fire)
+ for(var/turf/T in getline(src,A)) // Not 100% reliable but this is faster than simulating actual trajectory
+ for(var/mob/living/L in T)
+ if(L == src || L == A)
+ continue
+ if(faction_check(L) && !attack_same)
+ return
+ visible_message("[src] [ranged_message] at [A]!")
+ throw_at(A, jumpdistance, jumpspeed, spin = FALSE, diagonals_first = TRUE)
+ ranged_cooldown = world.time + ranged_cooldown_time
-/mob/living/simple_animal/hostile/headcrab/AttackingTarget()
- if(egg_lain)
- target.attack_animal(src)
- return
- if(iscarbon(target) && !issmall(target))
- // Changeling egg can survive in aliens!
- var/mob/living/carbon/C = target
- if(C.stat == DEAD)
- if(C.status_flags & XENO_HOST)
- to_chat(src, "A foreign presence repels us from this body. Perhaps we should try to infest another?")
- return
- Infect(target)
- to_chat(src, "With our egg laid, our death approaches rapidly...")
- spawn(100)
- death()
- return
- target.attack_animal(src)
+/mob/living/simple_animal/hostile/headcrab/proc/Zombify(mob/living/carbon/human/H)
+ if(!H.check_death_method())
+ H.death()
+ var/obj/item/organ/external/head/head_organ = H.get_organ("head")
+ is_zombie = TRUE
+ if(H.wear_suit)
+ var/obj/item/clothing/suit/armor/A = H.wear_suit
+ if(A.armor && A.armor["melee"])
+ maxHealth += A.armor["melee"] //That zombie's got armor, I want armor!
+ maxHealth += 50
+ health = maxHealth
+ name = "zombie"
+ desc = "A corpse animated by the alien being on its head."
+ melee_damage_lower = 10
+ melee_damage_upper = 15
+ ranged = 0
+ icon = H.icon
+ speak = list('sound/creatures/zombie_idle1.ogg','sound/creatures/zombie_idle2.ogg','sound/creatures/zombie_idle3.ogg')
+ speak_chance = 50
+ speak_emote = list("groans")
+ attacktext = "bites"
+ attack_sound = 'sound/creatures/zombie_attack.ogg'
+ icon_state = "zombie2_s"
+ if(head_organ)
+ head_organ.h_style = null
+ H.update_hair()
+ host_species = H.dna.species.name
+ human_overlays = H.overlays
+ update_icons()
+ H.forceMove(src)
+ visible_message("The corpse of [H.name] suddenly rises!")
-/obj/item/organ/internal/body_egg/changeling_egg
- name = "changeling egg"
- desc = "Twitching and disgusting."
- origin_tech = "biotech=7" // You need to be really lucky to obtain it.
- var/datum/mind/origin
- var/time
-
-/obj/item/organ/internal/body_egg/changeling_egg/egg_process()
- // Changeling eggs grow in dead people
- time++
- if(time >= EGG_INCUBATION_TIME)
- Pop()
- remove(owner)
+/mob/living/simple_animal/hostile/headcrab/death()
+ ..()
+ if(is_zombie)
qdel(src)
-/obj/item/organ/internal/body_egg/changeling_egg/proc/Pop()
- var/mob/living/carbon/human/monkey/M = new(owner)
- owner.stomach_contents += M
- for(var/obj/item/organ/internal/I in src)
- I.insert(M, 1)
+/mob/living/simple_animal/hostile/headcrab/handle_automated_speech() // This way they have different screams when attacking, sometimes. Might be seen as sphagetthi code though.
+ if(speak_chance)
+ if(rand(0,200) < speak_chance)
+ if(speak && speak.len)
+ playsound(get_turf(src), pick(speak), 200, 1)
- if(origin && origin.current && (origin.current.stat == DEAD))
- origin.transfer_to(M)
- if(!origin.changeling)
- M.make_changeling()
- if(origin.changeling.can_absorb_dna(M, owner))
- origin.changeling.absorb_dna(owner, M)
+/mob/living/simple_animal/hostile/headcrab/Destroy()
+ if(contents)
+ for(var/mob/M in contents)
+ M.loc = get_turf(src)
+ return ..()
- var/datum/action/changeling/humanform/HF = new
- HF.Grant(M)
- for(var/power in origin.changeling.purchasedpowers)
- var/datum/action/changeling/S = power
- if(istype(S) && S.needs_button)
- S.Grant(M)
- M.key = origin.key
- owner.gib()
-#undef EGG_INCUBATION_TIME
+/mob/living/simple_animal/hostile/headcrab/update_icons()
+ ..()
+ if(is_zombie)
+ overlays.Cut()
+ overlays = human_overlays
+ var/image/I = image('icons/mob/headcrab.dmi', icon_state = "headcrabpod")
+ if(host_species == "Vox")
+ I = image('icons/mob/headcrab.dmi', icon_state = "headcrabpod_vox")
+ else if(host_species == "Gray")
+ I = image('icons/mob/headcrab.dmi', icon_state = "headcrabpod_gray")
+ overlays += I
diff --git a/code/modules/mob/living/simple_animal/hostile/headslug.dm b/code/modules/mob/living/simple_animal/hostile/headslug.dm
new file mode 100644
index 00000000000..e2fc98c483f
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/hostile/headslug.dm
@@ -0,0 +1,100 @@
+#define EGG_INCUBATION_TIME 120
+
+/mob/living/simple_animal/hostile/headslug
+ name = "headslug"
+ desc = "Absolutely not de-beaked or harmless. Keep away from corpses."
+ icon_state = "headslug"
+ icon_living = "headslug"
+ icon_dead = "headslug_dead"
+ icon = 'icons/mob/mob.dmi'
+ health = 50
+ maxHealth = 50
+ melee_damage_lower = 5
+ melee_damage_upper = 5
+ attacktext = "chomps"
+ attack_sound = 'sound/weapons/bite.ogg'
+ faction = list("creature")
+ robust_searching = 1
+ stat_attack = 2
+ obj_damage = 0
+ environment_smash = 0
+ speak_emote = list("squeaks")
+ ventcrawler = 2
+ var/datum/mind/origin
+ var/egg_lain = 0
+
+/mob/living/simple_animal/hostile/headslug/examine(mob/user)
+ ..()
+ if(stat == DEAD)
+ to_chat(desc = "It appears to be dead.")
+
+/mob/living/simple_animal/hostile/headslug/proc/Infect(mob/living/carbon/victim)
+ var/obj/item/organ/internal/body_egg/changeling_egg/egg = new(victim)
+ egg.insert(victim)
+ if(origin)
+ egg.origin = origin
+ else if(mind) // Let's make this a feature
+ egg.origin = mind
+ for(var/obj/item/organ/internal/I in src)
+ I.loc = egg
+ visible_message("[src] plants something in [victim]'s flesh!", \
+ "We inject our egg into [victim]'s body!")
+ egg_lain = 1
+
+/mob/living/simple_animal/hostile/headslug/AttackingTarget()
+ if(egg_lain)
+ target.attack_animal(src)
+ return
+ if(iscarbon(target) && !issmall(target))
+ // Changeling egg can survive in aliens!
+ var/mob/living/carbon/C = target
+ if(C.stat == DEAD)
+ if(C.status_flags & XENO_HOST)
+ to_chat(src, "A foreign presence repels us from this body. Perhaps we should try to infest another?")
+ return
+ Infect(target)
+ to_chat(src, "With our egg laid, our death approaches rapidly...")
+ spawn(100)
+ death()
+ return
+ target.attack_animal(src)
+
+/obj/item/organ/internal/body_egg/changeling_egg
+ name = "changeling egg"
+ desc = "Twitching and disgusting."
+ origin_tech = "biotech=7" // You need to be really lucky to obtain it.
+ var/datum/mind/origin
+ var/time
+
+/obj/item/organ/internal/body_egg/changeling_egg/egg_process()
+ // Changeling eggs grow in dead people
+ time++
+ if(time >= EGG_INCUBATION_TIME)
+ Pop()
+ remove(owner)
+ qdel(src)
+
+/obj/item/organ/internal/body_egg/changeling_egg/proc/Pop()
+ var/mob/living/carbon/human/monkey/M = new(owner)
+ owner.stomach_contents += M
+
+ for(var/obj/item/organ/internal/I in src)
+ I.insert(M, 1)
+
+ if(origin && origin.current && (origin.current.stat == DEAD))
+ origin.transfer_to(M)
+ if(!origin.changeling)
+ M.make_changeling()
+ if(origin.changeling.can_absorb_dna(M, owner))
+ origin.changeling.absorb_dna(owner, M)
+
+ var/datum/action/changeling/humanform/HF = new
+ HF.Grant(M)
+ for(var/power in origin.changeling.purchasedpowers)
+ var/datum/action/changeling/S = power
+ if(istype(S) && S.needs_button)
+ S.Grant(M)
+ M.key = origin.key
+ owner.gib()
+
+#undef EGG_INCUBATION_TIME
diff --git a/icons/mob/headcrab.dmi b/icons/mob/headcrab.dmi
new file mode 100644
index 00000000000..4db08f13e76
Binary files /dev/null and b/icons/mob/headcrab.dmi differ
diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi
index 014242b9d90..ed193927004 100644
Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ
diff --git a/paradise.dme b/paradise.dme
index aab6fa63ad7..6b632ad1916 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -485,7 +485,7 @@
#include "code\game\gamemodes\changeling\powers\epinephrine.dm"
#include "code\game\gamemodes\changeling\powers\fakedeath.dm"
#include "code\game\gamemodes\changeling\powers\fleshmend.dm"
-#include "code\game\gamemodes\changeling\powers\headcrab.dm"
+#include "code\game\gamemodes\changeling\powers\headslug.dm"
#include "code\game\gamemodes\changeling\powers\hivemind.dm"
#include "code\game\gamemodes\changeling\powers\humanform.dm"
#include "code\game\gamemodes\changeling\powers\lesserform.dm"
@@ -1444,6 +1444,7 @@
#include "code\modules\events\false_alarm.dm"
#include "code\modules\events\floorcluwne.dm"
#include "code\modules\events\grid_check.dm"
+#include "code\modules\events\headcrabs.dm"
#include "code\modules\events\immovable_rod.dm"
#include "code\modules\events\infestation.dm"
#include "code\modules\events\ion_storm.dm"
@@ -1924,6 +1925,7 @@
#include "code\modules\mob\living\simple_animal\hostile\floorcluwne.dm"
#include "code\modules\mob\living\simple_animal\hostile\giant_spider.dm"
#include "code\modules\mob\living\simple_animal\hostile\headcrab.dm"
+#include "code\modules\mob\living\simple_animal\hostile\headslug.dm"
#include "code\modules\mob\living\simple_animal\hostile\hellhound.dm"
#include "code\modules\mob\living\simple_animal\hostile\hivebot.dm"
#include "code\modules\mob\living\simple_animal\hostile\hostile.dm"
@@ -2442,4 +2444,4 @@
#include "goon\code\datums\browserOutput.dm"
#include "interface\interface.dm"
#include "interface\skin.dmf"
-// END_INCLUDE
+// END_INCLUDE
\ No newline at end of file
diff --git a/sound/creatures/headcrab_attack.ogg b/sound/creatures/headcrab_attack.ogg
new file mode 100644
index 00000000000..4f6d114aa75
Binary files /dev/null and b/sound/creatures/headcrab_attack.ogg differ
diff --git a/sound/creatures/zombie_attack.ogg b/sound/creatures/zombie_attack.ogg
new file mode 100644
index 00000000000..1e9b2a63024
Binary files /dev/null and b/sound/creatures/zombie_attack.ogg differ
diff --git a/sound/creatures/zombie_idle1.ogg b/sound/creatures/zombie_idle1.ogg
new file mode 100644
index 00000000000..851c88deff4
Binary files /dev/null and b/sound/creatures/zombie_idle1.ogg differ
diff --git a/sound/creatures/zombie_idle2.ogg b/sound/creatures/zombie_idle2.ogg
new file mode 100644
index 00000000000..04e75da9b22
Binary files /dev/null and b/sound/creatures/zombie_idle2.ogg differ
diff --git a/sound/creatures/zombie_idle3.ogg b/sound/creatures/zombie_idle3.ogg
new file mode 100644
index 00000000000..b4cd2600757
Binary files /dev/null and b/sound/creatures/zombie_idle3.ogg differ