diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm
index 0906738b673..6041844b66f 100644
--- a/code/__DEFINES/antagonists.dm
+++ b/code/__DEFINES/antagonists.dm
@@ -24,16 +24,6 @@
#define APPRENTICE_ROBELESS "robeless"
#define APPRENTICE_HEALING "healing"
-
-//Blob
-/// blob gets a free reroll every X time
-#define BLOB_REROLL_TIME 2400
-#define BLOB_SPREAD_COST 4
-/// blob refunds this much if it attacks and doesn't spread
-#define BLOB_ATTACK_REFUND 2
-#define BLOB_REFLECTOR_COST 15
-
-
//ERT Types
#define ERT_BLUE "Blue"
#define ERT_RED "Red"
@@ -85,8 +75,6 @@ GLOBAL_LIST_INIT(heretic_start_knowledge,list(/datum/eldritch_knowledge/spell/ba
#define PATH_FLESH "Flesh"
#define PATH_VOID "Void"
-/// How much does it cost to reroll strains?
-#define BLOB_REROLL_COST 40
/// How many telecrystals a normal traitor starts with
#define TELECRYSTALS_DEFAULT 20
diff --git a/code/__DEFINES/blob_defines.dm b/code/__DEFINES/blob_defines.dm
new file mode 100644
index 00000000000..7cfec0e7d05
--- /dev/null
+++ b/code/__DEFINES/blob_defines.dm
@@ -0,0 +1,107 @@
+// Overmind defines
+
+#define OVERMIND_MAX_POINTS_DEFAULT 100 // Max point storage
+#define OVERMIND_STARTING_POINTS 60 // Points granted upon start
+#define OVERMIND_STARTING_REROLLS 1 // Free strain rerolls at the start
+#define OVERMIND_STARTING_MIN_PLACE_TIME 1 MINUTES // Minimum time before the core can be placed
+#define OVERMIND_STARTING_AUTO_PLACE_TIME 6 MINUTES // After this time, randomly place the core somewhere viable
+#define OVERMIND_WIN_CONDITION_AMOUNT 400 // Blob structures required to win
+#define OVERMIND_ANNOUNCEMENT_MIN_SIZE 75 // Once the blob has this many structures, announce their presence
+#define OVERMIND_ANNOUNCEMENT_MAX_TIME 10 MINUTES // If the blob hasn't reached the minimum size before this time, announce their presence
+#define OVERMIND_MAX_CAMERA_STRAY "3x3" // How far the overmind camera is allowed to stray from blob tiles. 3x3 is 1 tile away, 5x5 2 tiles etc
+
+
+// Generic blob defines
+
+#define BLOB_BASE_POINT_RATE 2 // Base amount of points per process()
+#define BLOB_EXPAND_COST 4 // Price to expand onto a new tile
+#define BLOB_ATTACK_REFUND 2 // Points 'refunded' when the expand attempt actually attacks something instead
+#define BLOB_BRUTE_RESIST 0.5 // Brute damage taken gets multiplied by this value
+#define BLOB_FIRE_RESIST 1 // Burn damage taken gets multiplied by this value
+#define BLOB_EXPAND_CHANCE_MULTIPLIER 1 // Increase this value to make blobs naturally expand faster
+#define BLOB_REINFORCE_CHANCE 2.5 // The delta_time chance for cores/nodes to reinforce their surroundings
+#define BLOB_REAGENTATK_VOL 25 // Amount of strain-reagents that get injected when the blob attacks: main source of blob damage
+
+
+// Structure properties
+
+#define BLOB_CORE_MAX_HP 400
+#define BLOB_CORE_HP_REGEN 2 // Bases health regeneration rate every process(), can be added on by strains
+#define BLOB_CORE_CLAIM_RANGE 12 // Range in which blob tiles are 'claimed' (converted from dead to alive, rarely useful)
+#define BLOB_CORE_PULSE_RANGE 4 // The radius up to which the core activates structures, and up to which structures can be built
+#define BLOB_CORE_EXPAND_RANGE 3 // Radius of automatic expansion
+#define BLOB_CORE_STRONG_REINFORCE_RANGE 1 // The radius of tiles surrounding the core that get upgraded
+#define BLOB_CORE_REFLECTOR_REINFORCE_RANGE 0
+#define BLOB_CORE_MAX_SPORES 0 // Spores that the core can produce for free
+
+#define BLOB_NODE_MAX_HP 200
+#define BLOB_NODE_HP_REGEN 3
+#define BLOB_NODE_MIN_DISTANCE 5 // Minimum distance between nodes
+#define BLOB_NODE_CLAIM_RANGE 10
+#define BLOB_NODE_PULSE_RANGE 3 // The radius up to which the core activates structures, and up to which structures can be built
+#define BLOB_NODE_EXPAND_RANGE 2 // Radius of automatic expansion
+#define BLOB_NODE_STRONG_REINFORCE_RANGE 0 // The radius of tiles surrounding the node that get upgraded
+#define BLOB_NODE_REFLECTOR_REINFORCE_RANGE 0
+#define BLOB_NODE_MAX_SPORES 0 // Spores that nodes can maintain
+
+#define BLOB_FACTORY_MAX_HP 200
+#define BLOB_FACTORY_HP_REGEN 1
+#define BLOB_FACTORY_MIN_DISTANCE 7 // Minimum distance between factories
+#define BLOB_FACTORY_MAX_SPORES 3
+
+#define BLOB_RESOURCE_MAX_HP 60
+#define BLOB_RESOURCE_HP_REGEN 15
+#define BLOB_RESOURCE_MIN_DISTANCE 4 // Minimum distance between resource blobs
+#define BLOB_RESOURCE_GATHER_DELAY 4 SECONDS // Gather points when pulsed outside this interval
+#define BLOB_RESOURCE_GATHER_ADDED_DELAY 0.25 SECONDS// Every additional resource blob adds this amount to the gather delay
+#define BLOB_RESOURCE_GATHER_AMOUNT 1 // The amount of points added to the overmind
+
+#define BLOB_REGULAR_MAX_HP 30
+#define BLOB_REGULAR_HP_REGEN 1 // Health regenerated when pulsed by a node/core
+
+#define BLOB_STRONG_MAX_HP 150
+#define BLOB_STRONG_HP_REGEN 2
+
+#define BLOB_REFLECTOR_MAX_HP 150
+#define BLOB_REFLECTOR_HP_REGEN 2
+
+
+// Structure purchasing
+
+#define BLOB_UPGRADE_STRONG_COST 15 // Upgrade and build costs here
+#define BLOB_UPGRADE_REFLECTOR_COST 15
+#define BLOB_STRUCTURE_RESOURCE_COST 40
+#define BLOB_STRUCTURE_FACTORY_COST 60
+#define BLOB_STRUCTURE_NODE_COST 50
+
+#define BLOB_REFUND_STRONG_COST 4 // Points refunded when destroying the structure
+#define BLOB_REFUND_REFLECTOR_COST 8
+#define BLOB_REFUND_FACTORY_COST 25
+#define BLOB_REFUND_NODE_COST 25
+
+// Blob power properties
+
+#define BLOB_POWER_RELOCATE_COST 80 // Resource cost to move your core to a different node
+#define BLOB_POWER_REROLL_COST 40 // Strain reroll
+#define BLOB_POWER_REROLL_FREE_TIME 4 MINUTES // Gain a free strain reroll every x minutes
+#define BLOB_POWER_REROLL_CHOICES 6 // Possibilities to choose from; keep in mind increasing this might fuck with the radial menu
+
+
+// Mob defines
+
+#define BLOBMOB_HEALING_MULTIPLIER 0.0125 // Multiplies by -maxHealth and heals the blob by this amount every blob_act
+#define BLOBMOB_SPORE_HEALTH 30 // Base spore health
+#define BLOBMOB_SPORE_SPAWN_COOLDOWN 8 SECONDS
+#define BLOBMOB_SPORE_DMG_LOWER 2
+#define BLOBMOB_SPORE_DMG_UPPER 4
+#define BLOBMOB_BLOBBERNAUT_RESOURCE_COST 40 // Purchase price for making a blobbernaut
+#define BLOBMOB_BLOBBERNAUT_HEALTH 200 // Base blobbernaut health
+#define BLOBMOB_BLOBBERNAUT_DMG_SOLO_LOWER 20 // Damage without active overmind (core dead or xenobio mob)
+#define BLOBMOB_BLOBBERNAUT_DMG_SOLO_UPPER 20
+#define BLOBMOB_BLOBBERNAUT_DMG_LOWER 4 // Damage dealt with active overmind (most damage comes from strain chems)
+#define BLOBMOB_BLOBBERNAUT_DMG_UPPER 4
+#define BLOBMOB_BLOBBERNAUT_REAGENTATK_VOL 20 // Amounts of strain reagents applied on attack -- basically the main damage stat
+#define BLOBMOB_BLOBBERNAUT_DMG_OBJ 60 // Damage dealth to objects/machines
+#define BLOBMOB_BLOBBERNAUT_HEALING_CORE 0.1 // Percentage multiplier HP restored on Life() when within 2 tiles of the blob core
+#define BLOBMOB_BLOBBERNAUT_HEALING_NODE 0.05 // Same, but for a nearby node
+#define BLOBMOB_BLOBBERNAUT_HEALTH_DECAY 0.025 // Percentage multiplier HP lost when not near blob tiles or without factory
diff --git a/code/_onclick/hud/blob_overmind.dm b/code/_onclick/hud/blob_overmind.dm
index bb4936fc549..110cabcc746 100644
--- a/code/_onclick/hud/blob_overmind.dm
+++ b/code/_onclick/hud/blob_overmind.dm
@@ -53,8 +53,14 @@
/atom/movable/screen/blob/blobbernaut
icon_state = "ui_blobbernaut"
- name = "Produce Blobbernaut (40)"
- desc = "Produces a strong, smart blobbernaut from a factory blob for 40 resources.
The factory blob used will become fragile and unable to produce spores."
+ // Name and description get given their proper values on Initialize()
+ name = "Produce Blobbernaut (ERROR)"
+ desc = "Produces a strong, smart blobbernaut from a factory blob for (ERROR) resources.
The factory blob used will become fragile and unable to produce spores."
+
+/atom/movable/screen/blob/blobbernaut/Initialize()
+ . = ..()
+ name = "Produce Blobbernaut ([BLOBMOB_BLOBBERNAUT_RESOURCE_COST])"
+ desc = "Produces a strong, smart blobbernaut from a factory blob for [BLOBMOB_BLOBBERNAUT_RESOURCE_COST] resources.
The factory blob used will become fragile and unable to produce spores."
/atom/movable/screen/blob/blobbernaut/Click()
if(isovermind(usr))
@@ -63,38 +69,57 @@
/atom/movable/screen/blob/resource_blob
icon_state = "ui_resource"
- name = "Produce Resource Blob (40)"
- desc = "Produces a resource blob for 40 resources.
Resource blobs will give you resources every few seconds."
+ // Name and description get given their proper values on Initialize()
+ name = "Produce Resource Blob (ERROR)"
+ desc = "Produces a resource blob for ERROR resources.
Resource blobs will give you resources every few seconds."
+
+/atom/movable/screen/blob/resource_blob/Initialize()
+ . = ..()
+ name = "Produce Resource Blob ([BLOB_STRUCTURE_RESOURCE_COST])"
+ desc = "Produces a resource blob for [BLOB_STRUCTURE_RESOURCE_COST] resources.
Resource blobs will give you resources every few seconds."
/atom/movable/screen/blob/resource_blob/Click()
if(isovermind(usr))
var/mob/camera/blob/B = usr
- B.create_resource()
+ B.createSpecial(BLOB_STRUCTURE_RESOURCE_COST, /obj/structure/blob/special/resource, BLOB_RESOURCE_MIN_DISTANCE, TRUE)
/atom/movable/screen/blob/node_blob
icon_state = "ui_node"
- name = "Produce Node Blob (50)"
- desc = "Produces a node blob for 50 resources.
Node blobs will expand and activate nearby resource and factory blobs."
+ // Name and description get given their proper values on Initialize()
+ name = "Produce Node Blob (ERROR)"
+ desc = "Produces a node blob for ERROR resources.
Node blobs will expand and activate nearby resource and factory blobs."
+
+/atom/movable/screen/blob/node_blob/Initialize()
+ . = ..()
+ name = "Produce Node Blob ([BLOB_STRUCTURE_NODE_COST])"
+ desc = "Produces a node blob for [BLOB_STRUCTURE_NODE_COST] resources.
Node blobs will expand and activate nearby resource and factory blobs."
/atom/movable/screen/blob/node_blob/Click()
if(isovermind(usr))
var/mob/camera/blob/B = usr
- B.create_node()
+ B.createSpecial(BLOB_STRUCTURE_NODE_COST, /obj/structure/blob/special/node, BLOB_NODE_MIN_DISTANCE, FALSE)
/atom/movable/screen/blob/factory_blob
icon_state = "ui_factory"
- name = "Produce Factory Blob (60)"
- desc = "Produces a factory blob for 60 resources.
Factory blobs will produce spores every few seconds."
+ // Name and description get given their proper values on Initialize()
+ name = "Produce Factory Blob (ERROR)"
+ desc = "Produces a factory blob for ERROR resources.
Factory blobs will produce spores every few seconds."
+
+/atom/movable/screen/blob/factory_blob/Initialize()
+ . = ..()
+ name = "Produce Factory Blob ([BLOB_STRUCTURE_FACTORY_COST])"
+ desc = "Produces a factory blob for [BLOB_STRUCTURE_FACTORY_COST] resources.
Factory blobs will produce spores every few seconds."
/atom/movable/screen/blob/factory_blob/Click()
if(isovermind(usr))
var/mob/camera/blob/B = usr
- B.create_factory()
+ B.createSpecial(BLOB_STRUCTURE_FACTORY_COST, /obj/structure/blob/special/factory, BLOB_FACTORY_MIN_DISTANCE, TRUE)
/atom/movable/screen/blob/readapt_strain
icon_state = "ui_chemswap"
+ // Description gets given its proper values on Initialize()
name = "Readapt Strain"
- desc = "Allows you to choose a new strain from 6 random choices for 40 resources."
+ desc = "Allows you to choose a new strain from ERROR random choices for ERROR resources."
/atom/movable/screen/blob/readapt_strain/MouseEntered(location,control,params)
if(hud?.mymob && isovermind(hud.mymob))
@@ -103,8 +128,8 @@
name = "[initial(name)] (FREE)"
desc = "Randomly rerolls your strain for free."
else
- name = "[initial(name)] ([BLOB_REROLL_COST])"
- desc = initial(desc)
+ name = "[initial(name)] ([BLOB_POWER_REROLL_COST])"
+ desc = "Allows you to choose a new strain from [BLOB_POWER_REROLL_CHOICES] random choices for [BLOB_POWER_REROLL_COST] resources."
..()
/atom/movable/screen/blob/readapt_strain/Click()
@@ -114,8 +139,14 @@
/atom/movable/screen/blob/relocate_core
icon_state = "ui_swap"
- name = "Relocate Core (80)"
- desc = "Swaps a node and your core for 80 resources."
+ // Name and description get given their proper values on Initialize()
+ name = "Relocate Core (ERROR)"
+ desc = "Swaps a node and your core for ERROR resources."
+
+/atom/movable/screen/blob/relocate_core/Initialize()
+ . = ..()
+ name = "Relocate Core ([BLOB_POWER_RELOCATE_COST])"
+ desc = "Swaps a node and your core for [BLOB_POWER_RELOCATE_COST] resources."
/atom/movable/screen/blob/relocate_core/Click()
if(isovermind(usr))
diff --git a/code/modules/antagonists/blob/blob.dm b/code/modules/antagonists/blob/blob.dm
index 0709ff412db..36d520a3238 100644
--- a/code/modules/antagonists/blob/blob.dm
+++ b/code/modules/antagonists/blob/blob.dm
@@ -6,8 +6,7 @@
job_rank = ROLE_BLOB
var/datum/action/innate/blobpop/pop_action
- var/starting_points_human_blob = 60
- var/point_rate_human_blob = 2
+ var/starting_points_human_blob = OVERMIND_STARTING_POINTS
/datum/antagonist/blob/roundend_report()
var/basic_report = ..()
@@ -57,7 +56,7 @@
var/mob/camera/blob/B = new /mob/camera/blob(get_turf(old_body), blobtag.starting_points_human_blob)
owner.mind.transfer_to(B)
old_body.gib()
- B.place_blob_core(blobtag.point_rate_human_blob, pop_override = TRUE)
+ B.place_blob_core(placement_override = TRUE, pop_override = TRUE)
/datum/antagonist/blob/antag_listing_status()
. = ..()
diff --git a/code/modules/antagonists/blob/blob_mobs.dm b/code/modules/antagonists/blob/blob_mobs.dm
index 7f5f29de816..9cb33f38952 100644
--- a/code/modules/antagonists/blob/blob_mobs.dm
+++ b/code/modules/antagonists/blob/blob_mobs.dm
@@ -19,7 +19,7 @@
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
initial_language_holder = /datum/language_holder/empty
var/mob/camera/blob/overmind = null
- var/obj/structure/blob/factory/factory = null
+ var/obj/structure/blob/special/factory = null
var/independent = FALSE
/mob/living/simple_animal/hostile/blob/update_icons()
@@ -53,7 +53,7 @@
H.color = overmind.blobstrain.complementary_color
else
H.color = "#000000"
- adjustHealth(-maxHealth*0.0125)
+ adjustHealth(-maxHealth*BLOBMOB_HEALING_MULTIPLIER)
/mob/living/simple_animal/hostile/blob/fire_act(exposed_temperature, exposed_volume)
..()
@@ -92,14 +92,14 @@
icon_state = "blobpod"
icon_living = "blobpod"
health_doll_icon = "blobpod"
- health = 30
- maxHealth = 30
+ health = BLOBMOB_SPORE_HEALTH
+ maxHealth = BLOBMOB_SPORE_HEALTH
verb_say = "psychically pulses"
verb_ask = "psychically probes"
verb_exclaim = "psychically yells"
verb_yell = "psychically screams"
- melee_damage_lower = 2
- melee_damage_upper = 4
+ melee_damage_lower = BLOBMOB_SPORE_DMG_LOWER
+ melee_damage_upper = BLOBMOB_SPORE_DMG_UPPER
environment_smash = ENVIRONMENT_SMASH_NONE
obj_damage = 0
attack_verb_continuous = "hits"
@@ -115,7 +115,7 @@
///Whether or not this is a fragile spore from Distributed Neurons
var/is_weak = FALSE
-/mob/living/simple_animal/hostile/blob/blobspore/Initialize(mapload, obj/structure/blob/factory/linked_node)
+/mob/living/simple_animal/hostile/blob/blobspore/Initialize(mapload, obj/structure/blob/special/linked_node)
. = ..()
if(istype(linked_node))
factory = linked_node
@@ -253,12 +253,12 @@
icon_state = "blobbernaut"
icon_living = "blobbernaut"
icon_dead = "blobbernaut_dead"
- health = 200
- maxHealth = 200
+ health = BLOBMOB_BLOBBERNAUT_HEALTH
+ maxHealth = BLOBMOB_BLOBBERNAUT_HEALTH
damage_coeff = list(BRUTE = 0.5, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
- melee_damage_lower = 20
- melee_damage_upper = 20
- obj_damage = 60
+ melee_damage_lower = BLOBMOB_BLOBBERNAUT_DMG_SOLO_LOWER
+ melee_damage_upper = BLOBMOB_BLOBBERNAUT_DMG_SOLO_UPPER
+ obj_damage = BLOBMOB_BLOBBERNAUT_DMG_OBJ
attack_verb_continuous = "slams"
attack_verb_simple = "slam"
attack_sound = 'sound/effects/blobattack.ogg'
@@ -289,15 +289,15 @@
if(!factory)
damagesources++
else
- if(locate(/obj/structure/blob/core) in blobs_in_area)
- adjustHealth(-maxHealth*0.1)
+ if(locate(/obj/structure/blob/special/core) in blobs_in_area)
+ adjustHealth(-maxHealth*BLOBMOB_BLOBBERNAUT_HEALING_CORE)
var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(src)) //hello yes you are being healed
if(overmind)
H.color = overmind.blobstrain.complementary_color
else
H.color = "#000000"
- if(locate(/obj/structure/blob/node) in blobs_in_area)
- adjustHealth(-maxHealth*0.05)
+ if(locate(/obj/structure/blob/special/node) in blobs_in_area)
+ adjustHealth(-maxHealth*BLOBMOB_BLOBBERNAUT_HEALING_NODE)
var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(src))
if(overmind)
H.color = overmind.blobstrain.complementary_color
@@ -305,7 +305,7 @@
H.color = "#000000"
if(damagesources)
for(var/i in 1 to damagesources)
- adjustHealth(maxHealth*0.025) //take 2.5% of max health as damage when not near the blob or if the naut has no factory, 5% if both
+ adjustHealth(maxHealth*BLOBMOB_BLOBBERNAUT_HEALTH_DECAY) //take 2.5% of max health as damage when not near the blob or if the naut has no factory, 5% if both
var/image/I = new('icons/mob/blob.dmi', src, "nautdamage", MOB_LAYER+0.01)
I.appearance_flags = RESET_COLOR
if(overmind)
@@ -329,8 +329,8 @@
/mob/living/simple_animal/hostile/blob/blobbernaut/update_icons()
..()
if(overmind) //if we have an overmind, we're doing chemical reactions instead of pure damage
- melee_damage_lower = 4
- melee_damage_upper = 4
+ melee_damage_lower = BLOBMOB_BLOBBERNAUT_DMG_LOWER
+ melee_damage_upper = BLOBMOB_BLOBBERNAUT_DMG_UPPER
attack_verb_continuous = overmind.blobstrain.blobbernaut_message
else
melee_damage_lower = initial(melee_damage_lower)
diff --git a/code/modules/antagonists/blob/blobstrains/_blobstrain.dm b/code/modules/antagonists/blob/blobstrains/_blobstrain.dm
index 4fa454a85e2..8e081706e70 100644
--- a/code/modules/antagonists/blob/blobstrains/_blobstrain.dm
+++ b/code/modules/antagonists/blob/blobstrains/_blobstrain.dm
@@ -3,19 +3,67 @@ GLOBAL_LIST_INIT(valid_blobstrains, subtypesof(/datum/blobstrain) - list(/datum/
/datum/blobstrain
var/name
var/description
- var/color = "#000000"
- var/complementary_color = "#000000" //a color that's complementary to the normal blob color
- var/shortdesc = null //just damage and on_mob effects, doesn't include special, blob-tile only effects
- var/effectdesc = null //any long, blob-tile specific effects
+ var/color = COLOR_BLACK
+ /// The color that stuff like healing effects and the overmind camera gets
+ var/complementary_color = COLOR_BLACK
+ /// A short description of the power and its effects
+ var/shortdesc = null
+ /// Any long, blob-tile specific effects
+ var/effectdesc = null
+ /// Short descriptor of what the strain does damage-wise, generally seen in the reroll menu
var/analyzerdescdamage = "Unknown. Report this bug to a coder, or just adminhelp."
+ /// Short descriptor of what the strain does in general, generally seen in the reroll menu
var/analyzerdesceffect
- var/blobbernaut_message = "slams" //blobbernaut attack verb
- var/message = "The blob strikes you" //message sent to any mob hit by the blob
- var/message_living = null //extension to first mob sent to only living mobs i.e. silicons have no skin to be burnt
- var/core_regen = 2
+ /// Blobbernaut attack verb
+ var/blobbernaut_message = "slams"
+ /// Message sent to any mob hit by the blob
+ var/message = "The blob strikes you"
+ /// Gets added onto 'message' if the mob stuck is of type living
+ var/message_living = null
+ /// Stores world.time to figure out when to next give resources
var/resource_delay = 0
- var/point_rate = 2
+ /// For blob-mobs and extinguishing-based effects
+ var/fire_based = FALSE
var/mob/camera/blob/overmind
+ /// The amount of health regenned on core_process
+ var/base_core_regen = BLOB_CORE_HP_REGEN
+ /// The amount of points gained on core_process
+ var/point_rate = BLOB_BASE_POINT_RATE
+
+ // Various vars that strains can buff the blob with
+ /// HP regen bonus added by strain
+ var/core_regen_bonus = 0
+ /// resource point bonus added by strain
+ var/point_rate_bonus = 0
+
+ /// Adds to claim, pulse, and expand range
+ var/core_range_bonus = 0
+ /// The core can sustain this many extra spores with this strain
+ var/core_spore_bonus = 0
+ /// Extra range up to which the core reinforces blobs
+ var/core_strong_reinforcement_range_bonus = 0
+ /// Extra range up to which the core reinforces blobs into reflectors
+ var/core_reflector_reinforcement_range_bonus = 0
+
+ /// Adds to claim, pulse, and expand range
+ var/node_range_bonus = 0
+ /// Nodes can sustain this any extra spores with this strain
+ var/node_spore_bonus = 0
+ /// Extra range up to which the node reinforces blobs
+ var/node_strong_reinforcement_range_bonus = 0
+ /// Extra range up to which the node reinforces blobs into reflectors
+ var/node_reflector_reinforcement_range_bonus = 0
+
+ /// Extra spores produced by factories with this strain
+ var/factory_spore_bonus = 0
+
+ /// Multiplies the max and current health of every blob with this value upon selecting this strain.
+ var/max_structure_health_multiplier = 1
+ /// Multiplies the max and current health of every mob with this value upon selecting this strain.
+ var/max_mob_health_multiplier = 1
+
+ /// Makes blobbernauts inject a bonus amount of reagents, making their attacks more powerful
+ var/blobbernaut_reagentatk_bonus = 0
/datum/blobstrain/New(mob/camera/blob/new_overmind)
if (!istype(new_overmind))
@@ -24,16 +72,66 @@ GLOBAL_LIST_INIT(valid_blobstrains, subtypesof(/datum/blobstrain) - list(/datum/
/datum/blobstrain/proc/on_gain()
overmind.color = complementary_color
- for(var/BL in GLOB.blobs)
- var/obj/structure/blob/B = BL
+
+ if(overmind.blob_core)
+ overmind.blob_core.max_spores += core_spore_bonus
+ overmind.blob_core.claim_range += core_range_bonus
+ overmind.blob_core.pulse_range += core_range_bonus
+ overmind.blob_core.expand_range += core_range_bonus
+ overmind.blob_core.strong_reinforce_range += core_strong_reinforcement_range_bonus
+ overmind.blob_core.reflector_reinforce_range += core_reflector_reinforcement_range_bonus
+
+ for(var/obj/structure/blob/special/node/N as anything in overmind.node_blobs)
+ N.max_spores += node_spore_bonus
+ N.claim_range += node_range_bonus
+ N.pulse_range += node_range_bonus
+ N.expand_range += node_range_bonus
+ N.strong_reinforce_range += node_strong_reinforcement_range_bonus
+ N.reflector_reinforce_range += node_reflector_reinforcement_range_bonus
+
+ for(var/obj/structure/blob/special/factory/F as anything in overmind.factory_blobs)
+ F.max_spores += factory_spore_bonus
+
+ for(var/obj/structure/blob/B as anything in overmind.all_blobs)
+ B.max_integrity *= max_structure_health_multiplier
+ B.obj_integrity *= max_structure_health_multiplier
B.update_icon()
- for(var/BLO in overmind.blob_mobs)
- var/mob/living/simple_animal/hostile/blob/BM = BLO
+
+ for(var/mob/living/simple_animal/hostile/blob/BM as anything in overmind.blob_mobs)
+ BM.maxHealth *= max_mob_health_multiplier
+ BM.health *= max_mob_health_multiplier
BM.update_icons() //If it's getting a new strain, tell it what it does!
to_chat(BM, "Your overmind's blob strain is now: [name]!")
to_chat(BM, "The [name] strain [shortdesc ? "[shortdesc]" : "[description]"]")
/datum/blobstrain/proc/on_lose()
+ if(overmind.blob_core)
+ overmind.blob_core.max_spores -= core_spore_bonus
+ overmind.blob_core.claim_range -= core_range_bonus
+ overmind.blob_core.pulse_range -= core_range_bonus
+ overmind.blob_core.expand_range -= core_range_bonus
+ overmind.blob_core.strong_reinforce_range -= core_strong_reinforcement_range_bonus
+ overmind.blob_core.reflector_reinforce_range -= core_reflector_reinforcement_range_bonus
+
+ for(var/obj/structure/blob/special/node/N as anything in overmind.node_blobs)
+ N.max_spores -= node_spore_bonus
+ N.claim_range -= node_range_bonus
+ N.pulse_range -= node_range_bonus
+ N.expand_range -= node_range_bonus
+ N.strong_reinforce_range -= node_strong_reinforcement_range_bonus
+ N.reflector_reinforce_range -= node_reflector_reinforcement_range_bonus
+
+ for(var/obj/structure/blob/special/factory/F as anything in overmind.factory_blobs)
+ F.max_spores -= factory_spore_bonus
+
+ for(var/obj/structure/blob/B as anything in overmind.all_blobs)
+ B.max_integrity /= max_structure_health_multiplier
+ B.obj_integrity /= max_structure_health_multiplier
+
+ for(var/mob/living/simple_animal/hostile/blob/BM as anything in overmind.blob_mobs)
+ BM.maxHealth /= max_mob_health_multiplier
+ BM.health /= max_mob_health_multiplier
+
/datum/blobstrain/proc/on_sporedeath(mob/living/spore)
@@ -47,8 +145,8 @@ GLOBAL_LIST_INIT(valid_blobstrains, subtypesof(/datum/blobstrain) - list(/datum/
/datum/blobstrain/proc/core_process()
if(resource_delay <= world.time)
resource_delay = world.time + 10 // 1 second
- overmind.add_points(point_rate)
- overmind.blob_core.obj_integrity = min(overmind.blob_core.max_integrity, overmind.blob_core.obj_integrity+core_regen)
+ overmind.add_points(point_rate+point_rate_bonus)
+ overmind.blob_core.obj_integrity = min(overmind.blob_core.max_integrity, overmind.blob_core.obj_integrity+base_core_regen+core_regen_bonus)
/datum/blobstrain/proc/attack_living(mob/living/L, list/nearby_blobs) // When the blob attacks people
send_message(L)
diff --git a/code/modules/antagonists/blob/blobstrains/_reagent.dm b/code/modules/antagonists/blob/blobstrains/_reagent.dm
index 8e253932890..ac8b6fe2b82 100644
--- a/code/modules/antagonists/blob/blobstrains/_reagent.dm
+++ b/code/modules/antagonists/blob/blobstrains/_reagent.dm
@@ -1,4 +1,4 @@
-/datum/blobstrain/reagent // Blobs that mess with reagents, all "legacy" ones
+/datum/blobstrain/reagent // Blobs that mess with reagents, all "legacy" ones // what do you mean "legacy" you never added an alternative
var/datum/reagent/reagent
/datum/blobstrain/reagent/New(mob/camera/blob/new_overmind)
@@ -8,12 +8,12 @@
/datum/blobstrain/reagent/attack_living(mob/living/L)
var/mob_protection = L.get_permeability_protection()
- reagent.expose_mob(L, VAPOR, 25, 1, mob_protection, overmind)
+ reagent.expose_mob(L, VAPOR, BLOB_REAGENTATK_VOL, 1, mob_protection, overmind)
send_message(L)
/datum/blobstrain/reagent/blobbernaut_attack(mob/living/L)
var/mob_protection = L.get_permeability_protection()
- reagent.expose_mob(L, VAPOR, 20, 0, mob_protection, overmind)//this will do between 10 and 20 damage(reduced by mob protection), depending on chemical, plus 4 from base brute damage.
+ reagent.expose_mob(L, VAPOR, BLOBMOB_BLOBBERNAUT_REAGENTATK_VOL+blobbernaut_reagentatk_bonus, 0, mob_protection, overmind)//this will do between 10 and 20 damage(reduced by mob protection), depending on chemical, plus 4 from base brute damage.
/datum/blobstrain/reagent/on_sporedeath(mob/living/spore)
spore.reagents.add_reagent(reagent.type, 10)
diff --git a/code/modules/antagonists/blob/blobstrains/blazing_oil.dm b/code/modules/antagonists/blob/blobstrains/blazing_oil.dm
index e9d8b6aef2a..c24200adeb0 100644
--- a/code/modules/antagonists/blob/blobstrains/blazing_oil.dm
+++ b/code/modules/antagonists/blob/blobstrains/blazing_oil.dm
@@ -12,6 +12,7 @@
message = "The blob splashes you with burning oil"
message_living = ", and you feel your skin char and melt"
reagent = /datum/reagent/blob/blazing_oil
+ fire_based = TRUE
/datum/blobstrain/reagent/blazing_oil/extinguish_reaction(obj/structure/blob/B)
B.take_damage(1.5, BURN, ENERGY)
diff --git a/code/modules/antagonists/blob/blobstrains/debris_devourer.dm b/code/modules/antagonists/blob/blobstrains/debris_devourer.dm
index 9fefe3bd0b3..dacb75c1923 100644
--- a/code/modules/antagonists/blob/blobstrains/debris_devourer.dm
+++ b/code/modules/antagonists/blob/blobstrains/debris_devourer.dm
@@ -18,7 +18,7 @@
debris_attack(L, blob)
/datum/blobstrain/debris_devourer/on_sporedeath(mob/living/spore)
- var/obj/structure/blob/core/core = overmind.blob_core
+ var/obj/structure/blob/special/core/core = overmind.blob_core
for(var/i in 1 to 3)
var/obj/item/I = pick(core.contents)
if (I && !QDELETED(I))
@@ -30,7 +30,7 @@
I.forceMove(overmind.blob_core)
/datum/blobstrain/debris_devourer/proc/debris_attack(mob/living/L, source)
- var/obj/structure/blob/core/core = overmind.blob_core
+ var/obj/structure/blob/special/core/core = overmind.blob_core
if (prob(40 * DEBRIS_DENSITY)) // Pretend the items are spread through the blob and its mobs and not in the core.
var/obj/item/I = pick(core.contents)
if (I && !QDELETED(I))
@@ -41,12 +41,12 @@
debris_attack(L,blobbernaut)
/datum/blobstrain/debris_devourer/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag, coefficient = 1) //when the blob takes damage, do this
- var/obj/structure/blob/core/core = overmind.blob_core
+ var/obj/structure/blob/special/core/core = overmind.blob_core
return round(max((coefficient*damage)-min(coefficient*DEBRIS_DENSITY, 10), 0)) // reduce damage taken by items per blob, up to 10
/datum/blobstrain/debris_devourer/examine(mob/user)
. = ..()
- var/obj/structure/blob/core/core = overmind.blob_core
+ var/obj/structure/blob/special/core/core = overmind.blob_core
if (isobserver(user))
. += "Absorbed debris is currently reducing incoming damage by [round(max(min(DEBRIS_DENSITY, 10),0))]"
else
diff --git a/code/modules/antagonists/blob/blobstrains/electromagnetic_web.dm b/code/modules/antagonists/blob/blobstrains/electromagnetic_web.dm
index 427e0f839a3..4a5c49d851a 100644
--- a/code/modules/antagonists/blob/blobstrains/electromagnetic_web.dm
+++ b/code/modules/antagonists/blob/blobstrains/electromagnetic_web.dm
@@ -10,14 +10,8 @@
reagent = /datum/reagent/blob/electromagnetic_web
/datum/blobstrain/reagent/electromagnetic_web/damage_reaction(obj/structure/blob/B, damage, damage_type, damage_flag)
- if(damage_type == BRUTE) //take full brute
- switch(B.brute_resist)
- if(0.5)
- return damage * 2
- if(0.25)
- return damage * 4
- if(0.1)
- return damage * 10
+ if(damage_type == BRUTE) // take full brute, divide by the multiplier to get full value
+ return damage / B.brute_resist
return damage * 1.25 //a laser will do 25 damage, which will kill any normal blob
/datum/blobstrain/reagent/electromagnetic_web/death_reaction(obj/structure/blob/B, damage_flag)
diff --git a/code/modules/antagonists/blob/blobstrains/networked_fibers.dm b/code/modules/antagonists/blob/blobstrains/networked_fibers.dm
index 0518d0bac05..5ceec1a4cad 100644
--- a/code/modules/antagonists/blob/blobstrains/networked_fibers.dm
+++ b/code/modules/antagonists/blob/blobstrains/networked_fibers.dm
@@ -9,7 +9,7 @@
color = "#4F4441"
complementary_color = "#414C4F"
reagent = /datum/reagent/blob/networked_fibers
- core_regen = 5
+ core_regen_bonus = 5
/datum/blobstrain/reagent/networked_fibers/expand_reaction(obj/structure/blob/spawning_blob, obj/structure/blob/new_blob, turf/chosen_turf, mob/camera/blob/overmind)
if(!overmind && new_blob.overmind)
@@ -19,7 +19,7 @@
if(isspaceturf(chosen_turf))
return
for(var/obj/structure/blob/possible_expander in range(1, new_blob))
- if(possible_expander.overmind == overmind && (istype(possible_expander, /obj/structure/blob/core) || istype(possible_expander, /obj/structure/blob/node)))
+ if(possible_expander.overmind == overmind && (istype(possible_expander, /obj/structure/blob/special/core) || istype(possible_expander, /obj/structure/blob/special/node)))
new_blob.forceMove(get_turf(possible_expander))
possible_expander.forceMove(chosen_turf)
possible_expander.setDir(get_dir(new_blob, possible_expander))
diff --git a/code/modules/antagonists/blob/blobstrains/regenerative_materia.dm b/code/modules/antagonists/blob/blobstrains/regenerative_materia.dm
index 6b7aa557ef3..d5d2e363659 100644
--- a/code/modules/antagonists/blob/blobstrains/regenerative_materia.dm
+++ b/code/modules/antagonists/blob/blobstrains/regenerative_materia.dm
@@ -7,8 +7,8 @@
complementary_color = "#AF7B8D"
message_living = ", and you feel alive"
reagent = /datum/reagent/blob/regenerative_materia
- core_regen = 20
- point_rate = 3
+ core_regen_bonus = 20
+ point_rate_bonus = 1
/datum/reagent/blob/regenerative_materia
name = "Regenerative Materia"
diff --git a/code/modules/antagonists/blob/blobstrains/synchronous_mesh.dm b/code/modules/antagonists/blob/blobstrains/synchronous_mesh.dm
index 1c57edea1c3..081b1f3dd31 100644
--- a/code/modules/antagonists/blob/blobstrains/synchronous_mesh.dm
+++ b/code/modules/antagonists/blob/blobstrains/synchronous_mesh.dm
@@ -15,10 +15,10 @@
if(damage_flag == MELEE || damage_flag == BULLET || damage_flag == LASER) //the cause isn't fire or bombs, so split the damage
var/damagesplit = 1 //maximum split is 9, reducing the damage each blob takes to 11% but doing that damage to 9 blobs
for(var/obj/structure/blob/C in orange(1, B))
- if(!istype(C, /obj/structure/blob/core) && !istype(C, /obj/structure/blob/node) && C.overmind && C.overmind.blobstrain.type == B.overmind.blobstrain.type) //if it doesn't have the same chemical or is a core or node, don't split damage to it
+ if(!C.ignore_syncmesh_share && C.overmind && C.overmind.blobstrain.type == B.overmind.blobstrain.type) //if it doesn't have the same chemical or is a core or node, don't split damage to it
damagesplit += 1
for(var/obj/structure/blob/C in orange(1, B))
- if(!istype(C, /obj/structure/blob/core) && !istype(C, /obj/structure/blob/node) && C.overmind && C.overmind.blobstrain.type == B.overmind.blobstrain.type) //only hurt blobs that have the same overmind chemical and aren't cores or nodes
+ if(!C.ignore_syncmesh_share && C.overmind && C.overmind.blobstrain.type == B.overmind.blobstrain.type) //only hurt blobs that have the same overmind chemical and aren't cores or nodes
C.take_damage(damage/damagesplit, CLONE, 0, 0)
return damage / damagesplit
else
diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm
index 85abedf7e3a..629bc3d2a2b 100644
--- a/code/modules/antagonists/blob/overmind.dm
+++ b/code/modules/antagonists/blob/overmind.dm
@@ -21,32 +21,36 @@ GLOBAL_LIST_EMPTY(blob_nodes)
faction = list(ROLE_BLOB)
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
hud_type = /datum/hud/blob_overmind
- var/obj/structure/blob/core/blob_core = null // The blob overmind's core
+ var/obj/structure/blob/special/core/blob_core = null // The blob overmind's core
var/blob_points = 0
- var/max_blob_points = 100
+ var/max_blob_points = OVERMIND_MAX_POINTS_DEFAULT
var/last_attack = 0
- var/datum/blobstrain/blobstrain
+ var/datum/blobstrain/reagent/blobstrain
var/list/blob_mobs = list()
+ /// A list of all blob structures
+ var/list/all_blobs = list()
var/list/resource_blobs = list()
- var/free_strain_rerolls = 1 //one free strain reroll
+ var/list/factory_blobs = list()
+ var/list/node_blobs = list()
+ var/free_strain_rerolls = OVERMIND_STARTING_REROLLS
var/last_reroll_time = 0 //time since we last rerolled, used to give free rerolls
var/nodes_required = TRUE //if the blob needs nodes to place resource and factory blobs
var/placed = FALSE
- var/manualplace_min_time = 600 //in deciseconds //a minute, to get bearings
- var/autoplace_max_time = 3600 //six minutes, as long as should be needed
+ var/manualplace_min_time = OVERMIND_STARTING_MIN_PLACE_TIME // Some time to get your bearings
+ var/autoplace_max_time = OVERMIND_STARTING_AUTO_PLACE_TIME // Automatically place the core in a random spot
var/list/blobs_legit = list()
var/max_count = 0 //The biggest it got before death
- var/blobwincount = 400
+ var/blobwincount = OVERMIND_WIN_CONDITION_AMOUNT
var/victory_in_progress = FALSE
var/rerolling = FALSE
- var/announcement_size = 75
+ var/announcement_size = OVERMIND_ANNOUNCEMENT_MIN_SIZE // Announce the biohazard when this size is reached
var/announcement_time
var/has_announced = FALSE
/// The list of strains the blob can reroll for.
var/list/strain_choices
-/mob/camera/blob/Initialize(mapload, starting_points = 60)
+/mob/camera/blob/Initialize(mapload, starting_points = OVERMIND_STARTING_POINTS)
validate_location()
blob_points = starting_points
manualplace_min_time += world.time
@@ -117,7 +121,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
max_blob_points = INFINITY
blob_points = INFINITY
addtimer(CALLBACK(src, .proc/victory), 450)
- else if(!free_strain_rerolls && (last_reroll_time + BLOB_REROLL_TIMEYou have gained another free strain re-roll.")
free_strain_rerolls = 1
@@ -184,6 +188,13 @@ GLOBAL_LIST_EMPTY(blob_nodes)
if(BM)
BM.overmind = null
BM.update_icons()
+ for(var/obj/structure/blob/blob_structure as anything in all_blobs)
+ blob_structure.overmind = null
+ all_blobs = null
+ resource_blobs = null
+ factory_blobs = null
+ node_blobs = null
+ blob_mobs = null
GLOB.overminds -= src
QDEL_LIST_ASSOC_VAL(strain_choices)
@@ -270,7 +281,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
/mob/camera/blob/Move(NewLoc, Dir = 0)
if(placed)
- var/obj/structure/blob/B = locate() in range("3x3", NewLoc)
+ var/obj/structure/blob/B = locate() in range(OVERMIND_MAX_CAMERA_STRAY, NewLoc)
if(B)
forceMove(NewLoc)
else
diff --git a/code/modules/antagonists/blob/powers.dm b/code/modules/antagonists/blob/powers.dm
index 21c61e340b0..c1eebaf0fc6 100644
--- a/code/modules/antagonists/blob/powers.dm
+++ b/code/modules/antagonists/blob/powers.dm
@@ -1,4 +1,3 @@
-#define BLOB_REROLL_CHOICES 6
#define BLOB_REROLL_RADIUS 60
/mob/camera/blob/proc/can_buy(cost = 15)
@@ -8,8 +7,6 @@
add_points(-cost)
return TRUE
-// Power verbs
-
/mob/camera/blob/proc/place_blob_core(placement_override, pop_override = FALSE)
if(placed && placement_override != -1)
return TRUE
@@ -54,34 +51,28 @@
if(placed && blob_core)
blob_core.forceMove(loc)
else
- var/obj/structure/blob/core/core = new(get_turf(src), src, 1)
+ var/obj/structure/blob/special/core/core = new(get_turf(src), src, 1)
core.overmind = src
blobs_legit += src
blob_core = core
core.update_icon()
update_health_hud()
- placed = 1
- announcement_time = world.time + 6000
+ placed = TRUE
+ announcement_time = world.time + OVERMIND_ANNOUNCEMENT_MAX_TIME
return TRUE
-/mob/camera/blob/verb/transport_core()
- set category = "Blob"
- set name = "Jump to Core"
- set desc = "Move your camera to your core."
+/mob/camera/blob/proc/transport_core()
if(blob_core)
forceMove(blob_core.drop_location())
-/mob/camera/blob/verb/jump_to_node()
- set category = "Blob"
- set name = "Jump to Node"
- set desc = "Move your camera to a selected node."
+/mob/camera/blob/proc/jump_to_node()
if(GLOB.blob_nodes.len)
var/list/nodes = list()
for(var/i in 1 to GLOB.blob_nodes.len)
- var/obj/structure/blob/node/B = GLOB.blob_nodes[i]
+ var/obj/structure/blob/special/node/B = GLOB.blob_nodes[i]
nodes["Blob Node #[i] ([get_area_name(B)])"] = B
var/node_name = input(src, "Choose a node to jump to.", "Node Jump") in nodes
- var/obj/structure/blob/node/chosen_node = nodes[node_name]
+ var/obj/structure/blob/special/node/chosen_node = nodes[node_name]
if(chosen_node)
forceMove(chosen_node.loc)
@@ -100,7 +91,7 @@
if(!(A.area_flags & BLOBS_ALLOWED)) //factory and resource blobs must be legit
to_chat(src, "This type of blob must be placed on the station!")
return
- if(nodes_required && !(locate(/obj/structure/blob/node) in orange(3, T)) && !(locate(/obj/structure/blob/core) in orange(4, T)))
+ if(nodes_required && !(locate(/obj/structure/blob/special/node) in orange(BLOB_NODE_PULSE_RANGE, T)) && !(locate(/obj/structure/blob/special/core) in orange(BLOB_CORE_PULSE_RANGE, T)))
to_chat(src, "You need to place this blob closer to a node or core!")
return //handholdotron 2000
if(minSeparation)
@@ -113,60 +104,30 @@
var/obj/structure/blob/N = B.change_to(blobstrain, src)
return N
-/mob/camera/blob/verb/toggle_node_req()
- set category = "Blob"
- set name = "Toggle Node Requirement"
- set desc = "Toggle requiring nodes to place resource and factory blobs."
+/mob/camera/blob/proc/toggle_node_req()
nodes_required = !nodes_required
if(nodes_required)
to_chat(src, "You now require a nearby node or core to place factory and resource blobs.")
else
to_chat(src, "You no longer require a nearby node or core to place factory and resource blobs.")
-/mob/camera/blob/verb/create_shield_power()
- set category = "Blob"
- set name = "Create/Upgrade Shield Blob (15)"
- set desc = "Create a shield blob, which will block fire and is hard to kill. Using this on an existing shield blob turns it into a reflective blob, capable of reflecting most projectiles but making it twice as weak to brute attacks."
- create_shield()
-
/mob/camera/blob/proc/create_shield(turf/T)
var/obj/structure/blob/shield/S = locate(/obj/structure/blob/shield) in T
if(S)
- if(!can_buy(BLOB_REFLECTOR_COST))
+ if(!can_buy(BLOB_UPGRADE_REFLECTOR_COST))
return
if(S.obj_integrity < S.max_integrity * 0.5)
- add_points(BLOB_REFLECTOR_COST)
+ add_points(BLOB_UPGRADE_REFLECTOR_COST)
to_chat(src, "This shield blob is too damaged to be modified properly!")
return
to_chat(src, "You secrete a reflective ooze over the shield blob, allowing it to reflect projectiles at the cost of reduced integrity.")
S.change_to(/obj/structure/blob/shield/reflective, src)
else
- createSpecial(15, /obj/structure/blob/shield, 0, FALSE, T)
+ createSpecial(BLOB_UPGRADE_STRONG_COST, /obj/structure/blob/shield, 0, FALSE, T)
-/mob/camera/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."
- createSpecial(40, /obj/structure/blob/resource, 4, TRUE)
-
-/mob/camera/blob/verb/create_node()
- set category = "Blob"
- set name = "Create Node Blob (50)"
- set desc = "Create a node, which will power nearby factory and resource blobs."
- createSpecial(50, /obj/structure/blob/node, 5, FALSE)
-
-/mob/camera/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."
- createSpecial(60, /obj/structure/blob/factory, 7, TRUE)
-
-/mob/camera/blob/verb/create_blobbernaut()
- set category = "Blob"
- set name = "Create Blobbernaut (40)"
- set desc = "Create a powerful blobbernaut which is mildly smart and will attack enemies."
+/mob/camera/blob/proc/create_blobbernaut()
var/turf/T = get_turf(src)
- var/obj/structure/blob/factory/B = locate(/obj/structure/blob/factory) in T
+ var/obj/structure/blob/special/factory/B = locate(/obj/structure/blob/special/factory) in T
if(!B)
to_chat(src, "You must be on a factory blob!")
return
@@ -176,7 +137,7 @@
if(B.obj_integrity < B.max_integrity * 0.5)
to_chat(src, "This factory blob is too damaged to sustain a blobbernaut.")
return
- if(!can_buy(40))
+ if(!can_buy(BLOBMOB_BLOBBERNAUT_RESOURCE_COST))
return
B.naut = TRUE //temporary placeholder to prevent creation of more than one per factory.
@@ -207,15 +168,12 @@
to_chat(blobber, "The [blobstrain.name] reagent [blobstrain.shortdesc ? "[blobstrain.shortdesc]" : "[blobstrain.description]"]")
else
to_chat(src, "You could not conjure a sentience for your blobbernaut. Your points have been refunded. Try again later.")
- add_points(40)
+ add_points(BLOBMOB_BLOBBERNAUT_RESOURCE_COST)
B.naut = null
-/mob/camera/blob/verb/relocate_core()
- set category = "Blob"
- set name = "Relocate Core (80)"
- set desc = "Swaps the locations of your core and the selected node."
+/mob/camera/blob/proc/relocate_core()
var/turf/T = get_turf(src)
- var/obj/structure/blob/node/B = locate(/obj/structure/blob/node) in T
+ var/obj/structure/blob/special/node/B = locate(/obj/structure/blob/special/node) in T
if(!B)
to_chat(src, "You must be on a blob node!")
return
@@ -226,7 +184,7 @@
if(isspaceturf(T) || A && !(A.area_flags & BLOBS_ALLOWED))
to_chat(src, "You cannot relocate your core here!")
return
- if(!can_buy(80))
+ if(!can_buy(BLOB_POWER_RELOCATE_COST))
return
var/turf/old_turf = get_turf(blob_core)
var/olddir = blob_core.dir
@@ -235,13 +193,6 @@
B.forceMove(old_turf)
B.setDir(olddir)
-/mob/camera/blob/verb/revert()
- set category = "Blob"
- set name = "Remove Blob"
- set desc = "Removes a blob, giving you back some resources."
- var/turf/T = get_turf(src)
- remove_blob(T)
-
/mob/camera/blob/proc/remove_blob(turf/T)
var/obj/structure/blob/B = locate() in T
if(!B)
@@ -258,13 +209,6 @@
to_chat(src, "Gained [B.point_return] resources from removing \the [B].")
qdel(B)
-/mob/camera/blob/verb/expand_blob_power()
- set category = "Blob"
- set name = "Expand/Attack Blob ([BLOB_SPREAD_COST])"
- set desc = "Attempts to create a new blob in this tile. If the tile isn't clear, instead attacks it, damaging mobs and objects and refunding [BLOB_ATTACK_REFUND] points."
- var/turf/T = get_turf(src)
- expand_blob(T)
-
/mob/camera/blob/proc/expand_blob(turf/T)
if(world.time < last_attack)
return
@@ -274,7 +218,7 @@
if(!possibleblobs.len)
to_chat(src, "There is no blob adjacent to the target tile!")
return
- if(can_buy(BLOB_SPREAD_COST))
+ if(can_buy(BLOB_EXPAND_COST))
var/attacksuccess = FALSE
for(var/mob/living/L in T)
if(ROLE_BLOB in L.faction) //no friendly/dead fire
@@ -289,7 +233,7 @@
add_points(BLOB_ATTACK_REFUND)
else
to_chat(src, "There is a blob there!")
- add_points(BLOB_SPREAD_COST) //otherwise, refund all of the cost
+ add_points(BLOB_EXPAND_COST) //otherwise, refund all of the cost
else
var/list/cardinalblobs = list()
var/list/diagonalblobs = list()
@@ -311,19 +255,12 @@
playsound(OB, 'sound/effects/splat.ogg', 50, TRUE)
add_points(BLOB_ATTACK_REFUND)
else
- add_points(BLOB_SPREAD_COST) //if we're attacking diagonally and didn't hit anything, refund
+ add_points(BLOB_EXPAND_COST) //if we're attacking diagonally and didn't hit anything, refund
if(attacksuccess)
last_attack = world.time + CLICK_CD_MELEE
else
last_attack = world.time + CLICK_CD_RAPID
-/mob/camera/blob/verb/rally_spores_power()
- set category = "Blob"
- set name = "Rally Spores"
- set desc = "Rally your spores to move to a target location."
- var/turf/T = get_turf(src)
- rally_spores(T)
-
/mob/camera/blob/proc/rally_spores(turf/T)
to_chat(src, "You rally your spores.")
var/list/surrounding_turfs = block(locate(T.x - 1, T.y - 1, T.z), locate(T.x + 1, T.y + 1, T.z))
@@ -334,27 +271,9 @@
BS.LoseTarget()
BS.Goto(pick(surrounding_turfs), BS.move_to_delay)
-/mob/camera/blob/verb/blob_broadcast()
- set category = "Blob"
- set name = "Blob Broadcast"
- set desc = "Speak with your blob spores and blobbernauts as your mouthpieces."
- var/speak_text = stripped_input(src, "What would you like to say with your minions?", "Blob Broadcast", null)
- if(!speak_text)
- return
- else
- to_chat(src, "You broadcast with your minions, [speak_text]")
- for(var/BLO in blob_mobs)
- var/mob/living/simple_animal/hostile/blob/BM = BLO
- if(BM.stat == CONSCIOUS)
- BM.say(speak_text)
-
-/mob/camera/blob/verb/strain_reroll()
- set category = "Blob"
- set name = "Reactive Strain Adaptation (40)"
- set desc = "Replaces your strain with a random, different one."
-
- if (!free_strain_rerolls && blob_points < BLOB_REROLL_COST)
- to_chat(src, "You need at least [BLOB_REROLL_COST] resources to reroll your strain again!")
+/mob/camera/blob/proc/strain_reroll()
+ if (!free_strain_rerolls && blob_points < BLOB_POWER_REROLL_COST)
+ to_chat(src, "You need at least [BLOB_POWER_REROLL_COST] resources to reroll your strain again!")
return
open_reroll_menu()
@@ -365,7 +284,7 @@
strain_choices = list()
var/list/new_strains = GLOB.valid_blobstrains.Copy() - blobstrain.type
- for (var/_ in 1 to BLOB_REROLL_CHOICES)
+ for (var/_ in 1 to BLOB_POWER_REROLL_CHOICES)
var/datum/blobstrain/strain = pick_n_take(new_strains)
var/image/strain_icon = image('icons/mob/blob.dmi', "blob_core")
@@ -386,7 +305,7 @@
if (isnull(strain_result))
return
- if (!free_strain_rerolls && !can_buy(BLOB_REROLL_COST))
+ if (!free_strain_rerolls && !can_buy(BLOB_POWER_REROLL_COST))
return
for (var/_other_strain in GLOB.valid_blobstrains)
@@ -402,10 +321,7 @@
return
-/mob/camera/blob/verb/blob_help()
- set category = "Blob"
- set name = "*Blob Help*"
- set desc = "Help on how to blob."
+/mob/camera/blob/proc/blob_help()
to_chat(src, "As the overmind, you can control the blob!")
to_chat(src, "Your blob reagent is: [blobstrain.name]!")
to_chat(src, "The [blobstrain.name] reagent [blobstrain.description]")
@@ -426,5 +342,4 @@
to_chat(src, "You will automatically place your blob core in [DisplayTimeText(autoplace_max_time - world.time)].")
to_chat(src, "You [manualplace_min_time ? "will be able to":"can"] manually place your blob core by pressing the Place Blob Core button in the bottom right corner of the screen.")
-#undef BLOB_REROLL_CHOICES
#undef BLOB_REROLL_RADIUS
diff --git a/code/modules/antagonists/blob/structures/_blob.dm b/code/modules/antagonists/blob/structures/_blob.dm
index dd19d9c67ed..3319c1a8fd5 100644
--- a/code/modules/antagonists/blob/structures/_blob.dm
+++ b/code/modules/antagonists/blob/structures/_blob.dm
@@ -10,21 +10,32 @@
layer = BELOW_MOB_LAYER
pass_flags_self = PASSBLOB
CanAtmosPass = ATMOS_PASS_PROC
- var/point_return = 0 //How many points the blob gets back when it removes a blob of that type. If less than 0, blob cannot be removed.
+ /// How many points the blob gets back when it removes a blob of that type. If less than 0, blob cannot be removed.
+ var/point_return = 0
max_integrity = 30
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 70)
- var/health_regen = 2 //how much health this blob regens when pulsed
- var/pulse_timestamp = 0 //we got pulsed when?
- var/heal_timestamp = 0 //we got healed when?
- var/brute_resist = 0.5 //multiplies brute damage by this
- var/fire_resist = 1 //multiplies burn damage by this
- var/atmosblock = FALSE //if the blob blocks atmos and heat spread
+ /// how much health this blob regens when pulsed
+ var/health_regen = BLOB_REGULAR_HP_REGEN
+ /// We got pulsed when?
+ COOLDOWN_DECLARE(pulse_timestamp)
+ /// we got healed when?
+ COOLDOWN_DECLARE(heal_timestamp)
+ /// Multiplies brute damage by this
+ var/brute_resist = BLOB_BRUTE_RESIST
+ /// Multiplies burn damage by this
+ var/fire_resist = BLOB_FIRE_RESIST
+ /// Only used by the synchronous mesh strain. If set to true, these blobs won't share or receive damage taken with others.
+ var/ignore_syncmesh_share = 0
+ /// If the blob blocks atmos and heat spread
+ var/atmosblock = FALSE
var/mob/camera/blob/overmind
+
/obj/structure/blob/Initialize(mapload, owner_overmind)
. = ..()
if(owner_overmind)
overmind = owner_overmind
+ overmind.all_blobs += src
var/area/Ablob = get_area(src)
if(Ablob.area_flags & BLOBS_ALLOWED) //Is this area allowed for winning as blob?
overmind.blobs_legit += src
@@ -44,7 +55,9 @@
atmosblock = FALSE
air_update_turf(TRUE, FALSE)
if(overmind)
+ overmind.all_blobs -= src
overmind.blobs_legit -= src //if it was in the legit blobs list, it isn't now
+ overmind = null
GLOB.blobs -= src //it's no longer in the all blobs list either
playsound(src.loc, 'sound/effects/splat.ogg', 50, TRUE) //Expand() is no longer broken, no check necessary.
return ..()
@@ -78,47 +91,14 @@
else
remove_atom_colour(FIXED_COLOUR_PRIORITY)
-/obj/structure/blob/proc/Pulse_Area(mob/camera/blob/pulsing_overmind, claim_range = 10, pulse_range = 3, expand_range = 2)
- if(QDELETED(pulsing_overmind))
- pulsing_overmind = overmind
- Be_Pulsed()
- var/expanded = FALSE
- if(prob(70) && expand())
- expanded = TRUE
- var/list/blobs_to_affect = list()
- for(var/obj/structure/blob/B in urange(claim_range, src, 1))
- blobs_to_affect += B
- shuffle_inplace(blobs_to_affect)
- for(var/L in blobs_to_affect)
- var/obj/structure/blob/B = L
- if(!B.overmind && !istype(B, /obj/structure/blob/core) && prob(30))
- B.overmind = pulsing_overmind //reclaim unclaimed, non-core blobs.
- B.update_icon()
- var/distance = get_dist(get_turf(src), get_turf(B))
- var/expand_probablity = max(20 - distance * 8, 1)
- if(B.Adjacent(src))
- expand_probablity = 20
- if(distance <= expand_range)
- var/can_expand = TRUE
- if(blobs_to_affect.len >= 120 && B.heal_timestamp > world.time)
- can_expand = FALSE
- if(can_expand && B.pulse_timestamp <= world.time && prob(expand_probablity))
- var/obj/structure/blob/newB = B.expand(null, null, !expanded) //expansion falls off with range but is faster near the blob causing the expansion
- if(newB)
- if(expanded)
- qdel(newB)
- expanded = TRUE
- if(distance <= pulse_range)
- B.Be_Pulsed()
-
/obj/structure/blob/proc/Be_Pulsed()
- if(pulse_timestamp <= world.time)
+ if(COOLDOWN_FINISHED(src, pulse_timestamp))
ConsumeTile()
- if(heal_timestamp <= world.time)
+ if(COOLDOWN_FINISHED(src, heal_timestamp))
obj_integrity = min(max_integrity, obj_integrity+health_regen)
- heal_timestamp = world.time + 20
+ COOLDOWN_START(src, heal_timestamp, 20)
update_icon()
- pulse_timestamp = world.time + 10
+ COOLDOWN_START(src, pulse_timestamp, 10)
return TRUE//we did it, we were pulsed!
return FALSE //oh no we failed
@@ -326,10 +306,9 @@
name = "normal blob"
icon_state = "blob"
light_range = 0
- obj_integrity = 21 //doesn't start at full health
- max_integrity = 25
- health_regen = 1
- brute_resist = 0.25
+ max_integrity = BLOB_REGULAR_MAX_HP
+ health_regen = BLOB_REGULAR_HP_REGEN
+ brute_resist = BLOB_BRUTE_RESIST * 0.5
/obj/structure/blob/normal/scannerreport()
if(obj_integrity <= 15)
@@ -342,14 +321,92 @@
icon_state = "blob_damaged"
name = "fragile blob"
desc = "A thin lattice of slightly twitching tendrils."
- brute_resist = 0.5
+ brute_resist = BLOB_BRUTE_RESIST
else if (overmind)
icon_state = "blob"
name = "blob"
desc = "A thick wall of writhing tendrils."
- brute_resist = 0.25
+ brute_resist = BLOB_BRUTE_RESIST * 0.5
else
icon_state = "blob"
name = "dead blob"
desc = "A thick wall of lifeless tendrils."
- brute_resist = 0.25
+ brute_resist = BLOB_BRUTE_RESIST * 0.5
+
+/obj/structure/blob/special // Generic type for nodes/factories/cores/resource
+ // Core and node vars: claiming, pulsing and expanding
+ /// The radius inside which (previously dead) blob tiles are 'claimed' again by the pulsing overmind. Very rarely used.
+ var/claim_range = 0
+ /// The radius inside which blobs are pulsed by this overmind. Does stuff like expanding, making blob spores from factories, make resources from nodes etc.
+ var/pulse_range = 0
+ /// The radius up to which this special structure naturally grows normal blobs.
+ var/expand_range = 0
+
+ // Spore production vars: for core, factories, and nodes (with strains)
+ var/mob/living/simple_animal/hostile/blob/blobbernaut/naut = null
+ var/max_spores = 0
+ var/list/spores = list()
+ COOLDOWN_DECLARE(spore_delay)
+ var/spore_cooldown = BLOBMOB_SPORE_SPAWN_COOLDOWN
+
+ // Area reinforcement vars: used by cores and nodes, for strains to modify
+ /// Range this blob free upgrades to strong blobs at: for the core, and for strains
+ var/strong_reinforce_range = 0
+ /// Range this blob free upgrades to reflector blobs at: for the core, and for strains
+ var/reflector_reinforce_range = 0
+
+/obj/structure/blob/special/proc/reinforce_area(delta_time) // Used by cores and nodes to upgrade their surroundings
+ if(strong_reinforce_range)
+ for(var/obj/structure/blob/normal/B in range(strong_reinforce_range, src))
+ if(DT_PROB(BLOB_REINFORCE_CHANCE, delta_time))
+ B.change_to(/obj/structure/blob/shield/core, overmind)
+ if(reflector_reinforce_range)
+ for(var/obj/structure/blob/shield/B in range(reflector_reinforce_range, src))
+ if(DT_PROB(BLOB_REINFORCE_CHANCE, delta_time))
+ B.change_to(/obj/structure/blob/shield/reflective/core, overmind)
+
+/obj/structure/blob/special/proc/pulse_area(mob/camera/blob/pulsing_overmind, claim_range = 10, pulse_range = 3, expand_range = 2)
+ if(QDELETED(pulsing_overmind))
+ pulsing_overmind = overmind
+ Be_Pulsed()
+ var/expanded = FALSE
+ if(prob(70*(1/BLOB_EXPAND_CHANCE_MULTIPLIER)) && expand())
+ expanded = TRUE
+ var/list/blobs_to_affect = list()
+ for(var/obj/structure/blob/B in urange(claim_range, src, 1))
+ blobs_to_affect += B
+ shuffle_inplace(blobs_to_affect)
+ for(var/L in blobs_to_affect)
+ var/obj/structure/blob/B = L
+ if(!B.overmind && prob(30))
+ B.overmind = pulsing_overmind //reclaim unclaimed, non-core blobs.
+ B.update_icon()
+ var/distance = get_dist(get_turf(src), get_turf(B))
+ var/expand_probablity = max(20 - distance * 8, 1)
+ if(B.Adjacent(src))
+ expand_probablity = 20
+ if(distance <= expand_range)
+ var/can_expand = TRUE
+ if(blobs_to_affect.len >= 120 && !(COOLDOWN_FINISHED(B, heal_timestamp)))
+ can_expand = FALSE
+ if(can_expand && COOLDOWN_FINISHED(B, pulse_timestamp) && prob(expand_probablity*BLOB_EXPAND_CHANCE_MULTIPLIER))
+ if(!expanded)
+ var/obj/structure/blob/newB = B.expand(null, null, !expanded) //expansion falls off with range but is faster near the blob causing the expansion
+ if(newB)
+ expanded = TRUE
+ if(distance <= pulse_range)
+ B.Be_Pulsed()
+
+/obj/structure/blob/special/proc/produce_spores()
+ if(naut)
+ return
+ if(spores.len >= max_spores)
+ return
+ if(!COOLDOWN_FINISHED(src, spore_delay))
+ return
+ COOLDOWN_START(src, spore_delay, spore_cooldown)
+ var/mob/living/simple_animal/hostile/blob/blobspore/BS = new (loc, src)
+ if(overmind) //if we don't have an overmind, we don't need to do anything but make a spore
+ BS.overmind = overmind
+ BS.update_icons()
+ overmind.blob_mobs.Add(BS)
diff --git a/code/modules/antagonists/blob/structures/core.dm b/code/modules/antagonists/blob/structures/core.dm
index af2e2340105..e2f8ff17636 100644
--- a/code/modules/antagonists/blob/structures/core.dm
+++ b/code/modules/antagonists/blob/structures/core.dm
@@ -1,16 +1,23 @@
-/obj/structure/blob/core
+/obj/structure/blob/special/core
name = "blob core"
icon = 'icons/mob/blob.dmi'
icon_state = "blank_blob"
desc = "A huge, pulsating yellow mass."
- max_integrity = 400
+ max_integrity = BLOB_CORE_MAX_HP
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 75, ACID = 90)
explosion_block = 6
point_return = -1
health_regen = 0 //we regen in Life() instead of when pulsed
resistance_flags = LAVA_PROOF
+ strong_reinforce_range = BLOB_CORE_STRONG_REINFORCE_RANGE
+ reflector_reinforce_range = BLOB_CORE_REFLECTOR_REINFORCE_RANGE
+ claim_range = BLOB_CORE_CLAIM_RANGE
+ pulse_range = BLOB_CORE_PULSE_RANGE
+ expand_range = BLOB_CORE_EXPAND_RANGE
+ max_spores = BLOB_CORE_MAX_SPORES
+ ignore_syncmesh_share = TRUE
-/obj/structure/blob/core/Initialize(mapload, client/new_overmind = null, placed = 0)
+/obj/structure/blob/special/core/Initialize(mapload, client/new_overmind = null, placed = 0)
GLOB.blob_cores += src
START_PROCESSING(SSobj, src)
AddElement(/datum/element/point_of_interest)
@@ -18,13 +25,14 @@
if(!placed && !overmind)
return INITIALIZE_HINT_QDEL
if(overmind)
+ overmind.blobstrain.on_gain()
update_icon()
. = ..()
-/obj/structure/blob/core/scannerreport()
+/obj/structure/blob/special/core/scannerreport()
return "Directs the blob's expansion, gradually expands, and sustains nearby blob spores and blobbernauts."
-/obj/structure/blob/core/update_icon()
+/obj/structure/blob/special/core/update_icon()
cut_overlays()
color = null
var/mutable_appearance/blob_overlay = mutable_appearance('icons/mob/blob.dmi', "blob")
@@ -33,7 +41,7 @@
add_overlay(blob_overlay)
add_overlay(mutable_appearance('icons/mob/blob.dmi', "blob_core_overlay"))
-/obj/structure/blob/core/Destroy()
+/obj/structure/blob/special/core/Destroy()
GLOB.blob_cores -= src
if(overmind)
overmind.blob_core = null
@@ -41,17 +49,17 @@
STOP_PROCESSING(SSobj, src)
return ..()
-/obj/structure/blob/core/ex_act(severity, target)
+/obj/structure/blob/special/core/ex_act(severity, target)
var/damage = 50 - 10 * severity //remember, the core takes half brute damage, so this is 20/15/10 damage based on severity
take_damage(damage, BRUTE, BOMB, 0)
-/obj/structure/blob/core/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir, overmind_reagent_trigger = 1)
+/obj/structure/blob/special/core/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir, overmind_reagent_trigger = 1)
. = ..()
if(obj_integrity > 0)
if(overmind) //we should have an overmind, but...
overmind.update_health_hud()
-/obj/structure/blob/core/process(delta_time)
+/obj/structure/blob/special/core/process(delta_time)
if(QDELETED(src))
return
if(!overmind)
@@ -59,17 +67,16 @@
if(overmind)
overmind.blobstrain.core_process()
overmind.update_health_hud()
- Pulse_Area(overmind, 12, 4, 3)
- for(var/obj/structure/blob/normal/B in range(1, src))
- if(DT_PROB(2.5, delta_time))
- B.change_to(/obj/structure/blob/shield/core, overmind)
+ pulse_area(overmind, claim_range, pulse_range, expand_range)
+ reinforce_area(delta_time)
+ produce_spores()
..()
-/obj/structure/blob/core/ComponentInitialize()
+/obj/structure/blob/special/core/ComponentInitialize()
. = ..()
AddComponent(/datum/component/stationloving, FALSE, TRUE)
-/obj/structure/blob/core/onTransitZ(old_z, new_z)
+/obj/structure/blob/special/core/onTransitZ(old_z, new_z)
if(overmind && is_station_level(new_z))
overmind.forceMove(get_turf(src))
return ..()
diff --git a/code/modules/antagonists/blob/structures/factory.dm b/code/modules/antagonists/blob/structures/factory.dm
index 138a359e72e..a65f16be155 100644
--- a/code/modules/antagonists/blob/structures/factory.dm
+++ b/code/modules/antagonists/blob/structures/factory.dm
@@ -1,25 +1,24 @@
-/obj/structure/blob/factory
+/obj/structure/blob/special/factory
name = "factory blob"
icon = 'icons/mob/blob.dmi'
icon_state = "blob_factory"
desc = "A thick spire of tendrils."
- max_integrity = 200
- health_regen = 1
- point_return = 25
+ max_integrity = BLOB_FACTORY_MAX_HP
+ health_regen = BLOB_FACTORY_HP_REGEN
+ point_return = BLOB_REFUND_FACTORY_COST
resistance_flags = LAVA_PROOF
- var/list/spores = list()
- var/mob/living/simple_animal/hostile/blob/blobbernaut/naut = null
- var/max_spores = 3
- var/spore_delay = 0
- var/spore_cooldown = 80 //8 seconds between spores and after spore death
+ max_spores = BLOB_FACTORY_MAX_SPORES
-
-/obj/structure/blob/factory/scannerreport()
+/obj/structure/blob/special/factory/scannerreport()
if(naut)
return "It is currently sustaining a blobbernaut, making it fragile and unable to produce blob spores."
return "Will produce a blob spore every few seconds."
-/obj/structure/blob/factory/Destroy()
+/obj/structure/blob/special/factory/creation_action()
+ if(overmind)
+ overmind.factory_blobs += src
+
+/obj/structure/blob/special/factory/Destroy()
for(var/mob/living/simple_animal/hostile/blob/blobspore/spore in spores)
if(spore.factory == src)
spore.factory = null
@@ -28,20 +27,10 @@
to_chat(naut, "Your factory was destroyed! You feel yourself dying!")
naut.throw_alert("nofactory", /atom/movable/screen/alert/nofactory)
spores = null
+ if(overmind)
+ overmind.factory_blobs -= src
return ..()
-/obj/structure/blob/factory/Be_Pulsed()
+/obj/structure/blob/special/factory/Be_Pulsed()
. = ..()
- if(naut)
- return
- if(spores.len >= max_spores)
- return
- if(spore_delay > world.time)
- return
- flick("blob_factory_glow", src)
- spore_delay = world.time + spore_cooldown
- var/mob/living/simple_animal/hostile/blob/blobspore/BS = new/mob/living/simple_animal/hostile/blob/blobspore(src.loc, src)
- if(overmind) //if we don't have an overmind, we don't need to do anything but make a spore
- BS.overmind = overmind
- BS.update_icons()
- overmind.blob_mobs.Add(BS)
+ produce_spores()
diff --git a/code/modules/antagonists/blob/structures/node.dm b/code/modules/antagonists/blob/structures/node.dm
index 456b2d8bcf0..73d2250d6d4 100644
--- a/code/modules/antagonists/blob/structures/node.dm
+++ b/code/modules/antagonists/blob/structures/node.dm
@@ -1,24 +1,29 @@
-/obj/structure/blob/node
+/obj/structure/blob/special/node
name = "blob node"
icon = 'icons/mob/blob.dmi'
icon_state = "blank_blob"
desc = "A large, pulsating yellow mass."
- max_integrity = 200
+ max_integrity = BLOB_NODE_MAX_HP
+ health_regen = BLOB_NODE_HP_REGEN
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 65, ACID = 90)
- health_regen = 3
- point_return = 25
+ point_return = BLOB_REFUND_NODE_COST
+ claim_range = BLOB_NODE_CLAIM_RANGE
+ pulse_range = BLOB_NODE_PULSE_RANGE
+ expand_range = BLOB_NODE_EXPAND_RANGE
resistance_flags = LAVA_PROOF
+ max_spores = BLOB_NODE_MAX_SPORES
+ ignore_syncmesh_share = TRUE
-/obj/structure/blob/node/Initialize()
+/obj/structure/blob/special/node/Initialize()
GLOB.blob_nodes += src
START_PROCESSING(SSobj, src)
. = ..()
-/obj/structure/blob/node/scannerreport()
+/obj/structure/blob/special/node/scannerreport()
return "Gradually expands and sustains nearby blob spores and blobbernauts."
-/obj/structure/blob/node/update_icon()
+/obj/structure/blob/special/node/update_icon()
cut_overlays()
color = null
var/mutable_appearance/blob_overlay = mutable_appearance('icons/mob/blob.dmi', "blob")
@@ -27,11 +32,19 @@
add_overlay(blob_overlay)
add_overlay(mutable_appearance('icons/mob/blob.dmi', "blob_node_overlay"))
-/obj/structure/blob/node/Destroy()
+/obj/structure/blob/special/node/creation_action()
+ if(overmind)
+ overmind.node_blobs += src
+
+/obj/structure/blob/special/node/Destroy()
GLOB.blob_nodes -= src
STOP_PROCESSING(SSobj, src)
+ if(overmind)
+ overmind.node_blobs -= src
return ..()
-/obj/structure/blob/node/process()
+/obj/structure/blob/special/node/process(delta_time)
if(overmind)
- Pulse_Area(overmind, 10, 3, 2)
+ pulse_area(overmind, claim_range, pulse_range, expand_range)
+ reinforce_area(delta_time)
+ produce_spores()
diff --git a/code/modules/antagonists/blob/structures/resource.dm b/code/modules/antagonists/blob/structures/resource.dm
index 81eda7f4edd..ec931f08dcc 100644
--- a/code/modules/antagonists/blob/structures/resource.dm
+++ b/code/modules/antagonists/blob/structures/resource.dm
@@ -1,4 +1,4 @@
-/obj/structure/blob/resource
+/obj/structure/blob/special/resource
name = "resource blob"
icon = 'icons/mob/blob.dmi'
icon_state = "blob_resource"
@@ -8,25 +8,25 @@
resistance_flags = LAVA_PROOF
var/resource_delay = 0
-/obj/structure/blob/resource/scannerreport()
+/obj/structure/blob/special/resource/scannerreport()
return "Gradually supplies the blob with resources, increasing the rate of expansion."
-/obj/structure/blob/resource/creation_action()
+/obj/structure/blob/special/resource/creation_action()
if(overmind)
overmind.resource_blobs += src
-/obj/structure/blob/resource/Destroy()
+/obj/structure/blob/special/resource/Destroy()
if(overmind)
overmind.resource_blobs -= src
return ..()
-/obj/structure/blob/resource/Be_Pulsed()
+/obj/structure/blob/special/resource/Be_Pulsed()
. = ..()
if(resource_delay > world.time)
return
flick("blob_resource_glow", src)
if(overmind)
- overmind.add_points(1)
- resource_delay = world.time + 40 + overmind.resource_blobs.len * 2.5 //4 seconds plus a quarter second for each resource blob the overmind has
+ overmind.add_points(BLOB_RESOURCE_GATHER_AMOUNT)
+ resource_delay = world.time + BLOB_RESOURCE_GATHER_DELAY + overmind.resource_blobs.len * BLOB_RESOURCE_GATHER_ADDED_DELAY //4 seconds plus a quarter second for each resource blob the overmind has
else
- resource_delay = world.time + 40
+ resource_delay = world.time + BLOB_RESOURCE_GATHER_DELAY
diff --git a/code/modules/antagonists/blob/structures/shield.dm b/code/modules/antagonists/blob/structures/shield.dm
index acd7419ef34..5da6ce75f51 100644
--- a/code/modules/antagonists/blob/structures/shield.dm
+++ b/code/modules/antagonists/blob/structures/shield.dm
@@ -5,9 +5,10 @@
desc = "A solid wall of slightly twitching tendrils."
var/damaged_desc = "A wall of twitching tendrils."
max_integrity = 150
- brute_resist = 0.25
+ health_regen = BLOB_STRONG_HP_REGEN
+ brute_resist = BLOB_BRUTE_RESIST * 0.5
explosion_block = 3
- point_return = 4
+ point_return = BLOB_REFUND_STRONG_COST
atmosblock = TRUE
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 90, ACID = 90)
@@ -16,7 +17,7 @@
return "Will prevent the spread of atmospheric changes."
return "N/A"
-/obj/structure/blob/shield/core
+/obj/structure/blob/shield/core // Automatically generated by the core
point_return = 0
/obj/structure/blob/shield/update_icon()
@@ -40,5 +41,10 @@
damaged_desc = "A wall of twitching tendrils with a reflective glow."
icon_state = "blob_glow"
flags_ricochet = RICOCHET_SHINY
- point_return = 8
+ point_return = BLOB_REFUND_REFLECTOR_COST
explosion_block = 2
+ max_integrity = BLOB_REFLECTOR_MAX_HP
+ health_regen = BLOB_REFLECTOR_HP_REGEN
+
+/obj/structure/blob/shield/reflective/core // Automatically generated by the core
+ point_return = 0
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 93700e92bc8..076e1391b4a 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -225,7 +225,7 @@
. = new_slime
qdel(src)
-/mob/proc/become_overmind(starting_points = 60)
+/mob/proc/become_overmind(starting_points = OVERMIND_STARTING_POINTS)
var/mob/camera/blob/B = new /mob/camera/blob(get_turf(src), starting_points)
B.key = key
. = B
diff --git a/tgstation.dme b/tgstation.dme
index 093d6d8992d..3674974e9be 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -33,6 +33,7 @@
#include "code\__DEFINES\atom_hud.dm"
#include "code\__DEFINES\bitfields.dm"
#include "code\__DEFINES\blackmarket.dm"
+#include "code\__DEFINES\blob_defines.dm"
#include "code\__DEFINES\botany.dm"
#include "code\__DEFINES\callbacks.dm"
#include "code\__DEFINES\cargo.dm"