Works on New Blob

This commit is contained in:
Neerti
2017-11-05 12:38:18 -05:00
parent 50d3710cbf
commit acb208dd3f
54 changed files with 1947 additions and 38 deletions

View File

@@ -0,0 +1,97 @@
var/list/overminds = list()
/mob/observer/blob
name = "Blob Overmind"
real_name = "Blob Overmind"
desc = "The overmind. It controls the blob."
icon = 'icons/mob/blob.dmi'
icon_state = "marker"
mouse_opacity = 1
see_in_dark = 8
invisibility = INVISIBILITY_OBSERVER
layer = FLY_LAYER + 0.1
faction = "blob"
var/obj/structure/blob/core/blob_core = null // The blob overmind's core
var/blob_points = 0
var/max_blob_points = 200
var/last_attack = 0
var/datum/blob_type/blob_type = null
var/list/blob_mobs = list()
var/list/resource_blobs = list()
var/placed = 0
var/base_point_rate = 2 //for blob core placement
var/ai_controlled = TRUE
var/auto_pilot = FALSE // If true, and if a client is attached, the AI routine will continue running.
/mob/observer/blob/New(var/newloc, pre_placed = 0, starting_points = 60, desired_blob_type = null)
blob_points = starting_points
if(pre_placed) //we already have a core!
placed = 1
overminds += src
var/new_name = "[initial(name)] ([rand(1, 999)])"
name = new_name
real_name = new_name
if(desired_blob_type)
blob_type = new desired_blob_type()
else
var/datum/blob_type/BT = pick(subtypesof(/datum/blob_type))
blob_type = new BT()
color = blob_type.complementary_color
if(blob_core)
blob_core.update_icon()
level_seven_blob_announcement(blob_core)
..(newloc)
/mob/observer/blob/Destroy()
for(var/BL in blobs)
var/obj/structure/blob/B = BL
if(B && B.overmind == src)
B.overmind = null
B.update_icon() //reset anything that was ours
for(var/BLO in blob_mobs)
var/mob/living/simple_animal/hostile/blob/BM = BLO
if(BM)
BM.overmind = null
BM.update_icons()
overminds -= src
return ..()
/mob/observer/blob/Stat()
..()
if(statpanel("Status"))
if(blob_core)
stat(null, "Core Health: [blob_core.integrity]")
stat(null, "Power Stored: [blob_points]/[max_blob_points]")
stat(null, "Total Blobs: [blobs.len]")
/mob/observer/blob/Move(NewLoc, Dir = 0)
if(placed)
var/obj/structure/blob/B = locate() in range("3x3", NewLoc)
if(B)
forceMove(NewLoc)
return TRUE
else
return FALSE
else
var/area/A = get_area(NewLoc)
if(istype(NewLoc, /turf/space) || istype(A, /area/shuttle)) //if unplaced, can't go on shuttles or space tiles
return FALSE
forceMove(NewLoc)
return TRUE
/mob/observer/blob/proc/add_points(points)
blob_points = between(0, blob_points + points, max_blob_points)
/mob/observer/blob/Life()
if(ai_controlled && (!client || auto_pilot))
if(prob(blob_type.ai_aggressiveness))
auto_attack()
if(blob_points >= 100)
if(!auto_factory() && !auto_resource())
auto_node()

View File

@@ -0,0 +1,229 @@
/mob/observer/blob/proc/can_buy(cost = 15)
if(blob_points < cost)
to_chat(src, "<span class='warning'>You cannot afford this, you need at least [cost] resources!</span>")
return FALSE
add_points(-cost)
return TRUE
/mob/observer/blob/verb/transport_core()
set category = "Blob"
set name = "Jump to Core"
set desc = "Move your camera to your core."
if(blob_core)
forceMove(blob_core.loc)
/mob/observer/blob/proc/createSpecial(price, blobType, nearEquals, needsNode, turf/T)
if(!T)
T = get_turf(src)
var/obj/structure/blob/B = (locate(/obj/structure/blob) in T)
if(!B)
to_chat(src, "<span class='warning'>There is no blob here!</span>")
return
if(!istype(B, /obj/structure/blob/normal))
to_chat(src, "<span class='warning'>Unable to use this blob, find a normal one.</span>")
return
if(nearEquals)
for(var/obj/structure/blob/L in orange(nearEquals, T))
if(L.type == blobType)
to_chat(src, "<span class='warning'>There is a similar blob nearby, move more than [nearEquals] tiles away from it!</span>")
return
if(!can_buy(price))
return
var/obj/structure/blob/N = B.change_to(blobType, src)
return N
/mob/observer/blob/verb/create_shield_power()
set category = "Blob"
set name = "Create Shield Blob (15)"
set desc = "Create a shield blob, which is hard to kill."
create_shield()
/mob/observer/blob/proc/create_shield(turf/T)
createSpecial(15, /obj/structure/blob/shield, 0, 0, T)
/mob/observer/blob/verb/create_resource()
set category = "Blob"
set name = "Create Resource Blob (40)"
set desc = "Create a resource tower which will generate resources for you."
if(!blob_type.can_build_resources)
return FALSE
createSpecial(40, /obj/structure/blob/resource, 4, 1)
/mob/observer/blob/verb/auto_resource()
set category = "Blob"
set name = "Auto Resource Blob (40)"
set desc = "Automatically places a resource tower near a node or your core, at a sufficent distance."
if(!blob_type.can_build_resources)
return FALSE
var/obj/structure/blob/B = null
var/list/potential_blobs = blobs.Copy()
while(potential_blobs.len)
var/obj/structure/blob/temp = pick(potential_blobs)
if(!(locate(/obj/structure/blob/node) in range(temp, BLOB_NODE_PULSE_RANGE) ) && !(locate(/obj/structure/blob/core) in range(temp, BLOB_CORE_PULSE_RANGE) ))
potential_blobs -= temp // Can't be pulsed.
else if(locate(/obj/structure/blob/resource) in range(temp, 4) )
potential_blobs -= temp // Too close to another resource blob.
else if(locate(/obj/structure/blob/core) in range(temp, 1) )
potential_blobs -= temp // Don't take up the core's shield spot.
else if(!istype(temp, /obj/structure/blob/normal))
potential_blobs -= temp // Not a normal blob.
else
B = temp
break
CHECK_TICK // Iterating over a list containing hundreds of blobs can get taxing.
if(B)
forceMove(B.loc)
return createSpecial(40, /obj/structure/blob/resource, 4, 1, B.loc)
/mob/observer/blob/verb/create_factory()
set category = "Blob"
set name = "Create Factory Blob (60)"
set desc = "Create a spore tower that will spawn spores to harass your enemies."
if(!blob_type.can_build_factories)
return FALSE
createSpecial(60, /obj/structure/blob/factory, 7, 1)
/mob/observer/blob/verb/auto_factory()
set category = "Blob"
set name = "Auto Factory Blob (60)"
set desc = "Automatically places a resource tower near a node or your core, at a sufficent distance."
if(!blob_type.can_build_factories)
return FALSE
var/obj/structure/blob/B = null
var/list/potential_blobs = blobs.Copy()
while(potential_blobs.len)
var/obj/structure/blob/temp = pick(potential_blobs)
if(!(locate(/obj/structure/blob/node) in range(temp, BLOB_NODE_PULSE_RANGE) ) && !(locate(/obj/structure/blob/core) in range(temp, BLOB_CORE_PULSE_RANGE) ))
potential_blobs -= temp // Can't be pulsed.
else if(locate(/obj/structure/blob/factory) in range(temp, 7) )
potential_blobs -= temp // Too close to another factory blob.
else if(locate(/obj/structure/blob/core) in range(temp, 1) )
potential_blobs -= temp // Don't take up the core's shield spot.
else if(!istype(temp, /obj/structure/blob/normal))
potential_blobs -= temp // Not a normal blob.
else
B = temp
break
CHECK_TICK
if(B)
forceMove(B.loc)
return createSpecial(60, /obj/structure/blob/factory, 7, 1, B.loc)
/mob/observer/blob/verb/create_node()
set category = "Blob"
set name = "Create Node Blob (100)"
set desc = "Create a node, which will expand blobs around it, and power nearby factory and resource blobs."
if(!blob_type.can_build_nodes)
return FALSE
createSpecial(100, /obj/structure/blob/node, 5, 0)
/mob/observer/blob/verb/auto_node()
set category = "Blob"
set name = "Auto Node Blob (100)"
set desc = "Automatically places a node blob at a sufficent distance."
if(!blob_type.can_build_nodes)
return FALSE
var/obj/structure/blob/B = null
var/list/potential_blobs = blobs.Copy()
while(potential_blobs.len)
var/obj/structure/blob/temp = pick(potential_blobs)
if(locate(/obj/structure/blob/node) in range(temp, 5) )
potential_blobs -= temp
else if(locate(/obj/structure/blob/core) in range(temp, 5) )
potential_blobs -= temp
else if(!istype(temp, /obj/structure/blob/normal))
potential_blobs -= temp
else
B = temp
break
CHECK_TICK
if(B)
forceMove(B.loc)
return createSpecial(100, /obj/structure/blob/node, 5, 0, B.loc)
/mob/observer/blob/verb/expand_blob_power()
set category = "Blob"
set name = "Expand/Attack Blob (4)"
set desc = "Attempts to create a new blob in this tile. If the tile isn't clear, instead attacks it, damaging mobs and objects."
var/turf/T = get_turf(src)
expand_blob(T)
/mob/observer/blob/proc/expand_blob(turf/T)
var/obj/structure/blob/B = null
var/turf/other_T = null
for(var/direction in cardinal)
other_T = get_step(T, direction)
if(other_T)
B = locate(/obj/structure/blob) in other_T
if(B)
break
if(!B)
to_chat(src, "<span class='warning'>There is no blob cardinally adjacent to the target tile!</span>")
return
if(!can_buy(4))
return
B.expand(T)
/mob/observer/blob/verb/auto_attack()
set category = "Blob"
set name = "Auto Attack (4)"
set desc = "Automatically tries to kill whatever's attacking you."
transport_core() // In-case the overmind wandered off somewhere else.
var/list/potential_targets = list()
for(var/mob/living/L in view(src))
if(L.stat == DEAD)
continue // Already dying or dead.
if(L.faction == "blob")
continue // No friendly fire.
if(locate(/obj/structure/blob) in L.loc)
continue // Already has a blob over them.
var/obj/structure/blob/B = null
for(var/direction in cardinal)
var/turf/T = get_step(L, direction)
B = locate(/obj/structure/blob) in T
if(B)
break
if(!B)
continue
potential_targets += L
if(potential_targets.len)
var/mob/living/victim = pick(potential_targets)
var/turf/T = get_turf(victim)
expand_blob(T)

View File

@@ -0,0 +1,545 @@
// There are different kinds of blobs, with different colors, properties, weaknesses, etc. This datum tells the blob objects what kind they are, without a million typepaths.
/datum/blob_type
var/name = "base blob"
var/desc = "This shouldn't exist." // Shown on examine.
var/effect_desc = "This does nothing special." // For examine panel.
var/ai_desc = "default" // Shown when examining the overmind.
var/difficulty = BLOB_DIFFICULTY_EASY // A rough guess on how hard a blob is to kill.
// When a harder blob spawns by event, the crew is given more information than usual from the announcement.
var/color = "#FFFFFF" // The actual blob's color.
var/complementary_color = "#000000" //a color that's complementary to the normal blob color. Blob mobs are colored in this.
var/attack_message = "The blob attacks you" // Base message the mob gets when blob_act() gets called on them by the blob. An exclaimation point is added to the end.
var/attack_message_living = null // Appended to attack_message, if the target fails isSynthetic() check.
var/attack_message_synth = null // Ditto, but if they pass isSynthetic().
var/attack_verb = "attacks" // Used for the visible_message(), as the above is shown to the mob getting hit directly.
// Format is '\The [blob name] [attack_verb] [victim]!' E.g. 'The explosive lattice blasts John Doe!'
var/damage_type = BRUTE // What kind of damage to do to living mobs via blob_act()
var/armor_check = "melee" // What armor to check for when blob_act()-ing living mobs.
var/armor_pen = 0 // How much armor to penetrate(ignore) when attacking via blob_act().
var/damage_lower = 30 // Lower bound for amount of damage to do for attacks.
var/damage_upper = 40 // Upper bound.
var/brute_multiplier = 0.5 // Adjust to make blobs stonger or weaker against brute damage.
var/burn_multiplier = 1.0 // Ditto, for burns.
var/spread_modifier = 0.5 // A multipler on how fast the blob should naturally spread from the core and nodes.
var/slow_spread_with_size = TRUE // Blobs that get really huge will slow down in expansion.
var/ai_aggressiveness = 10 // Probability of the blob AI attempting to attack someone next to the blob, independant of the attacks from node/core pulsing.
var/can_build_factories = FALSE // Forbids this blob type from building factories. Set to true to enable.
var/can_build_resources = FALSE // Ditto, for resource blobs.
var/can_build_nodes = TRUE // Ditto, for nodes.
var/spore_type = /mob/living/simple_animal/hostile/blob/spore
// 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
// Called when a blob dies due to integrity depletion. Not called if deleted by other means.
/datum/blob_type/proc/on_death(var/obj/structure/blob/B)
return
// Called when a blob expands onto another tile.
/datum/blob_type/proc/on_expand(var/obj/structure/blob/B, var/obj/structure/blob/new_B, var/turf/T, var/mob/observer/blob/O)
return
// Called when blob_act() is called on a living mob.
/datum/blob_type/proc/on_attack(var/obj/structure/blob/B, var/mob/living/victim, var/def_zone)
return
// Called when the blob is pulsed by a node or the core.
/datum/blob_type/proc/on_pulse(var/obj/structure/blob/B)
return
// Called when hit by EMP.
/datum/blob_type/proc/on_emp(obj/structure/blob/B, severity)
return
// Called when hit by water.
/datum/blob_type/proc/on_water(obj/structure/blob/B, amount)
return
// Spore things
/datum/blob_type/proc/on_spore_death(mob/living/simple_animal/hostile/blob/spore/S)
return
// Subtypes
// 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 shallow 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))
// 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_animal/hostile/blob/spore/infesting
/datum/blob_type/fungal_bloom/on_spore_death(mob/living/simple_animal/hostile/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("<span class='danger'>\A [B] forms on \the [T] as \the [S] bursts!</span>")
// 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_animal/hostile/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_animal/hostile/blob/S = new spore_type(T)
S.overmind = O
S.update_icons()
O.blob_mobs.Add(S)
/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_animal/hostile/blob/S = new spore_type(get_turf(B))
B.visible_message("<span class='danger'>A spore floats free from the [name]!</span>")
S.overmind = B.overmind
S.update_icons()
B.overmind.blob_mobs.Add(S)
// 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("<span class='danger'>The [name] retaliates, lashing out at \the [attacker]!</span>")
B.blob_attack_animation(attacker, B.overmind)
attacker.blob_act(B)
..()
// 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 = 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("<span class='danger'>The blob ruptures, spraying the area with liquid!</span>")
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)
radiation_repository.radiate(B, 200)