mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-10 18:32:03 +00:00
* mainly standardized the vending machine descriptions with exceptions * oops * more * this time i changed a proc name but there was only one use of it * everything gets changed! * this commit sponsored by low-quality forum posting * buisness * i broke it * but is it really robust? * why didn't this commit * finally, spent a lot of my morning for this * colour * sure it's not atomic, celt
474 lines
12 KiB
Plaintext
474 lines
12 KiB
Plaintext
//I will need to recode parts of this but I am way too tired atm <- whoever said this, I've got your back -Deity Link
|
|
|
|
/* Contents
|
|
/obj/effect/blob
|
|
/obj/effect/blob/blob_act()
|
|
/obj/effect/blob/New(turf/loc,newlook = "new")
|
|
/obj/effect/blob/Destroy()
|
|
/obj/effect/blob/projectile_check()
|
|
/obj/effect/blob/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0)
|
|
/obj/effect/blob/beam_connect(var/obj/effect/beam/B)
|
|
/obj/effect/blob/beam_disconnect(var/obj/effect/beam/B)
|
|
/obj/effect/blob/apply_beam_damage(var/obj/effect/beam/B)
|
|
/obj/effect/blob/handle_beams()
|
|
/obj/effect/blob/process()
|
|
/obj/effect/blob/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
|
/obj/effect/blob/ex_act(severity)
|
|
/obj/effect/blob/bullet_act(var/obj/item/projectile/Proj)
|
|
/obj/effect/blob/attackby(var/obj/item/weapon/W, var/mob/user)
|
|
/obj/effect/blob/update_icon(var/spawnend = 0)
|
|
|
|
/obj/effect/blob/proc/update_looks()
|
|
var/list/blob_looks
|
|
/obj/effect/blob/proc/Life()
|
|
/obj/effect/blob/proc/aftermove()
|
|
/obj/effect/blob/proc/Pulse(var/pulse = 0, var/origin_dir = 0)
|
|
/obj/effect/blob/proc/run_action()
|
|
/obj/effect/blob/proc/expand(var/turf/T = null, var/prob = 1)
|
|
/obj/effect/blob/proc/change_to(var/type, var/mob/camera/blob/M = null)
|
|
/obj/effect/blob/proc/Delete()
|
|
/obj/effect/blob/proc/update_health()
|
|
|
|
|
|
/obj/effect/blob/normal
|
|
/obj/effect/blob/normal/Delete()
|
|
/obj/effect/blob/normal/Pulse(var/pulse = 0, var/origin_dir = 0)
|
|
/obj/effect/blob/normal/update_icon(var/spawnend = 0)
|
|
*/
|
|
|
|
/obj/effect/blob
|
|
name = "blob"
|
|
icon = 'icons/mob/blob/blob_64x64.dmi'
|
|
icon_state = "center"
|
|
luminosity = 2
|
|
desc = "A part of a blob."
|
|
density = 0 //Necessary for spore pathfinding
|
|
opacity = 0
|
|
anchored = 1
|
|
penetration_dampening = 17
|
|
var/health = 20
|
|
var/maxhealth = 20
|
|
var/health_timestamp = 0
|
|
var/brute_resist = 4
|
|
var/fire_resist = 1
|
|
pixel_x = -WORLD_ICON_SIZE/2
|
|
pixel_y = -WORLD_ICON_SIZE/2
|
|
layer = BLOB_BASE_LAYER
|
|
plane = BLOB_PLANE
|
|
var/spawning = 2
|
|
var/dying = 0
|
|
var/mob/camera/blob/overmind = null
|
|
var/destroy_sound = "sound/effects/blobsplat.ogg"
|
|
|
|
var/looks = "new"
|
|
|
|
// A note to the beam processing shit.
|
|
var/custom_process=0
|
|
|
|
var/time_since_last_pulse
|
|
|
|
var/icon_new = "center"
|
|
var/icon_classic = "blob"
|
|
|
|
var/manual_remove = 0
|
|
var/icon_size = 64
|
|
|
|
/obj/effect/blob/blob_act()
|
|
return
|
|
|
|
|
|
/obj/effect/blob/New(turf/loc,newlook = "new",no_morph = 0)
|
|
looks = newlook
|
|
update_looks()
|
|
blobs += src
|
|
if(istype(ticker.mode,/datum/game_mode/blob))
|
|
var/datum/game_mode/blob/blobmode = ticker.mode
|
|
if((blobs.len >= blobmode.blobnukeposs) && prob(3) && !blobmode.nuclear)
|
|
blobmode.stage(2)
|
|
blobmode.nuclear = 1
|
|
src.dir = pick(cardinal)
|
|
time_since_last_pulse = world.time
|
|
|
|
if(icon_size == 64)
|
|
if(spawning && !no_morph)
|
|
icon_state = initial(icon_state) + "_spawn"
|
|
spawn(10)
|
|
spawning = 0//for sprites
|
|
icon_state = initial(icon_state)
|
|
src.update_icon(1)
|
|
else
|
|
spawning = 0
|
|
update_icon()
|
|
for(var/obj/effect/blob/B in orange(src,1))
|
|
B.update_icon()
|
|
|
|
..(loc)
|
|
for(var/atom/A in loc)
|
|
A.blob_act()
|
|
return
|
|
|
|
|
|
/obj/effect/blob/Destroy()
|
|
dying = 1
|
|
blobs -= src
|
|
|
|
if(icon_size == 64)
|
|
for(var/atom/movable/overlay/O in loc)
|
|
returnToPool(O)
|
|
|
|
for(var/obj/effect/blob/B in orange(loc,1))
|
|
B.update_icon()
|
|
if(!spawning)
|
|
anim(target = B.loc, a_icon = icon, flick_anim = "connect_die", sleeptime = 50, direction = get_dir(B,src), lay = layer+0.3, offX = -16, offY = -16, col = "red")
|
|
|
|
if(!manual_remove)
|
|
for(var/obj/effect/blob/core/C in range(loc,4))
|
|
if((C != src) && C.overmind && (C.overmind.blob_warning <= world.time))
|
|
C.overmind.blob_warning = world.time + (10 SECONDS)
|
|
to_chat(C.overmind,"<span class='danger'>A blob died near your core!</span> <b><a href='?src=\ref[C.overmind];blobjump=\ref[loc]'>(JUMP)</a></b>")
|
|
|
|
overmind = null
|
|
..()
|
|
|
|
/obj/effect/blob/projectile_check()
|
|
return PROJREACT_BLOB
|
|
|
|
/obj/effect/blob/Cross(atom/movable/mover, turf/target, height=1.5, air_group = 0)
|
|
if(air_group || (height==0))
|
|
return 1
|
|
if(istype(mover) && mover.checkpass(PASSBLOB))
|
|
return 1
|
|
mover.Bump(src) //Only automatic for dense objects
|
|
return 0
|
|
|
|
/obj/effect/blob/beam_connect(var/obj/effect/beam/B)
|
|
..()
|
|
last_beamchecks["\ref[B]"]=world.time+1
|
|
apply_beam_damage(B) // Contact damage for larger beams (deals 1/10th second of damage)
|
|
if(!custom_process && !(src in processing_objects))
|
|
processing_objects.Add(src)
|
|
|
|
|
|
/obj/effect/blob/beam_disconnect(var/obj/effect/beam/B)
|
|
..()
|
|
apply_beam_damage(B)
|
|
last_beamchecks.Remove("\ref[B]") // RIP
|
|
update_health()
|
|
update_icon()
|
|
if(beams.len == 0)
|
|
if(!custom_process && src in processing_objects)
|
|
processing_objects.Remove(src)
|
|
|
|
/obj/effect/blob/apply_beam_damage(var/obj/effect/beam/B)
|
|
var/lastcheck=last_beamchecks["\ref[B]"]
|
|
|
|
// Standard damage formula / 2
|
|
var/damage = ((world.time - lastcheck)/10) * (B.get_damage() / 2)
|
|
|
|
// Actually apply damage
|
|
health -= damage
|
|
|
|
// Update check time.
|
|
last_beamchecks["\ref[B]"]=world.time
|
|
|
|
/obj/effect/blob/handle_beams()
|
|
// New beam damage code (per-tick)
|
|
for(var/obj/effect/beam/B in beams)
|
|
apply_beam_damage(B)
|
|
update_health()
|
|
update_icon()
|
|
|
|
/obj/effect/blob/can_mech_drill()
|
|
return TRUE
|
|
|
|
/obj/effect/blob/process()
|
|
handle_beams()
|
|
Life()
|
|
return
|
|
|
|
/obj/effect/blob/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_health()
|
|
update_icon()
|
|
|
|
/obj/effect/blob/ex_act(severity)
|
|
var/damage = 150
|
|
health -= ((damage/brute_resist) - (severity * 5))
|
|
update_health()
|
|
update_icon()
|
|
return
|
|
|
|
/obj/effect/blob/bullet_act(var/obj/item/projectile/Proj)
|
|
..()
|
|
switch(Proj.damage_type)
|
|
if(BRUTE)
|
|
health -= (Proj.damage/brute_resist)
|
|
if(BURN)
|
|
health -= (Proj.damage/fire_resist)
|
|
|
|
update_health()
|
|
update_icon()
|
|
return 0
|
|
|
|
/obj/effect/blob/attackby(var/obj/item/weapon/W, var/mob/user)
|
|
user.delayNextAttack(10)
|
|
playsound(get_turf(src), 'sound/effects/attackblob.ogg', 50, 1)
|
|
src.visible_message("<span class='warning'><B>The [src.name] has been attacked with \the [W][(user ? " by [user]." : ".")]</span>")
|
|
var/damage = 0
|
|
switch(W.damtype)
|
|
if("fire")
|
|
damage = (W.force / max(src.fire_resist,1))
|
|
if(istype(W, /obj/item/weapon/weldingtool) || istype(W, /obj/item/weapon/pickaxe/plasmacutter))
|
|
playsound(get_turf(src), 'sound/effects/blobweld.ogg', 100, 1)
|
|
if("brute")
|
|
damage = (W.force / max(src.brute_resist,1))
|
|
|
|
health -= damage
|
|
update_health()
|
|
update_icon()
|
|
return
|
|
|
|
/obj/effect/blob/update_icon(var/spawnend = 0)
|
|
if(icon_size == 64)
|
|
if(health < maxhealth)
|
|
var/hurt_percentage = round((health * 100) / maxhealth)
|
|
var/hurt_icon
|
|
switch(hurt_percentage)
|
|
if(0 to 25)
|
|
hurt_icon = "hurt_100"
|
|
if(26 to 50)
|
|
hurt_icon = "hurt_75"
|
|
if(51 to 75)
|
|
hurt_icon = "hurt_50"
|
|
else
|
|
hurt_icon = "hurt_25"
|
|
overlays += image(icon,hurt_icon)
|
|
|
|
/obj/effect/blob/proc/update_looks(var/right_now = 0)
|
|
switch(blob_looks_admin[looks]) //blob_looks_admin should have every possible blob skin
|
|
if(64)
|
|
icon_state = icon_new
|
|
icon_size = 64
|
|
pixel_x = -WORLD_ICON_SIZE/2
|
|
pixel_y = -WORLD_ICON_SIZE/2
|
|
layer = initial(layer)
|
|
if(right_now)
|
|
spawning = 0
|
|
if(32)
|
|
icon_state = icon_classic
|
|
icon_size = 32
|
|
pixel_x = 0
|
|
pixel_y = 0
|
|
layer = OBJ_LAYER
|
|
overlays.len = 0
|
|
|
|
switch(looks)
|
|
if("new")
|
|
icon = 'icons/mob/blob/blob_64x64.dmi'
|
|
if("classic")
|
|
icon = 'icons/mob/blob/blob.dmi'
|
|
if("adminbus")
|
|
icon = adminblob_icon
|
|
if("clownscape")
|
|
icon = 'icons/mob/blob/blob_honkscape.dmi'
|
|
if("AME")
|
|
icon = 'icons/mob/blob/blob_AME.dmi'
|
|
if("AME_new")
|
|
icon = 'icons/mob/blob/blob_AME_64x64.dmi'
|
|
//<----------------------------------------------------------------------------DEAR SPRITERS, THIS IS WHERE YOU ADD YOUR NEW BLOB DMIs
|
|
/*EXAMPLES
|
|
if("fleshy")
|
|
icon = 'icons/mob/blob_fleshy.dmi'
|
|
if("machineblob")
|
|
icon = 'icons/mob/blob_machine.dmi'
|
|
*/
|
|
|
|
if(right_now)
|
|
update_icon()
|
|
|
|
var/list/blob_looks_admin = list(//Options available to admins
|
|
"new" = 64,
|
|
"classic" = 32,
|
|
"adminbus" = adminblob_size,
|
|
"clownscape" = 32,
|
|
"AME" = 32,
|
|
"AME_new" = 64,
|
|
)
|
|
|
|
var/list/blob_looks_player = list(//Options available to players
|
|
"new" = 64,
|
|
"classic" = 32,
|
|
)
|
|
//<---------------------------------------ALSO ADD THE NAME OF YOUR BLOB LOOKS HERE, AS WELL AS THE RESOLUTION OF THE DMIS (64 or 32)
|
|
|
|
/obj/effect/blob/proc/Life()
|
|
return
|
|
|
|
/obj/effect/blob/proc/aftermove()
|
|
for(var/obj/effect/blob/B in loc)
|
|
if(B != src)
|
|
manual_remove = 1
|
|
qdel(src)
|
|
return
|
|
update_icon()
|
|
for(var/obj/effect/blob/B in orange(src,1))
|
|
B.update_icon()
|
|
|
|
/obj/effect/blob/proc/Pulse(var/pulse = 0, var/origin_dir = 0)//Todo: Fix spaceblob expand
|
|
/*
|
|
if(time_since_last_pulse >= world.time)
|
|
return
|
|
*/
|
|
time_since_last_pulse = world.time
|
|
|
|
//set background = 1
|
|
|
|
for(var/mob/M in loc)
|
|
M.blob_act()
|
|
|
|
if(run_action())//If we can do something here then we dont need to pulse more
|
|
return
|
|
|
|
if(pulse > 30)
|
|
return//Inf loop check
|
|
|
|
//Looking for another blob to pulse
|
|
var/list/dirs = cardinal.Copy()
|
|
dirs.Remove(origin_dir)//Dont pulse the guy who pulsed us
|
|
for(var/i in 1 to 4)
|
|
if(!dirs.len)
|
|
break
|
|
var/dirn = pick_n_take(dirs)
|
|
var/turf/T = get_step(src, dirn)
|
|
var/obj/effect/blob/B = locate() in T
|
|
if(!B)
|
|
expand(T)//No blob here so try and expand
|
|
return
|
|
spawn(2)
|
|
B.Pulse((pulse+1),get_dir(src.loc,T))
|
|
return
|
|
return
|
|
|
|
|
|
/obj/effect/blob/proc/run_action()
|
|
return 0
|
|
|
|
/obj/effect/blob/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 = cardinal.Copy()
|
|
for(var/i in 1 to 4)
|
|
var/dirn = pick_n_take(dirs)
|
|
T = get_step(src, dirn)
|
|
if(!(locate(/obj/effect/blob) in T))
|
|
break
|
|
else
|
|
T = null
|
|
|
|
if(!T)
|
|
return 0
|
|
var/obj/effect/blob/normal/B = new(src.loc, newlook = looks)
|
|
B.density = 1
|
|
|
|
if(icon_size == 64)
|
|
if(istype(src,/obj/effect/blob/normal))
|
|
var/num = rand(1,100)
|
|
num /= 10000
|
|
B.layer = layer - num
|
|
|
|
if(T.Enter(B,src))//Attempt to move into the tile
|
|
B.density = initial(B.density)
|
|
if(icon_size == 64)
|
|
spawn(1)
|
|
B.dir = get_dir(loc,T)
|
|
B.forceMove(T)
|
|
B.aftermove()
|
|
if(B.spawning > 1)
|
|
B.spawning = 1
|
|
else
|
|
B.forceMove(T)
|
|
else
|
|
T.blob_act()//If we cant move in hit the turf
|
|
B.manual_remove = 1
|
|
B.Delete()
|
|
|
|
for(var/atom/A in T)//Hit everything in the turf
|
|
A.blob_act()
|
|
return 1
|
|
|
|
|
|
/obj/effect/blob/proc/change_to(var/type, var/mob/camera/blob/M = null)
|
|
if(!ispath(type))
|
|
error("[type] is an invalid type for the blob.")
|
|
if("[type]" == "/obj/effect/blob/core")
|
|
new type(src.loc, 200, null, 1, M, newlook = looks)
|
|
else
|
|
var/obj/effect/blob/B = new type(src.loc, newlook = looks)
|
|
B.dir = dir
|
|
spawning = 1//so we don't show red severed connections
|
|
manual_remove = 1
|
|
Delete()
|
|
return
|
|
|
|
/obj/effect/blob/proc/Delete()
|
|
qdel(src)
|
|
|
|
/obj/effect/blob/proc/update_health()
|
|
if(!dying && (health <= 0))
|
|
dying = 1
|
|
if(get_turf(src))
|
|
playsound(src, destroy_sound, 50, 1)
|
|
Delete()
|
|
|
|
//////////////////NORMAL BLOBS/////////////////////////////////
|
|
/obj/effect/blob/normal
|
|
luminosity = 2
|
|
health = 21
|
|
layer = BLOB_BASE_LAYER
|
|
|
|
/obj/effect/blob/normal/Delete()
|
|
..()
|
|
/*
|
|
/obj/effect/blob/normal/Pulse(var/pulse = 0, var/origin_dir = 0)
|
|
..()
|
|
if(icon_size == 64)
|
|
anim(target = loc, a_icon = icon, flick_anim = "pulse", sleeptime = 15, direction = dir, lay = 12, offX = -16, offY = -16, alph = 51)
|
|
*/
|
|
/obj/effect/blob/normal/update_icon(var/spawnend = 0)
|
|
if(icon_size == 64)
|
|
spawn(1)
|
|
overlays.len = 0
|
|
underlays.len = 0
|
|
|
|
underlays += image(icon,"roots")
|
|
|
|
if(!spawning)
|
|
for(var/obj/effect/blob/B in orange(src,1))
|
|
if(B.spawning == 1)
|
|
anim(target = loc, a_icon = icon, flick_anim = "connect_spawn", sleeptime = 15, direction = get_dir(src,B), lay = layer, offX = -16, offY = -16,plane = plane)
|
|
spawn(8)
|
|
update_icon()
|
|
else if(!B.dying && !B.spawning)
|
|
if(spawnend)
|
|
anim(target = loc, a_icon = icon, flick_anim = "connect_spawn", sleeptime = 15, direction = get_dir(src,B), lay = layer, offX = -16, offY = -16,plane = plane)
|
|
else
|
|
if(istype(B,/obj/effect/blob/core))
|
|
overlays += image(icon,"connect",dir = get_dir(src,B))
|
|
else
|
|
overlays += image(icon,"connect",dir = get_dir(src,B))
|
|
|
|
if(spawnend)
|
|
spawn(10)
|
|
update_icon()
|
|
|
|
..()
|
|
else
|
|
if(health <= 15)
|
|
icon_state = "blob_damaged"
|