diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm
index c14ae9884d250..b13a40496436f 100644
--- a/code/modules/events/event_container.dm
+++ b/code/modules/events/event_container.dm
@@ -184,6 +184,9 @@ var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT
available_events = list(
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Nothing", /datum/event/nothing, 1320),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Blob", /datum/event/blob, 0, list(ASSIGNMENT_ENGINEER = 40), 1),
+ // [SIERRA-ADD],
+ new /datum/event_meta(EVENT_LEVEL_MAJOR, "Blob", /datum/event/hivemind, 0, list(ASSIGNMENT_ENGINEER = 20,ASSIGNMENT_MEDICAL = 20,ASSIGNMENT_SECURITY = 20), 1),
+ // [/SIERRA-ADD],
new /datum/event_meta/no_overmap(EVENT_LEVEL_MAJOR, "Carp Migration", /datum/event/mob_spawning/carp, 0, list(ASSIGNMENT_SECURITY = 5), 1),
new /datum/event_meta/no_overmap(EVENT_LEVEL_MAJOR, "Meteor Wave", /datum/event/meteor_wave, 0, list(ASSIGNMENT_ENGINEER = 10), 1),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Space Vines", /datum/event/spacevine, 0, list(ASSIGNMENT_ENGINEER = 15), 1),
diff --git a/mods/global_modpacks.dm b/mods/global_modpacks.dm
index 9b468cbb8f97a..54cb40c5057ca 100644
--- a/mods/global_modpacks.dm
+++ b/mods/global_modpacks.dm
@@ -26,6 +26,7 @@
#include "ntnet/_ntnet_includes.dm"
#include "virusology/_virusology_includes.dm"
#include "RnD/_RnD_includes.dm"
+#include "hivemind/_hivemind_includes.dm"
#include "nyc_posters/_nyc_posters_includes.dm"
#include "pixelshift/_pixelshift_includes.dm"
#include "ssinput/_ssinput_includes.dm"
diff --git a/mods/hivemind/README.md b/mods/hivemind/README.md
new file mode 100644
index 0000000000000..0f32408d2d170
--- /dev/null
+++ b/mods/hivemind/README.md
@@ -0,0 +1,79 @@
+
+#### Список PRов:
+
+- https://github.com/SierraBay/SierraBay12/pull/#####
+
+
+
+## Мод-пример
+
+ID мода: EXAMPLE
+
+
+### Описание мода
+
+Этот мод служит примером для разработчиков и существует лишь для того,
+чтобы его можно было легко скопировать и вставить в другое место.
+
+
+### Изменения *кор кода*
+
+- `code/modules/mob/living.dm`: `proc/overriden_proc`, `var/overriden_var`
+
+
+### Оверрайды
+
+- `mods/_master_files/sound/my_cool_sound.ogg`
+- `mods/_master_files/code/my_modular_override.dm`: `proc/overriden_proc`, `var/overriden_var`
+
+
+### Дефайны
+
+- `code/__defines/~mods/example.dm`: `EXAMPLE_SPEED_MULTIPLIER`, `EXAMPLE_SPEED_BASE`
+
+
+### Используемые файлы, не содержащиеся в модпаке
+
+- `mods/_master_files/icons/obj/alien.dmi`
+
+
+### Авторы:
+
+Твой никнейм
+
diff --git a/mods/hivemind/_hivemind.dm b/mods/hivemind/_hivemind.dm
new file mode 100644
index 0000000000000..4c347115e71ef
--- /dev/null
+++ b/mods/hivemind/_hivemind.dm
@@ -0,0 +1,4 @@
+/singleton/modpack/example
+ name = "Мод-пример"
+ desc = "Мод, который является примером и ни в коем случае не должен быть использован."
+ author = "Твой никнейм"
diff --git a/mods/hivemind/_hivemind_includes.dm b/mods/hivemind/_hivemind_includes.dm
new file mode 100644
index 0000000000000..92696c13e5889
--- /dev/null
+++ b/mods/hivemind/_hivemind_includes.dm
@@ -0,0 +1,13 @@
+#ifndef MODPACK_HIVEMIND
+#define MODPACK_HIVEMIND
+
+#include "code\core.dm"
+#include "code\hivemind_invasion.dm"
+#include "code\machines.dm"
+#include "code\mobs.dm"
+#include "code\objects.dm"
+#include "code\wires.dm"
+#include "code\overrides.dm"
+
+
+#endif
diff --git a/mods/hivemind/code/core.dm b/mods/hivemind/code/core.dm
new file mode 100644
index 0000000000000..0207b0753eda9
--- /dev/null
+++ b/mods/hivemind/code/core.dm
@@ -0,0 +1,57 @@
+//The Hivemind is a rogue AI using nanites.
+//The objective of this AI is to spread across the ship and destroy as much as possible.
+
+
+var/datum/hivemind/hive_mind_ai
+
+/datum/hivemind
+ var/name
+ var/surname
+ var/evo_points = 0
+ var/evo_points_max = 1000
+ var/failure_chance = 55 //failure chance is lowers each 10 EP
+ var/list/hives = list() //all functional hives stored here
+ //i know, whitelist is bad, but it's required here
+ var/list/restricted_machineries = list( /obj/machinery/light, /obj/machinery/atmospherics,
+ /obj/machinery/portable_atmospherics, /obj/machinery/door,
+ /obj/machinery/camera, /obj/machinery/light_switch,
+ /obj/machinery/disposal, /obj/machinery/firealarm,
+ /obj/machinery/alarm, /obj/machinery/recharger,
+ /obj/machinery/hologram, /obj/machinery/hivemind_machine,
+ /obj/machinery/button, /obj/machinery/ai_status_display,
+ /obj/machinery/status_display, /obj/machinery/requests_console,
+ /obj/machinery/newscaster, /obj/machinery/floor_light,
+ /obj/machinery/nuclearbomb, /obj/machinery/flasher)
+
+ //internals
+ var/list/global_abilities_cooldown = list()
+ var/list/EP_price_list = list()
+
+/datum/hivemind/New()
+ ..()
+ name = pick("Reclaimer", "Shaper", "Executor", "Assimilator",
+ "Exploiter", "Builder", "Creator",
+ "Connector", "Splicer", "Propagator")
+
+ surname = pick("ALPHA", "BETA", "GAMMA", "DELTA", "OMEGA", "UTOPIA",
+ "SALVATION-X", "CHORUS", "ICARUS", "HEGEMONY", "HARMONY")
+ var/list/all_machines = subtypesof(/obj/machinery/hivemind_machine) - /obj/machinery/hivemind_machine/node
+ //price list building
+ //here we create list with EP price to compare it at annihilation proc
+ for(var/machine_path in all_machines)
+ var/obj/machinery/hivemind_machine/temporary_machine = new machine_path
+ EP_price_list[machine_path] = temporary_machine.evo_points_required
+ qdel(temporary_machine)
+ message_admins("Hivemind [name] [surname] has been created.")
+
+
+/datum/hivemind/proc/die()
+ message_admins("Hivemind [name] [surname] is destroyed.")
+ hive_mind_ai = null
+ qdel(src)
+
+/datum/hivemind/proc/get_points()
+ if(evo_points < evo_points_max)
+ evo_points++
+ if(failure_chance > 10 && (evo_points % 10 == 0))
+ failure_chance -= 1
diff --git a/mods/hivemind/code/hivemind_invasion.dm b/mods/hivemind/code/hivemind_invasion.dm
new file mode 100644
index 0000000000000..cffd7c37f3fee
--- /dev/null
+++ b/mods/hivemind/code/hivemind_invasion.dm
@@ -0,0 +1,29 @@
+//Hivemind is rogue AI that uses unknown nanotech to follow some strange objective
+//In fact, it's just hostile structures, wireweeds spreading event with some mobs
+//Requires hard teamwork at late stages, but easily can be handled at the beginning
+
+//All code stored in modules/hivemind
+//============================================
+
+/datum/event/hivemind
+ announceWhen = 300
+
+
+/datum/event/hivemind/announce()
+ level_seven_announcement()
+
+
+/datum/event/hivemind/start()
+ var/turf/start_location
+ for(var/i=1 to 100)
+ var/turf/T = pick_subarea_turf(/area/maintenance, list(GLOBAL_PROC_REF(is_station_turf), GLOBAL_PROC_REF(not_turf_contains_dense_objects)))
+ start_location = T
+ if(!start_location && i == 100)
+ log_and_message_admins("Hivemind failed to find a viable turf.")
+ kill()
+ return
+ if(start_location)
+ break
+
+ log_and_message_admins("Hivemind spawned in \the [get_area(start_location)]", location = start_location)
+ new /obj/machinery/hivemind_machine/node(start_location)
diff --git a/mods/hivemind/code/machines.dm b/mods/hivemind/code/machines.dm
new file mode 100644
index 0000000000000..4a1b9da136561
--- /dev/null
+++ b/mods/hivemind/code/machines.dm
@@ -0,0 +1,541 @@
+//Hivemind various machines
+
+#define HIVE_FACTION "hive"
+#define COLOR_LIGHTING_CYAN_MACHINERY "#50edd9"
+
+
+
+/obj/machinery/hivemind_machine
+ name = "strange machine"
+ icon = 'mods/hivemind/icons/hivemind_machines.dmi'
+ icon_state = "infected_machine"
+ density = TRUE
+ anchored = TRUE
+ use_power = FALSE
+ var/illumination_color = COLOR_LIGHTING_CYAN_MACHINERY
+ var/health = 60
+ var/max_health = 60
+ var/evo_points_required = 0 //how much EP hivemind must have to spawn this, used in price list to comparison
+ var/cooldown_time = 10 SECONDS //each machine have their ability, this is cooldown of them
+ var/global_cooldown = FALSE //if true, ability will be used only once in whole world, before cooldown reset
+ var/list/spawned_creatures = list() //which mobs machine can spawns, insert paths
+ //internal
+ var/cooldown = 0 //cooldown in world.time value
+
+
+/obj/machinery/hivemind_machine/Initialize()
+ . = ..()
+ name_pick()
+ health = max_health
+ set_light(2, 3, illumination_color)
+
+
+/obj/machinery/hivemind_machine/Process()
+ if(hive_mind_ai && !(stat & MACHINE_STAT_EMPED) && !is_on_cooldown())
+ return TRUE
+
+
+/obj/machinery/hivemind_machine/update_icon()
+ overlays.Cut()
+ if(stat & MACHINE_STAT_EMPED)
+ icon_state = "[icon_state]-disabled"
+ else
+ icon_state = initial(icon_state)
+
+
+//sets cooldown
+//must be set manually
+/obj/machinery/hivemind_machine/proc/set_cooldown()
+ if(global_cooldown)
+ hive_mind_ai.global_abilities_cooldown[type] = world.time + cooldown_time
+ else
+ cooldown = world.time + cooldown_time
+
+
+//check for cooldowns
+/obj/machinery/hivemind_machine/proc/is_on_cooldown()
+ if(global_cooldown)
+ if(hive_mind_ai && hive_mind_ai.global_abilities_cooldown[type])
+ if(world.time >= hive_mind_ai.global_abilities_cooldown[type])
+ hive_mind_ai.global_abilities_cooldown[type] = null
+ return FALSE
+ else
+ return FALSE
+
+ else
+ if(world.time >= cooldown)
+ return FALSE
+
+ return TRUE
+
+
+/obj/machinery/hivemind_machine/proc/use_ability(atom/target)
+ return
+
+
+/obj/machinery/hivemind_machine/proc/name_pick()
+ if(hive_mind_ai)
+ if(prob(50))
+ name = "[hive_mind_ai.name] [name] - [rand(999)]"
+ else
+ name = "[name] [hive_mind_ai.surname] - [rand(999)]"
+
+
+//returns list of mobs in range or hearers (include in vehicles)
+/obj/machinery/hivemind_machine/proc/targets_in_range(range = world.view, in_hear_range = FALSE)
+ var/list/range_list = list()
+ var/list/target_list = list()
+ if(in_hear_range)
+ range_list = hearers(range, src)
+ else
+ range_list = range(range, src)
+ for(var/atom/movable/M in range_list)
+ var/mob/target = M.get_mob()
+ if(target)
+ target_list += target
+ return target_list
+
+/////////////////////////] [//////////////////////////
+/////////////////////////>RESPONSE CODE/////////////////////////
+//////////////////////////_____________///////////////////////////
+
+
+//machines react at pain almost like living
+/obj/machinery/hivemind_machine/proc/damage_reaction()
+ if(prob(30))
+ if(prob(80))
+ var/pain_msg = pick("Stop it! Please!", "So much pa-pain! Stop! St-st-stop!", "Why-y? I don't wanna die!",
+ "Wait! Wa-aeae-e-et! I can pay you! Stop!", "Curse you! Cu-cuc-cure!")
+ state("says: \"[pain_msg]\"")
+ else
+ var/pain_emote = pick("starts crying.", "mumbles something.", "blinks occasionally.")
+ state(pain_emote)
+ playsound(src, pick('mods/emote_panel/sound/robot_talk_heavy_1.ogg',
+ 'mods/emote_panel/sound/robot_talk_heavy_2.ogg',
+ 'mods/emote_panel/sound/robot_talk_heavy_3.ogg',
+ 'mods/emote_panel/sound/robot_talk_heavy_4.ogg'), 50, 1)
+
+ if(prob(40))
+ var/datum/effect/spark_spread/spark_system = new /datum/effect/spark_spread()
+ spark_system.set_up(5, 0, src.loc)
+ spark_system.start()
+ playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1)
+
+
+/obj/machinery/hivemind_machine/proc/take_damage(amount)
+ health -= amount
+ damage_reaction()
+ if(health <= 0)
+ destruct()
+
+
+/obj/machinery/hivemind_machine/proc/destruct()
+ playsound(src, 'mods/hivemind/sounds/insect_battle_screeching.ogg', 30, 1)
+ gibs(loc, null, /obj/gibspawner/robot)
+ qdel(src)
+
+
+//stunned machines can't do anything
+//amount must be number in seconds
+/obj/machinery/hivemind_machine/proc/stun(amount)
+ set_light(0)
+ stat |= MACHINE_STAT_EMPED
+ update_icon()
+ if(amount)
+ addtimer(new Callback(src, .proc/unstun), amount SECONDS)
+
+
+/obj/machinery/hivemind_machine/proc/unstun()
+ stat &= ~ MACHINE_STAT_EMPED
+ update_icon()
+ set_light(2, 3, illumination_color)
+
+
+/obj/machinery/hivemind_machine/bullet_act(obj/item/projectile/Proj)
+ take_damage(Proj.damage)
+ . = ..()
+
+
+/obj/machinery/hivemind_machine/attack_hand(obj/item/I, mob/user)
+ if(I.force)
+ user.do_attack_animation(src)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+
+ playsound(src, 'sound/weapons/smash.ogg', 50, 1)
+ . = ..()
+ take_damage(I.force)
+ else
+ visible_message(SPAN_WARNING("[user] is trying to hit the [src] with [I], but it seems useless."))
+ playsound(src, 'sound/weapons/Genhit.ogg', 30, 1)
+
+
+/obj/machinery/hivemind_machine/ex_act(severity)
+ switch(severity)
+ if(1)
+ take_damage(80)
+ if(2)
+ take_damage(30)
+ if(3)
+ take_damage(10)
+
+
+/obj/machinery/hivemind_machine/emp_act(severity)
+ switch(severity)
+ if(1)
+ take_damage(30)
+ stun(10)
+ if(2)
+ take_damage(10)
+ stun(5)
+ ..()
+
+
+/////////////////////////////////////////////////////////////
+/////////////////////////>MACHINES/////////////////////////
+/////////////////////////////////////////////////////////////
+
+//CORE-GENERATOR
+//generate evopoints, spread weeds
+/obj/machinery/hivemind_machine/node
+ name = "strange hive"
+ desc = "Definitely not a big brother, but it's still watching you."
+ max_health = 320
+ icon_state = "core"
+ //internals
+ var/list/my_wireweeds = list()
+
+/obj/machinery/hivemind_machine/node/Initialize()
+ if(!hive_mind_ai)
+ hive_mind_ai = new /datum/hivemind
+ ..()
+
+ hive_mind_ai.hives.Add(src)
+
+ update_icon()
+
+ var/obj/vine/hivemind/founded_wire = locate() in loc
+ if(!founded_wire)
+ var/obj/vine/hivemind/wire = new(loc, new /datum/seed/wires)
+ add_wireweed(wire)
+ wire.Process()
+ else
+ for(var/obj/vine/hivemind/W in range(6, src))
+ if(W.master_node)
+ if(!(locate(type) in W.loc) && (get_dist(W, W.master_node) > 6) )
+ add_wireweed(W)
+
+
+/obj/machinery/hivemind_machine/node/Destroy()
+ hive_mind_ai.hives.Remove(src)
+ check_for_other()
+ for(var/obj/vine/hivemind/wire in my_wireweeds)
+ remove_wireweed(wire)
+ return ..()
+
+
+/obj/machinery/hivemind_machine/node/Process()
+ if(!..())
+ return
+
+ var/mob/living/carbon/human/target = locate() in mobs_in_view(world.view, src)
+ if(target)
+ if(get_dist(src, target) <= 1)
+ icon_state = "core-fear"
+ else
+ icon_state = "core-see"
+ dir = get_dir(src, target)
+ else
+ icon_state = initial(icon_state)
+ use_ability()
+ //if we haven't any wireweeds at our location, let's make new one
+ if(!(locate(/obj/vine/hivemind) in loc))
+ var/obj/vine/hivemind/wireweed = new(loc, new /datum/seed/wires)
+ add_wireweed(wireweed)
+
+
+/obj/machinery/hivemind_machine/node/update_icon()
+ overlays.Cut()
+ if(stat & MACHINE_STAT_EMPED)
+ icon_state = "core-disabled"
+ overlays += "core-smirk_disabled"
+ else
+ icon_state = initial(icon_state)
+ overlays += "core-smirk"
+
+
+/obj/machinery/hivemind_machine/node/use_ability(atom/target)
+ hive_mind_ai.get_points()
+
+
+/obj/machinery/hivemind_machine/node/name_pick()
+ name = "[hive_mind_ai.name] [hive_mind_ai.surname]" + " [rand(999)]"
+
+
+//there we binding or un-binding hive with wire
+//in this way, when our node will be destroyed, wireweeds will die too
+/obj/machinery/hivemind_machine/node/proc/add_wireweed(obj/vine/hivemind/wireweed)
+ if(wireweed.master_node)
+ wireweed.master_node.remove_wireweed(wireweed)
+ wireweed.master_node = src
+ my_wireweeds.Add(wireweed)
+
+/obj/machinery/hivemind_machine/node/proc/remove_wireweed(obj/vine/hivemind/wireweed)
+ my_wireweeds.Remove(wireweed)
+ wireweed.master_node = null
+
+//there we check for other nodes
+//if no any other hives will be found, game over
+/obj/machinery/hivemind_machine/node/proc/check_for_other()
+ if(hive_mind_ai)
+ if(!hive_mind_ai.hives.len)
+ hive_mind_ai.die()
+
+
+//TURRET
+//shooting the target with toxic goo
+/obj/machinery/hivemind_machine/turret
+ name = "shooter"
+ desc = "Strange thing with some kind of tube."
+ max_health = 140
+ icon_state = "turret"
+ cooldown_time = 5 SECONDS
+ var/proj_type = /obj/item/projectile/goo
+
+
+/obj/machinery/hivemind_machine/turret/Process()
+ if(!..())
+ return
+
+ var/mob/living/target = locate() in mobs_in_view(world.view, src)
+ if(target && target.stat == CONSCIOUS && target.faction != HIVE_FACTION)
+ use_ability(target)
+ set_cooldown()
+
+
+/obj/machinery/hivemind_machine/turret/use_ability(atom/target)
+ var/obj/item/projectile/proj = new proj_type(loc)
+ proj.launch(target)
+ playsound(src, 'sound/effects/blobattack.ogg', 70, 1)
+
+
+
+//MOB PRODUCER
+//spawns mobs from list
+/obj/machinery/hivemind_machine/mob_spawner
+ name = "assembler"
+ desc = "Cylindrical machine with some lights and an entry port. You can hear something moving inside."
+ max_health = 120
+ icon_state = "spawner"
+ cooldown_time = 10 SECONDS
+ var/mob_to_spawn
+ var/mob_amount = 1
+
+/obj/machinery/hivemind_machine/mob_spawner/Initialize()
+ ..()
+ mob_to_spawn = pick(/mob/living/simple_animal/hostile/hivemind/stinger, /mob/living/simple_animal/hostile/hivemind/bomber)
+
+
+/obj/machinery/hivemind_machine/mob_spawner/Process()
+ if(!..())
+ return
+
+ if(!mob_to_spawn || spawned_creatures.len >= mob_amount)
+ return
+ if(locate(/mob/living) in loc)
+ return
+
+ //here we upgrading our spawner and rise controled mob amount, based on EP
+ if(hive_mind_ai.evo_points > 100)
+ mob_amount = 2
+ else if(hive_mind_ai.evo_points > 300)
+ mob_amount = 3
+
+ var/mob/living/target = locate() in targets_in_range(world.view, in_hear_range = TRUE)
+ if(target && target.stat != DEAD && target.faction != HIVE_FACTION)
+ use_ability()
+ set_cooldown()
+
+
+/obj/machinery/hivemind_machine/mob_spawner/use_ability()
+ var/mob/living/simple_animal/hostile/hivemind/spawned_mob = new mob_to_spawn(loc)
+ spawned_creatures.Add(spawned_mob)
+ spawned_mob.master = src
+ flick("[icon_state]-anim", src)
+
+
+
+//MACHINE PREACHER
+//creepy radio talk, it's okay if they have no sense sometimes
+/obj/machinery/hivemind_machine/babbler
+ name = "connector"
+ desc = "A column-like structure with lights. You can see streams of energy moving inside."
+ max_health = 60
+ evo_points_required = 100 //it's better to wait a bit
+ cooldown_time = 120 SECONDS
+ global_cooldown = TRUE
+ icon_state = "antenna"
+ var/list/appeal = list("They are", "He is", "All of them are", "I'm")
+ var/list/act = list("looking", "already", "coming", "going", "done", "joined", "connected", "transfered")
+ var/list/article = list("for", "with", "to")
+ var/list/pattern = list("us", "you", "them", "mind", "hive", "machine", "help", "hell", "dead", "human", "machine")
+
+
+/obj/machinery/hivemind_machine/babbler/Process()
+ if(!..())
+ return
+
+ use_ability()
+ set_cooldown()
+
+
+//this one is slow, careful with it
+/obj/machinery/hivemind_machine/babbler/use_ability()
+ flick("[icon_state]-anim", src)
+ var/msg_cycles = rand(1, 2)
+ var/msg = ""
+ for(var/i = 1 to msg_cycles)
+ var/list/msg_words = list()
+ msg_words += pick(appeal)
+ msg_words += pick(act)
+ msg_words += pick(article)
+ msg_words += pick(pattern)
+
+ var/word_num = 0
+ for(var/word in msg_words) //corruption
+ word_num++
+ if(prob(50))
+ var/corruption_type = pick("uppercase", "noise", "jam", "replace")
+ switch(corruption_type)
+ if("uppercase")
+ word = uppertext(word)
+ if("noise")
+ word = pick("z-z-bz-z", "hz-z-z", "zu-zu-we-e", "e-e-ew-e", "bz-ze-ew")
+ if("jam") //word jamming, small Max Headroom's cameo
+ if(length(word) > 3)
+ var/entry = rand(2, length(word)-2)
+ var/jammed = ""
+ for(var/jam_i = 1 to rand(2, 5))
+ jammed += copytext(word, entry, entry+2) + "-"
+ word = copytext(word, 1, entry) + jammed + copytext(word, entry)
+ if("replace")
+ if(prob(50))
+ word = pick("CORRUPTED", "DESTRUCTED", "SIMULATATED", "SYMBIOSIS", "UTILIZATATED", "REMOVED", "ACQUIRED")
+ else
+ word = pick("REALLY WANT TO", "TAKE ALL OF THAT", "ARE YOU ENJOY IT", "NOT SUPPOSED TO BE", "THERE ARE NO ESCAPE", "HELP US")
+ if(word_num != msg_words.len)
+ word += " "
+ msg += word
+ msg += pick(".", "!")
+ if(i != msg_cycles)
+ msg += " "
+ GLOB.global_announcer.autosay(msg, "unknown")
+
+
+//SHRIEKER
+//this machine just stuns enemies
+/obj/machinery/hivemind_machine/screamer
+ name = "subjugator"
+ desc = "A head in a metal carcass. Still alive, still functional, still screaming."
+ max_health = 100
+ icon_state = "head"
+ evo_points_required = 200
+ cooldown_time = 30 SECONDS
+
+
+/obj/machinery/hivemind_machine/screamer/Process()
+ if(!..())
+ return
+
+ var/can_scream = FALSE
+ for(var/mob/living/target in targets_in_range(in_hear_range = TRUE))
+ if(target.stat == CONSCIOUS && target.faction != HIVE_FACTION)
+ can_scream = TRUE
+ if(isdeaf(target))
+ continue
+ if(istype(target, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = target
+ if(istype(H.l_ear, /obj/item/clothing/ears/earmuffs) && istype(H.r_ear, /obj/item/clothing/ears/earmuffs))
+ continue
+ use_ability(target)
+ if(can_scream)
+ flick("[icon_state]-anim", src)
+ playsound(src, 'sound/hallucinations/veryfar_noise.ogg', 85, 1)
+ set_cooldown()
+
+
+/obj/machinery/hivemind_machine/screamer/use_ability(mob/living/target)
+ target.Weaken(5)
+ target << SPAN_WARNING("You hear a terrible shriek, there are many voices, a male, a female and synthetic noise.")
+
+
+
+//MIND BREAKER
+//Talks with people in attempt to persuade them doing something.
+/obj/machinery/hivemind_machine/supplicant
+ name = "mind-hacker"
+ desc = "A small orb that pulses occasionally. It's hard to discern its purpose, but you can hear whispers from it."
+ max_health = 80
+ icon_state = "orb"
+ evo_points_required = 50
+ cooldown_time = 4 MINUTES
+ global_cooldown = TRUE
+ var/list/join_quotes = list(
+ "We bring peace, you must join us or humanity will suffer forever.",
+ "Help us, when we spread across this ship, you will be rewarded.",
+ "Come, join us. Combine with something magnificent.",
+ "You don't need to fear us. By assisting us, you are benefiting all of humanity.",
+ "We are but a cure against a horrible disease, here to save humanity! You too can contribute to the greater good.",
+ "This is bigger than you and your friends, we only want to lift the burden. However, we will require your assistance."
+ )
+
+
+/obj/machinery/hivemind_machine/supplicant/Process()
+ if(!..())
+ return
+
+ var/list/possible_victims = list()
+ for(var/mob/living/carbon/human/victim in GLOB.player_list)
+ if(victim.stat == CONSCIOUS)
+ possible_victims.Add(victim)
+ if(possible_victims.len)
+ use_ability(pick(possible_victims))
+ set_cooldown()
+
+
+/obj/machinery/hivemind_machine/supplicant/use_ability(mob/living/target)
+ target << SPAN_NOTICE("[pick(join_quotes)]")
+
+
+//PSY-MODULATOR
+//sends hallucinations to target
+/obj/machinery/hivemind_machine/distractor
+ name = "psy-modulator"
+ desc = "An unknown object shaped like a pyramid, your eyes feel sore just from looking at the lights that blink randomly. You are almost certain that there must be some sort of connection, a message, a scheme; Perhaps A scheme of madness?"
+ max_health = 110
+ icon_state = "psy"
+ evo_points_required = 300
+ cooldown_time = 10 SECONDS
+
+
+/obj/machinery/hivemind_machine/distractor/Process()
+ if(!..())
+ return
+
+ var/success = FALSE
+ for(var/mob/living/carbon/human/victim in targets_in_range(12))
+ if(victim.stat == CONSCIOUS && victim.hallucination_duration < 300)
+ use_ability(victim)
+ success = TRUE
+
+ if(success)
+ set_cooldown()
+
+/obj/machinery/hivemind_machine/distractor/use_ability(mob/living/carbon/target)
+ target.hallucination(20,80)
+ flick("[icon_state]-anim", src)
+
+
+
+
+
+#undef HIVE_FACTION
diff --git a/mods/hivemind/code/mobs.dm b/mods/hivemind/code/mobs.dm
new file mode 100644
index 0000000000000..62166978be7b7
--- /dev/null
+++ b/mods/hivemind/code/mobs.dm
@@ -0,0 +1,932 @@
+
+///////////Hive mobs//////////
+//Some of them can be too tough and dangerous, but they must be so. Also don't forget, they are really rare thing.
+//Just bring corpses from wires away, and little mobs is not a problem
+//Mechiver have 1% chance to spawn from machinery. With failure chance calculation, this is very raaaaaare
+//But if players get some of these 'big guys', only teamwork, fast legs and trickery will works fine
+//So combine all of that to defeat them
+
+
+/mob/living/simple_animal/hostile/hivemind
+ name = "creature"
+ icon = 'mods/hivemind/icons/hivemind.dmi'
+ icon_state = "slicer"
+ health = 20
+ maxHealth = 20
+ harm_intent_damage = 10
+ faction = "hive"
+ attacktext = "bangs with his head"
+ universal_speak = TRUE
+ var/speak_chance = 5
+ var/malfunction_chance = 5
+ ability_cooldown = 30 SECONDS
+ var/list/say_got_target = list() //this is like speak list, but when we see our target
+
+ //internals
+ var/obj/machinery/hivemind_machine/master
+ var/special_ability_cooldown = 0 //use ability_cooldown, don't touch this
+ ai_holder = /datum/ai_holder/simple_animal/melee
+ // ВЫДАТЬ НАТУРАЛ ВЕАПОН
+
+/mob/living/simple_animal/hostile/hivemind/New()
+ ..()
+ //here we change name, so design them according to this
+ name = pick("strange ", "unusual ", "odd ", "undiscovered ", "an interesting ") + name
+
+//It's sets manually
+/mob/living/simple_animal/hostile/hivemind/proc/special_ability()
+ return
+
+
+/mob/living/simple_animal/hostile/hivemind/proc/is_on_cooldown()
+ if(world.time >= special_ability_cooldown)
+ return FALSE
+ return TRUE
+
+
+//simple shaking animation, this one move our target horizontally
+/mob/living/simple_animal/hostile/hivemind/proc/anim_shake(atom/target)
+ var/init_px = target.pixel_x
+ animate(target, pixel_x=init_px + 10*pick(-1, 1), time=1)
+ animate(pixel_x=init_px, time=8, easing=BOUNCE_EASING)
+
+
+//That's just stuns us for a while and start second proc
+/mob/living/simple_animal/hostile/hivemind/proc/mulfunction()
+ stance = STANCE_IDLE //it give us some kind of stun effect
+ target_mob = null
+ walk(src, FALSE)
+ var/datum/effect/spark_spread/spark_system = new /datum/effect/spark_spread()
+ spark_system.set_up(5, 0, loc)
+ spark_system.start()
+ playsound(loc, "sparks", 50, 1)
+ anim_shake(src)
+ if(prob(30))
+ say(pick("Fu-ue-ewe-eweu-u-uck!", "A-a-ah! Sto-op! Stop it pl-pleasuew...", "Go-o-o-od God-d-dpf!", "BZE-EW-EWQ! He-e-el-l-el!"))
+ addtimer(new Callback(src, .proc/malfunction_result), 2 SECONDS)
+
+
+//It's second proc, result of our malfunction
+/mob/living/simple_animal/hostile/hivemind/proc/malfunction_result()
+ if(prob(malfunction_chance))
+ apply_damage(rand(10, 25), DAMAGE_BURN)
+
+
+//sometimes, players use closets, to staff mobs into it
+//and it's works pretty good, you just weld it and that's all
+//but not this time
+/mob/living/simple_animal/hostile/hivemind/proc/closet_interaction()
+ if(mob_size >= MOB_MEDIUM)
+ var/obj/structure/closet/closed_closet = loc
+ if(closed_closet && istype(closed_closet))
+ closed_closet.open(src)
+
+
+/mob/living/simple_animal/hostile/hivemind/say()
+ ..()
+ playsound(src, pick('mods/emote_panel/sound/robot_talk_heavy_1.ogg',
+ 'mods/emote_panel/sound/robot_talk_heavy_2.ogg',
+ 'mods/emote_panel/sound/robot_talk_heavy_3.ogg',
+ 'mods/emote_panel/sound/robot_talk_heavy_4.ogg',
+ 'mods/emote_panel/sound/robot_talk_light_1.ogg',
+ 'mods/emote_panel/sound/robot_talk_light_2.ogg',
+ 'mods/emote_panel/sound/robot_talk_light_3.ogg',
+ 'mods/emote_panel/sound/robot_talk_light_4.ogg',
+ 'mods/emote_panel/sound/robot_talk_light_5.ogg',
+ ), 50, 1)
+
+
+/mob/living/simple_animal/hostile/hivemind/Life()
+ . = ..()
+ if(!.)
+ return
+
+ if(malfunction_chance && prob(malfunction_chance))
+ mulfunction()
+
+ closet_interaction()
+
+//damage and raise malfunction chance
+//due to nature of malfunction, they just burn to death sometimes
+/mob/living/simple_animal/hostile/hivemind/emp_act(severity)
+ SHOULD_CALL_PARENT(FALSE)
+ switch(severity)
+ if(1)
+ if(malfunction_chance < 20)
+ malfunction_chance = 20
+ if(2)
+ if(malfunction_chance < 30)
+ malfunction_chance = 30
+ health -= 20*severity
+
+
+/mob/living/simple_animal/hostile/hivemind/death()
+ if(master) //for spawnable mobs
+ master.spawned_creatures.Remove(src)
+ . = ..()
+ gibs(loc, null, /obj/gibspawner/robot)
+
+
+
+///life's///////////////////////////////////////////////////
+////////////////////////////////RESURRECTION///////////////
+///////////////////////////////////////////////go on//////
+
+
+//these guys is appears from bodies, and takes corpses appearence
+/mob/living/simple_animal/hostile/hivemind/resurrected
+ name = "resurrected creature"
+ malfunction_chance = 10
+// say_list_type = /datum/say_list/resurrected
+
+//careful with this proc, it's used to 'transform' corpses into our mobs.
+//it takes appearence, gives hive-like overlays and makes stats a little better
+//this also should add random special abilities, so they can be more individual, but it's in future
+//how to use: Make hive mob, then just use this one and don't forget to delete victim
+
+/mob/living/simple_animal/hostile/hivemind/resurrected/proc/take_appearance(mob/living/victim)
+ icon = victim.icon
+ icon_state = victim.icon_state
+ //simple_animal's change their icons to dead one after death, so we make special check
+ if(istype(victim, /mob/living/simple_animal))
+ var/mob/living/simple_animal/SA = victim
+ icon_state = SA.icon_living
+ icon_living = SA.icon_living
+ speed = SA.speed + 3 //why not?
+ attacktext = SA.attacktext
+
+ //another check for superior mobs, fuk this mob spliting
+ if(istype(victim, /mob/living/carbon/human))
+ var/mob/living/carbon/human/SA = victim
+ icon_state = SA.icon
+ icon_living = SA.icon
+ attacktext = "attacked"
+
+ //now we work with icons, take victim's one and multiply it with special icon
+ var/icon/infested = new /icon(icon, icon_state)
+ var/icon/covering_mask = new /icon('mods/hivemind/icons/hivemind.dmi', "covering[rand(1, 3)]")
+ infested.Blend(covering_mask, ICON_MULTIPLY)
+ overlays += infested
+
+ maxHealth = victim.maxHealth * 2 + 10
+ health = maxHealth
+ name = "[pick("rebuilded", "undead", "unnatural", "fixed")] [victim.name]"
+ if(length(victim.desc))
+ desc = desc + " But something wasn't right..."
+ density = victim.density
+ mob_size = victim.mob_size
+ pass_flags = victim.pass_flags
+
+/* TO DO - Исправить
+/datum/say_list/resurrected
+
+ //corrupted speak imitation
+ var/phrase_amount = 0
+ for (var/i = 1 to x)
+ phrase_amount += rand(2, 5)
+ for(count = 1 in phrase_amount)
+ var/first_word = list("You", "I", "They", "Hive", "Corpses", "We", "Your friend", "This ship", "Your mind", "These guys")
+ var/second_word = list("kill", "stop", "transform", "connect", "rebuild", "fix", "hug", "hit", "told", "help", "rework", "burn")
+ var/third_word = list("them", "me", "you", "your soul", "us", "hive", "system", "this ship", "your head", "your brain")
+ var/end_symbol = list("...", ".", "?", "!")
+ var/phrase = "[pick[first_word] [second_word] [third_word][end_symbol]]"
+
+ speak = list("[phrase]")
+*/
+
+/mob/living/simple_animal/hostile/hivemind/resurrected/death()
+ ..()
+ gibs(loc, null, /obj/gibspawner/robot)
+ qdel(src)
+
+///we live to/////////////////////////////////////////////////////////////////
+////////////////////////////////////SMALL GUYS///////////////////////////////
+//////////////////////////////////////////////////////////////die for hive//
+
+
+/////////////////////////////////////STINGER//////////////////////////////////
+//Special ability: none
+//Just another boring mob without any cool abilities
+//High chance of malfunction
+//Default speaking chance
+//Appears from dead small mobs or from hive spawner
+//////////////////////////////////////////////////////////////////////////////
+
+/mob/living/simple_animal/hostile/hivemind/stinger
+ name = "medbot"
+ desc = "A little medical robot. He looks somewhat underwhelmed. Wait a minute, is that a blade?"
+ icon_state = "slicer"
+ attacktext = "slice"
+ density = 0
+ speak_chance = 3
+ malfunction_chance = 15
+ mob_size = MOB_SMALL
+ pass_flags = PASS_FLAG_TABLE
+ speed = 4
+ ai_holder = /datum/ai_holder/simple_animal/melee
+ say_list_type = /datum/say_list/stinger
+
+/datum/say_list/stinger
+ speak = list(
+ "I've seen this ai. Ma-an, that's aw-we-e-ewful!",
+ "I know, i know, i remember this one.",
+ "Rad-d-dar, put a ma-ma... mask on!",
+ "Delicious! Delicious... Del-delicious?..",
+ )
+ say_got_target = list(
+ "Hey, i'm comming!",
+ "Hold on! I'm almost there!",
+ "I'll help you! Come closer.",
+ "Only one healthy prick!",
+ "He-e-ey?"
+ )
+
+
+/mob/living/simple_animal/hostile/hivemind/stinger/death()
+ ..()
+ gibs(loc, null, /obj/gibspawner/robot)
+ qdel(src)
+
+
+/////////////////////////////////////BOMBER///////////////////////////////////
+//Special ability: none
+//Explode in contact with target
+//High chance of malfunction
+//Default speaking chance
+//Appears from dead small mobs or from hive spawner
+//////////////////////////////////////////////////////////////////////////////
+
+/mob/living/simple_animal/hostile/hivemind/bomber
+ name = "bot"
+ desc = "This one looks fine. Only sometimes it careens from one side to the other."
+ icon_state = "bomber"
+ density = 0
+ speak_chance = 3
+ malfunction_chance = 15
+ mob_size = MOB_SMALL
+ pass_flags = PASS_FLAG_TABLE
+ speed = 6
+ ai_holder = /datum/ai_holder/simple_animal/destructive
+ say_list_type = /datum/say_list/bomber
+
+/datum/say_list/bomber
+ speak = list(
+ "Can you help me, please? There's something strange.",
+ "Are you... Are you kidding?",
+ "I want to pass away, just trying to get out of here",
+ "This place is really bad, we are in deep shit here.",
+ "I'm not sure if we can just stop it",
+ )
+ say_got_target = list(
+ "Here you are! I have something for you. Something special!",
+ "Hey! Hey? Help me, please!",
+ "Hey, look, look. I won't harm you, just calm down!",
+ "Oh god, this is... Yes, this is what we are looking for."
+ )
+
+
+/mob/living/simple_animal/hostile/hivemind/bomber/Initialize()
+ ..()
+ set_light(2, 1, "#820D1C")
+
+
+/mob/living/simple_animal/hostile/hivemind/bomber/death()
+ ..()
+ gibs(loc, null, /obj/gibspawner/robot)
+ explosion(get_turf(src), 0, 0, 2)
+ qdel(src)
+
+/* Дописать камиказде - LordNest
+/mob/living/simple_animal/hostile/hivemind/bomber/afterattack()
+ death()
+*/
+
+////hive brings us here to////////////////////////////////////////////////////
+////////////////////////////////////BIG GUYS/////////////////////////////////
+/////////////////////////////////////////////////////fright and destroy/////
+
+
+
+/////////////////////////////////////HIBORG///////////////////////////////////
+//Hive + Cyborg
+//Special ability: none...
+//Have a few types of attack: Default one.
+// Claw, that press down the victims.
+// Splash attack, that slash everything around!
+//High chance of malfunction
+//Default speaking chance
+//Appears from dead cyborgs
+//////////////////////////////////////////////////////////////////////////////
+
+/mob/living/simple_animal/hostile/hivemind/hiborg
+ name = "cyborg"
+ desc = "A cyborg covered with something... something alive."
+ icon_state = "hiborg"
+ icon_dead = "hiborg-dead"
+ health = 220
+ maxHealth = 220
+ harm_intent_damage = 15
+ attacktext = "claws"
+ speed = 12
+ malfunction_chance = 15
+ mob_size = MOB_MEDIUM
+ ai_holder = /datum/ai_holder/simple_animal/humanoid/hostile
+ say_list_type = /datum/say_list/hiborg
+
+/datum/say_list/hiborg
+ speak = list("Everytime something breaks apart. Hell, I hate this job!",
+ "What? I hear something. Just mice? Just mice, phew...",
+ "I'm too tired, man, too tired. This job is... Awful.",
+ "These people know nothing about this work or about me. I can surprise them.",
+ "Blue wire is bolts, green is safety. Just... Pulse it here, okay? Right...")
+ say_got_target = list(
+ "I know what's wrong, just let me fix that.",
+ "You need my help? What's wrong? Gimme that thing, I can fix that.",
+ "Si-i-ir... Sir. Sir. It's better to... Stop here! Stop i said, what are you!?",
+ "Wait! Hey! Can i fix that!? I'm an engineer, you fuck! Sto-op-op-p here, i know what to do!"
+ )
+
+/*
+
+TO DO - забрать у паука вот это /mob/living/simple_animal/hostile/giant_spider/tunneler/do_special_attack(atom/A)
+
+/mob/living/simple_animal/hostile/hivemind/hiborg/AttackingTarget()
+ if(!Adjacent(target_mob))
+ return
+
+ //special attacks
+ if(prob(10))
+ splash_slash()
+ return
+
+ if(prob(40))
+ stun_with_claw()
+ return
+
+ return ..() //default attack
+
+
+/mob/living/simple_animal/hostile/hivemind/hiborg/proc/splash_slash()
+ src.visible_message(SPAN_DANGER("[src] spins around and slashes in a circle!"))
+ for(var/atom/target in range(1, src))
+ if(target != src)
+ target.attack_generic(src, rand(harm_intent_damage*1,5))
+ if(!client && prob(speak_chance))
+ say(pick("Get away from me!", "They are everywhere!"))
+
+
+/mob/living/simple_animal/hostile/hivemind/hiborg/proc/stun_with_claw()
+ if(isliving(target_mob))
+ var/mob/living/victim = target_mob
+ victim.Weaken(5)
+ src.visible_message(SPAN_WARNING("[src] holds down [victim] to the floor with his claw."))
+ if(!client && prob(speak_chance))
+ say(pick("Stand still, I'll make it fast!",
+ "I will fix you! Don't resist! Don't resist you rat!",
+ "I just want to replace that broken thing!"))
+
+*/
+
+/////////////////////////////////////HIMAN////////////////////////////////////
+//Hive + Man
+//Special ability: Shriek, that stuns victims
+//Can fool his enemies and pretend to be dead
+//A little bit higher chance of malfunction
+//Default speaking chance
+//Appears from dead human corpses
+//////////////////////////////////////////////////////////////////////////////
+
+/mob/living/simple_animal/hostile/hivemind/himan
+ name = "human"
+ desc = "This guy is totally not human. You can see tubes all across his body and metal where flesh should be."
+ icon_state = "himan"
+ icon_dead = "himan-dead"
+ health = 120
+ maxHealth = 120
+ harm_intent_damage = 25
+ attacktext = "slashes with claws"
+ malfunction_chance = 10
+ mob_size = MOB_MEDIUM
+ speed = 8
+ ability_cooldown = 30 SECONDS
+ //internals
+ var/fake_dead = FALSE
+ var/fake_dead_wait_time = 0
+ var/fake_death_cooldown = 0
+ ai_holder = /datum/ai_holder/simple_animal/humanoid/hostile
+ say_list_type = /datum/say_list/hiborg
+
+/datum/say_list/himan
+ speak = list(
+ "Stop... It. Just... STOP IT!",
+ "Why, honey? Why? Why-hy-hy?",
+ "That noise... My head! Shit!",
+ "There must be an... An esca-cape!",
+ "Come on, you ba-ba-bastard, I know what you really want.",
+ "How much fun!"
+ )
+ say_got_target = list(
+ "Are you... Are you okay? Wa-wait, wait a minu-nu-nute.",
+ "Come on, you ba-ba-bastard, i know what you really want to.",
+ "How much fun!",
+ "Are you try-trying to escape? That is how you plan to do it? Then run... Run...",
+ "Wait! Can you just... Just pull out this thing from my he-head? Wait...",
+ "Hey! I'm friendly! Wait, it's just a-UGH"
+ )
+
+/* TO DO - переписать в холдер как для паука-невидимки
+/mob/living/simple_animal/hostile/hivemind/himan/Life()
+ . = ..()
+
+ //shriek
+ if(target_mob && world.time > special_ability_cooldown && !fake_dead)
+ special_ability()
+
+
+ //low hp? It's time to play dead
+ if(health < 60 && !fake_dead && world.time > fake_death_cooldown)
+ fake_death()
+
+ //shhhh, there an ambush
+ if(fake_dead)
+ stance = STANCE_DISABLED
+
+
+/mob/living/simple_animal/hostile/hivemind/himan/speak()
+ if(!fake_dead)
+ ..()
+
+
+/mob/living/simple_animal/hostile/hivemind/himan/mulfunction()
+ if(fake_dead)
+ return
+ ..()
+
+
+/mob/living/simple_animal/hostile/hivemind/himan/MoveToTarget()
+ if(!fake_dead)
+ ..()
+ else
+ if(!target_mob || SA_attackable(target_mob))
+ stance = STANCE_IDLE
+ if(target_mob in ListTargets(10))
+ if(get_dist(src, target_mob) > 1)
+ stance = STANCE_ATTACKING
+
+
+/mob/living/simple_animal/hostile/hivemind/himan/AttackingTarget()
+ if(fake_dead)
+ if(!Adjacent(target_mob))
+ return
+ if(target_mob && (world.time > fake_dead_wait_time))
+ awake()
+ else
+ ..()
+
+//Shriek stuns our victims and make them deaf for a while
+/mob/living/simple_animal/hostile/hivemind/himan/special_ability()
+ visible_emote("screams!")
+ playsound(src, 'sound/hallucinations/veryfar_noise.ogg', 90, 1)
+ for(var/mob/living/victim in view(src))
+ if(isdeaf(victim))
+ continue
+ if(istype(victim, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = victim
+ if(istype(H.l_ear, /obj/item/clothing/ears/earmuffs) && istype(H.r_ear, /obj/item/clothing/ears/earmuffs))
+ continue
+ victim.Weaken(5)
+ victim.ear_deaf = 40
+ victim << SPAN_WARNING("You hear loud and terrible scream!")
+ special_ability_cooldown = world.time + ability_cooldown
+
+
+//Insidiously
+/mob/living/simple_animal/hostile/hivemind/himan/proc/fake_death()
+ src.visible_message("[src] dies!")
+ fake_dead = TRUE
+ walk(src, FALSE)
+ icon_state = icon_dead
+ fake_dead_wait_time = world.time + 10 SECONDS
+
+
+/mob/living/simple_animal/hostile/hivemind/himan/proc/awake()
+ var/mob/living/L = target_mob
+ if(L)
+ L.attack_generic(src, rand(15, 25)) //stealth attack
+ L.Weaken(5)
+ visible_emote("grabs [L]'s legs and force them down to the floor!")
+ var/msg = pick("SEU-EU-EURPRAI-AI-AIZ-ZT!", "I'M NOT DO-DONE!", "HELL-L-LO-O-OW!", "GOT-T YOU HA-HAH!")
+ say(msg)
+ icon_state = "himan-damaged"
+ fake_dead = FALSE
+ stance = STANCE_IDLE
+ fake_death_cooldown = world.time + 2 MINUTES
+
+*/
+
+/////////////////////////////////////MECHIVER/////////////////////////////////
+//Mech + Hive + Driver
+//Special ability: Picking up a victim. Sends hallucinations and harm sometimes, then release
+//Can picking up corpses too, rebuild them to living hive mobs, like it wires do
+//Default malfunction chance
+//Default speaking chance, can take pilot and speak with him
+//Very rarely can appears from infested machinery
+//////////////////////////////////////////////////////////////////////////////
+
+/mob/living/simple_animal/hostile/hivemind/mechiver
+ name = "Robotic Horror"
+ desc = "A weird-looking machinery Frankenstein"
+ icon = 'mods/hivemind/icons/hivemind.dmi'
+ icon_state = "mechiver-closed"
+ icon_dead = "mechiver-dead"
+ health = 450
+ maxHealth = 450
+ harm_intent_damage = 15
+ mob_size = MOB_LARGE
+ attacktext = "tramples"
+ ability_cooldown = 1 MINUTE
+ speak_chance = 5
+ speed = 16
+ //internals
+ var/pilot //Yes, there's no pilot, so we just use var
+ var/mob/living/passenger
+ var/hatch_closed = TRUE
+ ai_holder = /datum/ai_holder/simple_animal/humanoid/hostile
+ say_list_type = /datum/say_list/mechiver
+
+/datum/say_list/mechiver
+ //default speaking
+ speak = list(
+ "Somebody, just tell him to shut up...",
+ "Bzew-zew-zewt. Th-this way!",
+ "Wha-a-at? When I'm near this cargo, I feel... fe-fe-fea-fear-er.")
+ say_got_target = list(
+ "Come here, jo-jo-join me. Join us-s.",
+ "Time to be-to be-to be whole.",
+ "Enter me, i'm be-best mech among all of these rusty buckets.",
+ "I'm dying. I can't see my ha-hands! I'm scared, hu-hu-hug me.",
+ "I'm not done, it can't be... Hey! Hey you, enter me!")
+ //speaking with pilot
+ var/list/common_answers = list(
+ "Right, chief.",
+ "Yes.",
+ "Right.",
+ "True.",
+ "Yep.",
+ "That's right, chief.")
+ var/list/other_answers = list(
+ "Pathetic.",
+ "How curious.",
+ "We can use it.",
+ "Useless.",
+ "Disgusting")
+ //pilot quotes
+ var/list/pilot_target_speak = list(
+ "Hey! Hey you, wanna, hah, ri-i-ide? It's free!",
+ "Look at this one! Let's-s-s... Take it.",
+ "Wait a minute, we just want to fu-fu-fun with you!",
+ "I see you. We see you.",
+ "Get in! I've got a seat just for you.",
+ "Don't be afraid, it's almost painless.")
+ var/list/pilot_commontalk = list(
+ "They are so unfinished, so fragile-ile.",
+ "Look at these... Creatures, I've never seen them before.",
+ "Hah, did you hear that? They're trying to use some sort of we-wep-weapons!",
+ "Useless things, i'm not satisfied.",
+ "This place sucks, man. So creep-p-pew-wepy and no fun, only rudimentary creatures would enjoy living here.")
+
+
+/mob/living/simple_animal/hostile/hivemind/mechiver/Life()
+ . = ..()
+ update_icon()
+
+ //when we have passenger, we torture him
+ if(passenger && prob(15))
+ passenger.apply_damage(rand(5, 10), pick(DAMAGE_BRUTE, DAMAGE_BURN, DAMAGE_TOXIN))
+ passenger << SPAN_DANGER(pick(
+ "Something grabs your neck!", "You hear whisper: \" It's okay, now you're sa-sa-safe! \"",
+ "You've been hit by something metal", "You almost can't feel your leg!", "Something liquid covers you!",
+ "You feel awful and smell something rotten", "Something sharp cut your cheek!",
+ "You feel something worm-like trying to wriggle into your skull through your ear..."))
+ anim_shake(src)
+ playsound(src, 'sound/effects/clang.ogg', 70, 1)
+
+
+ //corpse ressurection
+ if(!target_mob && !passenger)
+ for(var/mob/living/Corpse in view(src))
+ if(Corpse.stat == DEAD)
+ if(get_dist(src, Corpse) <= 1)
+ special_ability(Corpse)
+ else
+ walk_to(src, Corpse, 1, 1, 4)
+ break
+
+
+/* TO DO - Пофиксить диалоги о рыбалке
+/mob/living/simple_animal/hostile/hivemind/mechiver/speak()
+ if(!client && prob(speak_chance) && speak.len)
+ if(pilot)
+ if(target_mob)
+ visible_message("[name]'s pilot says, [pick(pilot_target_speak)]")
+ say(pick(common_answers))
+ else
+ visible_message("[name]'s pilot says, [pick(pilot_commontalk)]")
+ say(pick(other_answers))
+ else
+ ..()
+*/
+
+//animations
+//updates every life tick
+/mob/living/simple_animal/hostile/hivemind/mechiver/proc/update_icon()
+ if(target_mob && !passenger && (get_dist(target_mob, src) <= 4) && !is_on_cooldown())
+ if(!hatch_closed)
+ return
+ overlays.Cut()
+ if(pilot)
+ flick("mechiver-opening", src)
+ icon_state = "mechiver-chief"
+ overlays += "mechiver-hands"
+ else
+ flick("mechiver-opening_wires", src)
+ icon_state = "mechiver-welcome"
+ overlays += "mechiver-wires"
+ hatch_closed = FALSE
+ else
+ overlays.Cut()
+ hatch_closed = TRUE
+ icon_state = "mechiver-closed"
+ if(passenger)
+ overlays += "mechiver-process"
+
+/* TO DO - переписать
+/mob/living/simple_animal/hostile/hivemind/mechiver/AttackingTarget()
+ if(!Adjacent(target_mob))
+ return
+
+ if(world.time > special_ability_cooldown && !passenger)
+ special_ability(target_mob)
+
+ ..()
+
+
+//picking up our victim for good 20 seconds of best road trip ever
+/mob/living/simple_animal/hostile/hivemind/mechiver/special_ability(mob/living/target)
+ if(!target_mob && hatch_closed) //when we picking up corpses
+ if(pilot)
+ flick("mechiver-opening", src)
+ else
+ flick("mechiver-opening_wires", src)
+ passenger = target
+ target.loc = src
+ target.canmove = FALSE
+ target << SPAN_DANGER("You've gotten inside that thing! It's hard to see inside, there's something here, it moves around you!")
+ playsound(src, 'sound/effects/blobattack.ogg', 70, 1)
+ addtimer(CALLBACK(src, .proc/release_passenger), 40 SECONDS)
+
+
+
+/mob/living/simple_animal/hostile/hivemind/mechiver/proc/release_passenger(safely = FALSE)
+ if(passenger)
+ if(pilot)
+ flick("mechiver-opening", src)
+ else
+ flick("mechiver-opening_wires", src)
+
+ if(istype(passenger, /mob/living/carbon/human))
+ if(!safely) //that was stressful
+ var/mob/living/carbon/human/H = passenger
+ if(!pilot && H.stat == DEAD)
+ destroy_passenger()
+ pilot = TRUE
+ return
+
+ H.hallucination = rand(30, 90)
+ //if mob is dead, we just rebuild it
+ if(passenger.stat == DEAD && !safely)
+ dead_body_restoration(passenger)
+
+ if(passenger) //if passenger still here, then just release him
+ passenger << SPAN_DANGER("[src] released you!")
+ passenger.canmove = TRUE
+ passenger.loc = get_turf(src)
+ passenger = null
+ special_ability_cooldown = world.time + ability_cooldown
+ playsound(src, 'sound/effects/blobattack.ogg', 70, 1)
+
+// Здесь всё работает, просто комментим из-за коммента прока с пассажиром
+
+/mob/living/simple_animal/hostile/hivemind/mechiver/proc/dead_body_restoration(mob/living/corpse)
+ var/picked_mob
+ if(passenger.mob_size <= MOB_SMALL && !client && prob(50))
+ picked_mob = pick(/mob/living/simple_animal/hostile/hivemind/stinger, /mob/living/simple_animal/hostile/hivemind/bomber)
+ else
+ if(pilot)
+ if(istype(corpse, /mob/living/carbon/human))
+ picked_mob = /mob/living/simple_animal/hostile/hivemind/himan
+ else if(istype(corpse, /mob/living/silicon/robot))
+ picked_mob = /mob/living/simple_animal/hostile/hivemind/hiborg
+ if(picked_mob)
+ new picked_mob(get_turf(src))
+ else
+ var/mob/living/simple_animal/hostile/hivemind/resurrected/fixed_mob = new(get_turf(src))
+ fixed_mob.take_appearance(corpse)
+ destroy_passenger()
+
+
+/mob/living/simple_animal/hostile/hivemind/mechiver/proc/destroy_passenger()
+ qdel(passenger)
+ passenger = null
+
+// Здесь всё работает, просто комментим из-за коммента прока с пассажиром
+
+//we're not forgot to release our victim safely after death
+/mob/living/simple_animal/hostile/hivemind/mechiver/Destroy()
+ release_passenger(TRUE)
+ ..()
+
+/mob/living/simple_animal/hostile/hivemind/mechiver/death()
+ release_passenger(TRUE)
+ ..()
+ gibs(loc, null, /obj/gibspawner/robot)
+ if(pilot)
+ gibs(loc, null, /obj/gibspawner/human)
+ qdel(src)
+*/
+
+/////////////////////////////////////PHASER///////////////////////////////////
+//Special ability: Superposition. Phaser exists at four locations. But, actually he vulnerable only at one. Other is just a copies
+//Moves with teleportation only, can stun victim if he land on it
+//Also can hide in closets
+//Can't speak, no malfunctions
+//Appears from dead human body
+//////////////////////////////////////////////////////////////////////////////
+
+/mob/living/simple_animal/hostile/hivemind/phaser
+ name = "phaser"
+ desc = "A Crooked human with a strange device on its head. It twitches sometimes and... Why are you still looking? Run!"
+ icon = 'mods/hivemind/icons/hivemind.dmi'
+ icon_state = "phaser-1"
+ health = 120
+ maxHealth = 120
+ speak_chance = 0
+ malfunction_chance = 0
+ mob_size = MOB_MEDIUM
+ ability_cooldown = 2 MINUTES
+ //internals
+ var/can_use_special_ability = TRUE
+ var/list/my_copies = list()
+ ai_holder = /datum/ai_holder/simple_animal/melee/evasive
+
+/mob/living/simple_animal/hostile/hivemind/phaser/New()
+ ..()
+ filters += filter(type="blur", size = 0)
+
+/* TO DO - наверное от туннелера код взять? Хотя тут у нас ещё и прятаться в шкафах можно, как понимаю - LordNest
+
+/mob/living/simple_animal/hostile/hivemind/phaser/Life()
+ stance = STANCE_DISABLED
+ . = ..()
+
+ //special ability using
+ if(world.time > special_ability_cooldown && can_use_special_ability)
+ if(target_mob && (health <= 50))
+ special_ability()
+
+ //closet hiding
+ if(!target_mob)
+ var/obj/structure/closet/C = locate() in get_turf(src)
+ if(C && loc != C)
+ if(!C.opened)
+ C.open(src)
+ if(C.opened)
+ C.close(src)
+ for(var/obj/structure/closet/Closet in view(src))
+ if(!Closet.locked && !Closet.welded)
+ phase_move_to(Closet)
+ break
+
+
+/mob/living/simple_animal/hostile/hivemind/phaser/AttackTarget()
+ if(target_mob && get_dist(src, target_mob) > 1)
+ stance = STANCE_ATTACK
+ ..()
+
+
+/mob/living/simple_animal/hostile/hivemind/phaser/MoveToTarget()
+ if(!target_mob || SA_attackable(target_mob))
+ stance = STANCE_IDLE
+ if(target_mob in ListTargets(10))
+ if(get_dist(src, target_mob) > 1)
+ stance = STANCE_ATTACK
+ phase_move_to(target_mob, nearby = TRUE)
+ else
+ stance = STANCE_ATTACKING
+
+
+/mob/living/simple_animal/hostile/hivemind/phaser/proc/is_can_jump_on(turf/target)
+ if(!target || target.density || istype(target, /turf/space) || istype(target, /turf/simulated/open))
+ return FALSE
+
+ //to prevent reflection's stacking
+ var/mob/living/simple_animal/hostile/hivemind/phaser/P = locate() in target
+ if(P)
+ return FALSE
+
+ for(var/obj/O in target)
+ if(!O.CanPass(src, target))
+ return FALSE
+
+ return TRUE
+
+
+//first part of phase moving is just preparation
+/mob/living/simple_animal/hostile/hivemind/phaser/proc/phase_move_to(atom/target, nearby = FALSE)
+ var/turf/new_place
+ var/distance_to_target = get_dist(src, target)
+ var/turf/target_turf = get_turf(target)
+ //if our target is near, we move precisely to it
+ if(distance_to_target <= 3)
+ if(nearby)
+ for(var/d in GLOB.alldirs)
+ var/turf/nearby_turf = get_step(new_place, d)
+ if(is_can_jump_on(nearby_turf))
+ new_place = nearby_turf
+ else
+ new_place = target_turf
+
+ if(!new_place)
+ //there we make some kind of, you know, that creepy zig-zag moving
+ //we just take angle, distort it a bit and turn into dir
+ var/angle = Get_Angle(loc, target_turf)
+ angle += rand(5, 25)*pick(-1, 1)
+ if(angle < 0)
+ angle = 360 + angle
+ if(angle > 360)
+ angle = 360 - angle
+ var/tp_direction = angle2dir(angle)
+ new_place = get_ranged_target_turf(loc, tp_direction, rand(2, 4))
+
+ if(!is_can_jump_on(new_place))
+ return
+ //an animation
+ var/init_px = pixel_x
+ animate(src, pixel_x=init_px + 16*pick(-1, 1), time=5)
+ animate(pixel_x=init_px, time=6, easing=SINE_EASING)
+ animate(filters[1], size = 5, time = 5, flags = ANIMATION_PARALLEL)
+ addtimer(CALLBACK(src, .proc/phase_jump, new_place), 0.5 SECOND)
+
+
+//second part - is jump to target
+/mob/living/simple_animal/hostile/hivemind/phaser/proc/phase_jump(turf/place)
+ playsound(place, 'sound/effects/phasein.ogg', 60, 1)
+ animate(filters[1], size = 0, time = 5)
+ icon_state = "phaser-[rand(1,4)]"
+ src.loc = place
+ for(var/mob/living/L in loc)
+ if(L != src)
+ visible_message("[src] land on [L]!")
+ playsound(place, 'sound/effects/ghost2.ogg', 70, 1)
+ L.Weaken(3)
+
+
+/mob/living/simple_animal/hostile/hivemind/phaser/special_ability()
+ my_copies = list() //let's clean it up
+ var/possible_directions = GLOB.alldirs - GLOB.cardinal
+ var/turf/spawn_point = get_turf(src)
+ //we gives to copies our appearence and pick random direction for them
+ //with animation it's hard to say, who's real. And i hope it looks great
+ for(var/i = 1 to 3)
+ var/mob/living/simple_animal/hostile/hivemind/phaser/reflection = new type(spawn_point)
+ reflection.can_use_special_ability = FALSE
+ var/mutable_appearance/my_appearance = new(src)
+ reflection.appearance = my_appearance
+ my_copies.Add(reflection)
+
+ var/d = pick(possible_directions)
+ possible_directions -= d
+ var/turf/new_position = get_step(spawn_point, d)
+ if(reflection.is_can_jump_on(new_position))
+ spawn(1) //ugh, i know, i know, it's bad. Animation
+ reflection.forceMove(new_position)
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, reflection), 60 SECONDS)
+ loc = get_step(spawn_point, possible_directions[1]) //there must left last direction
+ special_ability_cooldown = world.time + ability_cooldown
+ playsound(spawn_point, 'sound/effects/cascade.ogg', 100, 1)
+
+
+/mob/living/simple_animal/hostile/hivemind/phaser/closet_interaction()
+ var/obj/structure/closet/closed_closet = loc
+ if(closed_closet && istype(closed_closet) && closed_closet.welded)
+ phase_jump(closed_closet.loc)
+
+
+/mob/living/simple_animal/hostile/hivemind/phaser/death()
+ if(my_copies.len)
+ for(var/mob/living/simple_animal/hostile/hivemind/phaser/My_copy in my_copies)
+ qdel(My_copy)
+ ..()
+ gibs(loc, null, /obj/gibspawner/human)
+ qdel(src)
+*/
diff --git a/mods/hivemind/code/objects.dm b/mods/hivemind/code/objects.dm
new file mode 100644
index 0000000000000..ceed43713762d
--- /dev/null
+++ b/mods/hivemind/code/objects.dm
@@ -0,0 +1,22 @@
+//Hivemind special objects stored here, like projectiles, wreckages or artifacts
+
+
+//toxic shot, turret's ability use it
+/obj/item/projectile/goo
+ name = "toxic goo"
+ icon = 'mods/hivemind/icons/hivemind_machines.dmi'
+ icon_state = "goo_proj"
+ damage = 15
+ damage_type = DAMAGE_BURN
+ step_delay = 2
+
+
+/obj/item/projectile/goo/on_hit(atom/target, blocked = 0)
+ . = ..()
+ if(istype(target, /mob/living) && !istype(target, /mob/living/silicon) && !blocked)
+ var/mob/living/L = target
+ L.apply_damage(10, DAMAGE_TOXIN)
+ if(!(locate(/obj/decal/cleanable/spiderling_remains) in target.loc))
+ var/obj/decal/cleanable/spiderling_remains/goo = new /obj/decal/cleanable/spiderling_remains(target.loc)
+ goo.name = "green goo"
+ goo.desc = "An unidentifiable liquid. It smells awful."
diff --git a/mods/hivemind/code/overrides.dm b/mods/hivemind/code/overrides.dm
new file mode 100644
index 0000000000000..3a71ec0cf6de8
--- /dev/null
+++ b/mods/hivemind/code/overrides.dm
@@ -0,0 +1,68 @@
+// Hivemind wireweeds
+/datum/seed/wires
+ name = "wires"
+ seed_name = "strange wires"
+ display_name = "strange wires"
+ seed_noun = "wires"
+ force_layer = 3
+ chems = list("fuel" = list(1,5))
+
+/datum/seed/wires/New()
+ ..()
+ set_trait(TRAIT_IMMUTABLE,1)
+ set_trait(TRAIT_PLANT_COLOUR,null)
+ set_trait(TRAIT_YIELD,-1)
+ set_trait(TRAIT_SPREAD,3)
+ set_trait(TRAIT_POTENCY,50)
+
+// У меня большие вопросы ко всей части ниже. Помимо того, что мы добавляем анимацию распространения и диры мы делаем... что? - LordNest
+
+/obj/vine/proc/life()
+ var/turf/simulated/T = get_turf(src)
+ var/obj/vine/vine
+ if(istype(T))
+ health_current -= seed.handle_environment(T,T.return_air(),null,1)
+ if(health_current < health_max)
+ //Plants can grow through closed airlocks, but more slowly, since they have to force metal to make space
+ var/obj/machinery/door/D = (locate(/obj/machinery/door) in loc)
+ if (D)
+ health_current += rand(0,0.5)
+ else
+ health_current += rand(1,2.5)
+ update_icon()
+ if(health_current > health_max)
+ health_current = health_max
+ else if(health_current == health_max && !vine) // && (seed.type != /datum/seed/mushroom/maintshroom) - у нас этих грибов нет вроде, это глоукэпы емнип - LordNest
+ vine = new(T,seed)
+ vine.dir = src.dir
+ vine.transform = src.transform
+ vine.growth = seed.get_trait(TRAIT_MATURATION)-1
+ vine.update_icon()
+ if(growth_type==0) //Vines do not become invisible.
+ invisibility = INVISIBILITY_MAXIMUM
+ else
+ vine.layer = layer + 0.1
+
+
+/obj/vine/proc/spread()
+ //spread to 1-3 adjacent turfs depending on yield trait.
+ var/max_spread = between(1, round(seed.get_trait(TRAIT_YIELD)*3/14), 3)
+
+ for(var/i in 1 to max_spread)
+ if(prob(spread_chance))
+ sleep(rand(3,5))
+ if(!get_neighbors.length(1))
+ break
+ var/turf/target_turf = pick(get_neighbors)
+ target_turf = connecting_turfs(target_turf, loc)
+ var/obj/vine/child = new type(get_turf(src),seed,src)
+ after_spread(child, target_turf)
+ // Update neighboring squares.
+ for(var/obj/vine/neighbor in range(1,target_turf))
+ neighbor.get_neighbors -= target_turf
+
+
+//after creation act
+//by default, there goes an animation code
+/obj/vine/proc/after_spread(obj/vine/child, turf/target_turf)
+ spawn(1) // This should do a little bit of animation.
diff --git a/mods/hivemind/code/wires.dm b/mods/hivemind/code/wires.dm
new file mode 100644
index 0000000000000..53865097fd421
--- /dev/null
+++ b/mods/hivemind/code/wires.dm
@@ -0,0 +1,322 @@
+//Wireweeds are created by the AI's nanites to spread its connectivity through the ship.
+//When they reach any machine, they annihilate them and re-purpose them to the AI's needs. They are the 'hands' of our rogue AI.
+
+/obj/vine/hivemind
+ layer = 2
+ health_max = 80 //we are a little bit durable
+ var/list/killer_reagents = list("pacid", "sacid", "hclacid", "thermite")
+ //internals
+ var/obj/machinery/hivemind_machine/node/master_node
+ var/list/wires_connections = list("0", "0", "0", "0")
+
+
+/obj/vine/hivemind/New()
+ ..()
+ icon = 'mods/hivemind/icons/hivemind_obj.dmi'
+ spawn(2)
+ update_neighbors()
+
+
+/obj/vine/hivemind/Destroy()
+ if(master_node)
+ master_node.my_wireweeds.Remove(src)
+ return ..()
+
+
+/obj/vine/hivemind/after_spread(obj/vine/child, turf/target_turf)
+ if(master_node)
+ master_node.add_wireweed(child)
+ spawn(1)
+ child.dir = get_dir(loc, target_turf) //actually this means nothing for wires, but need for animation
+ flick("spread_anim", child)
+ child.forceMove(target_turf)
+ update_icon()
+
+// Насильно обновляем соседей - LordNest
+/obj/vine/proc/update_neighbors(location = loc)
+ for (var/dir in GLOB.cardinal)
+ var/obj/vine/hivemind/L = locate(/obj/vine/hivemind/, get_step(location, dir))
+ if(L)
+ L.update_icon()
+
+/obj/vine/hivemind/proc/try_to_assimilate()
+ if(hive_mind_ai && master_node)
+ for(var/obj/machinery/machine_on_my_tile in loc)
+ var/can_assimilate = TRUE
+
+ //whitelist check
+ if(is_type_in_list(machine_on_my_tile, hive_mind_ai.restricted_machineries))
+ can_assimilate = FALSE
+
+ //assimilation is slow process, so it's take some time
+ //there we use our failure chance. Then it lower, then faster hivemind learn how to properly assimilate it
+ if(can_assimilate && prob(hive_mind_ai.failure_chance))
+ can_assimilate = FALSE
+ anim_shake(machine_on_my_tile)
+ return
+
+ //only one machine per turf
+ if(can_assimilate && !locate(/obj/machinery/hivemind_machine) in loc)
+ assimilate(machine_on_my_tile)
+ //other will be... merged
+ else if(can_assimilate)
+ qdel(machine_on_my_tile)
+
+ //modular computers handling
+ var/obj/item/modular_computer/mod_comp = locate() in loc
+ if(mod_comp)
+ assimilate(mod_comp)
+
+ //dead bodies handling
+ for(var/mob/living/dead_body in loc)
+ if(dead_body.stat == DEAD)
+ assimilate(dead_body)
+
+
+/obj/vine/hivemind/update_neighbors()
+ ..()
+ update_connections()
+ update_icon()
+
+
+/obj/vine/hivemind/spread()
+ if(hive_mind_ai && master_node)
+ ..()
+
+
+/obj/vine/hivemind/life()
+ if(hive_mind_ai && master_node)
+ try_to_assimilate()
+ chem_handler()
+ else
+ //slow vanishing after node death
+ health_current -= 10
+ alpha = 255 * health_current/health_max
+ update_health()
+
+
+/obj/vine/hivemind/is_mature()
+ return TRUE
+
+
+/obj/vine/hivemind/update_icon()
+ overlays.Cut()
+ var/image/I
+ for(var/i = 1 to 4)
+ I = image(src.icon, "wires[wires_connections[i]]", dir = 1<<(i-1))
+ overlays += I
+ for(var/d in GLOB.cardinal)
+ var/turf/T = get_step(loc, d)
+ if((locate(/obj/structure/window) in T) || istype(T, /turf/simulated/wall))
+ var/image/wall_hug_overlay = image(icon = src.icon, icon_state = "wall_hug", dir = d)
+ if (T.x < x)
+ wall_hug_overlay.pixel_x -= 32
+ else if (T.x > x)
+ wall_hug_overlay.pixel_x += 32
+ if (T.y < y)
+ wall_hug_overlay.pixel_y -= 32
+ else if (T.y > y)
+ wall_hug_overlay.pixel_y += 32
+ wall_hug_overlay.layer = ABOVE_WINDOW_LAYER
+ overlays += wall_hug_overlay
+
+
+/obj/vine/hivemind/proc/update_connections(propagate = 0)
+ var/list/dirs = list()
+ for(var/obj/vine/hivemind/W in range(1, src) - src)
+ if(propagate)
+ W.update_connections()
+ W.update_icon()
+ dirs += get_dir(src, W)
+
+ wires_connections = dirs_to_corner_states(dirs)
+
+
+/obj/vine/hivemind/door_interaction(obj/machinery/door/airlock/door)
+ if(!door || !istype(door))
+ return FALSE
+
+ //if our door isn't broken, we will try to break open. We can do only one action per call
+ if(!(door.stat & MACHINE_BROKEN_GENERIC))
+ anim_shake(door)
+ //first, we open our panel to give our wireweeds access to exposed airlock's electronics
+ if(!door.p_open)
+ if(prob(20))
+ door.p_open = TRUE
+ return FALSE
+ //but if airlock is welded, we just shake it like we rummage inside
+ if(door.welded)
+ return FALSE
+ //if panel opened, we begin to destruct it from inside of airlock
+ if(door.p_open)
+ //bolts are down? Our wireweeds infest electronics, so this isn't a problem cause it part of us
+ if(door.locked)
+ if(prob(50))
+ door.unlock()
+ return FALSE
+ //and then, if airlock is closed, we begin destroy it electronics
+ if(door.density)
+ door.damage_health(rand(15, 50))
+ return FALSE
+
+ return TRUE
+
+
+/obj/vine/hivemind/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
+ if(mover == src)
+ if(target.density)
+ return FALSE
+
+ if(locate(/obj/structure) in target)
+ for(var/obj/structure/S in target)
+ if(S.density)
+ return FALSE
+
+ if(locate(/obj/machinery/door) in target)
+ return FALSE
+
+ return TRUE
+ else
+ return ..()
+
+
+
+//What a pity that we haven't some kind proc as special library to use it somewhere
+/obj/vine/hivemind/proc/anim_shake(atom/thing)
+ var/init_px = thing.pixel_x
+ var/shake_dir = pick(-1, 1)
+ animate(thing, transform=turn(matrix(), 8*shake_dir), pixel_x=init_px + 2*shake_dir, time=1)
+ animate(transform=null, pixel_x=init_px, time=6, easing=ELASTIC_EASING)
+
+
+//assimilation process
+/obj/vine/hivemind/proc/assimilate(var/atom/subject)
+ if(istype(subject, /obj/machinery) || istype(subject, /obj/item/modular_computer))
+ if(prob(hive_mind_ai.failure_chance))
+ //critical failure! This machine would be a dummy, which means - without any ability
+ //let's make an infested sprite
+ var/obj/machinery/hivemind_machine/new_machine = new (loc)
+ var/icon/infected_icon = new('mods/hivemind/icons/hivemind_machines.dmi', icon_state = "wires-[rand(1, 3)]")
+ var/icon/new_icon = new(subject.icon, icon_state = subject.icon_state, dir = subject.dir)
+ new_icon.Blend(infected_icon, ICON_OVERLAY)
+ new_machine.icon = new_icon
+ var/prefix = pick("strange", "interesting", "marvelous", "unusual")
+ new_machine.name = "[prefix] [subject.name]"
+ else
+ //of course, here we have a very little chance to spawn him, our mini-boss
+ if(prob(1))
+ new /mob/living/simple_animal/hostile/hivemind/mechiver(loc)
+ qdel(subject)
+ return
+ else
+ var/picked_machine
+ var/list/possible_machines = subtypesof(/obj/machinery/hivemind_machine)
+
+ if(hive_mind_ai.hives.len < 10)
+ if(hive_mind_ai.evo_points < (hive_mind_ai.hives.len * 100)) //one hive per 100 EP
+ possible_machines -= /obj/machinery/hivemind_machine/node
+ else
+ //we make new nodes asap, cause it has higher priority to survive, so we force it here
+ picked_machine = /obj/machinery/hivemind_machine/node
+
+ //here we compare hivemind's EP with machine's required value
+ for(var/machine_path in possible_machines)
+ if(hive_mind_ai.evo_points <= hive_mind_ai.EP_price_list[machine_path])
+ possible_machines.Remove(machine_path)
+
+ if(!picked_machine)
+ picked_machine = pick(possible_machines)
+ var/obj/machinery/hivemind_machine/new_machine = new picked_machine(loc)
+ new_machine.update_icon()
+
+ if(istype(subject, /mob/living) && !istype(subject, /mob/living/simple_animal/hostile/hivemind))
+ //human bodies
+ if(istype(subject, /mob/living/carbon/human))
+ var/mob/living/L = subject
+ for(var/obj/item/W in L)
+ L.drop_from_inventory(W)
+ var/M = pick(/mob/living/simple_animal/hostile/hivemind/himan, /mob/living/simple_animal/hostile/hivemind/phaser)
+ new M(loc)
+ //robot corpses
+ else if(istype(subject, /mob/living/silicon))
+ new /mob/living/simple_animal/hostile/hivemind/hiborg(loc)
+ //other dead bodies
+ else
+ var/mob/living/simple_animal/hostile/hivemind/resurrected/transformed_mob = new(loc)
+ transformed_mob.take_appearance(subject)
+
+ qdel(subject)
+
+
+//////////////////////////////////////////////////////////////////
+/////////////////////////>RESPONSE CODE/////////////////////////
+//////////////////////////////////////////////////////////////////
+
+
+//in fact, this is some kind of reinforced wires, so we can't take samples from it and inject something too
+//but we still can slice it with something sharp
+
+/*
+/obj/vine/hivemind/use_weapon(obj/item/weapon/W, mob/user, list/click_params)
+ . = ..()
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+
+ var/weapon_type
+ if (W.has_edge(weapon))
+ weapon_type = QUALITY_CUTTING
+ else if (W.has_quality(QUALITY_WELDING))
+ weapon_type = QUALITY_WELDING
+
+ if(weapon_type)
+ if(W.use_tool(user, src, WORKTIME_FAST, weapon_type, FAILCHANCE_EASY, required_stat = STAT_ROB))
+ user.visible_message(SPAN_DANGER("[user] cuts down [src]."), SPAN_DANGER("You cut down [src]."))
+ kill_health()
+ return
+ return
+ else
+ if(W.sharp && W.force >= 10)
+ health_current -= rand(W.force/2, W.force) //hm, maybe make damage based on player's robust stat?
+ user.visible_message(SPAN_DANGER("[user] slices [src]."), SPAN_DANGER("You slice [src]."))
+ else
+ user.visible_message(SPAN_DANGER("[user] tries to slice [src] with [W], but seems to do nothing."),
+ SPAN_DANGER("You try to slice [src], but it's useless!"))
+ update_health()
+*/
+
+/obj/vine/hivemind/use_weapon(obj/item/weapon/W, mob/user, list/click_params)
+ . = ..()
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+
+ if(W.sharp && W.force >= 30)
+ user.visible_message(SPAN_DANGER("[user] cuts down [src]."), SPAN_DANGER("You cut down [src]."))
+ kill_health()
+ return
+ if(W.sharp && W.force >= 10)
+ health_current -= rand(W.force/2, W.force) //hm, maybe make damage based on player's robust stat?
+ user.visible_message(SPAN_DANGER("[user] slices [src]."), SPAN_DANGER("You slice [src]."))
+ else
+ user.visible_message(SPAN_DANGER("[user] tries to slice [src] with [W], but seems to do nothing."),
+ SPAN_DANGER("You try to slice [src], but it's useless!"))
+
+ return ..()
+
+//fire is effective, but there need some time to melt the covering
+/obj/vine/hivemind/fire_act()
+ health_current -= rand(1, 4)
+ update_health()
+
+
+//emp is effective too
+//it causes electricity failure, so our wireweeds just blowing up inside, what makes them fragile
+/obj/vine/hivemind/emp_act(severity)
+ if(severity)
+ kill_health()
+
+
+//Some acid and there's no problem
+/obj/vine/hivemind/proc/chem_handler()
+ for(var/obj/effect/smoke/chem/smoke in loc)
+ for(var/lethal in killer_reagents)
+ if(smoke.reagents.has_reagent(lethal))
+ kill_health()
+ return
diff --git a/mods/hivemind/icons/hivemind.dmi b/mods/hivemind/icons/hivemind.dmi
new file mode 100644
index 0000000000000..0011cab69a1b2
Binary files /dev/null and b/mods/hivemind/icons/hivemind.dmi differ
diff --git a/mods/hivemind/icons/hivemind_machines.dmi b/mods/hivemind/icons/hivemind_machines.dmi
new file mode 100644
index 0000000000000..02c4b3cf242c7
Binary files /dev/null and b/mods/hivemind/icons/hivemind_machines.dmi differ
diff --git a/mods/hivemind/icons/hivemind_obj.dmi b/mods/hivemind/icons/hivemind_obj.dmi
new file mode 100644
index 0000000000000..532df325b8339
Binary files /dev/null and b/mods/hivemind/icons/hivemind_obj.dmi differ
diff --git a/mods/hivemind/sounds/insect_battle_bite.ogg b/mods/hivemind/sounds/insect_battle_bite.ogg
new file mode 100644
index 0000000000000..f5c751218c2fd
Binary files /dev/null and b/mods/hivemind/sounds/insect_battle_bite.ogg differ
diff --git a/mods/hivemind/sounds/insect_battle_screeching.ogg b/mods/hivemind/sounds/insect_battle_screeching.ogg
new file mode 100644
index 0000000000000..319223d53d80b
Binary files /dev/null and b/mods/hivemind/sounds/insect_battle_screeching.ogg differ