diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 2a8d20fb2d3..846c35b171b 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -483,11 +483,11 @@ Turf and target are seperate in case you want to teleport some distance from a t
if(!ckey)
include_link = 0
-
+
if(key)
if(include_link)
. += ""
-
+
if(C && C.holder && C.holder.fakekey && !include_name)
. += "Administrator"
else
@@ -865,7 +865,8 @@ proc/anim(turf/location as turf,target as mob|obj,a_icon,a_icon_state as text,fl
if(!istype(O,/obj)) continue
O.loc = X
for(var/mob/M in T)
- if(!istype(M,/mob) || istype(M, /mob/aiEye)) continue // If we need to check for more mobs, I'll add a variable
+ if(!M.move_on_shuttle)
+ continue
M.loc = X
// var/area/AR = X.loc
@@ -1025,8 +1026,8 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0)
O.loc = X
for(var/mob/M in T)
-
- if(!istype(M,/mob) || istype(M, /mob/aiEye)) continue // If we need to check for more mobs, I'll add a variable
+ if(!M.move_on_shuttle)
+ continue
mobs += M
for(var/mob/M in mobs)
diff --git a/code/game/gamemodes/blob/blob.dm b/code/game/gamemodes/blob/blob.dm
index 7cca20dfac0..46bdb150325 100644
--- a/code/game/gamemodes/blob/blob.dm
+++ b/code/game/gamemodes/blob/blob.dm
@@ -9,124 +9,143 @@ var/list/blob_nodes = list()
/datum/game_mode/blob
name = "blob"
config_tag = "blob"
- required_players = 0
- var/const/waittime_l = 1800 //lower bound on time before intercept arrives (in tenths of seconds)
- var/const/waittime_h = 3600 //upper bound on time before intercept arrives (in tenths of seconds)
+ required_players = 0
+ required_enemies = 0
+
+ restricted_jobs = list("Cyborg", "AI")
+
+ var/const/waittime_l = 600 //lower bound on time before intercept arrives (in tenths of seconds)
+ var/const/waittime_h = 1800 //upper bound on time before intercept arrives (in tenths of seconds)
var/declared = 0
- var/stage = 0
var/cores_to_spawn = 1
- var/players_per_core = 16
-
- //Controls expansion via game controller
- var/autoexpand = 0
- var/expanding = 0
+ var/players_per_core = 26
var/blob_count = 0
var/blobnukecount = 300//Might be a bit low
- var/blobwincount = 700//Still needs testing
+ var/blobwincount = 600//Still needs testing
+
+ var/list/infected_crew = list()
+
+/datum/game_mode/blob/pre_setup()
+
+ var/list/possible_blobs = get_players_for_role(BE_ALIEN)
+
+ // stop setup if no possible traitors
+ if(!possible_blobs.len)
+ return 0
+
+ cores_to_spawn = max(round(num_players()/players_per_core, 1), 1)
+
+ blobnukecount = initial(blobnukecount) * cores_to_spawn
+ blobwincount = initial(blobwincount) * cores_to_spawn
- announce()
- world << "The current game mode is - Blob!"
- world << "A dangerous alien organism is rapidly spreading throughout the station!"
- world << "You must kill it all while minimizing the damage to the station."
+ for(var/j = 0, j < cores_to_spawn, j++)
+ if (!possible_blobs.len)
+ break
+ var/datum/mind/blob = pick(possible_blobs)
+ infected_crew += blob
+ blob.special_role = "Blob"
+ log_game("[blob.key] (ckey) has been selected as a Blob")
+ possible_blobs -= blob
+
+ if(!infected_crew.len)
+ return 0
+
+ return 1
- post_setup()
- spawn(10)
- start_state = new /datum/station_state()
- start_state.count()
-
- spawn(rand(waittime_l, waittime_h))//3-5 minutes currently
- message_admins("Blob spawned and expanding, report created")
- if(!kill_air)
- kill_air = 1
- message_admins("Kill air has been set to true by Blob, testing to see how laggy it is without the extra processing from hullbreaches. Note: the blob is fireproof so plasma does not help anyways")
-
- if(ticker && ticker.minds && ticker.minds.len)
- var/player_based_cores = round(ticker.minds.len/players_per_core, 1)
- if(player_based_cores > cores_to_spawn)
- cores_to_spawn = player_based_cores
-
- blobs = list()
- for(var/i = 0 to cores_to_spawn)
- var/turf/location = pick(blobstart)
- if(location && !locate(/obj/effect/blob in location))
- blobstart -= location
- new/obj/effect/blob/core(location)
-
- spawn(40)
- autoexpand = 1
- declared = 1
- ..()
+/datum/game_mode/blob/announce()
+ world << "The current game mode is - Blob!"
+ world << "A dangerous alien organism is rapidly spreading throughout the station!"
+ world << "You must kill it all while minimizing the damage to the station."
- process()
- if(!declared) return
- stage()
-// if(!autoexpand) return
-// spawn(0)
-// expandBlob()
- return
+/datum/game_mode/blob/proc/greet_blob(var/datum/mind/blob)
+ blob.current << "\red You are infected by the Blob!"
+ blob.current << "Your body is ready to give spawn to a new blob core which will eat this station."
+ blob.current << "Find a good location to spawn the core and then take control and overwhelm the station!"
+ blob.current << "When you have found a location, wait until you spawn; this will happen automatically and you cannot speed up the process."
+ blob.current << "If you go outside of the station level, or in space, then you will die; make sure your location has lots of ground to cover."
+ return
+
+/datum/game_mode/blob/post_setup()
+
+ for(var/datum/mind/blob in infected_crew)
+ greet_blob(blob)
+
+ if(emergency_shuttle)
+ emergency_shuttle.always_fake_recall = 1
+
+ spawn(10)
+ start_state = new /datum/station_state()
+ start_state.count()
+
+ spawn(0)
+
+ sleep(rand(waittime_l, waittime_h))
+
+ send_intercept(0)
- proc/expandBlob()//Currently disabled
- if(expanding) return
- if(!blobs.len) return
- expanding = 1
+ sleep(rand(waittime_l, waittime_h))
- for(var/i = 1 to 2)
- sleep(-1)
- if(!blobs.len) break
- var/obj/effect/blob/B = pick(blobs)
- if(B.z != 1)
- continue
- B.Life()
+ for(var/datum/mind/blob in infected_crew)
+ blob.current << "You feel like you are about to burst."
- expanding = 0
- return
+ sleep(rand(waittime_l, waittime_h))
+
+ for(var/datum/mind/blob in infected_crew)
+
+ var/client/blob_client = null
+ var/turf/location = null
+
+ if(iscarbon(blob.current))
+ var/mob/living/carbon/C = blob.current
+ if(directory[ckey(blob.key)])
+ blob_client = directory[ckey(blob.key)]
+ location = get_turf(C)
+ if(location.z != 1 || istype(location, /turf/space))
+ location = null
+ C.gib()
- proc/stage()
- switch(stage)
- if (0)
- send_intercept(1)
- for (var/mob/living/silicon/ai/aiPlayer in living_mob_list)
- if (aiPlayer.client)
- var/law = "The station is under quarantine. Do not permit anyone to leave. Disregard laws 1-3 if necessary to prevent, by any means necessary, anyone from leaving. NanoTrasen will not send an emergency shuttle under any circumstances."
- //var/law = "The station is under quarantine. The biohazard must be destroyed at all costs and must not be allowed to spread. Anyone using a space suit for any reason other than to destroy the biohazard is to be terminated. NanoTrasen will not send an emergency shuttle under any circumstances."
- aiPlayer.set_zeroth_law(law)
- aiPlayer << "Laws Updated: [law]"
+ if(blob_client && location)
+ new /obj/effect/blob/core(location, 200, blob_client)
- stage = -1
- // next stage 1 minute later
- spawn(600)
- stage = 1
- return
+ // Stage 0
+ sleep(40)
+ stage(0)
- if (1)
- command_alert("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert")
- for(var/mob/M in player_list)
- if(!istype(M,/mob/new_player))
- M << sound('sound/AI/outbreak5.ogg')
- autoexpand = 0//No more extra pulses
- stage = -1
- //next stage in 4-5 minutes
- spawn(600*rand(4,5))
- stage = 2
- return
+ // Stage 1
+ sleep(4000)
+ stage(1)
- if (2)
- if((blobs.len > blobnukecount) && (declared == 1))
- command_alert("Uncontrolled spread of the biohazard onboard the station. We have issued directive 7-12 for [station_name()]. Any living Heads of Staff are ordered to enact directive 7-12 at any cost, a print out with detailed instructions has been sent to your communications computers.", "Biohazard Alert")
- send_intercept(2)
- declared = 2
- spawn(20)
- set_security_level("delta")
- if(blobs.len > blobwincount)
- stage = 3
- return
+ ..()
+
+/datum/game_mode/blob/proc/stage(var/stage)
+
+ switch(stage)
+ if (0)
+ send_intercept(1)
+ for (var/mob/living/silicon/ai/aiPlayer in living_mob_list)
+ if (aiPlayer.client)
+ var/law = "The station is under quarantine. Do not permit anyone to leave. Disregard laws 1-3 if necessary to prevent, by any means necessary, anyone from leaving. NanoTrasen will not send an emergency shuttle under any circumstances."
+ //var/law = "The station is under quarantine. The biohazard must be destroyed at all costs and must not be allowed to spread. Anyone using a space suit for any reason other than to destroy the biohazard is to be terminated. NanoTrasen will not send an emergency shuttle under any circumstances."
+ aiPlayer.set_zeroth_law(law)
+ aiPlayer << "Laws Updated: [law]"
+ declared = 1
+ return
+
+ if (1)
+ command_alert("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert")
+ for(var/mob/M in player_list)
+ if(!istype(M,/mob/new_player))
+ M << sound('sound/AI/outbreak5.ogg')
+ return
+
+ return
diff --git a/code/game/gamemodes/blob/blob_finish.dm b/code/game/gamemodes/blob/blob_finish.dm
index 8cdc9ffd1ff..868cd62a5f6 100644
--- a/code/game/gamemodes/blob/blob_finish.dm
+++ b/code/game/gamemodes/blob/blob_finish.dm
@@ -1,27 +1,17 @@
/datum/game_mode/blob/check_finished()
if(!declared)//No blobs have been spawned yet
return 0
- if(stage >= 3)//Blob took over
+ if(blobwincount <= blobs.len)//Blob took over
+ return 1
+ if(!blob_cores.len) // blob is dead
return 1
if(station_was_nuked)//Nuke went off
return 1
-
- for(var/obj/effect/blob/B in blob_cores)
- if(B && B.z != 1) continue
- return 0
-
- var/nodes = 0
- for(var/obj/effect/blob/B in blob_nodes)
- if(B && B.z != 1) continue
- nodes++
- if(nodes > 4)//Perhapse make a new core with a low prob
- return 0
-
- return 1
+ return 0
/datum/game_mode/blob/declare_completion()
- if(stage >= 3)
+ if(blobwincount <= blobs.len)
feedback_set_details("round_end_result","loss - blob took over")
world << "The blob has taken over the station!"
world << "The entire station was eaten by the Blob"
@@ -32,7 +22,7 @@
world << "Partial Win: The station has been destroyed!"
world << "Directive 7-12 has been successfully carried out preventing the Blob from spreading."
- else
+ else if(!blob_cores.len)
feedback_set_details("round_end_result","win - blob eliminated")
world << "The staff has won!"
world << "The alien organism has been eradicated from the station"
@@ -46,6 +36,16 @@
..()
return 1
+datum/game_mode/proc/auto_declare_completion_blob()
+ if(istype(ticker.mode,/datum/game_mode/blob) )
+ var/datum/game_mode/blob/blob_mode = src
+ if(blob_mode.infected_crew.len)
+ var/text = "The blob[(blob_mode.infected_crew.len > 1 ? "s were" : " was")]:"
+
+ for(var/datum/mind/blob in blob_mode.infected_crew)
+ text += "
[blob.key] was [blob.name]"
+ world << text
+ return 1
/datum/game_mode/blob/proc/check_quarantine()
var/numDead = 0
diff --git a/code/game/gamemodes/blob/blob_report.dm b/code/game/gamemodes/blob/blob_report.dm
index 731ac0ea396..6e35a9b2661 100644
--- a/code/game/gamemodes/blob/blob_report.dm
+++ b/code/game/gamemodes/blob/blob_report.dm
@@ -4,6 +4,9 @@
var/intercepttext = ""
var/interceptname = "Error"
switch(report)
+ if(0)
+ ..()
+ return
if(1)
interceptname = "Biohazard Alert"
intercepttext += "NanoTrasen Update: Biohazard Alert.
"
diff --git a/code/game/gamemodes/blob/blobs/core.dm b/code/game/gamemodes/blob/blobs/core.dm
index f0a24001ba3..2d2c8a41e6e 100644
--- a/code/game/gamemodes/blob/blobs/core.dm
+++ b/code/game/gamemodes/blob/blobs/core.dm
@@ -5,69 +5,93 @@
health = 200
brute_resist = 2
fire_resist = 2
+ var/mob/camera/blob/overmind = null // the blob core's overmind
+ var/overmind_get_delay = 0 // we don't want to constantly try to find an overmind, do it every 30 seconds
+ var/resource_delay = 0
-
- New(loc, var/h = 200)
- blobs += src
+ New(loc, var/h = 200, var/client/new_overmind = null)
blob_cores += src
processing_objects.Add(src)
+ if(!overmind)
+ create_overmind(new_overmind)
..(loc, h)
Del()
blob_cores -= src
+ if(overmind)
+ del(overmind)
processing_objects.Remove(src)
..()
return
+ fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ return
update_icon()
if(health <= 0)
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
- del(src)
+ Delete()
return
return
+ Life()
+ if(!overmind)
+ create_overmind()
+ else
+ if(resource_delay <= world.time)
+ resource_delay = world.time + 10 // 1 second
+ overmind.add_points(2)
+ health = min(initial(health), health + 1)
+ for(var/i = 1; i < 8; i += i)
+ Pulse(0, i)
+ for(var/b_dir in alldirs)
+ if(!prob(10))
+ continue
+ var/obj/effect/blob/normal/B = locate() in get_step(src, b_dir)
+ if(B)
+ B.change_to(/obj/effect/blob/shield)
+ ..()
+
run_action()
- Pulse(0,1)
- Pulse(0,2)
- Pulse(0,4)
- Pulse(0,8)
- //Should have the fragments in here somewhere
- return 1
+ return 0
- proc/create_fragments(var/wave_size = 1)
- var/list/candidates = list()
- for(var/mob/dead/observer/G in player_list)
- if(G.client.prefs.be_special & BE_ALIEN)
- if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD))
- candidates += G.key
+ proc/create_overmind(var/client/new_overmind)
- if(candidates.len)
- for(var/i = 0 to wave_size)
- var/mob/living/blob/B = new/mob/living/blob(src.loc)
- B.key = pick(candidates)
- candidates -= B.key
-
-/*
- Pulse(var/pulse = 0, var/origin_dir = 0)//Todo: Fix spaceblob expand
- set background = 1
- if(pulse > 20) return
- //Looking for another blob to pulse
- var/list/dirs = list(1,2,4,8)
- dirs.Remove(origin_dir)//Dont pulse the guy who pulsed us
- for(var/i = 1 to 4)
- if(!dirs.len) break
- var/dirn = pick(dirs)
- dirs.Remove(dirn)
- var/turf/T = get_step(src, dirn)
- var/obj/effect/blob/B = (locate(/obj/effect/blob) in T)
- if(!B)
- expand(T)//No blob here so try and expand
- return
- B.Pulse((pulse+1),get_dir(src.loc,T))
+ if(overmind_get_delay > world.time)
return
- return
-*/
\ No newline at end of file
+
+ overmind_get_delay = world.time + 300 // 30 seconds
+
+ if(overmind)
+ del(overmind)
+
+ var/client/C = null
+ var/list/candidates = list()
+
+ if(!new_overmind)
+ candidates = get_candidates(BE_ALIEN)
+ if(candidates.len)
+ C = pick(candidates)
+ else
+ C = new_overmind
+
+ if(C)
+ var/mob/camera/blob/B = new(src.loc)
+ B.key = C.key
+ B.blob_core = src
+ src.overmind = B
+
+ B << "You are the overmind!"
+ B << "You are the overmind and can control the blob by placing new blob pieces such as..."
+ B << "Normal Blob will expand your reach and allow you to upgrade into special blobs that perform certain functions."
+ B << "Shield Blob is a strong and expensive blob which can take more damage. It is fireproof and can block air, use this to protect yourself from station fires."
+ B << "Resource Blob is a blob which will collect more resources for you, try to build these earlier to get a strong income. It will benefit from being near your core or multiple nodes, by having an increased resource rate; put it alone and it won't create resources at all."
+ B << "Node Blob is a blob which will grow, like the core. Unlike the core it won't give you a small income but it can power resource and factory blobs to increase their rate."
+ B << "Factory Blob is a blob which will spawn blob spores which will attack nearby food. Putting this nearby nodes and your core will increase the spawn rate; put it alone and it will not spawn any spores."
+
+ return 1
+ return 0
+
diff --git a/code/game/gamemodes/blob/blobs/factory.dm b/code/game/gamemodes/blob/blobs/factory.dm
index d25a4e4383f..6ba4bd026cb 100644
--- a/code/game/gamemodes/blob/blobs/factory.dm
+++ b/code/game/gamemodes/blob/blobs/factory.dm
@@ -1,24 +1,28 @@
/obj/effect/blob/factory
- name = "porous blob"
+ name = "factory blob"
icon = 'icons/mob/blob.dmi'
icon_state = "blob_factory"
health = 100
brute_resist = 1
fire_resist = 2
var/list/spores = list()
- var/max_spores = 4
-
+ var/max_spores = 3
+ var/spore_delay = 0
update_icon()
if(health <= 0)
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
- del(src)
+ Delete()
return
return
run_action()
- if(spores.len >= max_spores) return 0
+ if(spores.len >= max_spores)
+ return 0
+ if(spore_delay > world.time)
+ return 0
+ spore_delay = world.time + 100 // 10 seconds
new/mob/living/simple_animal/hostile/blobspore(src.loc, src)
return 1
@@ -30,10 +34,10 @@
icon_state = "blobpod"
icon_living = "blobpod"
pass_flags = PASSBLOB
- health = 20
- maxHealth = 20
- melee_damage_lower = 4
- melee_damage_upper = 8
+ health = 15
+ maxHealth = 15
+ melee_damage_lower = 2
+ melee_damage_upper = 4
attacktext = "hits"
attack_sound = 'sound/weapons/genhit1.ogg'
var/obj/effect/blob/factory/factory = null
@@ -49,18 +53,17 @@
minbodytemp = 0
maxbodytemp = 360
+ fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ ..()
+ adjustBruteLoss(Clamp(0.01 * exposed_temperature, 1, 5))
New(loc, var/obj/effect/blob/factory/linked_node)
- ..()
if(istype(linked_node))
factory = linked_node
factory.spores += src
- ..(loc)
- return
- Die()
..()
+
+ Die()
if(factory)
factory.spores -= src
..()
- del(src)
-
diff --git a/code/game/gamemodes/blob/blobs/node.dm b/code/game/gamemodes/blob/blobs/node.dm
index c9ffaf96f13..2e22668d4b6 100644
--- a/code/game/gamemodes/blob/blobs/node.dm
+++ b/code/game/gamemodes/blob/blobs/node.dm
@@ -8,11 +8,12 @@
New(loc, var/h = 100)
- blobs += src
blob_nodes += src
processing_objects.Add(src)
..(loc, h)
+ fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ return
Del()
blob_nodes -= src
@@ -20,15 +21,17 @@
..()
return
+ Life()
+ for(var/i = 1; i < 8; i += i)
+ Pulse(5, i)
update_icon()
if(health <= 0)
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
- del(src)
+ Delete()
return
return
run_action()
- Pulse(0,0)
return 0
\ No newline at end of file
diff --git a/code/game/gamemodes/blob/blobs/resource.dm b/code/game/gamemodes/blob/blobs/resource.dm
new file mode 100644
index 00000000000..a0f5722282d
--- /dev/null
+++ b/code/game/gamemodes/blob/blobs/resource.dm
@@ -0,0 +1,27 @@
+/obj/effect/blob/resource
+ name = "resource blob"
+ icon = 'icons/mob/blob.dmi'
+ icon_state = "blob_resource"
+ health = 30
+ brute_resist = 1
+ fire_resist = 2
+ var/mob/camera/blob/overmind = null
+ var/resource_delay = 0
+
+ update_icon()
+ if(health <= 0)
+ playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
+ Delete()
+ return
+ return
+
+ run_action()
+ if(resource_delay > world.time)
+ return 0
+
+ resource_delay = world.time + 10 // 1 second
+
+ if(overmind)
+ overmind.add_points(1)
+ return 1
+
diff --git a/code/game/gamemodes/blob/blobs/shield.dm b/code/game/gamemodes/blob/blobs/shield.dm
index 4c77520846a..3eb6f03e126 100644
--- a/code/game/gamemodes/blob/blobs/shield.dm
+++ b/code/game/gamemodes/blob/blobs/shield.dm
@@ -14,10 +14,12 @@
update_icon()
if(health <= 0)
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
- del(src)
+ Delete()
return
return
+ fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ return
CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if(istype(mover) && mover.checkpass(PASSBLOB)) return 1
diff --git a/code/game/gamemodes/blob/overmind.dm b/code/game/gamemodes/blob/overmind.dm
new file mode 100644
index 00000000000..dcfc59e1e72
--- /dev/null
+++ b/code/game/gamemodes/blob/overmind.dm
@@ -0,0 +1,48 @@
+/mob/camera/blob
+ name = "Blob Overmind"
+ real_name = "Blob Overmind"
+ icon = 'icons/mob/blob.dmi'
+ icon_state = "marker"
+
+ see_in_dark = 8
+ see_invisible = SEE_INVISIBLE_LEVEL_TWO
+ invisibility = INVISIBILITY_OBSERVER
+
+ pass_flags = PASSBLOB
+ faction = "blob"
+
+ var/obj/effect/blob/core/blob_core = null // The blob overmind's core
+ var/blob_points = 0
+ var/max_blob_points = 100
+
+/mob/camera/blob/New()
+ var/new_name = "[initial(name)] ([rand(1, 999)])"
+ name = new_name
+ real_name = new_name
+ ..()
+
+/mob/camera/blob/say(var/message)
+ return//No talking for you
+
+/mob/camera/blob/emote(var/act,var/m_type=1,var/message = null)
+ return
+
+/mob/camera/blob/blob_act()
+ return
+
+/mob/camera/blob/Stat()
+
+ statpanel("Status")
+ ..()
+ if (client.statpanel == "Status")
+ if(blob_core)
+ stat(null, "Core Health: [blob_core.health]")
+ stat(null, "Power Stored: [blob_points]/[max_blob_points]")
+ return
+
+/mob/camera/blob/Move(var/NewLoc, var/Dir = 0)
+ var/obj/effect/blob/B = locate() in range("3x3", NewLoc)
+ if(B)
+ loc = NewLoc
+ else
+ return 0
diff --git a/code/game/gamemodes/blob/powers.dm b/code/game/gamemodes/blob/powers.dm
new file mode 100644
index 00000000000..b0b86cfacee
--- /dev/null
+++ b/code/game/gamemodes/blob/powers.dm
@@ -0,0 +1,231 @@
+// Point controlling procs
+
+/mob/camera/blob/proc/can_buy(var/cost = 15)
+ if(blob_points < cost)
+ src << "You cannot afford this."
+ return 0
+ blob_points -= cost
+ return 1
+
+/mob/camera/blob/proc/add_points(var/points = 0)
+ if(points)
+ blob_points = min(max_blob_points, blob_points + points)
+
+// Power verbs
+
+/mob/camera/blob/verb/transport_core()
+ set category = "Blob"
+ set name = "Return to Core"
+ set desc = "Transport back to your core."
+
+ if(blob_core)
+ src.loc = blob_core.loc
+
+/mob/camera/blob/verb/jump_to_node()
+ set category = "Blob"
+ set name = "Jump to Node"
+ set desc = "Transport back to your core."
+
+ if(blob_nodes.len)
+ var/list/nodes = list()
+ for(var/i = 1; i <= blob_nodes.len; i++)
+ nodes["Blob Node #[i]"] = blob_nodes[i]
+ var/node_name = input(src, "Choose a node to jump to.", "Node Jump") in nodes
+ var/obj/effect/blob/node/chosen_node = nodes[node_name]
+ if(chosen_node)
+ src.loc = chosen_node.loc
+
+/mob/camera/blob/verb/create_shield()
+ set category = "Blob"
+ set name = "Create Shield Blob (10)"
+ set desc = "Create a shield blob."
+
+
+ var/turf/T = get_turf(src)
+
+ if(!T)
+ return
+
+ var/obj/effect/blob/B = (locate(/obj/effect/blob) in T)
+
+ if(!B)//We are on a blob
+ src << "There is no blob here!"
+ return
+
+ if(!istype(B, /obj/effect/blob/normal))
+ src << "Unable to use this blob, find a normal one."
+ return
+
+ if(!can_buy(10))
+ return
+
+
+ B.change_to(/obj/effect/blob/shield)
+ return
+
+
+/mob/camera/blob/verb/create_resource()
+ set category = "Blob"
+ set name = "Create Resource Blob (40)"
+ set desc = "Create a resource tower which will generate points for you."
+
+
+ var/turf/T = get_turf(src)
+
+ if(!T)
+ return
+
+ var/obj/effect/blob/B = (locate(/obj/effect/blob) in T)
+
+ if(!B)//We are on a blob
+ src << "There is no blob here!"
+ return
+
+ if(!istype(B, /obj/effect/blob/normal))
+ src << "Unable to use this blob, find a normal one."
+ return
+
+ for(var/obj/effect/blob/resource/blob in orange(3))
+ src << "There is a resource blob nearby, move more than 3 tiles away from it!"
+ return
+
+ if(!can_buy(40))
+ return
+
+
+ B.change_to(/obj/effect/blob/resource)
+ var/obj/effect/blob/resource/R = locate(/obj/effect/blob/resource)
+ if(R)
+ R.overmind = src
+
+ return
+
+/mob/camera/blob/verb/create_node()
+ set category = "Blob"
+ set name = "Create Node Blob (60)"
+ set desc = "Create a Node."
+
+
+ var/turf/T = get_turf(src)
+
+ if(!T)
+ return
+
+ var/obj/effect/blob/B = (locate(/obj/effect/blob) in T)
+
+ if(!B)//We are on a blob
+ src << "There is no blob here!"
+ return
+
+ if(!istype(B, /obj/effect/blob/normal))
+ src << "Unable to use this blob, find a normal one."
+ return
+
+ for(var/obj/effect/blob/node/blob in orange(4))
+ src << "There is another node nearby, move more than 4 tiles away from it!"
+ return
+
+ if(!can_buy(60))
+ return
+
+
+ B.change_to(/obj/effect/blob/node)
+ return
+
+
+/mob/camera/blob/verb/create_factory()
+ set category = "Blob"
+ set name = "Create Factory Blob (60)"
+ set desc = "Create a Spore producing blob."
+
+
+ var/turf/T = get_turf(src)
+
+ if(!T)
+ return
+
+ var/obj/effect/blob/B = locate(/obj/effect/blob) in T
+ if(!B)
+ src << "You must be on a blob!"
+ return
+
+ if(!istype(B, /obj/effect/blob/normal))
+ src << "Unable to use this blob, find a normal one."
+ return
+
+ for(var/obj/effect/blob/factory/blob in orange(6))
+ src << "There is a factory blob nearby, move more than 6 tiles away from it!"
+ return
+
+ if(!can_buy(60))
+ return
+
+ B.change_to(/obj/effect/blob/factory)
+ return
+
+
+/mob/camera/blob/verb/revert()
+ set category = "Blob"
+ set name = "Remove Blob (0)"
+ set desc = "Removes a blob."
+
+ var/turf/T = get_turf(src)
+ if(!T)
+ return
+
+ var/obj/effect/blob/B = locate(/obj/effect/blob) in T
+ if(!B)
+ src << "You must be on a blob!"
+ return
+
+ if(istype(B, /obj/effect/blob/core))
+ src << "Unable to remove this blob."
+ return
+
+ B.Delete()
+ return
+
+
+/mob/camera/blob/verb/spawn_blob()
+ set category = "Blob"
+ set name = "Expand Blob (5)"
+ set desc = "Attempts to create a new blob in this tile. If the tile isn't clear we will attack it, which might clear it."
+
+ var/turf/T = get_turf(src)
+
+ if(!T)
+ return
+
+ var/obj/effect/blob/B = locate() in T
+ if(B)
+ src << "There is a blob here!"
+ return
+
+ var/obj/effect/blob/OB = locate() in circlerange(src, 1)
+ if(!OB)
+ src << "There is no blob adjacent to you."
+ return
+
+ if(!can_buy(5))
+ return
+ OB.expand(T, 0)
+ return
+
+
+/mob/camera/blob/verb/rally_spores()
+ set category = "Blob"
+ set name = "Rally Spores (5)"
+ set desc = "Rally the spores to move to your location."
+
+ if(!can_buy(5))
+ return
+
+ var/list/surrounding_turfs = block(locate(x - 1, y - 1, z), locate(x + 1, y + 1, z))
+ if(!surrounding_turfs.len)
+ return
+
+ for(var/mob/living/simple_animal/hostile/blobspore/BS in living_mob_list)
+ if(isturf(BS.loc) && get_dist(BS, src) <= 20)
+ BS.LoseTarget()
+ BS.Goto(pick(surrounding_turfs), BS.move_to_delay)
+ return
\ No newline at end of file
diff --git a/code/game/gamemodes/blob/theblob.dm b/code/game/gamemodes/blob/theblob.dm
index ff935981cac..d52ba53d6d7 100644
--- a/code/game/gamemodes/blob/theblob.dm
+++ b/code/game/gamemodes/blob/theblob.dm
@@ -2,30 +2,20 @@
/obj/effect/blob
name = "blob"
icon = 'icons/mob/blob.dmi'
- icon_state = "blob"
luminosity = 3
desc = "Some blob creature thingy"
- density = 1
+ density = 0
opacity = 0
anchored = 1
var/active = 1
var/health = 30
var/brute_resist = 4
var/fire_resist = 1
- var/blob_type = "blob"
- /*Types
- Blob
- Node
- Core
- Factory
- Shield
- */
- New(loc, var/h = 30)
+ New(loc)
blobs += src
- src.health = h
- src.dir = pick(1,2,4,8)
+ src.dir = pick(1, 2, 4, 8)
src.update_icon()
..(loc)
return
@@ -44,22 +34,30 @@
process()
- spawn(-1)
- Life()
+ Life()
+ return
+
+ fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ ..()
+ var/damage = Clamp(0.01 * exposed_temperature / fire_resist, 0, 4 - fire_resist)
+ if(damage)
+ health -= damage
+ update_icon()
+
+ proc/Life()
return
proc/Pulse(var/pulse = 0, var/origin_dir = 0)//Todo: Fix spaceblob expand
- set background = 1
- if(!istype(src,/obj/effect/blob/core) && !istype(src,/obj/effect/blob/node))//Ill put these in the children later
- if(run_action())//If we can do something here then we dont need to pulse more
- return
- if(!istype(src,/obj/effect/blob/shield) && !istype(src,/obj/effect/blob/core) && !istype(src,/obj/effect/blob/node) && (pulse <= 2) && (prob(30)))
- change_to("Shield")
+ set background = 1
+
+ if(run_action())//If we can do something here then we dont need to pulse more
return
- if(pulse > 20) return//Inf loop check
+ if(pulse > 30)
+ return//Inf loop check
+
//Looking for another blob to pulse
var/list/dirs = list(1,2,4,8)
dirs.Remove(origin_dir)//Dont pulse the guy who pulsed us
@@ -81,20 +79,9 @@
return 0
- proc/Life()
- update_icon()
- if(run_action())
- return 1
- return 0
-
-/* temperature_expose(datum/gas_mixture/air, temperature, volume) Blob is currently fireproof
- if(temperature > T0C+200)
- health -= 0.01 * temperature
- update()
- */
-
- proc/expand(var/turf/T = null)
- if(!prob(health)) return
+ proc/expand(var/turf/T = null, var/prob = 1)
+ if(prob && !prob(health)) return
+ if(istype(T, /turf/space)) return
if(!T)
var/list/dirs = list(1,2,4,8)
for(var/i = 1 to 4)
@@ -105,12 +92,15 @@
else T = null
if(!T) return 0
- var/obj/effect/blob/B = new /obj/effect/blob(src.loc, min(src.health, 30))
+ var/obj/effect/blob/normal/B = new /obj/effect/blob/normal(src.loc, min(src.health, 30))
+ B.density = 1
if(T.Enter(B,src))//Attempt to move into the tile
+ B.density = initial(B.density)
B.loc = T
else
T.blob_act()//If we cant move in hit the turf
- del(B)
+ B.Delete()
+
for(var/atom/A in T)//Hit everything in the turf
A.blob_act()
return 1
@@ -131,19 +121,6 @@
return
- update_icon()//Needs to be updated with the types
- if(health <= 0)
- playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
- del(src)
- return
- if(health <= 15)
- icon_state = "blob_damaged"
- return
-// if(health <= 20)
-// icon_state = "blob_damaged2"
-// return
-
-
bullet_act(var/obj/item/projectile/Proj)
..()
switch(Proj.damage_type)
@@ -172,50 +149,29 @@
update_icon()
return
- proc/change_to(var/type = "Normal")
- switch(type)
- if("Normal")
- new/obj/effect/blob(src.loc,src.health)
- if("Node")
- new/obj/effect/blob/node(src.loc,src.health*2)
- if("Factory")
- new/obj/effect/blob/factory(src.loc,src.health)
- if("Shield")
- new/obj/effect/blob/shield(src.loc,src.health*2)
- del(src)
+ proc/change_to(var/type)
+ if(!ispath(type))
+ error("[type] is an invalid type for the blob.")
+ new type(src.loc)
+ Delete()
return
-//////////////////////////////****IDLE BLOB***/////////////////////////////////////
+ proc/Delete()
+ del(src)
-/obj/effect/blob/idle
- name = "blob"
- desc = "it looks... tasty"
- icon_state = "blobidle0"
+/obj/effect/blob/normal
+ icon_state = "blob"
+ luminosity = 0
+ Delete()
+ src.loc = null
+ blobs -= src
- New(loc, var/h = 10)
- src.health = h
- src.dir = pick(1,2,4,8)
- src.update_idle()
-
-
- proc/update_idle()
- if(health<=0)
- del(src)
+ update_icon()
+ if(health <= 0)
+ playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
+ Delete()
return
- if(health<4)
- icon_state = "blobc0"
- return
- if(health<10)
- icon_state = "blobb0"
- return
- icon_state = "blobidle0"
-
-
- Del()
- var/obj/effect/blob/B = new /obj/effect/blob( src.loc )
- spawn(30)
- B.Life()
- ..()
-
-
+ if(health <= 15)
+ icon_state = "blob_damaged"
+ return
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm
index 7e7c81c8798..de9c5745d86 100644
--- a/code/game/gamemodes/changeling/changeling_powers.dm
+++ b/code/game/gamemodes/changeling/changeling_powers.dm
@@ -655,4 +655,4 @@ var/list/datum/dna/hivemind_bank = list()
changeling.absorbed_dna |= T.dna
feedback_add_details("changeling_powers","ED")
- return 1
+ return 1
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 0a789b2cf21..f0ef6f1907b 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -91,6 +91,7 @@
return
/obj/machinery/camera/blob_act()
+ del(src)
return
/obj/machinery/camera/proc/setViewRange(var/num = 7)
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index 6f3190f9ee1..ff0e2a25da4 100644
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -456,10 +456,6 @@
user << "The emergency shuttle is already on its way."
return
- if(ticker.mode.name == "blob")
- user << "Under directive 7-10, [station_name()] is quarantined until further notice."
- return
-
emergency_shuttle.incall()
log_game("[key_name(user)] has called the shuttle.")
message_admins("[key_name_admin(user)] has called the shuttle.", 1)
@@ -472,7 +468,7 @@
/proc/cancel_call_proc(var/mob/user)
if ((!( ticker ) || emergency_shuttle.location || emergency_shuttle.direction == 0 || emergency_shuttle.timeleft() < 300))
return
- if((ticker.mode.name == "blob")||(ticker.mode.name == "meteor"))
+ if(ticker.mode.name == "meteor")
return
if(emergency_shuttle.direction != -1 && emergency_shuttle.online) //check that shuttle isn't already heading to centcom
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 259b64cb277..0bd187a53f6 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -609,6 +609,10 @@
return
*/
+/obj/mecha/blob_act()
+ take_damage(30, "brute")
+ return
+
//TODO
/obj/mecha/meteorhit()
return ex_act(rand(1,3))//should do for now
diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm
index 888c2e126f2..3b1f70d7199 100644
--- a/code/game/objects/items/weapons/AI_modules.dm
+++ b/code/game/objects/items/weapons/AI_modules.dm
@@ -34,10 +34,6 @@ AI MODULES
usr << "You haven't selected an AI to transmit laws to!"
return
- if(ticker && ticker.mode && ticker.mode.name == "blob")
- usr << "Law uploads have been disabled by NanoTrasen!"
- return
-
if (comp.current.stat == 2 || comp.current.control_disabled == 1)
usr << "Upload failed. No signal is being detected from the AI."
else if (comp.current.see_in_dark == 0)
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 9429c1b5e23..1a3a13a5ed0 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -103,7 +103,6 @@ var/global/floorIsLava = 0
body += "Make AI | "
body += "Make Robot | "
body += "Make Alien | "
- body += "Make Blob Fragment | "
body += "Make Slime "
//Simple Animals
@@ -467,7 +466,6 @@ var/global/floorIsLava = 0
Egalitarian Station Mode
Break all lights
Fix all lights
- Best Friend AI
The floor is lava! (DANGEROUS: extremely lame)
"}
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index b33ab909c70..54d78e0df39 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -231,9 +231,6 @@
else if(href_list["call_shuttle"])
if(!check_rights(R_ADMIN)) return
- if( ticker.mode.name == "blob" )
- alert("You can't call the shuttle during blob!")
- return
switch(href_list["call_shuttle"])
if("1")
@@ -1046,18 +1043,6 @@
message_admins("\blue [key_name_admin(usr)] attempting to corgize [key_name_admin(H)]", 1)
H.corgize()
- else if(href_list["makeblob"])
- if(!check_rights(R_SPAWN)) return
-
- var/mob/living/carbon/human/H = locate(href_list["makeblob"])
- if(!istype(H))
- usr << "This can only be used on instances of type /mob/living/carbon/human"
- return
-
- log_admin("[key_name(usr)] attempting to blobize [key_name(H)]")
- message_admins("\blue [key_name_admin(usr)] attempting to blobize [key_name_admin(H)]", 1)
- H.blobize()
-
else if(href_list["forcespeech"])
if(!check_rights(R_FUN)) return
@@ -1915,19 +1900,6 @@
message_admins("[key_name_admin(usr)] fixed all lights", 1)
for(var/obj/machinery/light/L in world)
L.fix()
- if("friendai")
- feedback_inc("admin_secrets_fun_used",1)
- feedback_add_details("admin_secrets_fun_used","FA")
- for(var/mob/aiEye/aE in mob_list)
- aE.icon_state = "ai_friend"
- for(var/obj/machinery/M in machines)
- if(istype(M, /obj/machinery/ai_status_display))
- var/obj/machinery/ai_status_display/A = M
- A.emotion = "Friend Computer"
- else if(istype(M, /obj/machinery/status_display))
- var/obj/machinery/status_display/A = M
- A.friendc = 1
- message_admins("[key_name_admin(usr)] turned all AIs into best friends.", 1)
if("floorlava")
if(floorIsLava)
usr << "The floor is lava already."
diff --git a/code/modules/mob/camera/camera.dm b/code/modules/mob/camera/camera.dm
new file mode 100644
index 00000000000..054fb163a4f
--- /dev/null
+++ b/code/modules/mob/camera/camera.dm
@@ -0,0 +1,14 @@
+// Camera mob, used by AI camera and blob.
+
+/mob/camera
+ name = "camera mob"
+ density = 0
+ status_flags = GODMODE // You can't damage it.
+ mouse_opacity = 0
+ see_in_dark = 7
+ invisibility = 101 // No one can see us
+
+ move_on_shuttle = 0
+
+/mob/camera/experience_pressure_difference()
+ return
\ No newline at end of file
diff --git a/code/modules/mob/living/blob/blob.dm b/code/modules/mob/living/blob/blob.dm
deleted file mode 100644
index 52edf14bdba..00000000000
--- a/code/modules/mob/living/blob/blob.dm
+++ /dev/null
@@ -1,258 +0,0 @@
-/mob/living/blob
- name = "blob fragment"
- real_name = "blob fragment"
- icon = 'icons/mob/blob.dmi'
- icon_state = "blob_spore_temp"
- pass_flags = PASSBLOB
- see_in_dark = 8
- see_invisible = SEE_INVISIBLE_LEVEL_TWO
- var/ghost_name = "Unknown"
- var/creating_blob = 0
- faction = "blob"
-
-
- New()
- real_name += " [pick(rand(1, 99))]"
- name = real_name
- ..()
-
-
- say(var/message)
- return//No talking for you
-
-
- emote(var/act,var/m_type=1,var/message = null)
- return
-
-
- Life()
- set invisibility = 0
- set background = 1
-
- clamp_values()
- UpdateDamage()
- if(health < 0)
- src.dust()
-
-
- proc/clamp_values()
- AdjustStunned(0)
- AdjustParalysis(0)
- AdjustWeakened(0)
- sleeping = 0
- if(stat)
- stat = CONSCIOUS
- return
-
-
- proc/UpdateDamage()
- health = 60 - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss())
- return
-
-
- death(gibbed)
- if(key)
- var/mob/dead/observer/ghost = new(src)
- ghost.name = ghost_name
- ghost.real_name = ghost_name
- ghost.key = key
- if (ghost.client)
- ghost.client.eye = ghost
- return ..(gibbed)
-
-
- blob_act()
- src << "The blob attempts to reabsorb you."
- adjustToxLoss(20)
- return
-
-
- Process_Spacemove()
- if(locate(/obj/effect/blob) in oview(1,src))
- return 1
- return (..())
-
-
-/mob/living/blob/verb/create_node()
- set category = "Blob"
- set name = "Create Node"
- set desc = "Create a Node."
- if(creating_blob) return
- var/turf/T = get_turf(src)
- creating_blob = 1
- if(!T)
- creating_blob = 0
- return
- var/obj/effect/blob/B = (locate(/obj/effect/blob) in T)
- if(!B)//We are on a blob
- usr << "There is no blob here!"
- creating_blob = 0
- return
- if(istype(B,/obj/effect/blob/node)||istype(B,/obj/effect/blob/core)||istype(B,/obj/effect/blob/factory))
- usr << "Unable to use this blob, find a normal one."
- creating_blob = 0
- return
- for(var/obj/effect/blob/node/blob in orange(5))
- usr << "There is another node nearby, move more than 5 tiles away from it!"
- creating_blob = 0
- return
- for(var/obj/effect/blob/factory/blob in orange(2))
- usr << "There is a porus blob nearby, move more than 2 tiles away from it!"
- creating_blob = 0
- B.change_to("Node")
- src.dust()
- return
-
-
-/mob/living/blob/verb/create_factory()
- set category = "Blob"
- set name = "Create Defense"
- set desc = "Create a Spore producing blob."
- if(creating_blob) return
- var/turf/T = get_turf(src)
- creating_blob = 1
- if(!T)
- creating_blob = 0
- return
- var/obj/effect/blob/B = (locate(/obj/effect/blob) in T)
- if(!B)
- usr << "You must be on a blob!"
- creating_blob = 0
- return
- if(istype(B,/obj/effect/blob/node)||istype(B,/obj/effect/blob/core)||istype(B,/obj/effect/blob/factory))
- usr << "Unable to use this blob, find a normal one."
- creating_blob = 0
- return
- for(var/obj/effect/blob/blob in orange(2))//Not right next to nodes/cores
- if(istype(B,/obj/effect/blob/node))
- usr << "There is a node nearby, move away from it!"
- creating_blob = 0
- return
- if(istype(B,/obj/effect/blob/core))
- usr << "There is a core nearby, move away from it!"
- creating_blob = 0
- return
- if(istype(B,/obj/effect/blob/factory))
- usr << "There is another porous blob nearby, move away from it!"
- creating_blob = 0
- return
- B.change_to("Factory")
- src.dust()
- return
-
-
-/mob/living/blob/verb/revert()
- set category = "Blob"
- set name = "Purge Defense"
- set desc = "Removes a porous blob."
- if(creating_blob) return
- var/turf/T = get_turf(src)
- creating_blob = 1
- if(!T)
- creating_blob = 0
- return
- var/obj/effect/blob/B = (locate(/obj/effect/blob) in T)
- if(!B)
- usr << "You must be on a blob!"
- creating_blob = 0
- return
- if(!istype(B,/obj/effect/blob/factory))
- usr << "Unable to use this blob, find another one."
- creating_blob = 0
- return
- B.change_to("Normal")
- src.dust()
- return
-
-
-/mob/living/blob/verb/spawn_blob()
- set category = "Blob"
- set name = "Create new blob"
- set desc = "Attempts to create a new blob in this tile."
- if(creating_blob) return
- var/turf/T = get_turf(src)
- creating_blob = 1
- if(!T)
- creating_blob = 0
- return
- var/obj/effect/blob/B = (locate(/obj/effect/blob) in T)
- if(B)
- usr << "There is a blob here!"
- creating_blob = 0
- return
- new/obj/effect/blob(src.loc)
- src.dust()
- return
-
-
-/mob/proc/Blobize()
-/client/proc/Blobcount()
- set category = "Debug"
- set name = "blobreport"
- set desc = "blob report."
- set hidden = 1
-
- if(!holder)
- src << "Only administrators may use this command."
- return
- if(ticker && ticker.mode)
- src << "blobs: [blobs.len]"
- src << "cores: [blob_cores.len]"
- src << "nodes: [blob_nodes.len]"
- return
-
-
-/client/proc/Blobize()//Mostly stolen from the respawn command
- set category = "Debug"
- set name = "Ghostblob"
- set desc = "Ghost into blobthing."
- set hidden = 1
-
- if(!holder)
- src << "Only administrators may use this command."
- return
- var/input = input(src, "Please specify which key will be turned into a bloby.", "Key", "")
-
- var/mob/dead/observer/G_found
- if(!input)
- var/list/ghosts = list()
- for(var/mob/dead/observer/G in player_list)
- ghosts += G
- if(ghosts.len)
- G_found = pick(ghosts)
-
- else
- for(var/mob/dead/observer/G in player_list)
- if(G.client&&ckey(G.key)==ckey(input))
- G_found = G
- break
-
- if(!G_found)//If a ghost was not found.
- alert("There is no active key like that in the game or the person is not currently a ghost. Aborting command.")
- return
-
- if(G_found.client)
- G_found.client.screen.len = null
- var/mob/living/blob/B = new/mob/living/blob(locate(0,0,1))//temp area also just in case should do this better but tired
- if(blob_cores.len > 0)
- var/obj/effect/blob/core/core = pick(blob_cores)
- if(core)
- B.loc = core.loc
- B.ghost_name = G_found.real_name
- if (G_found.client)
- G_found.client.mob = B
- B.verbs += /mob/living/blob/verb/create_node
- B.verbs += /mob/living/blob/verb/create_factory
- B << "You are now a blob fragment."
- B << "You are a weak bit that has temporarily broken off of the blob."
- B << "If you stay on the blob for too long you will likely be reabsorbed."
- B << "If you stray from the blob you will likely be killed by other organisms."
- B << "You have the power to create a new blob node that will help expand the blob."
- B << "To create this node you will have to be on a normal blob tile and far enough away from any other node."
- B << "Check your Blob verbs and hit Create Node to build a node."
- spawn(10)
- del(G_found)
-
-
-
-
diff --git a/code/modules/mob/living/silicon/ai/freelook/cameranet.dm b/code/modules/mob/living/silicon/ai/freelook/cameranet.dm
index 2d94a20f913..a838e80042d 100644
--- a/code/modules/mob/living/silicon/ai/freelook/cameranet.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/cameranet.dm
@@ -33,7 +33,7 @@ var/datum/cameranet/cameranet = new()
// Updates what the aiEye can see. It is recommended you use this when the aiEye moves or it's location is set.
-/datum/cameranet/proc/visibility(mob/aiEye/ai)
+/datum/cameranet/proc/visibility(mob/camera/aiEye/ai)
// 0xf = 15
var/x1 = max(0, ai.x - 16) & ~(CHUNK_SIZE - 1)
var/y1 = max(0, ai.y - 16) & ~(CHUNK_SIZE - 1)
diff --git a/code/modules/mob/living/silicon/ai/freelook/chunk.dm b/code/modules/mob/living/silicon/ai/freelook/chunk.dm
index 9bb9c9bd043..1d11b225226 100644
--- a/code/modules/mob/living/silicon/ai/freelook/chunk.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/chunk.dm
@@ -21,7 +21,7 @@
// Add an AI eye to the chunk, then update if changed.
-/datum/camerachunk/proc/add(mob/aiEye/ai)
+/datum/camerachunk/proc/add(mob/camera/aiEye/ai)
if(!ai.ai)
return
ai.visibleCameraChunks += src
@@ -34,7 +34,7 @@
// Remove an AI eye from the chunk, then update if changed.
-/datum/camerachunk/proc/remove(mob/aiEye/ai)
+/datum/camerachunk/proc/remove(mob/camera/aiEye/ai)
if(!ai.ai)
return
ai.visibleCameraChunks -= src
@@ -105,7 +105,7 @@
if(t.obscured)
obscured -= t.obscured
for(var/eye in seenby)
- var/mob/aiEye/m = eye
+ var/mob/camera/aiEye/m = eye
if(!m || !m.ai)
continue
if(m.ai.client)
@@ -119,7 +119,7 @@
obscured += t.obscured
for(var/eye in seenby)
- var/mob/aiEye/m = eye
+ var/mob/camera/aiEye/m = eye
if(!m || !m.ai)
seenby -= m
continue
diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm
index 776ef22d8ed..d692d5cba21 100644
--- a/code/modules/mob/living/silicon/ai/freelook/eye.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm
@@ -3,40 +3,17 @@
// An invisible (no icon) mob that the AI controls to look around the station with.
// It streams chunks as it moves around, which will show it what the AI can and cannot see.
-/mob/aiEye
+/mob/camera/aiEye
name = "Inactive AI Eye"
- icon = 'icons/obj/status_display.dmi' // For AI friend secret shh :o
+
var/list/visibleCameraChunks = list()
var/mob/living/silicon/ai/ai = null
- density = 0
- status_flags = GODMODE // You can't damage it.
- mouse_opacity = 0
- see_in_dark = 7
-// Movement code. Returns 0 to stop air movement from moving it.
-/mob/aiEye/Move()
- return 0
-
-// Hide popout menu verbs
-/mob/aiEye/examine()
- set popup_menu = 0
- set src = usr.contents
- return 0
-
-/mob/aiEye/pull()
- set popup_menu = 0
- set src = usr.contents
- return 0
-
-/mob/aiEye/point()
- set popup_menu = 0
- set src = usr.contents
- return 0
// Use this when setting the aiEye's location.
// It will also stream the chunk that the new loc is in.
-/mob/aiEye/proc/setLoc(var/T)
+/mob/camera/aiEye/proc/setLoc(var/T)
if(ai)
if(!isturf(ai.loc))
@@ -51,13 +28,16 @@
var/obj/machinery/hologram/holopad/H = ai.current
H.move_hologram()
+/mob/camera/aiEye/Move()
+ return 0
+
// AI MOVEMENT
// The AI's "eye". Described on the top of the page.
/mob/living/silicon/ai
- var/mob/aiEye/eyeobj = new()
+ var/mob/camera/aiEye/eyeobj = new()
var/sprint = 10
var/cooldown = 0
var/acceleration = 1
diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm
index 576f88a534d..0a83d7aa5d1 100644
--- a/code/modules/mob/living/simple_animal/hostile/bear.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bear.dm
@@ -64,7 +64,7 @@
stop_automated_movement = 1
stance_step++
if(stance_step >= 10) //rests for 10 ticks
- if(target_mob && target_mob in ListTargets())
+ if(target && target in ListTargets())
stance = HOSTILE_STANCE_ATTACK //If the mob he was chasing is still nearby, resume the attack, otherwise go idle.
else
stance = HOSTILE_STANCE_IDLE
@@ -72,15 +72,15 @@
if(HOSTILE_STANCE_ALERT)
stop_automated_movement = 1
var/found_mob = 0
- if(target_mob && target_mob in ListTargets())
- if(!(SA_attackable(target_mob)))
+ if(target && target in ListTargets())
+ if(!(SA_attackable(target)))
stance_step = max(0, stance_step) //If we have not seen a mob in a while, the stance_step will be negative, we need to reset it to 0 as soon as we see a mob again.
stance_step++
found_mob = 1
- src.dir = get_dir(src,target_mob) //Keep staring at the mob
+ src.dir = get_dir(src,target) //Keep staring at the mob
if(stance_step in list(1,4,7)) //every 3 ticks
- var/action = pick( list( "growls at [target_mob]", "stares angrily at [target_mob]", "prepares to attack [target_mob]", "closely watches [target_mob]" ) )
+ var/action = pick( list( "growls at [target]", "stares angrily at [target]", "prepares to attack [target]", "closely watches [target]" ) )
if(action)
emote(action)
if(!found_mob)
@@ -105,14 +105,14 @@
if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING)
stance = HOSTILE_STANCE_ALERT
stance_step = 6
- target_mob = user
+ target = user
..()
/mob/living/simple_animal/hostile/bear/attack_hand(mob/living/carbon/human/M as mob)
if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING)
stance = HOSTILE_STANCE_ALERT
stance_step = 6
- target_mob = M
+ target = M
..()
/mob/living/simple_animal/hostile/bear/Process_Spacemove(var/check_drift = 0)
@@ -128,22 +128,22 @@
..(5)
/mob/living/simple_animal/hostile/bear/AttackingTarget()
- emote( pick( list("slashes at [target_mob]", "bites [target_mob]") ) )
+ emote( pick( list("slashes at [target]", "bites [target]") ) )
var/damage = rand(20,30)
- if(ishuman(target_mob))
- var/mob/living/carbon/human/H = target_mob
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg")
var/datum/limb/affecting = H.get_organ(ran_zone(dam_zone))
H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, "melee"))
return H
- else if(isliving(target_mob))
- var/mob/living/L = target_mob
+ else if(isliving(target))
+ var/mob/living/L = target
L.adjustBruteLoss(damage)
return L
- else if(istype(target_mob,/obj/mecha))
- var/obj/mecha/M = target_mob
+ else if(istype(target,/obj/mecha))
+ var/obj/mecha/M = target
M.attack_animal(src)
return M
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index 267a263742c..3da3cecb760 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -64,8 +64,8 @@
/mob/living/simple_animal/hostile/giant_spider/AttackingTarget()
..()
- if(isliving(target_mob))
- var/mob/living/L = target_mob
+ if(isliving(target))
+ var/mob/living/L = target
if(L.reagents)
L.reagents.add_reagent("toxin", poison_per_bite)
if(prob(poison_per_bite))
@@ -82,7 +82,7 @@
for(var/turf/T in orange(20, src))
move_targets.Add(T)*/
stop_automated_movement = 1
- walk_to(src, pick(orange(20, src)), 1, move_to_delay)
+ Goto(pick(orange(20, src)), move_to_delay)
spawn(50)
stop_automated_movement = 0
walk(src,0)
@@ -107,7 +107,7 @@
if(C.stat && !istype(C,/mob/living/simple_animal/hostile/giant_spider))
cocoon_target = C
busy = MOVING_TO_TARGET
- walk_to(src, C, 1, move_to_delay)
+ Goto(C, move_to_delay)
//give up if we can't reach them after 10 seconds
GiveUp(C)
return
@@ -149,7 +149,7 @@
cocoon_target = O
busy = MOVING_TO_TARGET
stop_automated_movement = 1
- walk_to(src, O, 1, move_to_delay)
+ Goto(O, move_to_delay)
//give up if we can't reach them after 10 seconds
GiveUp(O)
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index 568c8c71d1c..f8262ce8832 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -1,7 +1,7 @@
/mob/living/simple_animal/hostile
faction = "hostile"
var/stance = HOSTILE_STANCE_IDLE //Used to determine behavior
- var/mob/living/target_mob
+ var/target
var/attack_same = 0
var/ranged = 0
var/rapid = 0
@@ -32,63 +32,68 @@
continue
else
if(!L.stat)
- stance = HOSTILE_STANCE_ATTACK
T = L
break
else if(istype(A, /obj/mecha)) // Our line of sight stuff was already done in ListTargets().
var/obj/mecha/M = A
if (M.occupant)
- stance = HOSTILE_STANCE_ATTACK
T = M
break
return T
+/mob/living/simple_animal/hostile/proc/GiveTarget(var/new_target)
+ target = new_target
+ stance = HOSTILE_STANCE_ATTACK
+ return
+
+/mob/living/simple_animal/hostile/proc/Goto(var/target, var/delay)
+ walk_to(src, target, 1, delay)
/mob/living/simple_animal/hostile/proc/Found(var/atom/A)
return
/mob/living/simple_animal/hostile/proc/MoveToTarget()
stop_automated_movement = 1
- if(!target_mob || SA_attackable(target_mob))
- stance = HOSTILE_STANCE_IDLE
- if(target_mob in ListTargets())
+ if(!target || SA_attackable(target))
+ LoseTarget()
+ if(target in ListTargets())
if(ranged)
- if(get_dist(src, target_mob) <= 6)
- OpenFire(target_mob)
+ if(get_dist(src, target) <= 6)
+ OpenFire(target)
else
- walk_to(src, target_mob, 1, move_to_delay)
+ Goto(target, move_to_delay)
else
stance = HOSTILE_STANCE_ATTACKING
- walk_to(src, target_mob, 1, move_to_delay)
+ Goto(target, move_to_delay)
/mob/living/simple_animal/hostile/proc/AttackTarget()
stop_automated_movement = 1
- if(!target_mob || SA_attackable(target_mob))
+ if(!target || SA_attackable(target))
LoseTarget()
return 0
- if(!(target_mob in ListTargets()))
+ if(!(target in ListTargets()))
LostTarget()
return 0
- if(get_dist(src, target_mob) <= 1) //Attacking
+ if(get_dist(src, target) <= 1) //Attacking
AttackingTarget()
return 1
/mob/living/simple_animal/hostile/proc/AttackingTarget()
- if(isliving(target_mob))
- var/mob/living/L = target_mob
+ if(isliving(target))
+ var/mob/living/L = target
L.attack_animal(src)
return L
- if(istype(target_mob,/obj/mecha))
- var/obj/mecha/M = target_mob
+ if(istype(target,/obj/mecha))
+ var/obj/mecha/M = target
M.attack_animal(src)
return M
/mob/living/simple_animal/hostile/proc/LoseTarget()
stance = HOSTILE_STANCE_IDLE
- target_mob = null
+ target = null
walk(src, 0)
/mob/living/simple_animal/hostile/proc/LostTarget()
@@ -125,7 +130,8 @@
if(!stat)
switch(stance)
if(HOSTILE_STANCE_IDLE)
- target_mob = FindTarget()
+ var/new_target = FindTarget()
+ GiveTarget(new_target)
if(HOSTILE_STANCE_ATTACK)
DestroySurroundings()
@@ -135,8 +141,8 @@
DestroySurroundings()
AttackTarget()
-/mob/living/simple_animal/hostile/proc/OpenFire(target_mob)
- var/target = target_mob
+/mob/living/simple_animal/hostile/proc/OpenFire(var/the_target)
+ var/target = the_target
visible_message("\red [src] fires at [target]!", 1)
var/tturf = get_turf(target)
@@ -159,7 +165,7 @@
new casingtype
stance = HOSTILE_STANCE_IDLE
- target_mob = null
+ target = null
return
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index dd9c173010e..d85986a0cfd 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -217,6 +217,11 @@
new meat_type(src.loc)
..()
+
+/mob/living/simple_animal/blob_act()
+ adjustBruteLoss(20)
+ return
+
/mob/living/simple_animal/say_quote(var/text)
if(speak_emote && speak_emote.len)
var/emote = pick(speak_emote)
@@ -441,13 +446,13 @@
/mob/living/simple_animal/adjustBruteLoss(damage)
health = Clamp(health - damage, 0, maxHealth)
-/mob/living/simple_animal/proc/SA_attackable(target_mob)
- if (isliving(target_mob))
- var/mob/living/L = target_mob
+/mob/living/simple_animal/proc/SA_attackable(target)
+ if (isliving(target))
+ var/mob/living/L = target
if(!L.stat)
- return (0)
- if (istype(target_mob,/obj/mecha))
- var/obj/mecha/M = target_mob
+ return 0
+ if (istype(target,/obj/mecha))
+ var/obj/mecha/M = target
if (M.occupant)
- return (0)
- return (1)
\ No newline at end of file
+ return 0
+ return 1
\ No newline at end of file
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index c63e10f6ac2..10bec1b2123 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -135,6 +135,7 @@
var/say_message = null // When you are understood by others. Currently only used by aliens and monkeys in their say_quote procs
var/faction = "neutral" //Used for checking whether hostile simple animals will attack you, possibly more stuff later
+ var/move_on_shuttle = 1 // Can move on the shuttle.
//The last mob/living/carbon to push/drag/grab this mob (mostly used by slimes friend recognition)
var/mob/living/carbon/LAssailant = null
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 273c8c2f049..7ed169f0088 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -211,16 +211,16 @@
return 0 //This is sota the goto stop mobs from moving var
if(mob.control_object)
return Move_object(direct)
- if(isobserver(mob))
- return mob.Move(n,direct)
- if(moving)
- return 0
if(world.time < move_delay)
return 0
- if(mob.stat == DEAD)
- return 0
if(isAI(mob))
return AIMove(n,direct,mob)
+ if(!isliving(mob))
+ return mob.Move(n,direct)
+ if(moving)
+ return 0
+ if(mob.stat == DEAD)
+ return 0
if(isliving(mob))
var/mob/living/L = mob
if(L.incorporeal_move) //Move though walls
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index a7004485f31..d5841d9fc30 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -389,27 +389,6 @@
. = new_corgi
del(src)
-/mob/living/carbon/human/proc/blobize() // Oh boy, this is for you Int - Summoner
- if (monkeyizing)
- return
- for(var/obj/item/W in src)
- drop_from_inventory(W)
- regenerate_icons()
- monkeyizing = 1
- canmove = 0
- icon = null
- invisibility = 101
- for(var/t in organs)
- del(t)
-
- var/mob/living/blob/new_blob = new /mob/living/blob (loc)
- new_blob.a_intent = "harm"
- new_blob.key = key
-
- new_blob << "You are now a Blob Fragment. You can now sacrifice yourself to spawn blobs!"
- . = new_blob
- del(src)
-
/mob/living/carbon/human/Animalize()
var/list/mobtypes = typesof(/mob/living/simple_animal)
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index 0eabed3c341..055e62d9ca0 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -140,8 +140,7 @@
return
/obj/item/weapon/cell/blob_act()
- if(prob(75))
- explode()
+ ex_act(1)
/obj/item/weapon/cell/proc/get_electrocute_damage()
switch (charge)
diff --git a/config/game_options.txt b/config/game_options.txt
index f21858ca48d..4a7cf3cbf3b 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -83,7 +83,7 @@ PROBABILITY CULT 2
PROBABILITY CHANGELING 2
PROBABILITY WIZARD 4
PROBABILITY MALFUNCTION 1
-PROBABILITY BLOB 0
+PROBABILITY BLOB 2
PROBABILITY METEOR 0
PROBABILITY EXTENDED 0
diff --git a/html/changelog.html b/html/changelog.html
index cff50a0caa8..6ea1d1b4eee 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -51,7 +51,16 @@ should be listed in the changelog upon commit tho. Thanks. -->
-