mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-09 16:14:13 +00:00
Merge branch 'blobrevamp' of https://github.com/Giacomand/vgstation13 into Bleeding-Edge
Conflicts: html/changelog.html
This commit is contained in:
@@ -52,8 +52,8 @@
|
||||
#define FILE_DIR "sound/violin"
|
||||
#define FILE_DIR "sound/voice"
|
||||
#define FILE_DIR "sound/voice/Serithi"
|
||||
#define FILE_DIR "sound/weapons"
|
||||
#define FILE_DIR "sound/vox"
|
||||
#define FILE_DIR "sound/weapons"
|
||||
// END_FILE_DIR
|
||||
// BEGIN_PREFERENCES
|
||||
#define DEBUG
|
||||
@@ -222,10 +222,13 @@
|
||||
#include "code\game\gamemodes\blob\blob.dm"
|
||||
#include "code\game\gamemodes\blob\blob_finish.dm"
|
||||
#include "code\game\gamemodes\blob\blob_report.dm"
|
||||
#include "code\game\gamemodes\blob\overmind.dm"
|
||||
#include "code\game\gamemodes\blob\powers.dm"
|
||||
#include "code\game\gamemodes\blob\theblob.dm"
|
||||
#include "code\game\gamemodes\blob\blobs\core.dm"
|
||||
#include "code\game\gamemodes\blob\blobs\factory.dm"
|
||||
#include "code\game\gamemodes\blob\blobs\node.dm"
|
||||
#include "code\game\gamemodes\blob\blobs\resource.dm"
|
||||
#include "code\game\gamemodes\blob\blobs\shield.dm"
|
||||
#include "code\game\gamemodes\changeling\changeling.dm"
|
||||
#include "code\game\gamemodes\changeling\changeling_powers.dm"
|
||||
@@ -866,6 +869,7 @@
|
||||
#include "code\modules\mob\screen.dm"
|
||||
#include "code\modules\mob\transform_procs.dm"
|
||||
#include "code\modules\mob\update_icons.dm"
|
||||
#include "code\modules\mob\camera\camera.dm"
|
||||
#include "code\modules\mob\dead\death.dm"
|
||||
#include "code\modules\mob\dead\observer\hud.dm"
|
||||
#include "code\modules\mob\dead\observer\logout.dm"
|
||||
@@ -878,7 +882,6 @@
|
||||
#include "code\modules\mob\living\login.dm"
|
||||
#include "code\modules\mob\living\logout.dm"
|
||||
#include "code\modules\mob\living\say.dm"
|
||||
#include "code\modules\mob\living\blob\blob.dm"
|
||||
#include "code\modules\mob\living\carbon\carbon.dm"
|
||||
#include "code\modules\mob\living\carbon\carbon_defines.dm"
|
||||
#include "code\modules\mob\living\carbon\give.dm"
|
||||
|
||||
@@ -95,10 +95,10 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/panther/AttackTarget()
|
||||
..()
|
||||
if(stance == HOSTILE_STANCE_ATTACKING && get_dist(src, target_mob))
|
||||
if(stance == HOSTILE_STANCE_ATTACKING && get_dist(src, target))
|
||||
stalk_tick_delay -= 1
|
||||
if(stalk_tick_delay <= 0)
|
||||
src.loc = get_step_towards(src, target_mob)
|
||||
src.loc = get_step_towards(src, target)
|
||||
stalk_tick_delay = 3
|
||||
|
||||
//*******//
|
||||
@@ -151,8 +151,8 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/snake/AttackTarget()
|
||||
..()
|
||||
if(stance == HOSTILE_STANCE_ATTACKING && get_dist(src, target_mob))
|
||||
if(stance == HOSTILE_STANCE_ATTACKING && get_dist(src, target))
|
||||
stalk_tick_delay -= 1
|
||||
if(stalk_tick_delay <= 0)
|
||||
src.loc = get_step_towards(src, target_mob)
|
||||
src.loc = get_step_towards(src, target)
|
||||
stalk_tick_delay = 3
|
||||
|
||||
@@ -72,7 +72,8 @@
|
||||
|
||||
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 // If we need to check for more mobs, I'll add a variable
|
||||
mobs += M
|
||||
|
||||
for(var/mob/M in mobs)
|
||||
|
||||
@@ -429,6 +429,6 @@ zone/proc/movables()
|
||||
. = list()
|
||||
for(var/turf/T in contents)
|
||||
for(var/atom/A in T)
|
||||
if(istype(A, /obj/effect) || istype(A, /mob/aiEye))
|
||||
if(istype(A, /obj/effect) || istype(A, /mob/camera))
|
||||
continue
|
||||
. += A
|
||||
|
||||
@@ -350,6 +350,13 @@ var/list/DummyCache = list()
|
||||
i++
|
||||
return candidates
|
||||
|
||||
/proc/get_candidates(be_special_flag=0)
|
||||
. = list()
|
||||
for(var/mob/dead/observer/G in player_list)
|
||||
if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD))
|
||||
if(!G.client.is_afk() && (G.client.prefs.be_special & be_special_flag))
|
||||
. += G.client
|
||||
|
||||
/proc/ScreenText(obj/O, maptext="", screen_loc="CENTER-7,CENTER-7", maptext_height=480, maptext_width=480)
|
||||
if(!isobj(O)) O = new /obj/screen/text()
|
||||
O.maptext = maptext
|
||||
@@ -366,4 +373,4 @@ var/list/DummyCache = list()
|
||||
if(delay)
|
||||
spawn(delay)
|
||||
for(var/client/C in group)
|
||||
C.screen -= O
|
||||
C.screen -= O
|
||||
|
||||
@@ -956,7 +956,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
|
||||
@@ -1117,7 +1118,8 @@ proc/DuplicateObject(obj/original, var/perfectcopy = 0 , var/sameloc = 0)
|
||||
|
||||
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)
|
||||
|
||||
@@ -1142,18 +1142,21 @@ datum/mind
|
||||
|
||||
|
||||
|
||||
/mob/proc/sync_mind()
|
||||
mind_initialize() //updates the mind (or creates and initializes one if one doesn't exist)
|
||||
mind.active = 1 //indicates that the mind is currently synced with a client
|
||||
|
||||
//Initialisation procs
|
||||
/mob/living/proc/mind_initialize()
|
||||
/mob/proc/mind_initialize()
|
||||
if(mind)
|
||||
mind.key = key
|
||||
|
||||
else
|
||||
mind = new /datum/mind(key)
|
||||
mind.original = src
|
||||
if(ticker)
|
||||
ticker.minds += mind
|
||||
else
|
||||
world.log << "## DEBUG: mind_initialize(): No ticker ready yet! Please inform Carn"
|
||||
error("mind_initialize(): No ticker ready yet! Please inform Carn")
|
||||
if(!mind.name) mind.name = real_name
|
||||
mind.current = src
|
||||
|
||||
@@ -1212,6 +1215,11 @@ datum/mind
|
||||
mind.assigned_role = "pAI"
|
||||
mind.special_role = ""
|
||||
|
||||
//BLOB
|
||||
/mob/camera/overmind/mind_initialize()
|
||||
..()
|
||||
mind.special_role = "Blob"
|
||||
|
||||
//Animals
|
||||
/mob/living/simple_animal/mind_initialize()
|
||||
..()
|
||||
@@ -1240,5 +1248,3 @@ datum/mind
|
||||
mind.assigned_role = "Juggernaut"
|
||||
mind.special_role = "Cultist"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,124 +9,158 @@ 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 = 30
|
||||
|
||||
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
|
||||
var/players_per_core = 30
|
||||
var/blob_point_rate = 3
|
||||
|
||||
//Controls expansion via game controller
|
||||
var/autoexpand = 0
|
||||
var/expanding = 0
|
||||
var/blobwincount = 350
|
||||
|
||||
var/blob_count = 0
|
||||
var/blobnukecount = 300//Might be a bit low
|
||||
var/blobwincount = 700//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)
|
||||
|
||||
blobwincount = initial(blobwincount) * cores_to_spawn
|
||||
|
||||
|
||||
announce()
|
||||
world << "<B>The current game mode is - <font color='green'>Blob</font>!</B>"
|
||||
world << "<B>A dangerous alien organism is rapidly spreading throughout the station!</B>"
|
||||
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 << "<B>The current game mode is - <font color='green'>Blob</font>!</B>"
|
||||
world << "<B>A dangerous alien organism is rapidly spreading throughout the station!</B>"
|
||||
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 << "<B>\red You are infected by the Blob!</B>"
|
||||
blob.current << "<b>Your body is ready to give spawn to a new blob core which will eat this station.</b>"
|
||||
blob.current << "<b>Find a good location to spawn the core and then take control and overwhelm the station!</b>"
|
||||
blob.current << "<b>When you have found a location, wait until you spawn; this will happen automatically and you cannot speed up the process.</b>"
|
||||
blob.current << "<b>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.</b>"
|
||||
return
|
||||
|
||||
/datum/game_mode/blob/proc/show_message(var/message)
|
||||
for(var/datum/mind/blob in infected_crew)
|
||||
blob.current << message
|
||||
|
||||
/datum/game_mode/blob/proc/burst_blobs()
|
||||
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/expandBlob()//Currently disabled
|
||||
if(expanding) return
|
||||
if(!blobs.len) return
|
||||
expanding = 1
|
||||
|
||||
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()
|
||||
|
||||
expanding = 0
|
||||
return
|
||||
if(blob_client && location)
|
||||
var/obj/effect/blob/core/core = new(location, 200, blob_client, blob_point_rate)
|
||||
if(core.overmind && core.overmind.mind)
|
||||
core.overmind.mind.name = blob.name
|
||||
infected_crew -= blob
|
||||
infected_crew += core.overmind.mind
|
||||
|
||||
|
||||
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]"
|
||||
/datum/game_mode/blob/post_setup()
|
||||
|
||||
stage = -1
|
||||
// next stage 1 minute later
|
||||
spawn(600)
|
||||
stage = 1
|
||||
return
|
||||
for(var/datum/mind/blob in infected_crew)
|
||||
greet_blob(blob)
|
||||
|
||||
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
|
||||
if(emergency_shuttle)
|
||||
emergency_shuttle.always_fake_recall = 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
|
||||
/*// Disable the blob event for this round.
|
||||
if(events)
|
||||
var/datum/round_event_control/blob/B = locate() in events.control
|
||||
if(B)
|
||||
B.max_occurrences = 0 // disable the event
|
||||
else
|
||||
error("Events variable is null in blob gamemode post setup.")*/
|
||||
|
||||
spawn(10)
|
||||
start_state = new /datum/station_state()
|
||||
start_state.count()
|
||||
|
||||
spawn(0)
|
||||
|
||||
var/wait_time = rand(waittime_l, waittime_h)
|
||||
|
||||
sleep(wait_time)
|
||||
|
||||
send_intercept(0)
|
||||
|
||||
sleep(100)
|
||||
|
||||
show_message("<span class='alert'>You feel tired and bloated.</span>")
|
||||
|
||||
sleep(wait_time)
|
||||
|
||||
show_message("<span class='alert'>You feel like you are about to burst.</span>")
|
||||
|
||||
sleep(wait_time / 2)
|
||||
|
||||
burst_blobs()
|
||||
|
||||
// Stage 0
|
||||
sleep(40)
|
||||
stage(0)
|
||||
|
||||
// Stage 1
|
||||
sleep(2000)
|
||||
stage(1)
|
||||
|
||||
..()
|
||||
|
||||
/datum/game_mode/blob/proc/stage(var/stage)
|
||||
|
||||
switch(stage)
|
||||
if (0)
|
||||
send_intercept(1)
|
||||
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
|
||||
|
||||
|
||||
@@ -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 << "<FONT size = 3><B>The blob has taken over the station!</B></FONT>"
|
||||
world << "<B>The entire station was eaten by the Blob</B>"
|
||||
@@ -32,7 +22,7 @@
|
||||
world << "<FONT size = 3><B>Partial Win: The station has been destroyed!</B></FONT>"
|
||||
world << "<B>Directive 7-12 has been successfully carried out preventing the Blob from spreading.</B>"
|
||||
|
||||
else
|
||||
else if(!blob_cores.len)
|
||||
feedback_set_details("round_end_result","win - blob eliminated")
|
||||
world << "<FONT size = 3><B>The staff has won!</B></FONT>"
|
||||
world << "<B>The alien organism has been eradicated from the station</B>"
|
||||
@@ -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 = "<FONT size = 2><B>The blob[(blob_mode.infected_crew.len > 1 ? "s were" : " was")]:</B></FONT>"
|
||||
|
||||
for(var/datum/mind/blob in blob_mode.infected_crew)
|
||||
text += "<br>[blob.key] was [blob.name]"
|
||||
world << text
|
||||
return 1
|
||||
|
||||
/datum/game_mode/blob/proc/check_quarantine()
|
||||
var/numDead = 0
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
var/intercepttext = ""
|
||||
var/interceptname = "Error"
|
||||
switch(report)
|
||||
if(0)
|
||||
..()
|
||||
return
|
||||
if(1)
|
||||
interceptname = "Biohazard Alert"
|
||||
intercepttext += "<FONT size = 3><B>NanoTrasen Update</B>: Biohazard Alert.</FONT><HR>"
|
||||
|
||||
@@ -3,71 +3,87 @@
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blob_core"
|
||||
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
|
||||
var/point_rate = 2
|
||||
|
||||
|
||||
New(loc, var/h = 200)
|
||||
blobs += src
|
||||
New(loc, var/h = 200, var/client/new_overmind = null, var/new_rate = 2)
|
||||
blob_cores += src
|
||||
processing_objects.Add(src)
|
||||
if(!overmind)
|
||||
create_overmind(new_overmind)
|
||||
point_rate = new_rate
|
||||
..(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(point_rate)
|
||||
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(5))
|
||||
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
|
||||
*/
|
||||
|
||||
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
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
/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
|
||||
|
||||
@@ -26,14 +29,14 @@
|
||||
/mob/living/simple_animal/hostile/blobspore
|
||||
name = "blob"
|
||||
desc = "Some blob thing."
|
||||
icon = 'icons/mob/critter.dmi'
|
||||
icon_state = "blobsquiggle"
|
||||
icon_living = "blobsquiggle"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blobpod"
|
||||
icon_living = "blobpod"
|
||||
pass_flags = PASSBLOB
|
||||
health = 20
|
||||
maxHealth = 20
|
||||
melee_damage_lower = 4
|
||||
melee_damage_upper = 8
|
||||
health = 40
|
||||
maxHealth = 40
|
||||
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 +52,28 @@
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 360
|
||||
|
||||
fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
..()
|
||||
adjustBruteLoss(Clamp(0.01 * exposed_temperature, 1, 5))
|
||||
|
||||
blob_act()
|
||||
return
|
||||
|
||||
CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
if(istype(mover, /obj/effect/blob))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
New(loc, var/obj/effect/blob/factory/linked_node)
|
||||
..()
|
||||
if(istype(linked_node))
|
||||
factory = linked_node
|
||||
factory.spores += src
|
||||
..(loc)
|
||||
return
|
||||
Die()
|
||||
..()
|
||||
|
||||
Die()
|
||||
del(src)
|
||||
|
||||
Del()
|
||||
if(factory)
|
||||
factory.spores -= src
|
||||
..()
|
||||
del(src)
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blob_node"
|
||||
health = 100
|
||||
brute_resist = 1
|
||||
fire_resist = 2
|
||||
|
||||
|
||||
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 +20,18 @@
|
||||
..()
|
||||
return
|
||||
|
||||
Life()
|
||||
for(var/i = 1; i < 8; i += i)
|
||||
Pulse(5, i)
|
||||
health = min(initial(health), health + 1)
|
||||
|
||||
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
|
||||
26
code/game/gamemodes/blob/blobs/resource.dm
Normal file
26
code/game/gamemodes/blob/blobs/resource.dm
Normal file
@@ -0,0 +1,26 @@
|
||||
/obj/effect/blob/resource
|
||||
name = "resource blob"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blob_resource"
|
||||
health = 30
|
||||
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 + 40 // 4 seconds
|
||||
|
||||
if(overmind)
|
||||
overmind.add_points(1)
|
||||
return 1
|
||||
|
||||
@@ -3,21 +3,19 @@
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blob_idle"
|
||||
desc = "Some blob creature thingy"
|
||||
density = 1
|
||||
opacity = 0
|
||||
anchored = 1
|
||||
health = 100
|
||||
brute_resist = 1
|
||||
health = 75
|
||||
fire_resist = 2
|
||||
|
||||
|
||||
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
|
||||
|
||||
17
code/game/gamemodes/blob/hud.dm
Normal file
17
code/game/gamemodes/blob/hud.dm
Normal file
@@ -0,0 +1,17 @@
|
||||
/datum/hud/proc/blob_hud(ui_style = 'icons/mob/screen_midnight.dmi')
|
||||
|
||||
blobpwrdisplay = new /obj/screen()
|
||||
blobpwrdisplay.name = "blob power"
|
||||
blobpwrdisplay.icon_state = "block"
|
||||
blobpwrdisplay.screen_loc = ui_health
|
||||
blobpwrdisplay.layer = 20
|
||||
|
||||
blobhealthdisplay = new /obj/screen()
|
||||
blobhealthdisplay.name = "blob health"
|
||||
blobhealthdisplay.icon_state = "block"
|
||||
blobhealthdisplay.screen_loc = ui_internal
|
||||
blobhealthdisplay.layer = 20
|
||||
|
||||
mymob.client.screen = null
|
||||
|
||||
mymob.client.screen += list(blobpwrdisplay, blobhealthdisplay)
|
||||
66
code/game/gamemodes/blob/overmind.dm
Normal file
66
code/game/gamemodes/blob/overmind.dm
Normal file
@@ -0,0 +1,66 @@
|
||||
/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_MINIMUM
|
||||
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/Login()
|
||||
..()
|
||||
sync_mind()
|
||||
|
||||
src << "<span class='notice'>You are the overmind!</span>"
|
||||
src << "You are the overmind and can control the blob by placing new blob pieces such as..."
|
||||
src << "<b>Normal Blob</b> will expand your reach and allow you to upgrade into special blobs that perform certain functions."
|
||||
src << "<b>Shield Blob</b> 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."
|
||||
src << "<b>Resource Blob</b> 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."
|
||||
src << "<b>Node Blob</b> 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."
|
||||
src << "<b>Factory Blob</b> 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."
|
||||
|
||||
|
||||
mob/camera/blob/Life()
|
||||
//hud_used.blobpwrdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'> <font color='#82ed00'>[src.blob_points]</font></div>"
|
||||
//hud_used.blobhealthdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'> <font color='#e36600'>[blob_core.health]</font></div>"
|
||||
return
|
||||
|
||||
/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
|
||||
231
code/game/gamemodes/blob/powers.dm
Normal file
231
code/game/gamemodes/blob/powers.dm
Normal file
@@ -0,0 +1,231 @@
|
||||
// Point controlling procs
|
||||
|
||||
/mob/camera/blob/proc/can_buy(var/cost = 15)
|
||||
if(blob_points < cost)
|
||||
src << "<span class='warning'>You cannot afford this.</span>"
|
||||
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 = "Jump 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 a selected node."
|
||||
|
||||
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(4))
|
||||
src << "There is a resource blob nearby, move more than 4 tiles away from it!"
|
||||
return
|
||||
|
||||
if(!can_buy(40))
|
||||
return
|
||||
|
||||
|
||||
B.change_to(/obj/effect/blob/resource)
|
||||
var/obj/effect/blob/resource/R = locate() in T
|
||||
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(5))
|
||||
src << "There is another node nearby, move more than 5 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(7))
|
||||
src << "There is a factory blob nearby, move more than 7 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"
|
||||
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
|
||||
@@ -2,32 +2,23 @@
|
||||
/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)
|
||||
for(var/atom/A in loc)
|
||||
A.blob_act()
|
||||
return
|
||||
|
||||
|
||||
@@ -44,22 +35,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 +80,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) && prob(75)) return
|
||||
if(!T)
|
||||
var/list/dirs = list(1,2,4,8)
|
||||
for(var/i = 1 to 4)
|
||||
@@ -105,47 +93,29 @@
|
||||
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
|
||||
|
||||
|
||||
ex_act(severity)
|
||||
var/damage = 50
|
||||
switch(severity)
|
||||
if(1)
|
||||
src.health -= rand(100,120)
|
||||
if(2)
|
||||
src.health -= rand(60,100)
|
||||
if(3)
|
||||
src.health -= rand(20,60)
|
||||
|
||||
health -= (damage/brute_resist)
|
||||
var/damage = 150
|
||||
health -= ((damage/brute_resist) - (severity * 5))
|
||||
update_icon()
|
||||
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)
|
||||
if(!Proj) return
|
||||
..()
|
||||
switch(Proj.damage_type)
|
||||
if(BRUTE)
|
||||
health -= (Proj.damage/brute_resist)
|
||||
@@ -172,50 +142,30 @@
|
||||
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
|
||||
health = 21
|
||||
|
||||
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"
|
||||
if(health <= 15)
|
||||
icon_state = "blob_damaged"
|
||||
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()
|
||||
..()
|
||||
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
return
|
||||
|
||||
/obj/machinery/camera/blob_act()
|
||||
del(src)
|
||||
return
|
||||
|
||||
/obj/machinery/camera/proc/setViewRange(var/num = 7)
|
||||
|
||||
@@ -443,10 +443,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)
|
||||
@@ -485,7 +481,7 @@
|
||||
//New version pretends to call the shuttle but cause the shuttle to return after a random duration.
|
||||
emergency_shuttle.fake_recall = rand(300,500)
|
||||
|
||||
if(ticker.mode.name == "blob" || ticker.mode.name == "epidemic")
|
||||
if(ticker.mode.name == "epidemic")
|
||||
user << "Under directive 7-10, [station_name()] is quarantined until further notice."
|
||||
return
|
||||
|
||||
@@ -500,7 +496,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 centcomm
|
||||
|
||||
@@ -262,6 +262,7 @@
|
||||
if(istype(south)) air_master.tiles_to_update += south
|
||||
if(istype(east)) air_master.tiles_to_update += east
|
||||
if(istype(west)) air_master.tiles_to_update += west
|
||||
update_freelok_sight()
|
||||
return 1
|
||||
|
||||
/obj/machinery/door/proc/update_heat_protection(var/turf/simulated/source)
|
||||
|
||||
@@ -610,6 +610,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
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
return
|
||||
|
||||
/obj/item/blob_act()
|
||||
return
|
||||
del(src)
|
||||
|
||||
//user: The mob that is suiciding
|
||||
//damagetype: The type of damage the item will inflict on the user
|
||||
|
||||
@@ -51,10 +51,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)
|
||||
|
||||
@@ -581,7 +581,6 @@ var/global/floorIsLava = 0
|
||||
<A href='?src=\ref[src];secretsfun=moveminingshuttle'>Move Mining Shuttle</A><BR>
|
||||
<A href='?src=\ref[src];secretsfun=blackout'>Break all lights</A><BR>
|
||||
<A href='?src=\ref[src];secretsfun=whiteout'>Fix all lights</A><BR>
|
||||
<A href='?src=\ref[src];secretsfun=friendai'>Best Friend AI</A><BR>
|
||||
<A href='?src=\ref[src];secretsfun=floorlava'>The floor is lava! (DANGEROUS: extremely lame)</A><BR>
|
||||
"}
|
||||
|
||||
@@ -1116,4 +1115,4 @@ proc/formatLocation(var/location)
|
||||
return "[A.name] - [loc.x],[loc.y],[loc.z]"
|
||||
|
||||
proc/formatPlayerPanel(var/mob/U,var/text="PP")
|
||||
return "<A HREF='?_src_=holder;adminplayeropts=\ref[U]'>[text]</A>"
|
||||
return "<A HREF='?_src_=holder;adminplayeropts=\ref[U]'>[text]</A>"
|
||||
|
||||
@@ -499,6 +499,20 @@
|
||||
dat += "<tr><td><i>Traitor not found!</i></td></tr>"
|
||||
dat += "</table>"
|
||||
|
||||
if(istype(ticker.mode, /datum/game_mode/blob))
|
||||
var/datum/game_mode/blob/mode = ticker.mode
|
||||
dat += "<br><table cellspacing=5><tr><td><B>Blob</B></td><td></td><td></td></tr>"
|
||||
dat += "<tr><td><i>Progress: [blobs.len]/[mode.blobwincount]</i></td></tr>"
|
||||
|
||||
for(var/datum/mind/blob in mode.infected_crew)
|
||||
var/mob/M = blob.current
|
||||
if(M)
|
||||
dat += "<tr><td><a href='?_src_=holder;adminplayeropts=\ref[M]'>[M.real_name]</a>[M.client ? "" : " <i>(logged out)</i>"][M.stat == 2 ? " <b><font color=red>(DEAD)</font></b>" : ""]</td>"
|
||||
dat += "<td><A href='?priv_msg=[M.ckey]'>PM</A></td>"
|
||||
else
|
||||
dat += "<tr><td><i>Blob not found!</i></td></tr>"
|
||||
dat += "</table>"
|
||||
|
||||
dat += "</body></html>"
|
||||
usr << browse(dat, "window=roundstatus;size=400x500")
|
||||
else
|
||||
|
||||
@@ -202,10 +202,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")
|
||||
if ((!( ticker ) || emergency_shuttle.location))
|
||||
@@ -1960,19 +1956,6 @@
|
||||
for(var/obj/machinery/light/L in world)
|
||||
L.fix()
|
||||
message_admins("[key_name_admin(usr)] fixed all lights", 1)
|
||||
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("aliens")
|
||||
feedback_inc("admin_secrets_fun_used",1)
|
||||
feedback_add_details("admin_secrets_fun_used","AL")
|
||||
|
||||
11
code/modules/mob/camera/camera.dm
Normal file
11
code/modules/mob/camera/camera.dm
Normal file
@@ -0,0 +1,11 @@
|
||||
// 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
|
||||
@@ -1,259 +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"
|
||||
use_me = 0 //Blobs can't emote
|
||||
|
||||
|
||||
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 << "<B>You are now a blob fragment.</B>"
|
||||
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)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@
|
||||
show_message("\red The blob attacks you!")
|
||||
var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg")
|
||||
var/datum/organ/external/affecting = get_organ(ran_zone(dam_zone))
|
||||
apply_damage(rand(30,40), BRUTE, affecting, run_armor_check(affecting, "melee"))
|
||||
apply_damage(rand(20,30), BRUTE, affecting, run_armor_check(affecting, "melee"))
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/meteorhit(O as obj)
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
/mob/living/Login()
|
||||
..()
|
||||
//Mind updates
|
||||
mind_initialize() //updates the mind (or creates and initializes one if one doesn't exist)
|
||||
mind.active = 1 //indicates that the mind is currently synced with a client
|
||||
sync_mind()
|
||||
|
||||
//Round specific stuff like hud updates
|
||||
if(ticker && ticker.mode)
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
//
|
||||
// The datum containing all the chunks.
|
||||
|
||||
var/const/CHUNK_SIZE = 16 // Only chunk sizes that are to the power of 2. E.g: 2, 4, 8, 16, etc..
|
||||
|
||||
var/datum/cameranet/cameranet = new()
|
||||
|
||||
/datum/cameranet
|
||||
@@ -13,16 +15,16 @@ var/datum/cameranet/cameranet = new()
|
||||
|
||||
// Checks if a chunk has been Generated in x, y, z.
|
||||
/datum/cameranet/proc/chunkGenerated(x, y, z)
|
||||
x &= ~0xf
|
||||
y &= ~0xf
|
||||
x &= ~(CHUNK_SIZE - 1)
|
||||
y &= ~(CHUNK_SIZE - 1)
|
||||
var/key = "[x],[y],[z]"
|
||||
return (chunks[key])
|
||||
|
||||
// Returns the chunk in the x, y, z.
|
||||
// If there is no chunk, it creates a new chunk and returns that.
|
||||
/datum/cameranet/proc/getCameraChunk(x, y, z)
|
||||
x &= ~0xf
|
||||
y &= ~0xf
|
||||
x &= ~(CHUNK_SIZE - 1)
|
||||
y &= ~(CHUNK_SIZE - 1)
|
||||
var/key = "[x],[y],[z]"
|
||||
if(!chunks[key])
|
||||
chunks[key] = new /datum/camerachunk(null, x, y, z)
|
||||
@@ -31,18 +33,18 @@ 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) & ~0xf
|
||||
var/y1 = max(0, ai.y - 16) & ~0xf
|
||||
var/x2 = min(world.maxx, ai.x + 16) & ~0xf
|
||||
var/y2 = min(world.maxy, ai.y + 16) & ~0xf
|
||||
var/x1 = max(0, ai.x - 16) & ~(CHUNK_SIZE - 1)
|
||||
var/y1 = max(0, ai.y - 16) & ~(CHUNK_SIZE - 1)
|
||||
var/x2 = min(world.maxx, ai.x + 16) & ~(CHUNK_SIZE - 1)
|
||||
var/y2 = min(world.maxy, ai.y + 16) & ~(CHUNK_SIZE - 1)
|
||||
|
||||
var/list/visibleChunks = list()
|
||||
|
||||
for(var/x = x1; x <= x2; x += 16)
|
||||
for(var/y = y1; y <= y2; y += 16)
|
||||
visibleChunks += getCameraChunk(x, y, ai.z)
|
||||
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
|
||||
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
|
||||
visibleChunks |= getCameraChunk(x, y, ai.z)
|
||||
|
||||
var/list/remove = ai.visibleCameraChunks - visibleChunks
|
||||
var/list/add = visibleChunks - ai.visibleCameraChunks
|
||||
@@ -103,15 +105,15 @@ var/datum/cameranet/cameranet = new()
|
||||
|
||||
var/turf/T = get_turf(c)
|
||||
if(T)
|
||||
var/x1 = max(0, T.x - 8) & ~0xf
|
||||
var/y1 = max(0, T.y - 8) & ~0xf
|
||||
var/x2 = min(world.maxx, T.x + 8) & ~0xf
|
||||
var/y2 = min(world.maxy, T.y + 8) & ~0xf
|
||||
var/x1 = max(0, T.x - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
|
||||
var/y1 = max(0, T.y - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
|
||||
var/x2 = min(world.maxx, T.x + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
|
||||
var/y2 = min(world.maxy, T.y + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
|
||||
|
||||
//world << "X1: [x1] - Y1: [y1] - X2: [x2] - Y2: [y2]"
|
||||
|
||||
for(var/x = x1; x <= x2; x += 16)
|
||||
for(var/y = y1; y <= y2; y += 16)
|
||||
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
|
||||
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
|
||||
if(chunkGenerated(x, y, T.z))
|
||||
var/datum/camerachunk/chunk = getCameraChunk(x, y, T.z)
|
||||
if(choice == 0)
|
||||
|
||||
@@ -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
|
||||
@@ -81,11 +81,14 @@
|
||||
if(!c.can_use())
|
||||
continue
|
||||
|
||||
var/turf/point = locate(src.x + 8, src.y + 8, src.z)
|
||||
if(get_dist(point, c) > 24)
|
||||
var/turf/point = locate(src.x + (CHUNK_SIZE / 2), src.y + (CHUNK_SIZE / 2), src.z)
|
||||
if(get_dist(point, c) > CHUNK_SIZE + (CHUNK_SIZE / 2))
|
||||
continue
|
||||
|
||||
for(var/turf/t in c.can_see())
|
||||
// Possible optimization: if(turfs[t]) here, rather than &= turfs afterwards.
|
||||
// List associations use a tree or hashmap of some sort (alongside the list itself)
|
||||
// so are surprisingly fast. (significantly faster than var/thingy/x in list, in testing)
|
||||
newVisibleTurfs[t] = t
|
||||
|
||||
// Removes turf that isn't in turfs.
|
||||
@@ -102,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)
|
||||
@@ -116,32 +119,33 @@
|
||||
|
||||
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
|
||||
if(m.ai.client)
|
||||
m.ai.client.images += t.obscured
|
||||
|
||||
changed = 0
|
||||
|
||||
// Create a new camera chunk, since the chunks are made as they are needed.
|
||||
|
||||
/datum/camerachunk/New(loc, x, y, z)
|
||||
|
||||
// 0xf = 15
|
||||
x &= ~0xf
|
||||
y &= ~0xf
|
||||
x &= ~(CHUNK_SIZE - 1)
|
||||
y &= ~(CHUNK_SIZE - 1)
|
||||
|
||||
src.x = x
|
||||
src.y = y
|
||||
src.z = z
|
||||
|
||||
for(var/obj/machinery/camera/c in range(16, locate(x + 8, y + 8, z)))
|
||||
for(var/obj/machinery/camera/c in range(CHUNK_SIZE, locate(x + (CHUNK_SIZE / 2), y + (CHUNK_SIZE / 2), z)))
|
||||
if(c.can_use())
|
||||
cameras += c
|
||||
|
||||
for(var/turf/t in range(10, locate(x + 8, y + 8, z)))
|
||||
if(t.x >= x && t.y >= y && t.x < x + 16 && t.y < y + 16)
|
||||
turfs[t] = t
|
||||
for(var/turf/t in block(locate(x, y, z), locate(min(x + CHUNK_SIZE - 1, world.maxx), min(y + CHUNK_SIZE - 1, world.maxy), z)))
|
||||
turfs[t] = t
|
||||
|
||||
for(var/camera in cameras)
|
||||
var/obj/machinery/camera/c = camera
|
||||
@@ -152,6 +156,9 @@
|
||||
continue
|
||||
|
||||
for(var/turf/t in c.can_see())
|
||||
// Possible optimization: if(turfs[t]) here, rather than &= turfs afterwards.
|
||||
// List associations use a tree or hashmap of some sort (alongside the list itself)
|
||||
// so are surprisingly fast. (significantly faster than var/thingy/x in list, in testing)
|
||||
visibleTurfs[t] = t
|
||||
|
||||
// Removes turf that isn't in turfs.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -49,8 +49,7 @@
|
||||
// DOORS
|
||||
|
||||
// Simply updates the visibility of the area when it opens/closes/destroyed.
|
||||
/obj/machinery/door/update_nearby_tiles(need_rebuild)
|
||||
. = ..(need_rebuild)
|
||||
/obj/machinery/door/proc/update_freelok_sight()
|
||||
// Glass door glass = 1
|
||||
// don't check then?
|
||||
if(!glass && cameranet)
|
||||
|
||||
@@ -298,6 +298,9 @@
|
||||
adjustBruteLoss(60)
|
||||
updatehealth()
|
||||
return 1
|
||||
else
|
||||
gib()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
// this function shows information about the malf_ai gameplay type in the status screen
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
turns_per_move = 5
|
||||
see_in_dark = 6
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/bearmeat
|
||||
response_help = "pets the"
|
||||
response_disarm = "gently pushes aside the"
|
||||
response_harm = "pokes the"
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "hits"
|
||||
stop_automated_movement_when_pulled = 0
|
||||
maxHealth = 60
|
||||
health = 60
|
||||
@@ -43,25 +43,28 @@
|
||||
desc = ""
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "pokes"
|
||||
response_harm = "hits"
|
||||
|
||||
/mob/living/simple_animal/hostile/bear/Move()
|
||||
..()
|
||||
if(stat != DEAD)
|
||||
if(loc && istype(loc,/turf/space))
|
||||
icon_state = "bear"
|
||||
else
|
||||
icon_state = "bearfloor"
|
||||
|
||||
/mob/living/simple_animal/hostile/bear/Life()
|
||||
. =..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(loc && istype(loc,/turf/space))
|
||||
icon_state = "bear"
|
||||
else
|
||||
icon_state = "bearfloor"
|
||||
|
||||
switch(stance)
|
||||
|
||||
if(HOSTILE_STANCE_TIRED)
|
||||
stop_automated_movement = 1
|
||||
stance_step++
|
||||
if(stance_step >= 10) //rests for 10 ticks
|
||||
if(target_mob && target_mob in ListTargets(10))
|
||||
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
|
||||
@@ -69,15 +72,15 @@
|
||||
if(HOSTILE_STANCE_ALERT)
|
||||
stop_automated_movement = 1
|
||||
var/found_mob = 0
|
||||
if(target_mob && target_mob in ListTargets(10))
|
||||
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)
|
||||
@@ -102,18 +105,18 @@
|
||||
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)
|
||||
return //No drifting in space for space bears!
|
||||
return 1 //No drifting in space for space bears!
|
||||
|
||||
/mob/living/simple_animal/hostile/bear/FindTarget()
|
||||
. = ..()
|
||||
@@ -125,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/organ/external/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
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
max_n2 = 0
|
||||
minbodytemp = 0
|
||||
|
||||
break_stuff_probability = 2
|
||||
//break_stuff_probability = 2
|
||||
|
||||
faction = "carp"
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
turns_per_move = 5
|
||||
see_in_dark = 10
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/bearmeat
|
||||
response_help = "pets the"
|
||||
response_disarm = "gently pushes aside the"
|
||||
response_harm = "pokes the"
|
||||
response_help = "pets"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "hits"
|
||||
stop_automated_movement_when_pulled = 0
|
||||
maxHealth = 200
|
||||
health = 200
|
||||
@@ -33,7 +33,6 @@
|
||||
var/busy = 0
|
||||
pass_flags = PASSTABLE
|
||||
move_to_delay = 6
|
||||
speed = 3
|
||||
|
||||
//nursemaids - these create webs and eggs
|
||||
/mob/living/simple_animal/hostile/giant_spider/nurse
|
||||
@@ -65,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))
|
||||
@@ -83,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)
|
||||
@@ -105,10 +104,10 @@
|
||||
if(!busy && prob(30))
|
||||
//first, check for potential food nearby to cocoon
|
||||
for(var/mob/living/C in can_see)
|
||||
if(C.stat)
|
||||
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
|
||||
@@ -150,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)
|
||||
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
/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
|
||||
var/projectiletype
|
||||
var/projectilesound
|
||||
var/casingtype
|
||||
var/move_to_delay = 4 //delay for the automated movement.
|
||||
var/move_to_delay = 2 //delay for the automated movement.
|
||||
var/list/friends = list()
|
||||
var/break_stuff_probability = 10
|
||||
var/vision_range = 10
|
||||
stop_automated_movement_when_pulled = 0
|
||||
var/destroy_surroundings = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/FindTarget()
|
||||
|
||||
var/atom/T = null
|
||||
stop_automated_movement = 0
|
||||
for(var/atom/A in ListTargets(10))
|
||||
|
||||
if(A == src)
|
||||
continue
|
||||
for(var/atom/A in ListTargets())
|
||||
|
||||
var/atom/F = Found(A)
|
||||
if(F)
|
||||
@@ -36,72 +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
|
||||
|
||||
if(istype(A, /obj/machinery/bot))
|
||||
var/obj/machinery/bot/B = A
|
||||
if (B.health > 0)
|
||||
stance = HOSTILE_STANCE_ATTACK
|
||||
T = B
|
||||
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(10))
|
||||
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(10)))
|
||||
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
|
||||
if(istype(target_mob,/obj/machinery/bot))
|
||||
var/obj/machinery/bot/B = target_mob
|
||||
B.attack_animal(src)
|
||||
|
||||
/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()
|
||||
@@ -109,9 +101,17 @@
|
||||
walk(src, 0)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/ListTargets(var/dist = 7)
|
||||
var/list/L = hearers(src, dist)
|
||||
L += mechas_list
|
||||
/mob/living/simple_animal/hostile/proc/ListTargets(var/override = -1)
|
||||
|
||||
// Allows you to override how much the mob can see. Defaults to vision_range if none is entered.
|
||||
if(override == -1)
|
||||
override = vision_range
|
||||
|
||||
var/list/L = hearers(src, override)
|
||||
for(var/obj/mecha/M in mechas_list)
|
||||
// Will check the distance before checking the line of sight, if the distance is small enough.
|
||||
if(get_dist(M, src) <= override && can_see(src, M, override))
|
||||
L += M
|
||||
return L
|
||||
|
||||
/mob/living/simple_animal/hostile/Die()
|
||||
@@ -130,20 +130,19 @@
|
||||
if(!stat)
|
||||
switch(stance)
|
||||
if(HOSTILE_STANCE_IDLE)
|
||||
target_mob = FindTarget()
|
||||
var/new_target = FindTarget()
|
||||
GiveTarget(new_target)
|
||||
|
||||
if(HOSTILE_STANCE_ATTACK)
|
||||
if(destroy_surroundings)
|
||||
DestroySurroundings()
|
||||
DestroySurroundings()
|
||||
MoveToTarget()
|
||||
|
||||
if(HOSTILE_STANCE_ATTACKING)
|
||||
if(destroy_surroundings)
|
||||
DestroySurroundings()
|
||||
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 <b>[src]</b> fires at [target]!", 1)
|
||||
|
||||
var/tturf = get_turf(target)
|
||||
@@ -166,7 +165,7 @@
|
||||
new casingtype
|
||||
|
||||
stance = HOSTILE_STANCE_IDLE
|
||||
target_mob = null
|
||||
target = null
|
||||
return
|
||||
|
||||
|
||||
@@ -189,8 +188,7 @@
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/DestroySurroundings()
|
||||
if(prob(break_stuff_probability))
|
||||
for(var/dir in cardinal) // North, South, East, West
|
||||
var/obj/structure/obstacle = locate(/obj/structure, get_step(src, dir))
|
||||
if(istype(obstacle, /obj/structure/window) || istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table) || istype(obstacle, /obj/structure/grille))
|
||||
obstacle.attack_animal(src)
|
||||
for(var/dir in cardinal) // North, South, East, West
|
||||
var/obj/structure/obstacle = locate(/obj/structure, get_step(src, dir))
|
||||
if(istype(obstacle, /obj/structure/window) || istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table) || istype(obstacle, /obj/structure/grille))
|
||||
obstacle.attack_animal(src)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
speed = 8
|
||||
projectiletype = /obj/item/projectile/beam/drone
|
||||
projectilesound = 'sound/weapons/laser3.ogg'
|
||||
destroy_surroundings = 0
|
||||
//destroy_surroundings = 0
|
||||
var/datum/effect/effect/system/ion_trail_follow/ion_trail
|
||||
|
||||
//the drone randomly switches between these states because it's malfunctioning
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
icon = 'icons/mob/animal.dmi'
|
||||
health = 20
|
||||
maxHealth = 20
|
||||
immune_to_ssd = 1
|
||||
|
||||
var/icon_living = ""
|
||||
var/icon_dead = ""
|
||||
var/icon_gib = null //We only try to show a gibbing animation if this exists.
|
||||
@@ -24,9 +24,9 @@
|
||||
var/stop_automated_movement_when_pulled = 1 //When set to 1 this stops the animal from moving when someone is pulling it.
|
||||
|
||||
//Interaction
|
||||
var/response_help = "You try to help"
|
||||
var/response_disarm = "You try to disarm"
|
||||
var/response_harm = "You try to hurt"
|
||||
var/response_help = "pokes"
|
||||
var/response_disarm = "shoves"
|
||||
var/response_harm = "hits"
|
||||
var/harm_intent_damage = 3
|
||||
|
||||
//Temperature effect
|
||||
@@ -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)
|
||||
@@ -224,10 +229,14 @@
|
||||
return "[emote], \"[text]\""
|
||||
return "says, \"[text]\"";
|
||||
|
||||
/mob/living/simple_animal/emote(var/act, var/type, var/desc)
|
||||
/mob/living/simple_animal/emote(var/act)
|
||||
if(stat)
|
||||
return
|
||||
if(act)
|
||||
if(act == "scream") act = "whimper" //ugly hack to stop animals screaming when crushed :P
|
||||
..(act, type, desc)
|
||||
if(act == "scream") act = "makes a loud and pained whimper" //ugly hack to stop animals screaming when crushed :P
|
||||
for (var/mob/O in viewers(src, null))
|
||||
O.show_message("<B>[src]</B> [act].")
|
||||
|
||||
|
||||
/mob/living/simple_animal/attack_animal(mob/living/simple_animal/M as mob)
|
||||
if(M.melee_damage_upper == 0)
|
||||
@@ -236,7 +245,7 @@
|
||||
if(M.attack_sound)
|
||||
playsound(loc, M.attack_sound, 50, 1, 1)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message("\red <B>[M]</B> [M.attacktext] [src]!", 1)
|
||||
O.show_message("\red <B>\The [M]</B> [M.attacktext] [src]!", 1)
|
||||
M.attack_log += text("\[[time_stamp()]\] <font color='red'>attacked [src.name] ([src.ckey])</font>")
|
||||
src.attack_log += text("\[[time_stamp()]\] <font color='orange'>was attacked by [M.name] ([M.ckey])</font>")
|
||||
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
|
||||
@@ -256,15 +265,15 @@
|
||||
if (health > 0)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
if ((O.client && !( O.blinded )))
|
||||
O.show_message("\blue [M] [response_help] [src]")
|
||||
O.show_message("\blue [M] [response_help] [src].")
|
||||
|
||||
if("grab")
|
||||
if (M == src)
|
||||
if (M == src || anchored)
|
||||
return
|
||||
if (!(status_flags & CANPUSH))
|
||||
return
|
||||
|
||||
var/obj/item/weapon/grab/G = new /obj/item/weapon/grab( M, M, src )
|
||||
var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src )
|
||||
|
||||
M.put_in_active_hand(G)
|
||||
|
||||
@@ -277,11 +286,11 @@
|
||||
if ((O.client && !( O.blinded )))
|
||||
O.show_message(text("\red [] has grabbed [] passively!", M, src), 1)
|
||||
|
||||
if("hurt", "disarm")
|
||||
if("harm", "disarm")
|
||||
adjustBruteLoss(harm_intent_damage)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
if ((O.client && !( O.blinded )))
|
||||
O.show_message("\red [M] [response_harm] [src]")
|
||||
O.show_message("\red [M] [response_harm] [src]!")
|
||||
|
||||
return
|
||||
|
||||
@@ -295,12 +304,12 @@
|
||||
if ((O.client && !( O.blinded )))
|
||||
O.show_message(text("\blue [M] caresses [src] with its scythe like arm."), 1)
|
||||
if ("grab")
|
||||
if(M == src)
|
||||
if(M == src || anchored)
|
||||
return
|
||||
if(!(status_flags & CANPUSH))
|
||||
return
|
||||
|
||||
var/obj/item/weapon/grab/G = new /obj/item/weapon/grab( M, M, src )
|
||||
var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src )
|
||||
|
||||
M.put_in_active_hand(G)
|
||||
|
||||
@@ -313,7 +322,7 @@
|
||||
if ((O.client && !( O.blinded )))
|
||||
O.show_message(text("\red [] has grabbed [] passively!", M, src), 1)
|
||||
|
||||
if("hurt", "disarm")
|
||||
if("harm", "disarm")
|
||||
var/damage = rand(15, 30)
|
||||
visible_message("\red <B>[M] has slashed at [src]!</B>")
|
||||
adjustBruteLoss(damage)
|
||||
@@ -344,7 +353,7 @@
|
||||
|
||||
if(M.Victim) return // can't attack while eating!
|
||||
|
||||
visible_message("\red <B>The [M.name] glomps [src]!</B>")
|
||||
visible_message("\red <B>[M.name] glomps [src]!</B>")
|
||||
|
||||
var/damage = rand(1, 3)
|
||||
|
||||
@@ -366,22 +375,32 @@
|
||||
var/obj/item/stack/medical/MED = O
|
||||
if(health < maxHealth)
|
||||
if(MED.amount >= 1)
|
||||
adjustBruteLoss(-MED.heal_brute)
|
||||
MED.amount -= 1
|
||||
if(MED.amount <= 0)
|
||||
del(MED)
|
||||
for(var/mob/M in viewers(src, null))
|
||||
if ((M.client && !( M.blinded )))
|
||||
M.show_message("\blue [user] applies the [MED] on [src]")
|
||||
if(MED.heal_brute >= 1)
|
||||
adjustBruteLoss(-MED.heal_brute)
|
||||
MED.amount -= 1
|
||||
if(MED.amount <= 0)
|
||||
del(MED)
|
||||
for(var/mob/M in viewers(src, null))
|
||||
if ((M.client && !( M.blinded )))
|
||||
M.show_message("\blue [user] applies [MED] on [src]")
|
||||
return
|
||||
else
|
||||
user << "\blue [MED] won't help at all."
|
||||
return
|
||||
else
|
||||
user << "\blue [src] is at full health."
|
||||
return
|
||||
else
|
||||
user << "\blue this [src] is dead, medical items won't bring it back to life."
|
||||
if(meat_type && (stat == DEAD)) //if the animal has a meat, and if it is dead.
|
||||
user << "\blue [src] is dead, medical items won't bring it back to life."
|
||||
return
|
||||
else if(meat_type && (stat == DEAD)) //if the animal has a meat, and if it is dead.
|
||||
if(istype(O, /obj/item/weapon/kitchenknife) || istype(O, /obj/item/weapon/butch))
|
||||
new meat_type (get_turf(src))
|
||||
if(prob(95))
|
||||
del(src)
|
||||
return
|
||||
gib()
|
||||
return
|
||||
else
|
||||
if(O.force)
|
||||
var/damage = O.force
|
||||
@@ -390,12 +409,12 @@
|
||||
adjustBruteLoss(damage)
|
||||
for(var/mob/M in viewers(src, null))
|
||||
if ((M.client && !( M.blinded )))
|
||||
M.show_message("\red \b [src] has been attacked with the [O] by [user]. ")
|
||||
M.show_message("\red \b "+"[src] has been attacked with [O] by [user]. ")
|
||||
else
|
||||
usr << "\red This weapon is ineffective, it does no damage."
|
||||
for(var/mob/M in viewers(src, null))
|
||||
if ((M.client && !( M.blinded )))
|
||||
M.show_message("\red [user] gently taps [src] with the [O]. ")
|
||||
M.show_message("\red [user] gently taps [src] with [O]. ")
|
||||
|
||||
|
||||
|
||||
@@ -438,26 +457,16 @@
|
||||
|
||||
/mob/living/simple_animal/adjustBruteLoss(damage)
|
||||
health = Clamp(health - damage, 0, maxHealth)
|
||||
if(health < 1)
|
||||
Die()
|
||||
|
||||
/mob/living/simple_animal/proc/SA_attackable(target_mob)
|
||||
if (isliving(target_mob))
|
||||
var/mob/living/L = target_mob
|
||||
if(!L.stat && L.health >= 0)
|
||||
return (0)
|
||||
if (istype(target_mob,/obj/mecha))
|
||||
var/obj/mecha/M = 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,/obj/mecha))
|
||||
var/obj/mecha/M = target
|
||||
if (M.occupant)
|
||||
return (0)
|
||||
if (istype(target_mob,/obj/machinery/bot))
|
||||
var/obj/machinery/bot/B = target_mob
|
||||
if(B.health > 0)
|
||||
return (0)
|
||||
return (1)
|
||||
|
||||
//Call when target overlay should be added/removed
|
||||
/mob/living/simple_animal/update_targeted()
|
||||
if(!targeted_by && target_locked)
|
||||
del(target_locked)
|
||||
overlays = null
|
||||
if (targeted_by && target_locked)
|
||||
overlays += target_locked
|
||||
return 0
|
||||
return 1
|
||||
|
||||
@@ -156,7 +156,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.
|
||||
|
||||
//Generic list for proc holders. Only way I can see to enable certain verbs/procs. Should be modified if needed.
|
||||
var/proc_holder_list[] = list()//Right now unused.
|
||||
|
||||
@@ -226,12 +226,14 @@
|
||||
|
||||
if(mob.control_object) Move_object(direct)
|
||||
|
||||
if(isobserver(mob)) return mob.Move(n,direct)
|
||||
if(world.time < move_delay) return
|
||||
|
||||
if(isAI(mob)) return AIMove(n,direct,mob)
|
||||
|
||||
if(!isliving(mob)) return mob.Move(n,direct)
|
||||
|
||||
if(moving) return 0
|
||||
|
||||
if(world.time < move_delay) return
|
||||
|
||||
if(!mob) return
|
||||
|
||||
if(locate(/obj/effect/stop/, mob.loc))
|
||||
@@ -241,8 +243,6 @@
|
||||
|
||||
if(mob.stat==2) return
|
||||
|
||||
if(isAI(mob)) return AIMove(n,direct,mob)
|
||||
|
||||
if(mob.monkeyizing) return//This is sota the goto stop mobs from moving var
|
||||
|
||||
if(isliving(mob))
|
||||
|
||||
@@ -147,8 +147,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)
|
||||
|
||||
@@ -78,11 +78,6 @@ proc/move_research_shuttle()
|
||||
usr.machine = src
|
||||
src.add_fingerprint(usr)
|
||||
if(href_list["move"])
|
||||
if(ticker.mode.name == "blob")
|
||||
if(ticker.mode:declared)
|
||||
usr << "Under directive 7-10, [station_name()] is quarantined until further notice."
|
||||
return
|
||||
|
||||
if (!research_shuttle_moving)
|
||||
usr << "\blue Shuttle recieved message and will be sent shortly."
|
||||
move_research_shuttle()
|
||||
|
||||
@@ -79,7 +79,7 @@ PROBABILITY EXTENDED 0
|
||||
PROBABILITY TRAITOR 2
|
||||
PROBABILITY METEOR 0
|
||||
PROBABILITY MALFUNCTION 2
|
||||
PROBABILITY BLOB 0
|
||||
PROBABILITY BLOB 2
|
||||
PROBABILITY NUCLEAR 0
|
||||
PROBABILITY SANDBOX 0
|
||||
PROBABILITY WIZARD 0
|
||||
|
||||
@@ -75,6 +75,14 @@
|
||||
should be listed in the changelog upon commit though. Thanks. -->
|
||||
<!-- To take advantage of the pretty new format (well it was new when I wrote this anyway), open the "add-to-changelog.html" file in any browser and add the stuff and then generate the html code and paste it here -->
|
||||
|
||||
<div class="commit sansserif">
|
||||
<h2 class="date">2013-08-25</h2>
|
||||
<h3 class="author">Giacom updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="rscadd">Ported /tg/'s new blob mode for you guys, enjoy! If you don't know what it is, new blob is basically player controlled blobs with RTS elements like producing cannon fodder units, resource gathering and expanding.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="commit sansserif">
|
||||
<h2 class="date">2013.08.22</h2>
|
||||
<h3 class="author">N3X15 updated:</h3>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 229 KiB |
Reference in New Issue
Block a user