diff --git a/code/__defines/species_languages.dm b/code/__defines/species_languages.dm
index bacd4ebd37..656b0dff2a 100644
--- a/code/__defines/species_languages.dm
+++ b/code/__defines/species_languages.dm
@@ -53,6 +53,7 @@
#define LANGUAGE_AKHANI "Akhani"
#define LANGUAGE_ALAI "Alai"
#define LANGUAGE_ZADDAT "Vedahq"
+#define LANGUAGE_BLOB "Blob"
#define LANGUAGE_GIBBERISH "Babel"
// Language flags.
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index b9ce4c7f5a..ea40e3dc0e 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -43,7 +43,7 @@
next_click = world.time + 1
- if(client.buildmode)
+ if(client && client.buildmode)
build_click(src, client.buildmode, params, A)
return
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index e31dd5e56a..8a61b87251 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -358,11 +358,13 @@
mymob.radio_use_icon.color = ui_color
mymob.radio_use_icon.alpha = ui_alpha
- mymob.client.screen = list()
+ if(mymob.client)
+ mymob.client.screen = list()
+
+ mymob.client.screen += hud_elements
+ mymob.client.screen += src.adding + src.hotkeybuttons
+ mymob.client.screen += mymob.client.void
- mymob.client.screen += hud_elements
- mymob.client.screen += src.adding + src.hotkeybuttons
- mymob.client.screen += mymob.client.void
inventory_shown = 0
return
diff --git a/code/game/objects/effects/chem/chemsmoke.dm b/code/game/objects/effects/chem/chemsmoke.dm
index 2bbb10c8af..5538755d24 100644
--- a/code/game/objects/effects/chem/chemsmoke.dm
+++ b/code/game/objects/effects/chem/chemsmoke.dm
@@ -3,7 +3,7 @@
/////////////////////////////////////////////
/obj/effect/effect/smoke/chem
icon = 'icons/effects/chemsmoke.dmi'
- opacity = 0
+ opacity = TRUE
time_to_live = 300
pass_flags = PASSTABLE | PASSGRILLE | PASSGLASS //PASSGLASS is fine here, it's just so the visual effect can "flow" around glass
@@ -16,6 +16,9 @@
walk(src, 0) // Because we might have called walk_to, we must stop the walk loop or BYOND keeps an internal reference to us forever.
return ..()
+/obj/effect/effect/smoke/chem/transparent
+ opacity = FALSE
+
/datum/effect/effect/system/smoke_spread/chem
smoke_type = /obj/effect/effect/smoke/chem
var/obj/chemholder
@@ -35,6 +38,10 @@
CRASH("Invalid seed datum passed! [seed] ([seed?.type])")
..()
+/datum/effect/effect/system/smoke_spread/chem/blob
+ show_log = 0
+ smoke_type = /obj/effect/effect/smoke/chem/transparent
+
/datum/effect/effect/system/smoke_spread/chem/New()
..()
chemholder = new/obj()
@@ -155,7 +162,7 @@
if(passed_smoke)
smoke = passed_smoke
else
- smoke = new /obj/effect/effect/smoke/chem(location)
+ smoke = new smoke_type(location)
if(chemholder.reagents.reagent_list.len)
chemholder.reagents.trans_to_obj(smoke, chemholder.reagents.total_volume / dist, copy = 1) //copy reagents to the smoke so mob/breathe() can handle inhaling the reagents
@@ -165,11 +172,13 @@
smoke.pixel_x = -32 + rand(-8, 8)
smoke.pixel_y = -32 + rand(-8, 8)
walk_to(smoke, T)
- smoke.set_opacity(1) //switching opacity on after the smoke has spawned, and then
- sleep(150+rand(0,20)) // turning it off before it is deleted results in cleaner
- smoke.set_opacity(0) // lighting and view range updates
- fadeOut(smoke)
- qdel(smoke)
+ if(initial(smoke.opacity))
+ smoke.set_opacity(1) //switching opacity on after the smoke has spawned, and then
+ spawn()
+ sleep(150+rand(0,20)) // turning it off before it is deleted results in cleaner
+ smoke.set_opacity(0) // lighting and view range updates
+ fadeOut(smoke)
+ qdel(smoke)
/datum/effect/effect/system/smoke_spread/chem/spores/spawnSmoke(var/turf/T, var/icon/I, var/dist = 1)
var/obj/effect/effect/smoke/chem/spores = new /obj/effect/effect/smoke/chem(location)
diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm
index 7d5275cbcd..00896e7107 100644
--- a/code/game/objects/effects/effect_system.dm
+++ b/code/game/objects/effects/effect_system.dm
@@ -238,6 +238,15 @@ steam.start() -- spawns the effect
if(prob(25))
L.emote("cough")
+/obj/effect/effect/smoke/bad/noxious
+ opacity = 0
+
+/obj/effect/effect/smoke/bad/noxious/affect(var/mob/living/L)
+ if (!..())
+ return 0
+ if(L.needs_to_breathe())
+ L.adjustToxLoss(1)
+
/* Not feasile until a later date
/obj/effect/effect/smoke/bad/Crossed(atom/movable/M as mob|obj)
..()
@@ -369,6 +378,9 @@ steam.start() -- spawns the effect
/datum/effect/effect/system/smoke_spread/bad
smoke_type = /obj/effect/effect/smoke/bad
+/datum/effect/effect/system/smoke_spread/noxious
+ smoke_type = /obj/effect/effect/smoke/bad/noxious
+
/datum/effect/effect/system/smoke_spread/fire
smoke_type = /obj/effect/effect/smoke/elemental/fire
diff --git a/code/modules/ai/ai_holder.dm b/code/modules/ai/ai_holder.dm
index aadcdaa9e2..b5272ea996 100644
--- a/code/modules/ai/ai_holder.dm
+++ b/code/modules/ai/ai_holder.dm
@@ -9,6 +9,10 @@
/mob/living/Initialize()
if(ai_holder_type)
ai_holder = new ai_holder_type(src)
+ if(istype(src, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = src
+ H.hud_used = new /datum/hud(H)
+ H.instantiate_hud(H.hud_used)
return ..()
/mob/living/Destroy()
@@ -220,7 +224,7 @@
/datum/ai_holder/proc/handle_stance_strategical()
ai_log("++++++++++ Slow Process Beginning ++++++++++", AI_LOG_TRACE)
ai_log("handle_stance_strategical() : Called.", AI_LOG_TRACE)
-
+
//We got left around for some reason. Goodbye cruel world.
if(!holder)
qdel(src)
diff --git a/code/modules/ai/ai_holder_targeting.dm b/code/modules/ai/ai_holder_targeting.dm
index f1f5ff4a3a..f33906c662 100644
--- a/code/modules/ai/ai_holder_targeting.dm
+++ b/code/modules/ai/ai_holder_targeting.dm
@@ -28,7 +28,7 @@
. = hearers(vision_range, holder) - holder // Remove ourselves to prevent suicidal decisions. ~ SRC is the ai_holder.
. -= dview_mob // Not the dview mob either, nerd.
- var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha))
+ var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha, /obj/structure/blob))
for(var/HM in typecache_filter_list(range(vision_range, holder), hostile_machines))
if(can_see(holder, HM, vision_range))
@@ -75,7 +75,7 @@
/datum/ai_holder/proc/give_target(new_target, urgent = FALSE)
ai_log("give_target() : Given '[new_target]', urgent=[urgent].", AI_LOG_TRACE)
target = new_target
-
+
if(target != null)
lose_target_time = 0
track_target_position()
@@ -155,6 +155,11 @@
return FALSE // Turrets won't get hurt if they're still in their cover.
return TRUE
+ if(istype(the_target, /obj/structure/blob)) // Blob mobs are always blob faction, but the blob can anger other things.
+ var/obj/structure/blob/Blob = the_target
+ if(holder.faction == Blob.faction)
+ return FALSE
+
return TRUE
// return FALSE
@@ -189,12 +194,12 @@
ai_log("remove_target() : Entering.", AI_LOG_TRACE)
if(target)
target = null
-
+
lose_target_time = 0
give_up_movement()
lose_target_position()
set_stance(STANCE_IDLE)
-
+
// Check if target is visible to us.
/datum/ai_holder/proc/can_see_target(atom/movable/the_target, view_range = vision_range)
ai_log("can_see_target() : Entering.", AI_LOG_TRACE)
@@ -274,7 +279,7 @@
// Sets a few vars so mobs that threaten will react faster to an attacker or someone who attacked them before.
/datum/ai_holder/proc/on_attacked(atom/movable/AM)
last_conflict_time = world.time
- add_attacker(AM)
+ add_attacker(AM)
// Checks to see if an atom attacked us lately
/datum/ai_holder/proc/check_attacker(var/atom/movable/A)
@@ -287,7 +292,7 @@
// Forgive this attacker
/datum/ai_holder/proc/remove_attacker(var/atom/movable/A)
attackers -= A.name
-
+
// Causes targeting to prefer targeting the taunter if possible.
// This generally occurs if more than one option is within striking distance, including the taunter.
// Otherwise the default filter will prefer the closest target.
diff --git a/code/modules/ai/interfaces.dm b/code/modules/ai/interfaces.dm
index b4323782d3..6cf085c52e 100644
--- a/code/modules/ai/interfaces.dm
+++ b/code/modules/ai/interfaces.dm
@@ -11,6 +11,11 @@
return ATTACK_ON_COOLDOWN
return attack_target(A) // This will set click cooldown.
+/mob/living/carbon/human/IAttack(atom/A)
+ if(!canClick()) // Still on cooldown from a "click".
+ return FALSE
+ return ClickOn(A) // Except this is an actual fake "click".
+
/mob/living/proc/IRangedAttack(atom/A)
return FALSE
diff --git a/code/modules/blob2/_defines.dm b/code/modules/blob2/_defines.dm
index 1ad0b73893..85f9d39115 100644
--- a/code/modules/blob2/_defines.dm
+++ b/code/modules/blob2/_defines.dm
@@ -7,4 +7,7 @@
#define BLOB_DIFFICULTY_EASY 0
#define BLOB_DIFFICULTY_MEDIUM 1
#define BLOB_DIFFICULTY_HARD 2
-#define BLOB_DIFFICULTY_SUPERHARD 3
\ No newline at end of file
+#define BLOB_DIFFICULTY_SUPERHARD 3
+
+#define BLOB_CHUNK_CONSTANT 0
+#define BLOB_CHUNK_TOGGLE 1
diff --git a/code/modules/blob2/blobs/base_blob.dm b/code/modules/blob2/blobs/base_blob.dm
index 02a7827825..2e04c36b95 100644
--- a/code/modules/blob2/blobs/base_blob.dm
+++ b/code/modules/blob2/blobs/base_blob.dm
@@ -17,6 +17,7 @@ GLOBAL_LIST_EMPTY(all_blobs)
var/heal_timestamp = 0 //we got healed when?
var/mob/observer/blob/overmind = null
var/base_name = "blob" // The name that gets appended along with the blob_type's name.
+ var/faction = "blob"
/obj/structure/blob/Initialize(newloc, new_overmind)
if(new_overmind)
@@ -56,6 +57,8 @@ GLOBAL_LIST_EMPTY(all_blobs)
return TRUE
else if(istype(mover, /obj/item/projectile))
var/obj/item/projectile/P = mover
+ if(istype(P.firer, /obj/structure/blob))
+ return TRUE
if(istype(P.firer) && P.firer.faction == "blob")
return TRUE
return FALSE
@@ -218,13 +221,97 @@ GLOBAL_LIST_EMPTY(all_blobs)
qdel(src)
return B
+/obj/structure/blob/attack_generic(var/mob/user, var/damage, var/attack_verb)
+ visible_message("[user] [attack_verb] the [src]!")
+ playsound(loc, 'sound/effects/attackblob.ogg', 100, 1)
+ user.do_attack_animation(src)
+ if(overmind)
+ damage *= overmind.blob_type.brute_multiplier
+ else
+ damage *= 2
+
+ if(overmind)
+ damage = overmind.blob_type.on_received_damage(src, damage, BRUTE, user)
+
+ adjust_integrity(-damage)
+
+ return
+
+/obj/structure/blob/attack_hand(mob/living/M as mob)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ H.setClickCooldown(H.get_attack_speed())
+ var/datum/unarmed_attack/attack = H.get_unarmed_attack(src, BP_TORSO)
+ if(!attack)
+ return FALSE
+
+ if(attack.unarmed_override(H, src, BP_TORSO))
+ return FALSE
+
+ H.do_attack_animation(src)
+ H.visible_message("[H] strikes \the [src]!")
+
+ var/real_damage = rand(3,6)
+ var/hit_dam_type = attack.damage_type
+ real_damage += attack.get_unarmed_damage(H)
+ if(H.gloves)
+ if(istype(H.gloves, /obj/item/clothing/gloves))
+ var/obj/item/clothing/gloves/G = H.gloves
+ real_damage += G.punch_force
+ hit_dam_type = G.punch_damtype
+ if(HULK in H.mutations)
+ real_damage *= 2 // Hulks do twice the damage
+
+ real_damage = max(1, real_damage)
+
+ var/damage_mult_burn = 1
+ var/damage_mult_brute = 1
+
+ if(hit_dam_type == SEARING)
+ damage_mult_burn *= 0.3
+ damage_mult_brute *= 0.6
+
+ else if(hit_dam_type == BIOACID)
+ damage_mult_burn *= 0.6
+ damage_mult_brute = 0
+
+ else if(hit_dam_type in list(ELECTROCUTE, BURN))
+ damage_mult_brute = 0
+
+ else if(hit_dam_type in list(BRUTE, CLONE))
+ damage_mult_burn = 0
+
+ else if(hit_dam_type != HALLOSS) // Tox, Oxy, or something new. Half damage split to the organism.
+ damage_mult_burn = 0.25
+ damage_mult_brute = 0.25
+
+ else
+ damage_mult_brute = 0.25
+ damage_mult_burn = 0
+
+ var/burn_dam = real_damage * damage_mult_burn
+ var/brute_dam = real_damage * damage_mult_brute
+
+ if(overmind)
+ if(brute_dam)
+ brute_dam = overmind.blob_type.on_received_damage(src, brute_dam, BRUTE, M)
+ if(burn_dam)
+ burn_dam = overmind.blob_type.on_received_damage(src, burn_dam, BURN, M)
+
+ real_damage = burn_dam + brute_dam
+
+ adjust_integrity(-real_damage)
+
+ else
+ attack_generic(M, rand(1,10), "bashed")
+
/obj/structure/blob/attackby(var/obj/item/weapon/W, var/mob/user)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
playsound(loc, 'sound/effects/attackblob.ogg', 50, 1)
visible_message("\The [src] has been attacked with \the [W][(user ? " by [user]." : ".")]")
var/damage = W.force
switch(W.damtype)
- if(BURN)
+ if(BURN, BIOACID, ELECTROCUTE, OXY)
if(overmind)
damage *= overmind.blob_type.burn_multiplier
else
@@ -234,7 +321,7 @@ GLOBAL_LIST_EMPTY(all_blobs)
playsound(src.loc, 'sound/items/welder.ogg', 100, 1)
else
playsound(src, 'sound/weapons/tap.ogg', 50, 1)
- if(BRUTE)
+ if(BRUTE, SEARING, TOX, CLONE)
if(overmind)
damage *= overmind.blob_type.brute_multiplier
else
diff --git a/code/modules/blob2/blobs/core.dm b/code/modules/blob2/blobs/core.dm
index 84092ac566..b3633b406e 100644
--- a/code/modules/blob2/blobs/core.dm
+++ b/code/modules/blob2/blobs/core.dm
@@ -83,6 +83,15 @@ var/list/blob_cores = list()
/obj/structure/blob/core/volatile_alluvium
desired_blob_type = /datum/blob_type/volatile_alluvium
+/obj/structure/blob/core/ravenous_macrophage
+ desired_blob_type = /datum/blob_type/ravenous_macrophage
+
+/obj/structure/blob/core/roiling_mold
+ desired_blob_type = /datum/blob_type/roiling_mold
+
+/obj/structure/blob/core/ectoplasmic_horror
+ desired_blob_type = /datum/blob_type/ectoplasmic_horror
+
/obj/structure/blob/core/classic
desired_blob_type = /datum/blob_type/classic
@@ -98,6 +107,9 @@ var/list/blob_cores = list()
point_rate = new_rate
/obj/structure/blob/core/Destroy()
+ var/turf/T = get_turf(src)
+ new /obj/item/weapon/blobcore_chunk(T, overmind.blob_type)
+
blob_cores -= src
if(overmind)
overmind.blob_core = null
@@ -135,6 +147,8 @@ var/list/blob_cores = list()
if(prob(5))
B.change_to(/obj/structure/blob/shield/core, overmind)
+ overmind.blob_type.on_core_process(src)
+
/obj/structure/blob/core/proc/create_overmind(client/new_overmind, override_delay)
if(overmind_get_delay > world.time && !override_delay)
return
@@ -190,4 +204,4 @@ var/list/blob_cores = list()
if(initial(BT.difficulty) < difficulty_floor) // Too easy.
continue
valid_types += BT
- return pick(valid_types)
\ No newline at end of file
+ return pick(valid_types)
diff --git a/code/modules/blob2/blobs/factory.dm b/code/modules/blob2/blobs/factory.dm
index 6ee41ccd53..f9415a6e66 100644
--- a/code/modules/blob2/blobs/factory.dm
+++ b/code/modules/blob2/blobs/factory.dm
@@ -42,6 +42,8 @@
if(overmind.blob_type.ranged_spores)
S.projectiletype = overmind.blob_type.spore_projectile
S.projectilesound = overmind.blob_type.spore_firesound
+ S.projectile_accuracy = overmind.blob_type.spore_accuracy
+ S.projectile_dispersion = overmind.blob_type.spore_dispersion
else //Other mobs don't add themselves in New. Ew.
S.nest = src
spores += S
@@ -51,3 +53,8 @@
name = "sluggish factory blob"
max_spores = 4
spore_cooldown = 16 SECONDS
+
+/obj/structure/blob/factory/turret // Produces a single spore slowly, but is intended to be used as a 'mortar' by the blob type.
+ name = "volatile factory blob"
+ max_spores = 1
+ spore_cooldown = 10 SECONDS
diff --git a/code/modules/blob2/blobs/node.dm b/code/modules/blob2/blobs/node.dm
index aa1dcb3e8f..5f54b6b80a 100644
--- a/code/modules/blob2/blobs/node.dm
+++ b/code/modules/blob2/blobs/node.dm
@@ -33,4 +33,6 @@ var/list/blob_nodes = list()
/obj/structure/blob/node/process()
set waitfor = FALSE
if(overmind) // This check is so that if the core is killed, the nodes stop.
- pulse_area(overmind, 10, BLOB_NODE_PULSE_RANGE, BLOB_NODE_EXPAND_RANGE)
\ No newline at end of file
+ pulse_area(overmind, 10, BLOB_NODE_PULSE_RANGE, BLOB_NODE_EXPAND_RANGE)
+
+ overmind.blob_type.on_node_process(src)
diff --git a/code/modules/blob2/core_chunk.dm b/code/modules/blob2/core_chunk.dm
new file mode 100644
index 0000000000..8a5795aae9
--- /dev/null
+++ b/code/modules/blob2/core_chunk.dm
@@ -0,0 +1,99 @@
+
+/obj/item/weapon/blobcore_chunk
+ name = "core chunk"
+ desc = "The remains of some strange life-form. It smells awful."
+ description_info = "Some blob types will have core effects when the chunk is used in-hand, toggled with an alt click, or constantly active."
+ icon = 'icons/mob/blob.dmi'
+ icon_state = "blobcore"
+ var/datum/blob_type/blob_type // The blob type this dropped from.
+
+ var/active_ability_cooldown = 20 SECONDS
+ var/last_active_use = 0
+
+ var/should_tick = TRUE // Incase it's a toggle.
+
+ var/passive_ability_cooldown = 5 SECONDS
+ var/last_passive_use = 0
+
+ drop_sound = 'sound/effects/slime_squish.ogg'
+
+/obj/item/weapon/blobcore_chunk/New(var/atom/newloc, var/datum/blob_type/parentblob = null)
+ ..(newloc)
+
+ setup_blobtype(parentblob)
+
+/obj/item/weapon/blobcore_chunk/Destroy()
+ STOP_PROCESSING(SSobj, src)
+
+ blob_type = null
+
+ ..()
+
+/obj/item/weapon/blobcore_chunk/proc/setup_blobtype(var/datum/blob_type/parentblob = null)
+ if(!parentblob)
+ name = "inert [initial(name)]"
+
+ else
+ blob_type = parentblob
+ name = "[blob_type.name] [initial(name)]"
+
+ if(blob_type)
+ color = blob_type.color
+ if(LAZYLEN(blob_type.core_tech))
+ origin_tech = blob_type.core_tech.Copy()
+
+ if(blob_type.chunk_active_type == BLOB_CHUNK_CONSTANT)
+ should_tick = TRUE
+ else if(blob_type.chunk_active_type == BLOB_CHUNK_TOGGLE)
+ should_tick = FALSE
+
+ active_ability_cooldown = blob_type.chunk_active_ability_cooldown
+ passive_ability_cooldown = blob_type.chunk_passive_ability_cooldown
+
+ blob_type.chunk_setup(src)
+
+ START_PROCESSING(SSobj, src)
+
+/obj/item/weapon/blobcore_chunk/proc/call_chunk_unique()
+ if(blob_type)
+ blob_type.chunk_unique(src, args)
+ return
+
+/obj/item/weapon/blobcore_chunk/proc/get_carrier(var/atom/target)
+ var/atom/A = target ? target.loc : src
+ if(!istype(A, /mob/living))
+ A = get_carrier(A)
+
+ if(isturf(A) || isarea(A)) // Something has gone horribly wrong if the second is true.
+ return FALSE // No mob is carrying us.
+
+ return A
+
+/obj/item/weapon/blobcore_chunk/blob_act(obj/structure/blob/B)
+ if(B.overmind && !blob_type)
+ setup_blobtype(B.overmind.blob_type)
+
+ return
+
+/obj/item/weapon/blobcore_chunk/attack_self(var/mob/user)
+ if(blob_type && world.time > active_ability_cooldown + last_active_use)
+ last_active_use = world.time
+ to_chat(user, "\icon [src] \The [src] gesticulates.")
+ blob_type.on_chunk_use(src, user)
+ else
+ to_chat(user, "\The [src] doesn't seem to respond.")
+ ..()
+
+/obj/item/weapon/blobcore_chunk/process()
+ if(blob_type && should_tick && world.time > passive_ability_cooldown + last_passive_use)
+ last_passive_use = world.time
+ blob_type.on_chunk_tick(src)
+
+/obj/item/weapon/blobcore_chunk/AltClick(mob/living/carbon/user)
+ if(blob_type &&blob_type.chunk_active_type == BLOB_CHUNK_TOGGLE)
+ should_tick = !should_tick
+
+ if(should_tick)
+ to_chat(user, "\The [src] shudders with life.")
+ else
+ to_chat(user, "\The [src] stills, returning to a death-like state.")
diff --git a/code/modules/blob2/overmind/types.dm b/code/modules/blob2/overmind/types.dm
index 24ffbd6b1b..79df541aae 100644
--- a/code/modules/blob2/overmind/types.dm
+++ b/code/modules/blob2/overmind/types.dm
@@ -37,12 +37,19 @@
var/spore_firesound = 'sound/effects/slime_squish.ogg'
var/spore_range = 7 // The range the spore can fire.
var/spore_projectile = /obj/item/projectile/energy/blob
+ var/spore_accuracy = 0 // Projectile accuracy
+ var/spore_dispersion = 0 // Dispersion.
var/factory_type = /obj/structure/blob/factory
var/resource_type = /obj/structure/blob/resource
var/node_type = /obj/structure/blob/node
var/shield_type = /obj/structure/blob/shield
+ var/list/core_tech = list(TECH_BIO = 4, TECH_MATERIAL = 3) // Tech for the item created when a core is destroyed.
+ var/chunk_active_type = BLOB_CHUNK_TOGGLE
+ var/chunk_active_ability_cooldown = 20 SECONDS
+ var/chunk_passive_ability_cooldown = 5 SECONDS
+
// Called when a blob receives damage. This needs to return the final damage or blobs will be immortal.
/datum/blob_type/proc/on_received_damage(var/obj/structure/blob/B, damage, damage_type)
return damage
@@ -63,6 +70,14 @@
/datum/blob_type/proc/on_pulse(var/obj/structure/blob/B)
return
+// Called when the core processes.
+/datum/blob_type/proc/on_core_process(var/obj/structure/blob/B)
+ return
+
+// Called when a node processes.
+/datum/blob_type/proc/on_node_process(var/obj/structure/blob/B)
+ return
+
// Called when hit by EMP.
/datum/blob_type/proc/on_emp(obj/structure/blob/B, severity)
return
@@ -71,574 +86,26 @@
/datum/blob_type/proc/on_water(obj/structure/blob/B, amount)
return
-// Spore things
+// Spore death
/datum/blob_type/proc/on_spore_death(mob/living/simple_mob/blob/spore/S)
return
+// Spore handle_special call.
+/datum/blob_type/proc/on_spore_lifetick(mob/living/simple_mob/blob/spore/S)
+ return
-// Subtypes
+// Blob core chunk process.
+/datum/blob_type/proc/on_chunk_tick(obj/item/weapon/blobcore_chunk/B)
+ return
-// Super fast spreading, but weak to EMP.
-/datum/blob_type/grey_goo
- name = "grey tide"
- desc = "A swarm of self replicating nanomachines. Extremely illegal and dangerous, the EIO was meant to prevent this from showing up a second time."
- effect_desc = "Spreads much faster than average, but is harmed greatly by electromagnetic pulses."
- ai_desc = "genocidal"
- difficulty = BLOB_DIFFICULTY_SUPERHARD // Fastest spread of them all and has snowballing capabilities.
- color = "#888888"
- complementary_color = "#CCCCCC"
- spread_modifier = 1.0
- slow_spread_with_size = FALSE
- ai_aggressiveness = 80
- can_build_resources = TRUE
- attack_message = "The tide tries to swallow you"
- attack_message_living = ", and you feel your skin dissolve"
- attack_message_synth = ", and your external plating dissolves"
+// Blob core chunk use in-hand.
+/datum/blob_type/proc/on_chunk_use(obj/item/weapon/blobcore_chunk/B, mob/user)
+ return
-/datum/blob_type/grey_goo/on_emp(obj/structure/blob/B, severity)
- B.adjust_integrity(-(20 / severity))
+// Proc that is unique to the blob type.
+/datum/blob_type/proc/chunk_unique(obj/item/weapon/blobcore_chunk/B, var/list/extra_args = null)
+ return
-// Slow, tanky blobtype which uses not spores, but hivebots, as its soldiers.
-/datum/blob_type/fabrication_swarm
- name = "iron tide"
- desc = "A swarm of self replicating construction nanites. Incredibly illegal, but only mildly dangerous."
- effect_desc = "Slow-spreading, but incredibly resiliant. It has a chance to harden itself against attacks automatically for no resource cost, and uses cheaply-constructed hivebots as soldiers."
- ai_desc = "defensive"
- difficulty = BLOB_DIFFICULTY_MEDIUM // Emitters are okay, EMP is great.
- color = "#666666"
- complementary_color = "#B7410E"
- spread_modifier = 0.2
- can_build_factories = TRUE
- can_build_resources = TRUE
- attack_message = "The tide tries to shove you away"
- attack_message_living = ", and your skin itches"
- attack_message_synth = ", and your external plating dulls"
- attack_verb = "shoves"
- armor_pen = 40
- damage_lower = 10
- damage_upper = 25
- brute_multiplier = 0.25
- burn_multiplier = 0.6
- ai_aggressiveness = 50 //Really doesn't like you near it.
- spore_type = /mob/living/simple_mob/mechanical/hivebot/swarm
-
-/datum/blob_type/fabrication_swarm/on_received_damage(var/obj/structure/blob/B, damage, damage_type, mob/living/attacker)
- if(istype(B, /obj/structure/blob/normal))
- if(damage > 0)
- var/reinforce_probability = min(damage, 70)
- if(prob(reinforce_probability))
- B.visible_message("The [name] quakes, before rapidly hardening!")
- new/obj/structure/blob/shield(get_turf(B), B.overmind)
- qdel(B)
- return ..()
-
-/datum/blob_type/fabrication_swarm/on_emp(obj/structure/blob/B, severity)
- B.adjust_integrity(-(30 / severity))
-
-// A blob meant to be fought like a fire.
-/datum/blob_type/blazing_oil
- name = "blazing oil"
- desc = "A strange, extremely vicious liquid that seems to burn endlessly."
- ai_desc = "aggressive"
- effect_desc = "Cannot be harmed by burning weapons, and ignites entities it attacks. It will also gradually heat up the area it is in. Water harms it greatly."
- difficulty = BLOB_DIFFICULTY_MEDIUM // Emitters don't work but extinguishers are fairly common. Might need fire/atmos suits.
- color = "#B68D00"
- complementary_color = "#BE5532"
- spread_modifier = 0.5
- ai_aggressiveness = 50
- damage_type = BURN
- burn_multiplier = 0 // Fire immunity
- attack_message = "The blazing oil splashes you with its burning oil"
- attack_message_living = ", and you feel your skin char and melt"
- attack_message_synth = ", and your external plating melts"
- attack_verb = "splashes"
-
-/datum/blob_type/blazing_oil/on_attack(obj/structure/blob/B, mob/living/victim)
- victim.fire_act() // Burn them.
-
-/datum/blob_type/blazing_oil/on_water(obj/structure/blob/B, amount)
- spawn(1)
- B.adjust_integrity(-(amount * 5))
-
-/datum/blob_type/blazing_oil/on_pulse(var/obj/structure/blob/B)
- var/turf/T = get_turf(B)
- if(!T)
- return
- var/datum/gas_mixture/env = T.return_air()
- if(env)
- env.add_thermal_energy(10 * 1000)
-
-
-// Mostly a classic blob. No nodes, no other blob types.
-/datum/blob_type/classic
- name = "lethargic blob"
- desc = "A mass that seems bound to its core."
- ai_desc = "unambitious"
- effect_desc = "Will not create any nodes. Has average strength and resistances."
- difficulty = BLOB_DIFFICULTY_EASY // Behaves almost like oldblob, and as such is about as easy as oldblob.
- color = "#AAFF00"
- complementary_color = "#57787B"
- can_build_nodes = FALSE
- spread_modifier = 1.0
- ai_aggressiveness = 0
-
-
-// Makes robots cry. Really weak to brute damage.
-/datum/blob_type/electromagnetic_web
- name = "electromagnetic web"
- desc = "A gooy mesh that generates an electromagnetic field. Electronics will likely be ruined if nearby."
- ai_desc = "balanced"
- effect_desc = "Causes an EMP on attack, and will EMP upon death. It is also more fragile than average, especially to brute force."
- difficulty = BLOB_DIFFICULTY_MEDIUM // Rough for robots but otherwise fragile and can be fought at range like most blobs anyways.
- color = "#83ECEC"
- complementary_color = "#EC8383"
- damage_type = BURN
- damage_lower = 10
- damage_upper = 20
- brute_multiplier = 3
- burn_multiplier = 2
- ai_aggressiveness = 60
- attack_message = "The web lashes you"
- attack_message_living = ", and you hear a faint buzzing"
- attack_message_synth = ", and your electronics get badly damaged"
- attack_verb = "lashes"
-
-/datum/blob_type/electromagnetic_web/on_death(obj/structure/blob/B)
- empulse(B.loc, 0, 1, 2)
-
-/datum/blob_type/electromagnetic_web/on_attack(obj/structure/blob/B, mob/living/victim)
- victim.emp_act(2)
-
-
-// Makes spores that spread the blob and infest dead people.
-/datum/blob_type/fungal_bloom
- name = "fungal bloom"
- desc = "A massive network of rapidly expanding mycelium. Large spore-like particles can be seen spreading from it."
- ai_desc = "swarming"
- effect_desc = "Creates floating spores that attack enemies from specialized blobs, and will spread the blob if killed. The spores can also \
- infest deceased biological humanoids. It is vulnerable to fire."
- difficulty = BLOB_DIFFICULTY_MEDIUM // The spores are more of an annoyance but can be difficult to contain.
- color = "#AAAAAA"
- complementary_color = "#FFFFFF"
- damage_type = TOX
- damage_lower = 15
- damage_upper = 25
- spread_modifier = 0.3 // Lower, since spores will do a lot of the spreading.
- burn_multiplier = 3
- ai_aggressiveness = 40
- can_build_factories = TRUE
- spore_type = /mob/living/simple_mob/blob/spore/infesting
-
-/datum/blob_type/fungal_bloom/on_spore_death(mob/living/simple_mob/blob/spore/S)
- if(S.is_infesting)
- return // Don't make blobs if they were on someone's head.
- var/turf/T = get_turf(S)
- var/obj/structure/blob/B = locate(/obj/structure/blob) in T
- if(B) // Is there already a blob here? If so, just heal it.
- B.adjust_integrity(10)
- else
- B = new /obj/structure/blob/normal(T, S.overmind) // Otherwise spread it.
- B.visible_message("\A [B] forms on \the [T] as \the [S] bursts!")
-
-// Makes tons of weak spores whenever it spreads.
-/datum/blob_type/fulminant_organism
- name = "fulminant organism"
- desc = "A self expanding mass of living biomaterial, that appears to produce entities to defend it, much like a living organism's immune system."
- ai_desc = "swarming"
- effect_desc = "Creates weak floating spores that attack enemies from specialized blobs, has a chance to also create a spore when \
- it spreads onto a new tile, and has a chance to create a spore when a blob tile is destroyed. It is more fragile than average to all types of damage."
- difficulty = BLOB_DIFFICULTY_HARD // Loads of spores that can overwhelm, and spreads quickly.
- color = "#FF0000" // Red
- complementary_color = "#FFCC00" // Orange-ish
- damage_type = TOX
- damage_lower = 10
- damage_upper = 20
- spread_modifier = 0.7
- burn_multiplier = 1.5
- brute_multiplier = 1.5
- ai_aggressiveness = 30 // The spores do most of the fighting.
- can_build_factories = TRUE
- spore_type = /mob/living/simple_mob/blob/spore/weak
-
-/datum/blob_type/fulminant_organism/on_expand(var/obj/structure/blob/B, var/obj/structure/blob/new_B, var/turf/T, var/mob/observer/blob/O)
- if(prob(10)) // 10% chance to make a weak spore when expanding.
- var/mob/living/simple_mob/blob/spore/S = new spore_type(T)
- if(istype(S))
- S.overmind = O
- O.blob_mobs.Add(S)
- else
- S.faction = "blob"
- S.update_icons()
-
-/datum/blob_type/fulminant_organism/on_death(obj/structure/blob/B)
- if(prob(33)) // 33% chance to make a spore when dying.
- var/mob/living/simple_mob/blob/spore/S = new spore_type(get_turf(B))
- B.visible_message("\The [S] floats free from the [name]!")
- if(istype(S))
- S.overmind = B.overmind
- B.overmind.blob_mobs.Add(S)
- else
- S.faction = "blob"
- S.update_icons()
-
-
-// Auto-retaliates against melee attacks. Weak to projectiles.
-/datum/blob_type/reactive_spines
- name = "reactive spines"
- desc = "An ever-growing lifeform with a large amount of sharp, powerful looking spines. They look like they could pierce most armor."
- ai_desc = "defensive"
- effect_desc = "When attacked by a melee weapon, it will automatically retaliate, striking the attacker with an armor piercing attack. \
- The blob itself is rather weak to all forms of attacks regardless, and lacks automatic realitation from ranged attacks."
- difficulty = BLOB_DIFFICULTY_EASY // Potentially deadly to people not knowing the mechanics, but otherwise fairly tame, due to its slow spread and weakness.
- color = "#9ACD32"
- complementary_color = "#FFA500"
- damage_type = BRUTE
- damage_lower = 30
- damage_upper = 40
- armor_pen = 50 // Even with riot armor and tactical jumpsuit, you'd have 90 armor, reduced by 50, totaling 40. Getting hit for around 21 damage is still rough.
- burn_multiplier = 2.0
- brute_multiplier = 2.0
- spread_modifier = 0.35 // Ranged projectiles tend to have a higher material cost, so ease up on the spreading.
- ai_aggressiveness = 40
- attack_message = "The blob stabs you"
- attack_message_living = ", and you feel sharp spines pierce your flesh"
- attack_message_synth = ", and your external plating is pierced by sharp spines"
- attack_verb = "stabs"
-
-// Even if the melee attack is enough to one-shot this blob, it gets to retaliate at least once.
-/datum/blob_type/reactive_spines/on_received_damage(var/obj/structure/blob/B, damage, damage_type, mob/living/attacker)
- if(damage > 0 && attacker && get_dist(B, attacker) <= 1)
- B.visible_message("The [name] retaliates, lashing out at \the [attacker]!")
- B.blob_attack_animation(attacker, B.overmind)
- attacker.blob_act(B)
- return ..()
-
-
-// Spreads damage to nearby blobs, and attacks with the force of all nearby blobs.
-/datum/blob_type/synchronous_mesh
- name = "synchronous mesh"
- desc = "A mesh that seems strongly interconnected to itself. It moves slowly, but with purpose."
- ai_desc = "defensive"
- effect_desc = "When damaged, spreads the damage to nearby blobs. When attacking, damage is increased based on how many blobs are near the target. It is resistant to burn damage."
- difficulty = BLOB_DIFFICULTY_EASY // Mostly a tank and spank.
- color = "#65ADA2"
- complementary_color = "#AD6570"
- damage_type = BRUTE
- damage_lower = 10
- damage_upper = 15
- brute_multiplier = 0.5
- burn_multiplier = 0.2 // Emitters do so much damage that this will likely not matter too much.
- spread_modifier = 0.3 // Since the blob spreads damage, it takes awhile to actually kill, so spread is reduced.
- ai_aggressiveness = 60
- attack_message = "The mesh synchronously strikes you"
- attack_verb = "synchronously strikes"
- var/synchronously_attacking = FALSE
-
-/datum/blob_type/synchronous_mesh/on_attack(obj/structure/blob/B, mob/living/victim)
- if(synchronously_attacking)
- return
- synchronously_attacking = TRUE // To avoid infinite loops.
- for(var/obj/structure/blob/C in orange(1, victim))
- if(victim) // Some things delete themselves when dead...
- C.blob_attack_animation(victim)
- victim.blob_act(C)
- synchronously_attacking = FALSE
-
-/datum/blob_type/synchronous_mesh/on_received_damage(var/obj/structure/blob/B, damage, damage_type)
- var/list/blobs_to_hurt = list() // Maximum split is 9, reducing the damage each blob takes to 11.1% but doing that damage to 9 blobs.
- for(var/obj/structure/blob/C in range(1, B))
- if(!istype(C, /obj/structure/blob/core) && !istype(C, /obj/structure/blob/node) && C.overmind && (C.overmind == B.overmind) ) //if it doesn't have the same 'ownership' or is a core or node, don't split damage to it
- blobs_to_hurt += C
-
- for(var/thing in blobs_to_hurt)
- var/obj/structure/blob/C = thing
- if(C == B)
- continue // We'll damage this later.
-
- C.adjust_integrity(-(damage / blobs_to_hurt.len))
-
- return damage / max(blobs_to_hurt.len, 1) // To hurt the blob that got hit.
-
-
-/datum/blob_type/shifting_fragments
- name = "shifting fragments"
- desc = "A collection of fragments that seem to shuffle around constantly."
- ai_desc = "evasive"
- effect_desc = "Swaps places with nearby blobs when hit or when expanding."
- difficulty = BLOB_DIFFICULTY_EASY
- color = "#C8963C"
- complementary_color = "#3C6EC8"
- damage_type = BRUTE
- damage_lower = 20
- damage_upper = 30
- brute_multiplier = 0.5
- burn_multiplier = 0.5
- spread_modifier = 0.5
- ai_aggressiveness = 30
- attack_message = "A fragment strikes you"
- attack_verb = "strikes"
-
-/datum/blob_type/shifting_fragments/on_received_damage(var/obj/structure/blob/B, damage, damage_type)
- if(damage > 0 && prob(60))
- var/list/available_blobs = list()
- for(var/obj/structure/blob/OB in orange(1, B))
- if((istype(OB, /obj/structure/blob/normal) || (istype(OB, /obj/structure/blob/shield) && prob(25))) && OB.overmind && OB.overmind == B.overmind)
- available_blobs += OB
- if(available_blobs.len)
- var/obj/structure/blob/targeted = pick(available_blobs)
- var/turf/T = get_turf(targeted)
- targeted.forceMove(get_turf(B))
- B.forceMove(T) // Swap places.
- return ..()
-
-/datum/blob_type/shifting_fragments/on_expand(var/obj/structure/blob/B, var/obj/structure/blob/new_B, var/turf/T, var/mob/observer/blob/O)
- if(istype(B, /obj/structure/blob/normal) || (istype(B, /obj/structure/blob/shield) && prob(25)))
- new_B.forceMove(get_turf(B))
- B.forceMove(T)
-
-// A very cool blob, literally.
-/datum/blob_type/cryogenic_goo
- name = "cryogenic goo"
- desc = "A mass of goo that freezes anything it touches."
- ai_desc = "balanced"
- effect_desc = "Lowers the temperature of the room passively, and will also greatly lower the temperature of anything it attacks."
- difficulty = BLOB_DIFFICULTY_MEDIUM
- color = "#8BA6E9"
- complementary_color = "#7D6EB4"
- damage_type = BURN
- damage_lower = 15
- damage_upper = 25
- brute_multiplier = 0.25
- burn_multiplier = 1.2
- spread_modifier = 0.5
- ai_aggressiveness = 50
- attack_message = "The goo stabs you"
- attack_message_living = ", and you feel an intense chill from within"
- attack_message_synth = ", and your system reports lower internal temperatures"
- attack_verb = "stabs"
-
-/datum/blob_type/cryogenic_goo/on_attack(obj/structure/blob/B, mob/living/victim)
- if(ishuman(victim))
- var/mob/living/carbon/human/H = victim
- var/protection = H.get_cold_protection(50)
- if(protection < 1)
- var/temp_change = 80 // Each hit can reduce temperature by up to 80 kelvin.
- var/datum/species/baseline = GLOB.all_species["Human"]
- var/temp_cap = baseline.cold_level_3 - 5 // Can't go lower than this.
-
- var/cold_factor = abs(protection - 1)
- temp_change *= cold_factor // If protection was at 0.5, then they only lose 40 kelvin.
-
- H.bodytemperature = max(H.bodytemperature - temp_change, temp_cap)
- else // Just do some extra burn for mobs who don't process bodytemp
- victim.adjustFireLoss(20)
-
-/datum/blob_type/cryogenic_goo/on_pulse(var/obj/structure/blob/B)
- var/turf/simulated/T = get_turf(B)
- if(!istype(T))
- return
- T.freeze_floor()
- var/datum/gas_mixture/env = T.return_air()
- if(env)
- env.add_thermal_energy(-10 * 1000)
-
-// Electric blob that stuns.
-/datum/blob_type/energized_jelly
- name = "energized jelly"
- desc = "A substance that seems to generate electricity."
- ai_desc = "suppressive"
- effect_desc = "When attacking an entity, it will shock them with a strong electric shock. Repeated attacks can stun the target."
- difficulty = BLOB_DIFFICULTY_MEDIUM
- color = "#EFD65A"
- complementary_color = "#00E5B1"
- damage_type = BURN
- damage_lower = 5
- damage_upper = 10
- brute_multiplier = 0.5
- burn_multiplier = 0.5
- spread_modifier = 0.35
- ai_aggressiveness = 80
- attack_message = "The jelly prods you"
- attack_message_living = ", and your flesh burns as electricity arcs into you"
- attack_message_synth = ", and your internal circuity is overloaded as electricity arcs into you"
- attack_verb = "prods"
-
-/datum/blob_type/energized_jelly/on_attack(obj/structure/blob/B, mob/living/victim, def_zone)
- victim.electrocute_act(10, src, 1, def_zone)
- victim.stun_effect_act(0, 40, BP_TORSO, src)
-
-
-// A blob with area of effect attacks.
-/datum/blob_type/explosive_lattice
- name = "explosive lattice"
- desc = "A very unstable lattice that looks quite explosive."
- ai_desc = "aggressive"
- effect_desc = "When attacking an entity, it will cause a small explosion, hitting things near the target. It is somewhat resilient, but weaker to brute damage."
- difficulty = BLOB_DIFFICULTY_MEDIUM
- color = "#8B2500"
- complementary_color = "#00668B"
- damage_type = BURN
- damage_lower = 25
- damage_upper = 35
- armor_check = "bomb"
- armor_pen = 5 // This is so blob hits still hurt just slightly when wearing a bomb suit (100 bomb resist).
- brute_multiplier = 0.75
- burn_multiplier = 0.5
- spread_modifier = 0.4
- ai_aggressiveness = 75
- attack_message = "The lattice blasts you"
- attack_message_living = ", and your flesh burns from the blast wave"
- attack_message_synth = ", and your plating burns from the blast wave"
- attack_verb = "blasts"
- var/exploding = FALSE
-
-/datum/blob_type/explosive_lattice/on_attack(obj/structure/blob/B, mob/living/victim, def_zone) // This doesn't use actual bombs since they're too strong and it would hurt the blob.
- if(exploding) // We're busy, don't infinite loop us.
- return
-
- exploding = TRUE
- for(var/mob/living/L in range(get_turf(victim), 1)) // We don't use orange(), in case there is more than one mob on the target tile.
- if(L == victim) // Already hit.
- continue
- if(L.faction == "blob") // No friendly fire
- continue
- L.blob_act()
-
- // Visual effect.
- var/datum/effect/system/explosion/E = new/datum/effect/system/explosion/smokeless()
- var/turf/T = get_turf(victim)
- E.set_up(T)
- E.start()
-
- // Now for sounds.
- playsound(T, "explosion", 75, 1) // Local sound.
-
- for(var/mob/M in player_list) // For everyone else.
- if(M.z == T.z && get_dist(M, T) > world.view && !M.ear_deaf && !istype(M.loc,/turf/space))
- M << 'sound/effects/explosionfar.ogg'
-
- exploding = FALSE
-
-
-// A blob that slips and drowns you.
-/datum/blob_type/pressurized_slime
- name = "pressurized slime"
- desc = "A large mass that seems to leak slippery fluid everywhere."
- ai_desc = "drowning"
- effect_desc = "Wets the floor when expanding and when hit. Tries to drown its enemies when attacking. It forces itself past internals. Resistant to burn damage."
- difficulty = BLOB_DIFFICULTY_HARD
- color = "#AAAABB"
- complementary_color = "#BBBBAA"
- damage_type = OXY
- damage_lower = 5
- damage_upper = 15
- armor_check = null
- brute_multiplier = 0.6
- burn_multiplier = 0.2
- spread_modifier = 0.4
- ai_aggressiveness = 75
- attack_message = "The slime splashes into you"
- attack_message_living = ", and you gasp for breath"
- attack_message_synth = ", and the fluid wears down on your components"
- attack_verb = "splashes"
-
-/datum/blob_type/pressurized_slime/on_attack(obj/structure/blob/B, mob/living/victim, def_zone)
- victim.water_act(5)
- var/turf/simulated/T = get_turf(victim)
- if(T)
- T.wet_floor()
-
-/datum/blob_type/pressurized_slime/on_received_damage(var/obj/structure/blob/B, damage, damage_type)
- wet_surroundings(B, damage)
- return ..()
-
-/datum/blob_type/pressurized_slime/on_pulse(var/obj/structure/blob/B)
- var/turf/simulated/T = get_turf(B)
- if(!istype(T))
- return
- T.wet_floor()
-
-/datum/blob_type/pressurized_slime/on_death(obj/structure/blob/B)
- B.visible_message("The blob ruptures, spraying the area with liquid!")
- wet_surroundings(B, 50)
-
-/datum/blob_type/pressurized_slime/proc/wet_surroundings(var/obj/structure/blob/B, var/probability = 50)
- for(var/turf/simulated/T in range(1, B))
- if(prob(probability))
- T.wet_floor()
- for(var/atom/movable/AM in T)
- AM.water_act(2)
-
-
-// A blob that irradiates everything.
-/datum/blob_type/radioactive_ooze
- name = "radioactive ooze"
- desc = "A goopy mess that glows with an unhealthy aura."
- ai_desc = "radical"
- effect_desc = "Irradiates the surrounding area, and inflicts toxic attacks. Weak to brute damage."
- difficulty = BLOB_DIFFICULTY_MEDIUM
- color = "#33CC33"
- complementary_color = "#99FF66"
- damage_type = TOX
- damage_lower = 20
- damage_upper = 30
- armor_check = "rad"
- brute_multiplier = 0.75
- burn_multiplier = 0.2
- spread_modifier = 0.8
- ai_aggressiveness = 50
- attack_message = "The ooze splashes you"
- attack_message_living = ", and you feel warm"
- attack_message_synth = ", and your internal systems are bombarded by ionizing radiation"
- attack_verb = "splashes"
-
-/datum/blob_type/radioactive_ooze/on_pulse(var/obj/structure/blob/B)
- SSradiation.radiate(B, 200)
-
-/datum/blob_type/volatile_alluvium
- name = "volatile alluvium"
- desc = "A churning, earthy mass that moves in waves."
- ai_desc = "earthen"
- effect_desc = "Moves slowly, producing weak ranged spores to defend itself, and inflicts brute attacks. Attempts to disarm nearby attackers. Weak to water."
- difficulty = BLOB_DIFFICULTY_HARD //Slow-starting, but can be overwhelming if left alone.
- color = "#6B481E"
- complementary_color = "#7F471F"
- damage_lower = 10
- damage_upper = 20
- armor_pen = 40
- brute_multiplier = 0.7
- burn_multiplier = 0.5
- spread_modifier = 0.5
- ai_aggressiveness = 50
- attack_message = "The alluvium crashes against you"
- attack_verb = "crashes against"
- can_build_factories = TRUE
- can_build_resources = TRUE
- spore_type = /mob/living/simple_mob/blob/spore/weak
- ranged_spores = TRUE
- spore_range = 3
- spore_projectile = /obj/item/projectile/energy/blob/splattering
- factory_type = /obj/structure/blob/factory/sluggish
- resource_type = /obj/structure/blob/resource/sluggish
-
-/datum/blob_type/volatile_alluvium/on_received_damage(var/obj/structure/blob/B, damage, damage_type, mob/living/attacker)
- if(damage > 0 && attacker && get_dist(B, attacker) <= 2 && prob(min(damage, 70)) && istype(attacker, /mob/living/carbon/human)) // Melee weapons of any type carried by a human will have a high chance of being stolen.
- var/mob/living/carbon/human/H = attacker
- var/obj/item/I = H.get_active_hand()
- H.drop_item()
- if(I)
- if((I.sharp || I.edge) && !istype(I, /obj/item/weapon/gun))
- I.forceMove(get_turf(B)) // Disarmed entirely.
- B.visible_message("The [name] heaves, \the [attacker]'s weapon becoming stuck in the churning mass!")
- else
- I.throw_at(B, 2, 4) // Just yoinked.
- B.visible_message("The [name] heaves, pulling \the [attacker]'s weapon from their hands!")
- B.blob_attack_animation(attacker, B.overmind)
- return ..()
-
-/datum/blob_type/volatile_alluvium/on_water(obj/structure/blob/B, amount)
- spawn(1)
- var/damage = amount * 2
- B.adjust_integrity(-(damage))
- if(B && prob(damage))
- B.visible_message("The [name] begins to crumble!")
+// Set up the blob type for the chunk.
+/datum/blob_type/proc/chunk_setup(obj/item/weapon/blobcore_chunk/B)
+ return
diff --git a/code/modules/blob2/overmind/types/blazing_oil.dm b/code/modules/blob2/overmind/types/blazing_oil.dm
new file mode 100644
index 0000000000..094083e778
--- /dev/null
+++ b/code/modules/blob2/overmind/types/blazing_oil.dm
@@ -0,0 +1,45 @@
+// A blob meant to be fought like a fire.
+/datum/blob_type/blazing_oil
+ name = "blazing oil"
+ desc = "A strange, extremely vicious liquid that seems to burn endlessly."
+ ai_desc = "aggressive"
+ effect_desc = "Cannot be harmed by burning weapons, and ignites entities it attacks. It will also gradually heat up the area it is in. Water harms it greatly."
+ difficulty = BLOB_DIFFICULTY_MEDIUM // Emitters don't work but extinguishers are fairly common. Might need fire/atmos suits.
+ color = "#B68D00"
+ complementary_color = "#BE5532"
+ spread_modifier = 0.5
+ ai_aggressiveness = 50
+ damage_type = BURN
+ burn_multiplier = 0 // Fire immunity
+ chunk_active_ability_cooldown = 4 MINUTES
+ attack_message = "The blazing oil splashes you with its burning oil"
+ attack_message_living = ", and you feel your skin char and melt"
+ attack_message_synth = ", and your external plating melts"
+ attack_verb = "splashes"
+
+/datum/blob_type/blazing_oil/on_attack(obj/structure/blob/B, mob/living/victim)
+ victim.fire_act() // Burn them.
+
+/datum/blob_type/blazing_oil/on_water(obj/structure/blob/B, amount)
+ spawn(1)
+ B.adjust_integrity(-(amount * 5))
+
+/datum/blob_type/blazing_oil/on_pulse(var/obj/structure/blob/B)
+ var/turf/T = get_turf(B)
+ if(!T)
+ return
+ var/datum/gas_mixture/env = T.return_air()
+ if(env)
+ env.add_thermal_energy(10 * 1000)
+
+/datum/blob_type/blazing_oil/on_chunk_tick(obj/item/weapon/blobcore_chunk/B)
+ var/turf/T = get_turf(B)
+ if(!T)
+ return
+ var/datum/gas_mixture/env = T.return_air()
+ if(env)
+ env.add_thermal_energy(10 * 1000)
+
+/datum/blob_type/blazing_oil/on_chunk_use(obj/item/weapon/blobcore_chunk/B, mob/living/user)
+ user.add_modifier(/datum/modifier/exothermic, 5 MINUTES)
+ return
\ No newline at end of file
diff --git a/code/modules/blob2/overmind/types/classic.dm b/code/modules/blob2/overmind/types/classic.dm
new file mode 100644
index 0000000000..450324b493
--- /dev/null
+++ b/code/modules/blob2/overmind/types/classic.dm
@@ -0,0 +1,37 @@
+// Mostly a classic blob. No nodes, no other blob types.
+/datum/blob_type/classic
+ name = "lethargic blob"
+ desc = "A mass that seems bound to its core."
+ ai_desc = "unambitious"
+ effect_desc = "Will not create any nodes. Has average strength and resistances."
+ difficulty = BLOB_DIFFICULTY_EASY // Behaves almost like oldblob, and as such is about as easy as oldblob.
+ color = "#AAFF00"
+ complementary_color = "#57787B"
+ can_build_nodes = FALSE
+ spread_modifier = 1.0
+ ai_aggressiveness = 0
+
+/datum/blob_type/classic/on_chunk_use(obj/item/weapon/blobcore_chunk/B, mob/living/user)
+ var/turf/T = get_turf(B)
+
+ to_chat(user, "\The [B] produces a soothing ooze!")
+
+ T.visible_message("\The [B] shudders at \the [user]'s touch, before disgorging a disgusting ooze.")
+
+ for(var/turf/simulated/floor/F in view(2, T))
+ spawn()
+ var/obj/effect/effect/water/splash = new(T)
+ splash.create_reagents(15)
+ splash.reagents.add_reagent("blood", 10,list("blood_colour" = color))
+ splash.set_color()
+
+ splash.set_up(F, 2, 3)
+
+ var/obj/effect/decal/cleanable/chemcoating/blood = locate() in T
+ if(!istype(blood))
+ blood = new(T)
+ blood.reagents.add_reagent("blood", 10,list("blood_colour" = color))
+ blood.reagents.add_reagent("tricorlidaze", 5)
+ blood.update_icon()
+
+ return
\ No newline at end of file
diff --git a/code/modules/blob2/overmind/types/cryogenic_goo.dm b/code/modules/blob2/overmind/types/cryogenic_goo.dm
new file mode 100644
index 0000000000..32684ed58f
--- /dev/null
+++ b/code/modules/blob2/overmind/types/cryogenic_goo.dm
@@ -0,0 +1,59 @@
+// A very cool blob, literally.
+/datum/blob_type/cryogenic_goo
+ name = "cryogenic goo"
+ desc = "A mass of goo that freezes anything it touches."
+ ai_desc = "balanced"
+ effect_desc = "Lowers the temperature of the room passively, and will also greatly lower the temperature of anything it attacks."
+ difficulty = BLOB_DIFFICULTY_MEDIUM
+ color = "#8BA6E9"
+ complementary_color = "#7D6EB4"
+ damage_type = BURN
+ damage_lower = 15
+ damage_upper = 25
+ brute_multiplier = 0.25
+ burn_multiplier = 1.2
+ spread_modifier = 0.5
+ ai_aggressiveness = 50
+ chunk_active_ability_cooldown = 4 MINUTES
+ attack_message = "The goo stabs you"
+ attack_message_living = ", and you feel an intense chill from within"
+ attack_message_synth = ", and your system reports lower internal temperatures"
+ attack_verb = "stabs"
+
+/datum/blob_type/cryogenic_goo/on_attack(obj/structure/blob/B, mob/living/victim)
+ if(ishuman(victim))
+ var/mob/living/carbon/human/H = victim
+ var/protection = H.get_cold_protection(50)
+ if(protection < 1)
+ var/temp_change = 80 // Each hit can reduce temperature by up to 80 kelvin.
+ var/datum/species/baseline = GLOB.all_species["Human"]
+ var/temp_cap = baseline.cold_level_3 - 5 // Can't go lower than this.
+
+ var/cold_factor = abs(protection - 1)
+ temp_change *= cold_factor // If protection was at 0.5, then they only lose 40 kelvin.
+
+ H.bodytemperature = max(H.bodytemperature - temp_change, temp_cap)
+ else // Just do some extra burn for mobs who don't process bodytemp
+ victim.adjustFireLoss(20)
+
+/datum/blob_type/cryogenic_goo/on_pulse(var/obj/structure/blob/B)
+ var/turf/simulated/T = get_turf(B)
+ if(!istype(T))
+ return
+ T.freeze_floor()
+ var/datum/gas_mixture/env = T.return_air()
+ if(env)
+ env.add_thermal_energy(-10 * 1000)
+
+/datum/blob_type/cryogenic_goo/on_chunk_tick(obj/item/weapon/blobcore_chunk/B)
+ var/turf/simulated/T = get_turf(B)
+ if(!istype(T))
+ return
+ T.freeze_floor()
+ var/datum/gas_mixture/env = T.return_air()
+ if(env)
+ env.add_thermal_energy(-10 * 1000)
+
+/datum/blob_type/cryogenic_goo/on_chunk_use(obj/item/weapon/blobcore_chunk/B, mob/living/user)
+ user.add_modifier(/datum/modifier/endothermic, 5 MINUTES)
+ return
diff --git a/code/modules/blob2/overmind/types/ectoplasmic_horror.dm b/code/modules/blob2/overmind/types/ectoplasmic_horror.dm
new file mode 100644
index 0000000000..f7689847cd
--- /dev/null
+++ b/code/modules/blob2/overmind/types/ectoplasmic_horror.dm
@@ -0,0 +1,128 @@
+// A blob that drains energy from nearby mobs in order to fuel itself, and 'negates' some attacks extradimensionally.
+/datum/blob_type/ectoplasmic_horror
+ name = "ectoplasmic horror"
+ desc = "A disgusting translucent slime that feels out of place."
+ ai_desc = "dodging"
+ effect_desc = "Drains energy from nearby life-forms in order to expand itself. Weak to all damage."
+ difficulty = BLOB_DIFFICULTY_MEDIUM
+ color = "#72109eaa"
+ complementary_color = "#1a9de8"
+ damage_type = HALLOSS
+ damage_lower = 10
+ damage_upper = 30
+ armor_check = "energy"
+ brute_multiplier = 1.5
+ burn_multiplier = 1.5
+ spread_modifier = 0.9
+ ai_aggressiveness = 50
+ attack_message = "The horror strikes you"
+ attack_message_living = ", and you feel a wave of exhaustion"
+ attack_message_synth = ", and your systems begin to slow"
+ attack_verb = "strikes"
+ can_build_factories = TRUE
+ factory_type = /obj/structure/blob/factory/sluggish
+ spore_type = /mob/living/simple_mob/blob/spore/weak
+
+ var/list/active_beams = list()
+
+/datum/blob_type/ectoplasmic_horror/on_pulse(var/obj/structure/blob/B)
+ if(B.type == /obj/structure/blob && (locate(/obj/structure/blob/node) in oview(2, get_turf(B))))
+ B.visible_message("The [name] quakes, before hardening.")
+ new/obj/structure/blob/shield(get_turf(B), B.overmind)
+ qdel(B)
+
+ if(istype(B, /obj/structure/blob/factory))
+ listclearnulls(active_beams)
+ var/atom/movable/beam_origin = B
+ for(var/mob/living/L in oview(world.view, B))
+ if(L.stat == DEAD || L.faction == "blob")
+ continue
+ if(prob(5))
+ var/beamtarget_exists = FALSE
+
+ if(active_beams.len)
+ for(var/datum/beam/Beam in active_beams)
+ if(Beam.target == L)
+ beamtarget_exists = TRUE
+ break
+
+ if(!beamtarget_exists && GetAnomalySusceptibility(L) >= 0.5)
+ B.visible_message("\The [B] lashes out at \the [L]!")
+ var/datum/beam/drain_beam = beam_origin.Beam(L, icon_state = "drain_life", time = 10 SECONDS)
+ active_beams |= drain_beam
+ spawn(9 SECONDS)
+ if(B && drain_beam)
+ B.visible_message("\The [B] siphons energy from \the [L]")
+ L.add_modifier(/datum/modifier/berserk_exhaustion, 60 SECONDS)
+ B.overmind.add_points(rand(10,30))
+ if(!QDELETED(drain_beam))
+ qdel(drain_beam)
+
+/datum/blob_type/ectoplasmic_horror/on_received_damage(var/obj/structure/blob/B, damage, damage_type)
+ if(prob(round(damage * 0.5)))
+ B.visible_message("\The [B] shimmers, distorting through some unseen dimension.")
+ var/initial_alpha = B.alpha
+ spawn()
+ animate(B,alpha = initial_alpha, alpha = 10, time = 10)
+ animate(B,alpha = 10, alpha = initial_alpha, time = 10)
+ return 0
+ return ..()
+
+/datum/blob_type/ectoplasmic_horror/on_chunk_tick(obj/item/weapon/blobcore_chunk/B)
+ var/mob/living/carrier = B.get_carrier()
+
+ if(!carrier)
+ return
+
+ var/list/nearby_mobs = list()
+ for(var/mob/living/L in oview(world.view, carrier))
+ if(L.stat != DEAD)
+ nearby_mobs |= L
+
+ if(nearby_mobs.len)
+ listclearnulls(active_beams)
+ for(var/mob/living/L in nearby_mobs)
+ if(L.stat == DEAD || L.faction == "blob")
+ continue
+ if(prob(5))
+ var/beamtarget_exists = FALSE
+
+ if(active_beams.len)
+ for(var/datum/beam/Beam in active_beams)
+ if(Beam.target == L)
+ beamtarget_exists = TRUE
+ break
+
+ if(!beamtarget_exists && GetAnomalySusceptibility(L) >= 0.5)
+ carrier.visible_message("\icon [B] \The [B] lashes out at \the [L]!")
+ var/datum/beam/drain_beam = carrier.Beam(L, icon_state = "drain_life", time = 10 SECONDS)
+ active_beams |= drain_beam
+ spawn(9 SECONDS)
+ if(B && drain_beam)
+ carrier.visible_message("\The [B] siphons energy from \the [L]")
+ L.add_modifier(/datum/modifier/berserk_exhaustion, 30 SECONDS)
+ var/total_heal = 0
+
+ if(carrier.getBruteLoss())
+ carrier.adjustBruteLoss(-5)
+ total_heal += 5
+
+ if(carrier.getFireLoss())
+ carrier.adjustFireLoss(-5)
+ total_heal += 5
+
+ if(carrier.getToxLoss())
+ carrier.adjustToxLoss(-5)
+ total_heal += 5
+
+ if(carrier.getOxyLoss())
+ carrier.adjustOxyLoss(-5)
+ total_heal += 5
+
+ if(carrier.getCloneLoss())
+ carrier.adjustCloneLoss(-5)
+ total_heal += 5
+
+ carrier.add_modifier(/datum/modifier/berserk_exhaustion, total_heal SECONDS)
+ if(!QDELETED(drain_beam))
+ qdel(drain_beam)
diff --git a/code/modules/blob2/overmind/types/electromagnetic_web.dm b/code/modules/blob2/overmind/types/electromagnetic_web.dm
new file mode 100644
index 0000000000..9831998587
--- /dev/null
+++ b/code/modules/blob2/overmind/types/electromagnetic_web.dm
@@ -0,0 +1,34 @@
+// Makes robots cry. Really weak to brute damage.
+/datum/blob_type/electromagnetic_web
+ name = "electromagnetic web"
+ desc = "A gooy mesh that generates an electromagnetic field. Electronics will likely be ruined if nearby."
+ ai_desc = "balanced"
+ effect_desc = "Causes an EMP on attack, and will EMP upon death. It is also more fragile than average, especially to brute force."
+ difficulty = BLOB_DIFFICULTY_MEDIUM // Rough for robots but otherwise fragile and can be fought at range like most blobs anyways.
+ color = "#83ECEC"
+ complementary_color = "#EC8383"
+ damage_type = BURN
+ damage_lower = 10
+ damage_upper = 20
+ brute_multiplier = 3
+ burn_multiplier = 2
+ ai_aggressiveness = 60
+ chunk_active_type = BLOB_CHUNK_CONSTANT
+ attack_message = "The web lashes you"
+ attack_message_living = ", and you hear a faint buzzing"
+ attack_message_synth = ", and your electronics get badly damaged"
+ attack_verb = "lashes"
+
+/datum/blob_type/electromagnetic_web/on_death(obj/structure/blob/B)
+ empulse(B.loc, 0, 1, 2)
+
+/datum/blob_type/electromagnetic_web/on_attack(obj/structure/blob/B, mob/living/victim)
+ victim.emp_act(2)
+
+/datum/blob_type/electromagnetic_web/on_chunk_tick(obj/item/weapon/blobcore_chunk/B)
+ var/turf/T = get_turf(B)
+ if(!T)
+ return
+
+ for(var/mob/living/L in view(2, T))
+ L.add_modifier(/datum/modifier/faraday, 30 SECONDS)
\ No newline at end of file
diff --git a/code/modules/blob2/overmind/types/energized_jelly.dm b/code/modules/blob2/overmind/types/energized_jelly.dm
new file mode 100644
index 0000000000..33c570f24f
--- /dev/null
+++ b/code/modules/blob2/overmind/types/energized_jelly.dm
@@ -0,0 +1,39 @@
+// Electric blob that stuns.
+/datum/blob_type/energized_jelly
+ name = "energized jelly"
+ desc = "A substance that seems to generate electricity."
+ ai_desc = "suppressive"
+ effect_desc = "When attacking an entity, it will shock them with a strong electric shock. Repeated attacks can stun the target."
+ difficulty = BLOB_DIFFICULTY_MEDIUM
+ color = "#EFD65A"
+ complementary_color = "#00E5B1"
+ damage_type = BURN
+ damage_lower = 5
+ damage_upper = 10
+ brute_multiplier = 0.5
+ burn_multiplier = 0.5
+ spread_modifier = 0.35
+ ai_aggressiveness = 80
+ attack_message = "The jelly prods you"
+ attack_message_living = ", and your flesh burns as electricity arcs into you"
+ attack_message_synth = ", and your internal circuity is overloaded as electricity arcs into you"
+ attack_verb = "prods"
+ spore_projectile = /obj/item/projectile/beam/shock
+
+/datum/blob_type/energized_jelly/on_attack(obj/structure/blob/B, mob/living/victim, def_zone)
+ victim.electrocute_act(10, src, 1, def_zone)
+ victim.stun_effect_act(0, 40, BP_TORSO, src)
+
+/datum/blob_type/energized_jelly/on_chunk_tick(obj/item/weapon/blobcore_chunk/B)
+ for(var/mob/living/L in oview(world.view, get_turf(B)))
+ var/mob/living/carrier = B.get_carrier()
+
+ if(istype(carrier) && carrier == L)
+ continue
+
+ var/obj/item/projectile/P = new spore_projectile(get_turf(B))
+
+ carrier.visible_message("\The [B] discharges energy toward \the [L]!")
+ P.launch_projectile(L, BP_TORSO, carrier)
+
+ return
\ No newline at end of file
diff --git a/code/modules/blob2/overmind/types/explosive_lattice.dm b/code/modules/blob2/overmind/types/explosive_lattice.dm
new file mode 100644
index 0000000000..d0484c3725
--- /dev/null
+++ b/code/modules/blob2/overmind/types/explosive_lattice.dm
@@ -0,0 +1,58 @@
+// A blob with area of effect attacks.
+/datum/blob_type/explosive_lattice
+ name = "explosive lattice"
+ desc = "A very unstable lattice that looks quite explosive."
+ ai_desc = "aggressive"
+ effect_desc = "When attacking an entity, it will cause a small explosion, hitting things near the target. It is somewhat resilient, but weaker to brute damage."
+ difficulty = BLOB_DIFFICULTY_MEDIUM
+ color = "#8B2500"
+ complementary_color = "#00668B"
+ damage_type = BURN
+ damage_lower = 25
+ damage_upper = 35
+ armor_check = "bomb"
+ armor_pen = 5 // This is so blob hits still hurt just slightly when wearing a bomb suit (100 bomb resist).
+ brute_multiplier = 0.75
+ burn_multiplier = 0.5
+ spread_modifier = 0.4
+ ai_aggressiveness = 75
+ attack_message = "The lattice blasts you"
+ attack_message_living = ", and your flesh burns from the blast wave"
+ attack_message_synth = ", and your plating burns from the blast wave"
+ attack_verb = "blasts"
+ var/exploding = FALSE
+
+/datum/blob_type/explosive_lattice/on_attack(obj/structure/blob/B, mob/living/victim, def_zone) // This doesn't use actual bombs since they're too strong and it would hurt the blob.
+ if(exploding) // We're busy, don't infinite loop us.
+ return
+
+ exploding = TRUE
+ for(var/mob/living/L in range(get_turf(victim), 1)) // We don't use orange(), in case there is more than one mob on the target tile.
+ if(L == victim) // Already hit.
+ continue
+ if(L.faction == "blob") // No friendly fire
+ continue
+ L.blob_act()
+
+ // Visual effect.
+ var/datum/effect/system/explosion/E = new/datum/effect/system/explosion/smokeless()
+ var/turf/T = get_turf(victim)
+ E.set_up(T)
+ E.start()
+
+ // Now for sounds.
+ playsound(T, "explosion", 75, 1) // Local sound.
+
+ for(var/mob/M in player_list) // For everyone else.
+ if(M.z == T.z && get_dist(M, T) > world.view && !M.ear_deaf && !istype(M.loc,/turf/space))
+ M << 'sound/effects/explosionfar.ogg'
+
+ exploding = FALSE
+
+/datum/blob_type/explosive_lattice/on_chunk_tick(obj/item/weapon/blobcore_chunk/B)
+ var/turf/T = get_turf(B)
+ if(!T)
+ return
+
+ for(var/mob/living/L in view(1, T))
+ L.add_modifier(/datum/modifier/blastshield, 30 SECONDS)
\ No newline at end of file
diff --git a/code/modules/blob2/overmind/types/fabrication_swarm.dm b/code/modules/blob2/overmind/types/fabrication_swarm.dm
new file mode 100644
index 0000000000..7e267558d9
--- /dev/null
+++ b/code/modules/blob2/overmind/types/fabrication_swarm.dm
@@ -0,0 +1,44 @@
+// Slow, tanky blobtype which uses not spores, but hivebots, as its soldiers.
+/datum/blob_type/fabrication_swarm
+ name = "iron tide"
+ desc = "A swarm of self replicating construction nanites. Incredibly illegal, but only mildly dangerous."
+ effect_desc = "Slow-spreading, but incredibly resiliant. It has a chance to harden itself against attacks automatically for no resource cost, and uses cheaply-constructed hivebots as soldiers."
+ ai_desc = "defensive"
+ difficulty = BLOB_DIFFICULTY_MEDIUM // Emitters are okay, EMP is great.
+ color = "#666666"
+ complementary_color = "#B7410E"
+ spread_modifier = 0.2
+ can_build_factories = TRUE
+ can_build_resources = TRUE
+ attack_message = "The tide tries to shove you away"
+ attack_message_living = ", and your skin itches"
+ attack_message_synth = ", and your external plating dulls"
+ attack_verb = "shoves"
+ armor_pen = 40
+ damage_lower = 10
+ damage_upper = 25
+ brute_multiplier = 0.25
+ burn_multiplier = 0.6
+ ai_aggressiveness = 50 //Really doesn't like you near it.
+ spore_type = /mob/living/simple_mob/mechanical/hivebot/swarm
+
+/datum/blob_type/fabrication_swarm/on_received_damage(var/obj/structure/blob/B, damage, damage_type, mob/living/attacker)
+ if(istype(B, /obj/structure/blob/normal))
+ if(damage > 0)
+ var/reinforce_probability = min(damage, 70)
+ if(prob(reinforce_probability))
+ B.visible_message("The [name] quakes, before rapidly hardening!")
+ new/obj/structure/blob/shield(get_turf(B), B.overmind)
+ qdel(B)
+ return ..()
+
+/datum/blob_type/fabrication_swarm/on_emp(obj/structure/blob/B, severity)
+ B.adjust_integrity(-(30 / severity))
+
+/datum/blob_type/fabrication_swarm/on_chunk_tick(obj/item/weapon/blobcore_chunk/B)
+ var/turf/T = get_turf(B)
+ for(var/mob/living/L in view(world.view, T))
+ if(L.stat != DEAD && L.isSynthetic())
+ L.adjustBruteLoss(-1)
+ L.adjustFireLoss(-1)
+ return
\ No newline at end of file
diff --git a/code/modules/blob2/overmind/types/fulminant_organism.dm b/code/modules/blob2/overmind/types/fulminant_organism.dm
new file mode 100644
index 0000000000..2d940f9359
--- /dev/null
+++ b/code/modules/blob2/overmind/types/fulminant_organism.dm
@@ -0,0 +1,50 @@
+// Makes tons of weak spores whenever it spreads.
+/datum/blob_type/fulminant_organism
+ name = "fulminant organism"
+ desc = "A self expanding mass of living biomaterial, that appears to produce entities to defend it, much like a living organism's immune system."
+ ai_desc = "swarming"
+ effect_desc = "Creates weak floating spores that attack enemies from specialized blobs, has a chance to also create a spore when \
+ it spreads onto a new tile, and has a chance to create a spore when a blob tile is destroyed. It is more fragile than average to all types of damage."
+ difficulty = BLOB_DIFFICULTY_HARD // Loads of spores that can overwhelm, and spreads quickly.
+ color = "#FF0000" // Red
+ complementary_color = "#FFCC00" // Orange-ish
+ damage_type = TOX
+ damage_lower = 10
+ damage_upper = 20
+ spread_modifier = 0.7
+ burn_multiplier = 1.5
+ brute_multiplier = 1.5
+ ai_aggressiveness = 30 // The spores do most of the fighting.
+ can_build_factories = TRUE
+ spore_type = /mob/living/simple_mob/blob/spore/weak
+ chunk_active_ability_cooldown = 60 SECONDS
+
+/datum/blob_type/fulminant_organism/on_expand(var/obj/structure/blob/B, var/obj/structure/blob/new_B, var/turf/T, var/mob/observer/blob/O)
+ if(prob(10)) // 10% chance to make a weak spore when expanding.
+ var/mob/living/simple_mob/blob/spore/S = new spore_type(T)
+ if(istype(S))
+ S.overmind = O
+ O.blob_mobs.Add(S)
+ else
+ S.faction = "blob"
+ S.update_icons()
+
+/datum/blob_type/fulminant_organism/on_death(obj/structure/blob/B)
+ if(prob(33)) // 33% chance to make a spore when dying.
+ var/mob/living/simple_mob/blob/spore/S = new spore_type(get_turf(B))
+ B.visible_message("\The [S] floats free from the [name]!")
+ if(istype(S))
+ S.overmind = B.overmind
+ B.overmind.blob_mobs.Add(S)
+ else
+ S.faction = "blob"
+ S.update_icons()
+
+/datum/blob_type/fulminant_organism/on_chunk_use(obj/item/weapon/blobcore_chunk/B, mob/living/user)
+ for(var/I = 1 to rand(3,4))
+ var/mob/living/simple_mob/blob/spore/S = new spore_type(get_turf(B))
+ S.faction = user.faction
+ S.blob_type = src
+ S.update_icons()
+ S.ai_holder.forget_everything()
+ S.add_modifier(/datum/modifier/doomed, 2 MINUTES)
diff --git a/code/modules/blob2/overmind/types/fungal_bloom.dm b/code/modules/blob2/overmind/types/fungal_bloom.dm
new file mode 100644
index 0000000000..6bf20b99d3
--- /dev/null
+++ b/code/modules/blob2/overmind/types/fungal_bloom.dm
@@ -0,0 +1,37 @@
+// Makes spores that spread the blob and infest dead people.
+/datum/blob_type/fungal_bloom
+ name = "fungal bloom"
+ desc = "A massive network of rapidly expanding mycelium. Large spore-like particles can be seen spreading from it."
+ ai_desc = "swarming"
+ effect_desc = "Creates floating spores that attack enemies from specialized blobs, and will spread the blob if killed. The spores can also \
+ infest deceased biological humanoids. It is vulnerable to fire."
+ difficulty = BLOB_DIFFICULTY_MEDIUM // The spores are more of an annoyance but can be difficult to contain.
+ color = "#AAAAAA"
+ complementary_color = "#FFFFFF"
+ damage_type = TOX
+ damage_lower = 15
+ damage_upper = 25
+ spread_modifier = 0.3 // Lower, since spores will do a lot of the spreading.
+ burn_multiplier = 3
+ ai_aggressiveness = 40
+ can_build_factories = TRUE
+ spore_type = /mob/living/simple_mob/blob/spore/infesting
+ chunk_active_ability_cooldown = 2 MINUTES
+
+/datum/blob_type/fungal_bloom/on_spore_death(mob/living/simple_mob/blob/spore/S)
+ if(S.is_infesting)
+ return // Don't make blobs if they were on someone's head.
+ var/turf/T = get_turf(S)
+ var/obj/structure/blob/B = locate(/obj/structure/blob) in T
+ if(B) // Is there already a blob here? If so, just heal it.
+ B.adjust_integrity(10)
+ else
+ B = new /obj/structure/blob/normal(T, S.overmind) // Otherwise spread it.
+ B.visible_message("\A [B] forms on \the [T] as \the [S] bursts!")
+
+/datum/blob_type/fungal_bloom/on_chunk_use(obj/item/weapon/blobcore_chunk/B, mob/living/user)
+ var/mob/living/simple_mob/blob/spore/S = new spore_type(get_turf(B))
+ S.faction = user.faction
+ S.blob_type = src
+ S.update_icons()
+ S.ai_holder.forget_everything()
\ No newline at end of file
diff --git a/code/modules/blob2/overmind/types/grey_goo.dm b/code/modules/blob2/overmind/types/grey_goo.dm
new file mode 100644
index 0000000000..5c93fb46c8
--- /dev/null
+++ b/code/modules/blob2/overmind/types/grey_goo.dm
@@ -0,0 +1,27 @@
+// Super fast spreading, but weak to EMP.
+/datum/blob_type/grey_goo
+ name = "grey tide"
+ desc = "A swarm of self replicating nanomachines. Extremely illegal and dangerous, the EIO was meant to prevent this from showing up a second time."
+ effect_desc = "Spreads much faster than average, but is harmed greatly by electromagnetic pulses."
+ ai_desc = "genocidal"
+ difficulty = BLOB_DIFFICULTY_SUPERHARD // Fastest spread of them all and has snowballing capabilities.
+ color = "#888888"
+ complementary_color = "#CCCCCC"
+ spread_modifier = 1.0
+ slow_spread_with_size = FALSE
+ ai_aggressiveness = 80
+ can_build_resources = TRUE
+ attack_message = "The tide tries to swallow you"
+ attack_message_living = ", and you feel your skin dissolve"
+ attack_message_synth = ", and your external plating dissolves"
+
+/datum/blob_type/grey_goo/on_emp(obj/structure/blob/B, severity)
+ B.adjust_integrity(-(20 / severity))
+
+/datum/blob_type/grey_goo/on_chunk_tick(obj/item/weapon/blobcore_chunk/B)
+ var/turf/T = get_turf(B)
+ for(var/mob/living/L in view(world.view, T))
+ if(L.stat != DEAD)
+ L.adjustBruteLoss(-1)
+ L.adjustFireLoss(-1)
+ return
diff --git a/code/modules/blob2/overmind/types/pressurized_slime.dm b/code/modules/blob2/overmind/types/pressurized_slime.dm
new file mode 100644
index 0000000000..6b2ff5800f
--- /dev/null
+++ b/code/modules/blob2/overmind/types/pressurized_slime.dm
@@ -0,0 +1,56 @@
+// A blob that slips and drowns you.
+/datum/blob_type/pressurized_slime
+ name = "pressurized slime"
+ desc = "A large mass that seems to leak slippery fluid everywhere."
+ ai_desc = "drowning"
+ effect_desc = "Wets the floor when expanding and when hit. Tries to drown its enemies when attacking. It forces itself past internals. Resistant to burn damage."
+ difficulty = BLOB_DIFFICULTY_HARD
+ color = "#AAAABB"
+ complementary_color = "#BBBBAA"
+ damage_type = OXY
+ damage_lower = 5
+ damage_upper = 15
+ armor_check = null
+ brute_multiplier = 0.6
+ burn_multiplier = 0.2
+ spread_modifier = 0.4
+ ai_aggressiveness = 75
+ attack_message = "The slime splashes into you"
+ attack_message_living = ", and you gasp for breath"
+ attack_message_synth = ", and the fluid wears down on your components"
+ attack_verb = "splashes"
+
+/datum/blob_type/pressurized_slime/on_attack(obj/structure/blob/B, mob/living/victim, def_zone)
+ victim.water_act(5)
+ var/turf/simulated/T = get_turf(victim)
+ if(T)
+ T.wet_floor()
+
+/datum/blob_type/pressurized_slime/on_received_damage(var/obj/structure/blob/B, damage, damage_type)
+ wet_surroundings(B, damage)
+ return ..()
+
+/datum/blob_type/pressurized_slime/on_pulse(var/obj/structure/blob/B)
+ var/turf/simulated/T = get_turf(B)
+ if(!istype(T))
+ return
+ T.wet_floor()
+
+/datum/blob_type/pressurized_slime/on_death(obj/structure/blob/B)
+ B.visible_message("The blob ruptures, spraying the area with liquid!")
+ wet_surroundings(B, 50)
+
+/datum/blob_type/pressurized_slime/proc/wet_surroundings(var/obj/structure/blob/B, var/probability = 50)
+ for(var/turf/simulated/T in range(1, get_turf(B)))
+ if(prob(probability))
+ T.wet_floor()
+ for(var/atom/movable/AM in T)
+ AM.water_act(2)
+
+/datum/blob_type/pressurized_slime/on_chunk_tick(obj/item/weapon/blobcore_chunk/B)
+ wet_surroundings(B, 10)
+
+/datum/blob_type/pressurized_slime/on_chunk_use(obj/item/weapon/blobcore_chunk/B, mob/living/user) // Drenches you in water.
+ if(user)
+ user.ExtinguishMob()
+ user.fire_stacks = CLAMP(user.fire_stacks - 1, -25, 25)
\ No newline at end of file
diff --git a/code/modules/blob2/overmind/types/radioactive_ooze.dm b/code/modules/blob2/overmind/types/radioactive_ooze.dm
new file mode 100644
index 0000000000..f3226f2b5b
--- /dev/null
+++ b/code/modules/blob2/overmind/types/radioactive_ooze.dm
@@ -0,0 +1,27 @@
+// A blob that irradiates everything.
+/datum/blob_type/radioactive_ooze
+ name = "radioactive ooze"
+ desc = "A goopy mess that glows with an unhealthy aura."
+ ai_desc = "radical"
+ effect_desc = "Irradiates the surrounding area, and inflicts toxic attacks. Weak to brute damage."
+ difficulty = BLOB_DIFFICULTY_MEDIUM
+ color = "#33CC33"
+ complementary_color = "#99FF66"
+ damage_type = TOX
+ damage_lower = 20
+ damage_upper = 30
+ armor_check = "rad"
+ brute_multiplier = 0.75
+ burn_multiplier = 0.2
+ spread_modifier = 0.8
+ ai_aggressiveness = 50
+ attack_message = "The ooze splashes you"
+ attack_message_living = ", and you feel warm"
+ attack_message_synth = ", and your internal systems are bombarded by ionizing radiation"
+ attack_verb = "splashes"
+
+/datum/blob_type/radioactive_ooze/on_pulse(var/obj/structure/blob/B)
+ SSradiation.radiate(B, 200)
+
+/datum/blob_type/radioactive_ooze/on_chunk_tick(obj/item/weapon/blobcore_chunk/B)
+ SSradiation.radiate(B, rand(25,100))
\ No newline at end of file
diff --git a/code/modules/blob2/overmind/types/ravenous_macrophage.dm b/code/modules/blob2/overmind/types/ravenous_macrophage.dm
new file mode 100644
index 0000000000..0a73501c34
--- /dev/null
+++ b/code/modules/blob2/overmind/types/ravenous_macrophage.dm
@@ -0,0 +1,50 @@
+// A blob that produces noxious smoke-clouds and recycles its dying parts.
+/datum/blob_type/ravenous_macrophage
+ name = "ravenous macrophage"
+ desc = "A disgusting gel that reeks of death."
+ ai_desc = "resourceful"
+ effect_desc = "Produces noxious fumes, and melts prey with acidic attacks. Weak to brute damage."
+ difficulty = BLOB_DIFFICULTY_MEDIUM
+ color = "#639b3f"
+ complementary_color = "#d1ec3c"
+ damage_type = BIOACID
+ damage_lower = 20
+ damage_upper = 30
+ armor_check = "bio"
+ armor_pen = 50
+ brute_multiplier = 0.8
+ burn_multiplier = 0.3
+ spread_modifier = 0.8
+ ai_aggressiveness = 70
+ attack_message = "The macrophage splashes you"
+ attack_message_living = ", and you feel a horrible burning"
+ attack_message_synth = ", and your body begins to corrode"
+ attack_verb = "splashes"
+
+/datum/blob_type/ravenous_macrophage/on_pulse(var/obj/structure/blob/B)
+ var/mob/living/L = locate() in range(world.view, B)
+ if(prob(1) && L.mind && !L.stat) // There's some active living thing nearby, produce offgas.
+ var/turf/T = get_turf(B)
+ var/datum/effect/effect/system/smoke_spread/noxious/BS = new /datum/effect/effect/system/smoke_spread/noxious
+ BS.attach(T)
+ BS.set_up(3, 0, T)
+ playsound(T, 'sound/effects/smoke.ogg', 50, 1, -3)
+ BS.start()
+
+/datum/blob_type/ravenous_macrophage/on_death(obj/structure/blob/B)
+ var/obj/structure/blob/other = locate() in oview(2, B)
+ if(other)
+ B.visible_message("The dying mass is rapidly consumed by the nearby [other]!")
+ if(other.overmind)
+ other.overmind.add_points(rand(1,4))
+
+/datum/blob_type/ravenous_macrophage/on_chunk_tick(obj/item/weapon/blobcore_chunk/B)
+ var/mob/living/L = locate() in range(world.view, B)
+ if(prob(5) && !L.stat) // There's some active living thing nearby, produce offgas.
+ B.visible_message("\icon [B] \The [B] disgorches a cloud of noxious gas!")
+ var/turf/T = get_turf(B)
+ var/datum/effect/effect/system/smoke_spread/noxious/BS = new /datum/effect/effect/system/smoke_spread/noxious
+ BS.attach(T)
+ BS.set_up(3, 0, T)
+ playsound(T, 'sound/effects/smoke.ogg', 50, 1, -3)
+ BS.start()
\ No newline at end of file
diff --git a/code/modules/blob2/overmind/types/reactive_spines.dm b/code/modules/blob2/overmind/types/reactive_spines.dm
new file mode 100644
index 0000000000..0d0021f243
--- /dev/null
+++ b/code/modules/blob2/overmind/types/reactive_spines.dm
@@ -0,0 +1,59 @@
+// Auto-retaliates against melee attacks. Weak to projectiles.
+/datum/blob_type/reactive_spines
+ name = "reactive spines"
+ desc = "An ever-growing lifeform with a large amount of sharp, powerful looking spines. They look like they could pierce most armor."
+ ai_desc = "defensive"
+ effect_desc = "When attacked by a melee weapon, it will automatically retaliate, striking the attacker with an armor piercing attack. \
+ The blob itself is rather weak to all forms of attacks regardless, and lacks automatic realitation from ranged attacks."
+ difficulty = BLOB_DIFFICULTY_EASY // Potentially deadly to people not knowing the mechanics, but otherwise fairly tame, due to its slow spread and weakness.
+ color = "#9ACD32"
+ complementary_color = "#FFA500"
+ damage_type = BRUTE
+ damage_lower = 30
+ damage_upper = 40
+ armor_pen = 50 // Even with riot armor and tactical jumpsuit, you'd have 90 armor, reduced by 50, totaling 40. Getting hit for around 21 damage is still rough.
+ burn_multiplier = 2.0
+ brute_multiplier = 2.0
+ spread_modifier = 0.35 // Ranged projectiles tend to have a higher material cost, so ease up on the spreading.
+ ai_aggressiveness = 40
+ chunk_passive_ability_cooldown = 0.5 SECONDS
+ attack_message = "The blob stabs you"
+ attack_message_living = ", and you feel sharp spines pierce your flesh"
+ attack_message_synth = ", and your external plating is pierced by sharp spines"
+ attack_verb = "stabs"
+ spore_projectile = /obj/item/projectile/bullet/thorn
+
+// Even if the melee attack is enough to one-shot this blob, it gets to retaliate at least once.
+/datum/blob_type/reactive_spines/on_received_damage(var/obj/structure/blob/B, damage, damage_type, mob/living/attacker)
+ if(damage > 0 && attacker && get_dist(B, attacker) <= 1)
+ B.visible_message("The [name] retaliates, lashing out at \the [attacker]!")
+ B.blob_attack_animation(attacker, B.overmind)
+ attacker.blob_act(B)
+ return ..()
+
+// We're expecting 1 to be a target, 2 to be an old move loc, and 3 to be a new move loc.
+/datum/blob_type/reactive_spines/chunk_unique(obj/item/weapon/blobcore_chunk/B, var/list/extra_data = null)
+ if(!LAZYLEN(extra_data))
+ return
+
+ var/atom/movable/A = extra_data[1]
+
+ if(istype(A, /mob/living) && world.time > (B.last_passive_use + B.passive_ability_cooldown) && B.should_tick)
+ B.last_passive_use = world.time
+ var/mob/living/L = A
+
+ var/mob/living/carrier = B.get_carrier()
+
+ if(!istype(carrier) || L.z != carrier.z || L == carrier || get_dist(L, carrier) > 3)
+ return
+
+ var/obj/item/projectile/P = new spore_projectile(get_turf(B))
+
+ carrier.visible_message("\The [B] fires a spine at \the [L]!")
+ P.launch_projectile(L, BP_TORSO, carrier)
+
+ return
+
+/datum/blob_type/reactive_spines/chunk_setup(obj/item/weapon/blobcore_chunk/B)
+ GLOB.moved_event.register_global(B, /obj/item/weapon/blobcore_chunk/proc/call_chunk_unique)
+ return
\ No newline at end of file
diff --git a/code/modules/blob2/overmind/types/roiling_mold.dm b/code/modules/blob2/overmind/types/roiling_mold.dm
new file mode 100644
index 0000000000..dd42be30ac
--- /dev/null
+++ b/code/modules/blob2/overmind/types/roiling_mold.dm
@@ -0,0 +1,63 @@
+// Blob that fires biological mortar shells from its factories.
+/datum/blob_type/roiling_mold
+ name = "roiling mold"
+ desc = "A bubbling, creeping mold."
+ ai_desc = "bombarding"
+ effect_desc = "Bombards nearby organisms with toxic spores. Weak to all damage."
+ difficulty = BLOB_DIFFICULTY_MEDIUM
+ color = "#571509"
+ complementary_color = "#ec4940"
+ damage_type = BRUTE
+ damage_lower = 5
+ damage_upper = 20
+ armor_check = "melee"
+ brute_multiplier = 1.2
+ burn_multiplier = 1.2
+ spread_modifier = 0.8
+ can_build_factories = TRUE
+ ai_aggressiveness = 50
+ attack_message = "The mold whips you"
+ attack_message_living = ", and you feel a searing pain"
+ attack_message_synth = ", and your shell buckles"
+ attack_verb = "lashes"
+ spore_projectile = /obj/item/projectile/arc/spore
+
+/datum/blob_type/roiling_mold/proc/find_target(var/obj/structure/blob/B, var/tries = 0, var/list/previous_targets = null)
+ if(tries > 3)
+ return
+ var/mob/living/L = locate() in (view(world.view + 3, get_turf(B)) - view(2,get_turf(B)) - previous_targets) // No adjacent mobs.
+
+ if(!check_trajectory(L, B, PASSTABLE))
+ if(!LAZYLEN(previous_targets))
+ previous_targets = list()
+
+ previous_targets |= L
+
+ L = find_target(B, tries + 1, previous_targets)
+
+ return L
+
+/datum/blob_type/roiling_mold/on_pulse(var/obj/structure/blob/B)
+ var/mob/living/L = find_target(B)
+
+ if(!istype(L))
+ return
+
+ if(istype(B, /obj/structure/blob/factory) && L.stat != DEAD && prob(ai_aggressiveness) && L.faction != "blob")
+ var/obj/item/projectile/arc/spore/P = new(get_turf(B))
+ P.launch_projectile(L, BP_TORSO, B)
+
+/datum/blob_type/roiling_mold/on_chunk_use(obj/item/weapon/blobcore_chunk/B, mob/living/user)
+ for(var/mob/living/L in oview(world.view, get_turf(B)))
+ if(istype(user) && user == L)
+ continue
+
+ if(!check_trajectory(L, B, PASSTABLE)) // Can't fire at things on the other side of walls / windows.
+ continue
+
+ var/obj/item/projectile/P = new spore_projectile(get_turf(B))
+
+ user.visible_message("\icon [B] \The [B] discharges energy toward \the [L]!")
+ P.launch_projectile(L, BP_TORSO, user)
+
+ return
\ No newline at end of file
diff --git a/code/modules/blob2/overmind/types/shifting_fragments.dm b/code/modules/blob2/overmind/types/shifting_fragments.dm
new file mode 100644
index 0000000000..ffca17760b
--- /dev/null
+++ b/code/modules/blob2/overmind/types/shifting_fragments.dm
@@ -0,0 +1,40 @@
+/datum/blob_type/shifting_fragments
+ name = "shifting fragments"
+ desc = "A collection of fragments that seem to shuffle around constantly."
+ ai_desc = "evasive"
+ effect_desc = "Swaps places with nearby blobs when hit or when expanding."
+ difficulty = BLOB_DIFFICULTY_EASY
+ color = "#C8963C"
+ complementary_color = "#3C6EC8"
+ damage_type = BRUTE
+ damage_lower = 20
+ damage_upper = 30
+ brute_multiplier = 0.5
+ burn_multiplier = 0.5
+ spread_modifier = 0.5
+ ai_aggressiveness = 30
+ chunk_active_ability_cooldown = 3 MINUTES
+ attack_message = "A fragment strikes you"
+ attack_verb = "strikes"
+
+/datum/blob_type/shifting_fragments/on_received_damage(var/obj/structure/blob/B, damage, damage_type)
+ if(damage > 0 && prob(60))
+ var/list/available_blobs = list()
+ for(var/obj/structure/blob/OB in orange(1, B))
+ if((istype(OB, /obj/structure/blob/normal) || (istype(OB, /obj/structure/blob/shield) && prob(25))) && OB.overmind && OB.overmind == B.overmind)
+ available_blobs += OB
+ if(available_blobs.len)
+ var/obj/structure/blob/targeted = pick(available_blobs)
+ var/turf/T = get_turf(targeted)
+ targeted.forceMove(get_turf(B))
+ B.forceMove(T) // Swap places.
+ return ..()
+
+/datum/blob_type/shifting_fragments/on_expand(var/obj/structure/blob/B, var/obj/structure/blob/new_B, var/turf/T, var/mob/observer/blob/O)
+ if(istype(B, /obj/structure/blob/normal) || (istype(B, /obj/structure/blob/shield) && prob(25)))
+ new_B.forceMove(get_turf(B))
+ B.forceMove(T)
+
+/datum/blob_type/shifting_fragments/on_chunk_use(obj/item/weapon/blobcore_chunk/B, mob/living/user)
+ user.add_modifier(/datum/modifier/sprinting, 2 MINUTES)
+ return
\ No newline at end of file
diff --git a/code/modules/blob2/overmind/types/synchronous_mesh.dm b/code/modules/blob2/overmind/types/synchronous_mesh.dm
new file mode 100644
index 0000000000..e234756b2d
--- /dev/null
+++ b/code/modules/blob2/overmind/types/synchronous_mesh.dm
@@ -0,0 +1,73 @@
+// Spreads damage to nearby blobs, and attacks with the force of all nearby blobs.
+/datum/blob_type/synchronous_mesh
+ name = "synchronous mesh"
+ desc = "A mesh that seems strongly interconnected to itself. It moves slowly, but with purpose."
+ ai_desc = "defensive"
+ effect_desc = "When damaged, spreads the damage to nearby blobs. When attacking, damage is increased based on how many blobs are near the target. It is resistant to burn damage."
+ difficulty = BLOB_DIFFICULTY_EASY // Mostly a tank and spank.
+ color = "#65ADA2"
+ complementary_color = "#AD6570"
+ damage_type = BRUTE
+ damage_lower = 10
+ damage_upper = 15
+ brute_multiplier = 0.5
+ burn_multiplier = 0.2 // Emitters do so much damage that this will likely not matter too much.
+ spread_modifier = 0.3 // Since the blob spreads damage, it takes awhile to actually kill, so spread is reduced.
+ ai_aggressiveness = 60
+ attack_message = "The mesh synchronously strikes you"
+ attack_verb = "synchronously strikes"
+ var/synchronously_attacking = FALSE
+
+/datum/blob_type/synchronous_mesh/on_attack(obj/structure/blob/B, mob/living/victim)
+ if(synchronously_attacking)
+ return
+ synchronously_attacking = TRUE // To avoid infinite loops.
+ for(var/obj/structure/blob/C in orange(1, victim))
+ if(victim) // Some things delete themselves when dead...
+ C.blob_attack_animation(victim)
+ victim.blob_act(C)
+ synchronously_attacking = FALSE
+
+/datum/blob_type/synchronous_mesh/on_received_damage(var/obj/structure/blob/B, damage, damage_type)
+ var/list/blobs_to_hurt = list() // Maximum split is 9, reducing the damage each blob takes to 11.1% but doing that damage to 9 blobs.
+ for(var/obj/structure/blob/C in range(1, B))
+ if(!istype(C, /obj/structure/blob/core) && !istype(C, /obj/structure/blob/node) && C.overmind && (C.overmind == B.overmind) ) //if it doesn't have the same 'ownership' or is a core or node, don't split damage to it
+ blobs_to_hurt += C
+
+ for(var/thing in blobs_to_hurt)
+ var/obj/structure/blob/C = thing
+ if(C == B)
+ continue // We'll damage this later.
+
+ C.adjust_integrity(-(damage / blobs_to_hurt.len))
+
+ return damage / max(blobs_to_hurt.len, 1) // To hurt the blob that got hit.
+
+/datum/blob_type/synchronous_mesh/on_chunk_tick(obj/item/weapon/blobcore_chunk/B)
+ var/mob/living/carrier = B.get_carrier()
+
+ if(!carrier)
+ return
+
+ var/list/nearby_mobs = list()
+ for(var/mob/living/L in oview(world.view, carrier))
+ if(L.stat != DEAD)
+ nearby_mobs |= L
+
+ if(nearby_mobs.len)
+ for(var/mob/living/victim in nearby_mobs)
+ var/need_beam = FALSE
+
+ if(carrier.getBruteLoss())
+ need_beam = TRUE
+ victim.adjustBruteLoss(3 / nearby_mobs.len)
+ carrier.adjustBruteLoss(-3 / nearby_mobs.len)
+
+ if(carrier.getFireLoss())
+ need_beam = TRUE
+ victim.adjustFireLoss(3 / nearby_mobs.len)
+ carrier.adjustFireLoss(-3 / nearby_mobs.len)
+
+ if(need_beam)
+ carrier.visible_message("\icon [B] \The [B] sends noxious spores toward \the [victim]!")
+ carrier.Beam(victim, icon_state = "lichbeam", time = 2 SECONDS)
\ No newline at end of file
diff --git a/code/modules/blob2/overmind/types/volatile_alluvium.dm b/code/modules/blob2/overmind/types/volatile_alluvium.dm
new file mode 100644
index 0000000000..a689bb856f
--- /dev/null
+++ b/code/modules/blob2/overmind/types/volatile_alluvium.dm
@@ -0,0 +1,55 @@
+// A blob that steals your weapon.
+/datum/blob_type/volatile_alluvium
+ name = "volatile alluvium"
+ desc = "A churning, earthy mass that moves in waves."
+ ai_desc = "earthen"
+ effect_desc = "Moves slowly, producing weak ranged spores to defend itself, and inflicts brute attacks. Attempts to disarm nearby attackers. Weak to water."
+ difficulty = BLOB_DIFFICULTY_HARD //Slow-starting, but can be overwhelming if left alone.
+ color = "#6B481E"
+ complementary_color = "#7F471F"
+ damage_lower = 10
+ damage_upper = 20
+ armor_pen = 40
+ brute_multiplier = 0.7
+ burn_multiplier = 0.5
+ spread_modifier = 0.5
+ ai_aggressiveness = 50
+ attack_message = "The alluvium crashes against you"
+ attack_verb = "crashes against"
+ can_build_factories = TRUE
+ can_build_resources = TRUE
+ spore_type = /mob/living/simple_mob/blob/spore/weak
+ ranged_spores = TRUE
+ spore_range = 3
+ spore_projectile = /obj/item/projectile/energy/blob/splattering
+ spore_accuracy = 15
+ spore_dispersion = 45
+ factory_type = /obj/structure/blob/factory/sluggish
+ resource_type = /obj/structure/blob/resource/sluggish
+ chunk_active_ability_cooldown = 2 MINUTES
+
+/datum/blob_type/volatile_alluvium/on_received_damage(var/obj/structure/blob/B, damage, damage_type, mob/living/attacker)
+ if(damage > 0 && attacker && get_dist(B, attacker) <= 2 && prob(min(damage, 70)) && istype(attacker, /mob/living/carbon/human)) // Melee weapons of any type carried by a human will have a high chance of being stolen.
+ var/mob/living/carbon/human/H = attacker
+ var/obj/item/I = H.get_active_hand()
+ H.drop_item()
+ if(I)
+ if((I.sharp || I.edge) && !istype(I, /obj/item/weapon/gun))
+ I.forceMove(get_turf(B)) // Disarmed entirely.
+ B.visible_message("The [name] heaves, \the [attacker]'s weapon becoming stuck in the churning mass!")
+ else
+ I.throw_at(B, 2, 4) // Just yoinked.
+ B.visible_message("The [name] heaves, pulling \the [attacker]'s weapon from their hands!")
+ B.blob_attack_animation(attacker, B.overmind)
+ return ..()
+
+/datum/blob_type/volatile_alluvium/on_water(obj/structure/blob/B, amount)
+ spawn(1)
+ var/damage = amount * 4
+ B.adjust_integrity(-(damage))
+ if(B && prob(damage))
+ B.visible_message("The [name] begins to crumble!")
+
+/datum/blob_type/volatile_alluvium/on_chunk_use(obj/item/weapon/blobcore_chunk/B, mob/living/user)
+ if(user)
+ user.add_modifier(/datum/modifier/fortify, 60 SECONDS)
diff --git a/code/modules/mob/_modifiers/modifiers.dm b/code/modules/mob/_modifiers/modifiers.dm
index ca0f96d07b..5950d9e98d 100644
--- a/code/modules/mob/_modifiers/modifiers.dm
+++ b/code/modules/mob/_modifiers/modifiers.dm
@@ -48,6 +48,8 @@
var/pain_immunity // Makes the holder not care about pain while this is on. Only really useful to human mobs.
var/pulse_modifier // Modifier for pulse, will be rounded on application, then added to the normal 'pulse' multiplier which ranges between 0 and 5 normally. Only applied if they're living.
var/pulse_set_level // Positive number. If this is non-null, it will hard-set the pulse level to this. Pulse ranges from 0 to 5 normally.
+ var/emp_modifier // Added to the EMP strength, which is an inverse scale from 1 to 4, with 1 being the strongest EMP. 5 is a nullification.
+ var/explosion_modifier // Added to the bomb strength, which is an inverse scale from 1 to 3, with 1 being gibstrength. 4 is a nullification.
/datum/modifier/New(var/new_holder, var/new_origin)
holder = new_holder
diff --git a/code/modules/mob/_modifiers/modifiers_misc.dm b/code/modules/mob/_modifiers/modifiers_misc.dm
index 743e41bd1d..8e6a094910 100644
--- a/code/modules/mob/_modifiers/modifiers_misc.dm
+++ b/code/modules/mob/_modifiers/modifiers_misc.dm
@@ -324,3 +324,67 @@ the artifact triggers the rage.
/datum/modifier/homeothermic/tick()
..()
holder.bodytemperature = round((holder.bodytemperature + T20C) / 2)
+
+/datum/modifier/exothermic
+ name = "heat resistance"
+ desc = "Your body lowers to room temperature."
+
+ on_created_text = "You feel comfortable."
+ on_expired_text = "You feel.. still probably comfortable."
+ stacks = MODIFIER_STACK_EXTEND
+
+/datum/modifier/exothermic/tick()
+ ..()
+ if(holder.bodytemperature > T20C)
+ holder.bodytemperature = round((holder.bodytemperature + T20C) / 2)
+
+/datum/modifier/endothermic
+ name = "cold resistance"
+ desc = "Your body rises to room temperature."
+
+ on_created_text = "You feel comfortable."
+ on_expired_text = "You feel.. still probably comfortable."
+ stacks = MODIFIER_STACK_EXTEND
+
+/datum/modifier/endothermic/tick()
+ ..()
+ if(holder.bodytemperature < T20C)
+ holder.bodytemperature = round((holder.bodytemperature + T20C) / 2)
+
+// Nullifies EMP.
+/datum/modifier/faraday
+ name = "EMP shielding"
+ desc = "You are covered in some form of faraday shielding. EMPs have no effect."
+ mob_overlay_state = "electricity"
+
+ on_created_text = "You feel a surge of energy, that fades to a calm tide."
+ on_expired_text = "You feel a longing for the flow of energy."
+ stacks = MODIFIER_STACK_EXTEND
+
+ emp_modifier = 5
+
+// Nullifies explosions.
+/datum/modifier/blastshield
+ name = "Blast Shielding"
+ desc = "You are protected from explosions somehow."
+ mob_overlay_state = "electricity"
+
+ on_created_text = "You feel a surge of energy, that fades to a stalwart hum."
+ on_expired_text = "You feel a longing for the flow of energy."
+ stacks = MODIFIER_STACK_EXTEND
+
+ explosion_modifier = 3
+
+// Kills on expiration.
+/datum/modifier/doomed
+ name = "Doomed"
+ desc = "You are doomed."
+
+ on_created_text = "You feel an overwhelming sense of dread."
+ on_expired_text = "You feel the life drain from your body."
+ stacks = MODIFIER_STACK_EXTEND
+
+/datum/modifier/doomed/on_expire()
+ if(holder.stat != DEAD)
+ holder.visible_message("\The [holder] collapses, the life draining from their body.")
+ holder.death()
diff --git a/code/modules/mob/living/carbon/human/ai_controlled/ai_controlled.dm b/code/modules/mob/living/carbon/human/ai_controlled/ai_controlled.dm
index 431b7c4456..7b222d8a61 100644
--- a/code/modules/mob/living/carbon/human/ai_controlled/ai_controlled.dm
+++ b/code/modules/mob/living/carbon/human/ai_controlled/ai_controlled.dm
@@ -3,6 +3,8 @@
ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive
+ a_intent = I_HURT
+
var/generate_species = SPECIES_HUMAN
var/generate_dead = FALSE
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 557a3dd83b..642eaa2c4f 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -100,6 +100,15 @@
if(!blinded)
flash_eyes()
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.explosion_modifier))
+ severity = CLAMP(severity + M.explosion_modifier, 1, 4)
+
+ severity = round(severity)
+
+ if(severity > 3)
+ return
+
var/shielded = 0
var/b_loss = null
var/f_loss = null
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 0184a54d59..428cff3659 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -167,6 +167,15 @@
/mob/living/emp_act(severity)
var/list/L = src.get_contents()
+
+ if(LAZYLEN(modifiers))
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.emp_modifier))
+ severity = CLAMP(severity + M.emp_modifier, 1, 5)
+
+ if(severity == 5) // Effectively nullified.
+ return
+
for(var/obj/O in L)
O.emp_act(severity)
..()
@@ -206,6 +215,9 @@
var/soaked = get_armor_soak(def_zone, armor_check, armor_pen)
var/absorb = run_armor_check(def_zone, armor_check, armor_pen)
+ if(ai_holder)
+ ai_holder.react_to_attack(B)
+
apply_damage(damage, damage_type, def_zone, absorb, soaked)
/mob/living/proc/resolve_item_attack(obj/item/I, mob/living/user, var/target_zone)
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 6c7456f80e..6a74eb41d5 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -305,6 +305,15 @@
if(!blinded)
flash_eyes()
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.explosion_modifier))
+ severity = CLAMP(severity + M.explosion_modifier, 1, 4)
+
+ severity = round(severity)
+
+ if(severity > 3)
+ return
+
switch(severity)
if(1.0)
if (stat != 2)
diff --git a/code/modules/mob/living/simple_mob/defense.dm b/code/modules/mob/living/simple_mob/defense.dm
index 744237b21d..c09bf272cc 100644
--- a/code/modules/mob/living/simple_mob/defense.dm
+++ b/code/modules/mob/living/simple_mob/defense.dm
@@ -96,6 +96,16 @@
/mob/living/simple_mob/ex_act(severity)
if(!blinded)
flash_eyes()
+
+ for(var/datum/modifier/M in modifiers)
+ if(!isnull(M.explosion_modifier))
+ severity = CLAMP(severity + M.explosion_modifier, 1, 4)
+
+ severity = round(severity)
+
+ if(severity > 3)
+ return
+
var/armor = run_armor_check(def_zone = null, attack_flag = "bomb")
var/bombdam = 500
switch (severity)
diff --git a/code/modules/mob/living/simple_mob/subtypes/blob/blob.dm b/code/modules/mob/living/simple_mob/subtypes/blob/blob.dm
index 2d700646ae..44ab4fdd09 100644
--- a/code/modules/mob/living/simple_mob/subtypes/blob/blob.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/blob/blob.dm
@@ -23,6 +23,7 @@
var/mob/observer/blob/overmind = null
var/obj/structure/blob/factory/factory = null
+ var/datum/blob_type/blob_type = null // Used for the blob core items, as they have no overmind mob.
mob_class = MOB_CLASS_SLIME
ai_holder_type = /datum/ai_holder/simple_mob/melee
@@ -33,6 +34,8 @@
/mob/living/simple_mob/blob/update_icons()
if(overmind)
color = overmind.blob_type.complementary_color
+ else if(blob_type)
+ color = blob_type.complementary_color
else
color = null
..()
@@ -40,6 +43,8 @@
/mob/living/simple_mob/blob/Destroy()
if(overmind)
overmind.blob_mobs -= src
+ if(blob_type)
+ blob_type = null
return ..()
/mob/living/simple_mob/blob/blob_act(obj/structure/blob/B)
@@ -59,4 +64,17 @@
/mob/living/simple_mob/blob/Process_Spacemove()
for(var/obj/structure/blob/B in range(1, src))
return TRUE
- return ..()
\ No newline at end of file
+ return ..()
+
+/mob/living/simple_mob/blob/IIsAlly(mob/living/L)
+ var/ally = ..(L)
+ if(!ally)
+ var/list/items = L.get_all_held_items()
+ for(var/obj/item/I in items)
+ if(istype(I, /obj/item/weapon/blobcore_chunk))
+ var/obj/item/weapon/blobcore_chunk/BC = I
+ if(!overmind || (BC.blob_type && overmind.blob_type.type == BC.blob_type.type))
+ ally = TRUE
+ break
+
+ return ally
diff --git a/code/modules/mob/living/simple_mob/subtypes/blob/spore.dm b/code/modules/mob/living/simple_mob/subtypes/blob/spore.dm
index 29663f9e2c..579c97be78 100644
--- a/code/modules/mob/living/simple_mob/subtypes/blob/spore.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/blob/spore.dm
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
// Spores are made from blob factories.
// They are very weak and expendable, but can overwhelm when a lot of them are together.
// When attacking, spores will hit harder if near other friendly spores.
@@ -146,3 +147,160 @@
if(helpers)
to_chat(src, span("notice", "Your attack is assisted by [helpers] other spore\s."))
return damage_to_do
+=======
+// Spores are made from blob factories.
+// They are very weak and expendable, but can overwhelm when a lot of them are together.
+// When attacking, spores will hit harder if near other friendly spores.
+// Some blobs can infest dead non-robotic mobs, making them into Not Zombies.
+
+/mob/living/simple_mob/blob/spore
+ name = "blob spore"
+ desc = "A floating, fragile spore."
+
+ icon_state = "blobpod"
+ icon_living = "blobpod"
+ glow_range = 3
+ glow_intensity = 5
+ layer = ABOVE_MOB_LAYER // Over the blob.
+
+ health = 30
+ maxHealth = 30
+ melee_damage_lower = 2
+ melee_damage_upper = 4
+ movement_cooldown = 0
+ hovering = TRUE
+
+ attacktext = list("slammed into")
+ attack_sound = 'sound/effects/slime_squish.ogg'
+ say_list_type = /datum/say_list/spore
+
+ var/mob/living/carbon/human/infested = null // The human this thing is totally not making into a zombie.
+ var/can_infest = FALSE
+ var/is_infesting = FALSE
+
+/datum/say_list/spore
+ emote_see = list("sways", "inflates briefly")
+
+/datum/say_list/infested
+ emote_see = list("shambles around", "twitches", "stares")
+
+
+/mob/living/simple_mob/blob/spore/infesting
+ name = "infesting blob spore"
+ can_infest = TRUE
+
+/mob/living/simple_mob/blob/spore/weak
+ name = "fragile blob spore"
+ health = 15
+ maxHealth = 15
+ melee_damage_lower = 1
+ melee_damage_upper = 2
+
+/mob/living/simple_mob/blob/spore/Initialize(mapload, var/obj/structure/blob/factory/my_factory)
+ if(istype(my_factory))
+ factory = my_factory
+ factory.spores += src
+ return ..()
+
+/mob/living/simple_mob/blob/spore/Destroy()
+ if(factory)
+ factory.spores -= src
+ factory = null
+ if(infested)
+ infested.forceMove(get_turf(src))
+ visible_message(span("warning", "\The [infested] falls to the ground as the blob spore bursts."))
+ infested = null
+ return ..()
+
+/mob/living/simple_mob/blob/spore/death(gibbed, deathmessage = "bursts!")
+ if(overmind)
+ overmind.blob_type.on_spore_death(src)
+ ..(gibbed, deathmessage)
+ qdel(src)
+
+/mob/living/simple_mob/blob/spore/update_icons()
+ ..() // This will cut our overlays.
+
+ if(overmind)
+ color = overmind.blob_type.complementary_color
+ glow_color = color
+ glow_toggle = TRUE
+ else if(blob_type)
+ color = blob_type.complementary_color
+ glow_color = color
+ glow_toggle = TRUE
+ else
+ color = null
+ glow_color = null
+ glow_toggle = FALSE
+
+ if(is_infesting)
+ icon = infested.icon
+ copy_overlays(infested)
+ // overlays = infested.overlays
+ var/mutable_appearance/blob_head_overlay = mutable_appearance('icons/mob/blob.dmi', "blob_head")
+ if(overmind)
+ blob_head_overlay.color = overmind.blob_type.complementary_color
+ color = initial(color)//looks better.
+ // overlays += blob_head_overlay
+ add_overlay(blob_head_overlay, TRUE)
+
+/mob/living/simple_mob/blob/spore/handle_special()
+ ..()
+ if(can_infest && !is_infesting && isturf(loc))
+ for(var/mob/living/carbon/human/H in view(src,1))
+ if(H.stat != DEAD) // We want zombies.
+ continue
+ if(H.isSynthetic()) // Not philosophical zombies.
+ continue
+ infest(H)
+ break
+
+ if(overmind)
+ overmind.blob_type.on_spore_lifetick(src)
+
+ if(factory && z != factory.z) // This is to prevent spores getting lost in space and making the factory useless.
+ qdel(src)
+
+/mob/living/simple_mob/blob/spore/proc/infest(mob/living/carbon/human/H)
+ is_infesting = TRUE
+ if(H.wear_suit)
+ var/obj/item/clothing/suit/A = H.wear_suit
+ if(A.armor && A.armor["melee"])
+ maxHealth += A.armor["melee"] //That zombie's got armor, I want armor!
+
+ maxHealth += 40
+ health = maxHealth
+ name = "Infested [H.real_name]" // Not using the Z word.
+ desc = "A parasitic organism attached to a deceased body, controlling it directly as if it were a puppet."
+ melee_damage_lower += 8 // 10 total.
+ melee_damage_upper += 11 // 15 total.
+ attacktext = list("clawed")
+
+ H.forceMove(src)
+ infested = H
+
+ say_list = new /datum/say_list/infested()
+
+ update_icons()
+ visible_message(span("warning", "The corpse of [H.name] suddenly rises!"))
+
+/mob/living/simple_mob/blob/spore/GetIdCard()
+ if(infested) // If we've infested someone, use their ID.
+ return infested.GetIdCard()
+
+/mob/living/simple_mob/blob/spore/apply_bonus_melee_damage(A, damage_to_do)
+ var/helpers = 0
+ for(var/mob/living/simple_mob/blob/spore/S in view(1, src))
+ if(S == src) // Don't count ourselves.
+ continue
+ if(!IIsAlly(S)) // Only friendly spores make us stronger.
+ continue
+ // Friendly spores contribute 1/4th of their averaged attack power to our attack.
+ damage_to_do += ((S.melee_damage_lower + S.melee_damage_upper) / 2) / 4
+ helpers++
+
+ if(helpers)
+ to_chat(src, span("notice", "Your attack is assisted by [helpers] other spore\s."))
+ return damage_to_do
+>>>>>>> 32a573f... Merge pull request #6878 from Mechoid/ATaleofBlobsandMen
diff --git a/code/modules/projectiles/projectile/arc.dm b/code/modules/projectiles/projectile/arc.dm
index 1f19dc0242..12f135a9bb 100644
--- a/code/modules/projectiles/projectile/arc.dm
+++ b/code/modules/projectiles/projectile/arc.dm
@@ -49,7 +49,6 @@
on_impact(loc)
return ..()
-
/obj/item/projectile/arc/launch_projectile(atom/target, target_zone, mob/user, params, angle_override, forced_spread = 0)
fired_dir = get_dir(user, target) // Used to determine if the projectile should turn in the air.
distance_to_fly = calculate_initial_pixel_distance(user, target) // Calculates how many pixels to travel before hitting the ground.
@@ -168,3 +167,34 @@
/obj/item/projectile/arc/radioactive/on_impact(turf/T)
SSradiation.radiate(T, rad_power)
+
+// Blob mortar
+/obj/item/projectile/arc/spore
+ name = "spore"
+ icon_state = "declone"
+ damage = 20
+ damage_type = BIOACID
+ armor_penetration = 30
+ fire_sound = 'sound/effects/slime_squish.ogg'
+
+/obj/item/projectile/arc/spore/on_impact(turf/T)
+ for(var/mob/living/L in T)
+ attack_mob(L)
+
+ spawn()
+ T.visible_message("\The [src] covers \the [T] in a corrosive paste!")
+ for(var/turf/simulated/floor/F in view(2, T))
+ spawn()
+ var/obj/effect/effect/water/splash = new(T)
+ splash.create_reagents(15)
+ splash.reagents.add_reagent("stomacid", 5)
+ splash.reagents.add_reagent("blood", 10,list("blood_colour" = "#ec4940"))
+ splash.set_color()
+
+ splash.set_up(F, 2, 3)
+
+ var/obj/effect/decal/cleanable/chemcoating/acid = locate() in T
+ if(!istype(acid))
+ acid = new(T)
+ acid.reagents.add_reagent("stomacid", 5)
+ acid.update_icon()
diff --git a/code/modules/projectiles/projectile/blob.dm b/code/modules/projectiles/projectile/blob.dm
index 7ebc5cdfad..f73fe9d008 100644
--- a/code/modules/projectiles/projectile/blob.dm
+++ b/code/modules/projectiles/projectile/blob.dm
@@ -28,9 +28,9 @@
/obj/item/projectile/energy/blob/on_impact(var/atom/A)
if(splatter)
var/turf/location = get_turf(src)
- var/datum/effect/effect/system/smoke_spread/chem/S = new /datum/effect/effect/system/smoke_spread/chem
+ var/datum/effect/effect/system/smoke_spread/chem/blob/S = new /datum/effect/effect/system/smoke_spread/chem/blob
S.attach(location)
- S.set_up(reagents, splatter_volume, 0, location)
+ S.set_up(reagents, rand(1, splatter_volume), 0, location)
playsound(location, 'sound/effects/slime_squish.ogg', 30, 1, -3)
spawn(0)
S.start()
@@ -70,3 +70,12 @@
/obj/item/projectile/energy/blob/freezing/splattering
splatter = TRUE
+
+/obj/item/projectile/bullet/thorn
+ name = "spike"
+ icon_state = "SpearFlight"
+ damage = 20
+ damage_type = BIOACID
+ armor_penetration = 20
+ penetrating = 3
+ fire_sound = 'sound/effects/slime_squish.ogg'
diff --git a/icons/mob/blob.dmi b/icons/mob/blob.dmi
index 86d961c4c8..073a2b03ee 100644
Binary files a/icons/mob/blob.dmi and b/icons/mob/blob.dmi differ
diff --git a/vorestation.dme b/vorestation.dme
index 54accba354..ff2f287830 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -1641,6 +1641,7 @@
#include "code\modules\awaymissions\zlevel.dm"
#include "code\modules\blob\blob.dm"
#include "code\modules\blob2\_defines.dm"
+#include "code\modules\blob2\core_chunk.dm"
#include "code\modules\blob2\blobs\base_blob.dm"
#include "code\modules\blob2\blobs\core.dm"
#include "code\modules\blob2\blobs\factory.dm"
@@ -1651,6 +1652,25 @@
#include "code\modules\blob2\overmind\overmind.dm"
#include "code\modules\blob2\overmind\powers.dm"
#include "code\modules\blob2\overmind\types.dm"
+#include "code\modules\blob2\overmind\types\blazing_oil.dm"
+#include "code\modules\blob2\overmind\types\classic.dm"
+#include "code\modules\blob2\overmind\types\cryogenic_goo.dm"
+#include "code\modules\blob2\overmind\types\ectoplasmic_horror.dm"
+#include "code\modules\blob2\overmind\types\electromagnetic_web.dm"
+#include "code\modules\blob2\overmind\types\energized_jelly.dm"
+#include "code\modules\blob2\overmind\types\explosive_lattice.dm"
+#include "code\modules\blob2\overmind\types\fabrication_swarm.dm"
+#include "code\modules\blob2\overmind\types\fulminant_organism.dm"
+#include "code\modules\blob2\overmind\types\fungal_bloom.dm"
+#include "code\modules\blob2\overmind\types\grey_goo.dm"
+#include "code\modules\blob2\overmind\types\pressurized_slime.dm"
+#include "code\modules\blob2\overmind\types\radioactive_ooze.dm"
+#include "code\modules\blob2\overmind\types\ravenous_macrophage.dm"
+#include "code\modules\blob2\overmind\types\reactive_spines.dm"
+#include "code\modules\blob2\overmind\types\roiling_mold.dm"
+#include "code\modules\blob2\overmind\types\shifting_fragments.dm"
+#include "code\modules\blob2\overmind\types\synchronous_mesh.dm"
+#include "code\modules\blob2\overmind\types\volatile_alluvium.dm"
#include "code\modules\busy_space\air_traffic.dm"
#include "code\modules\busy_space\loremaster.dm"
#include "code\modules\busy_space_vr\organizations.dm"