Cleans up blob code, removes a lot of hardcoded stuff, many new defines (#56306)

Cleaned up, commented on, and (hopefully) improves a lot of blob code.
Put pretty much everything balance-related (except for the strains themselves) into a define file, for easier viewing, changing, and balancing.
Added a bunch of new functionality that new strains (some of which I plan to add in the future) could use: from increased expansion range to more spores per factory.
This commit is contained in:
NotRanged
2021-02-02 18:20:28 +01:00
committed by GitHub
parent 96bf9536b4
commit 2c12e87256
23 changed files with 542 additions and 325 deletions
+2 -3
View File
@@ -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()
. = ..()
+19 -19
View File
@@ -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)
@@ -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: <b><font color=\"[color]\">[name]</b></font>!")
to_chat(BM, "The <b><font color=\"[color]\">[name]</b></font> 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)
@@ -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)
@@ -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)
@@ -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))
. += "<span class='notice'>Absorbed debris is currently reducing incoming damage by [round(max(min(DEBRIS_DENSITY, 10),0))]</span>"
else
@@ -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)
@@ -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))
@@ -7,8 +7,8 @@
complementary_color = "#AF7B8D"
message_living = ", and you feel <i>alive</i>"
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"
@@ -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
+22 -11
View File
@@ -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_TIME<world.time))
else if(!free_strain_rerolls && (last_reroll_time + BLOB_POWER_REROLL_FREE_TIME<world.time))
to_chat(src, "<b><span class='big'><font color=\"#EE4000\">You have gained another free strain re-roll.</font></span></b>")
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
+28 -113
View File
@@ -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, "<span class='warning'>This type of blob must be placed on the station!</span>")
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, "<span class='warning'>You need to place this blob closer to a node or core!</span>")
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, "<span class='warning'>You now require a nearby node or core to place factory and resource blobs.</span>")
else
to_chat(src, "<span class='warning'>You no longer require a nearby node or core to place factory and resource blobs.</span>")
/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, "<span class='warning'>This shield blob is too damaged to be modified properly!</span>")
return
to_chat(src, "<span class='warning'>You secrete a reflective ooze over the shield blob, allowing it to reflect projectiles at the cost of reduced integrity.</span>")
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, "<span class='warning'>You must be on a factory blob!</span>")
return
@@ -176,7 +137,7 @@
if(B.obj_integrity < B.max_integrity * 0.5)
to_chat(src, "<span class='warning'>This factory blob is too damaged to sustain a blobbernaut.</span>")
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 <b><font color=\"[blobstrain.color]\">[blobstrain.name]</b></font> reagent [blobstrain.shortdesc ? "[blobstrain.shortdesc]" : "[blobstrain.description]"]")
else
to_chat(src, "<span class='warning'>You could not conjure a sentience for your blobbernaut. Your points have been refunded. Try again later.</span>")
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, "<span class='warning'>You must be on a blob node!</span>")
return
@@ -226,7 +184,7 @@
if(isspaceturf(T) || A && !(A.area_flags & BLOBS_ALLOWED))
to_chat(src, "<span class='warning'>You cannot relocate your core here!</span>")
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, "<span class='notice'>Gained [B.point_return] resources from removing \the [B].</span>")
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, "<span class='warning'>There is no blob adjacent to the target tile!</span>")
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, "<span class='warning'>There is a blob there!</span>")
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, <B>[speak_text]</B>")
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, "<span class='warning'>You need at least [BLOB_REROLL_COST] resources to reroll your strain again!</span>")
/mob/camera/blob/proc/strain_reroll()
if (!free_strain_rerolls && blob_points < BLOB_POWER_REROLL_COST)
to_chat(src, "<span class='warning'>You need at least [BLOB_POWER_REROLL_COST] resources to reroll your strain again!</span>")
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, "<b>As the overmind, you can control the blob!</b>")
to_chat(src, "Your blob reagent is: <b><font color=\"[blobstrain.color]\">[blobstrain.name]</b></font>!")
to_chat(src, "The <b><font color=\"[blobstrain.color]\">[blobstrain.name]</b></font> reagent [blobstrain.description]")
@@ -426,5 +342,4 @@
to_chat(src, "<span class='big'><font color=\"#EE4000\">You will automatically place your blob core in [DisplayTimeText(autoplace_max_time - world.time)].</font></span>")
to_chat(src, "<span class='big'><font color=\"#EE4000\">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.</font></span>")
#undef BLOB_REROLL_CHOICES
#undef BLOB_REROLL_RADIUS
+108 -51
View File
@@ -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)
@@ -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 ..()
@@ -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, "<span class='userdanger'>Your factory was destroyed! You feel yourself dying!</span>")
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()
@@ -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()
@@ -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
@@ -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
+1 -1
View File
@@ -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