diff --git a/code/datums/antagonists/blob.dm b/code/datums/antagonists/blob.dm new file mode 100644 index 0000000000..5689e6a567 --- /dev/null +++ b/code/datums/antagonists/blob.dm @@ -0,0 +1,59 @@ +/datum/antagonist/blob + name = "Blob" + roundend_category = "blobs" + job_rank = ROLE_BLOB + + var/datum/action/innate/blobpop/pop_action + var/starting_points_human_blob = 60 + var/point_rate_human_blob = 2 + +/datum/antagonist/blob/roundend_report() + var/basic_report = ..() + //Display max blobpoints for blebs that lost + if(isovermind(owner.current)) //embarrasing if not + var/mob/camera/blob/overmind = owner.current + if(!overmind.victory_in_progress) //if it won this doesn't really matter + var/point_report = "
[owner.name] took over [overmind.max_count] tiles at the height of its growth." + return basic_report+point_report + return basic_report + +/datum/antagonist/blob/greet() + if(!isovermind(owner.current)) + to_chat(owner,"You feel bloated.") + +/datum/antagonist/blob/on_gain() + create_objectives() + . = ..() + +/datum/antagonist/blob/proc/create_objectives() + var/datum/objective/blob_takeover/main = new + main.owner = owner + objectives += main + owner.objectives |= objectives + +/datum/antagonist/blob/apply_innate_effects(mob/living/mob_override) + if(!isovermind(owner.current)) + if(!pop_action) + pop_action = new + pop_action.Grant(owner.current) + +/datum/objective/blob_takeover + explanation_text = "Reach critical mass!" + +//Non-overminds get this on blob antag assignment +/datum/action/innate/blobpop + name = "Pop" + desc = "Unleash the blob" + icon_icon = 'icons/mob/blob.dmi' + button_icon_state = "blob" + +/datum/action/innate/blobpop/Activate() + var/mob/old_body = owner + var/datum/antagonist/blob/blobtag = owner.mind.has_antag_datum(/datum/antagonist/blob) + if(!blobtag) + Remove() + return + 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) \ No newline at end of file diff --git a/code/game/gamemodes/blob/overmind.dm b/code/game/gamemodes/blob/overmind.dm index 22074392fc..cc96a69f34 100644 --- a/code/game/gamemodes/blob/overmind.dm +++ b/code/game/gamemodes/blob/overmind.dm @@ -4,6 +4,7 @@ GLOBAL_LIST_EMPTY(blob_cores) GLOBAL_LIST_EMPTY(overminds) GLOBAL_LIST_EMPTY(blob_nodes) + /mob/camera/blob name = "Blob Overmind" real_name = "Blob Overmind" @@ -33,10 +34,12 @@ GLOBAL_LIST_EMPTY(blob_nodes) 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/list/blobs_legit = list() + var/max_count = 0 //The biggest it got before death var/blobwincount = 400 var/victory_in_progress = FALSE /mob/camera/blob/Initialize(mapload, starting_points = 60) + validate_location() blob_points = starting_points manualplace_min_time += world.time autoplace_max_time += world.time @@ -50,13 +53,13 @@ GLOBAL_LIST_EMPTY(blob_nodes) color = blob_reagent_datum.complementary_color if(blob_core) blob_core.update_icon() - SSshuttle.registerHostileEnvironment(src) + .= ..() /mob/camera/blob/proc/validate_location() var/turf/T = get_turf(src) var/area/A = get_area(T) - if(((A && !A.blob_allowed) || !T || !is_station_level(T.z)) && LAZYLEN(GLOB.blobstart)) + if(((A && !A.blob_allowed) || !T || !(T.z in GLOB.station_z_levels)) && LAZYLEN(GLOB.blobstart)) T = get_turf(pick(GLOB.blobstart)) if(!T) CRASH("No blobspawnpoints and blob spawned in nullspace.") @@ -80,7 +83,7 @@ GLOBAL_LIST_EMPTY(blob_nodes) max_blob_points = INFINITY blob_points = INFINITY addtimer(CALLBACK(src, .proc/victory), 450) - + if(!victory_in_progress && max_count < blobs_legit.len) max_count = blobs_legit.len ..() @@ -92,7 +95,7 @@ GLOBAL_LIST_EMPTY(blob_nodes) for(var/i in GLOB.mob_living_list) var/mob/living/L = i var/turf/T = get_turf(L) - if(!T || !is_station_level(T.z)) + if(!T || !(T.z in GLOB.station_z_levels)) continue if(L in GLOB.overminds || (L.pass_flags & PASSBLOB)) @@ -121,6 +124,11 @@ GLOBAL_LIST_EMPTY(blob_nodes) A.layer = BELOW_MOB_LAYER A.invisibility = 0 A.blend_mode = 0 + var/datum/antagonist/blob/B = mind.has_antag_datum(/datum/antagonist/blob) + if(B) + var/datum/objective/blob_takeover/main_objective = locate() in B.objectives + if(main_objective) + main_objective.completed = TRUE to_chat(world, "[real_name] consumed the station in an unstoppable tide!") SSticker.news_report = BLOB_WIN SSticker.force_ending = 1 @@ -144,7 +152,6 @@ GLOBAL_LIST_EMPTY(blob_nodes) /mob/camera/blob/Login() ..() - sync_mind() to_chat(src, "You are the overmind!") blob_help() update_health_hud() @@ -234,3 +241,9 @@ GLOBAL_LIST_EMPTY(blob_nodes) return 0 forceMove(NewLoc) return 1 + +/mob/camera/blob/mind_initialize() + . = ..() + var/datum/antagonist/blob/B = mind.has_antag_datum(/datum/antagonist/blob) + if(!B) + mind.add_antag_datum(/datum/antagonist/blob) \ No newline at end of file diff --git a/code/game/gamemodes/blob/powers.dm b/code/game/gamemodes/blob/powers.dm index 2ef047506f..e88cc8fb96 100644 --- a/code/game/gamemodes/blob/powers.dm +++ b/code/game/gamemodes/blob/powers.dm @@ -7,22 +7,23 @@ // Power verbs -/mob/camera/blob/proc/place_blob_core(point_rate, placement_override) +/mob/camera/blob/proc/place_blob_core(point_rate, placement_override , pop_override = FALSE) if(placed && placement_override != -1) return 1 if(!placement_override) - for(var/mob/living/M in range(7, src)) - if("blob" in M.faction) - continue - if(M.client) - to_chat(src, "There is someone too close to place your blob core!") - return 0 - for(var/mob/living/M in view(13, src)) - if("blob" in M.faction) - continue - if(M.client) - to_chat(src, "Someone could see your blob core from here!") - return 0 + if(!pop_override) + for(var/mob/living/M in range(7, src)) + if("blob" in M.faction) + continue + if(M.client) + to_chat(src, "There is someone too close to place your blob core!") + return 0 + for(var/mob/living/M in view(13, src)) + if("blob" in M.faction) + continue + if(M.client) + to_chat(src, "Someone could see your blob core from here!") + return 0 var/turf/T = get_turf(src) if(T.density) to_chat(src, "This spot is too dense to place a blob core on!") @@ -37,7 +38,7 @@ else if(O.density) to_chat(src, "This spot is too dense to place a blob core on!") return 0 - if(world.time <= manualplace_min_time && world.time <= autoplace_max_time) + if(!pop_override && world.time <= manualplace_min_time && world.time <= autoplace_max_time) to_chat(src, "It is too early to place your blob core!") return 0 else if(placement_override == 1) diff --git a/code/game/turfs/ChangeTurf.dm b/code/game/turfs/ChangeTurf.dm index b3e542ca0f..26bbc84078 100644 --- a/code/game/turfs/ChangeTurf.dm +++ b/code/game/turfs/ChangeTurf.dm @@ -139,22 +139,33 @@ // Make a new turf and put it on top // The args behave identical to PlaceOnBottom except they go on top /turf/proc/PlaceOnTop(list/new_baseturfs, turf/fake_turf_type) + var/turf/newT if(fake_turf_type) - if(!new_baseturfs) + if(!new_baseturfs) // If no baseturfs list then we want to create one from the turf type var/list/old_baseturfs = baseturfs.Copy() - assemble_baseturfs(fake_turf_type) + newT = ChangeTurf(fake_turf_type) + newT.assemble_baseturfs(initial(fake_turf_type.baseturfs)) // The baseturfs list is created like roundstart if(!length(baseturfs)) - baseturfs = list(baseturfs) - baseturfs.Insert(1, old_baseturfs) - return - else if(!length(new_baseturfs)) - new_baseturfs = list(new_baseturfs, fake_turf_type) - else - new_baseturfs += fake_turf_type + newT.baseturfs = list(baseturfs) + newT.baseturfs.Insert(1, old_baseturfs) // The old baseturfs are put underneath + return newT + if(!length(baseturfs)) + baseturfs = list(baseturfs) + baseturfs += type + baseturfs += new_baseturfs + return ChangeTurf(fake_turf_type) if(!length(baseturfs)) baseturfs = list(baseturfs) - baseturfs += new_baseturfs - + baseturfs += type + var/turf/change_type + if(length(new_baseturfs)) + change_type = new_baseturfs[new_baseturfs.len] + new_baseturfs.len-- + if(new_baseturfs.len) + baseturfs += new_baseturfs + else + change_type = new_baseturfs + return ChangeTurf(change_type) // Copy an existing turf and put it on top /turf/proc/CopyOnTop(turf/copytarget, ignore_bottom=1, depth=INFINITY) // x, 1, 0 diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 42a1ce725f..c501984de8 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -468,11 +468,7 @@ qdel(src) /mob/proc/become_overmind(starting_points = 60) - var/turf/T = get_turf(loc) //just to avoid messing up in lockers - var/area/A = get_area(T) - if(((A && !A.blob_allowed) || !(T.z in GLOB.station_z_levels)) && LAZYLEN(GLOB.blobstart)) - T = get_turf(pick(GLOB.blobstart)) - var/mob/camera/blob/B = new /mob/camera/blob(T, starting_points) + var/mob/camera/blob/B = new /mob/camera/blob(get_turf(src), starting_points) B.key = key . = B qdel(src) diff --git a/html/changelogs/AutoChangeLog-pr-4633.yml b/html/changelogs/AutoChangeLog-pr-4633.yml new file mode 100644 index 0000000000..2a9d05d984 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4633.yml @@ -0,0 +1,4 @@ +author: "ninjanomnom" +delete-after: True +changes: + - bugfix: "Turfs are construct-able again" diff --git a/tgstation.dme b/tgstation.dme index 3dbf6168f1..01effafe8d 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -327,6 +327,7 @@ #include "code\datums\actions\ninja.dm" #include "code\datums\antagonists\abductor.dm" #include "code\datums\antagonists\antag_datum.dm" +#include "code\datums\antagonists\blob.dm" #include "code\datums\antagonists\brother.dm" #include "code\datums\antagonists\changeling.dm" #include "code\datums\antagonists\clockcult.dm"