mirror of
https://github.com/Citadel-Station-13/Citadel-Station-13-RP.git
synced 2026-08-23 07:26:50 +01:00
@@ -1,25 +1,20 @@
|
||||
/**
|
||||
* effect supertype
|
||||
*
|
||||
* currently does nothing
|
||||
*
|
||||
* "weakly interactive visual objects" should usually go under this, especially if they're temporary/short lasting
|
||||
* Effects are mostly temporary visual effects like sparks, smoke, as well as decals, etc...
|
||||
*
|
||||
* these, however, have full object damgae/interaction support, so it's not limited to those
|
||||
*
|
||||
* however, at a certain point, do consider using /structure or /machinery instead.
|
||||
*/
|
||||
/obj/effect
|
||||
anchored = TRUE
|
||||
integrity_enabled = FALSE
|
||||
density = FALSE
|
||||
opacity = FALSE
|
||||
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
integrity_flags = INTEGRITY_ACIDPROOF | INTEGRITY_FIREPROOF | INTEGRITY_LAVAPROOF | INTEGRITY_INDESTRUCTIBLE
|
||||
move_resist = INFINITY
|
||||
obj_flags = NONE
|
||||
blocks_emissive = EMISSIVE_BLOCK_GENERIC
|
||||
integrity_enabled = FALSE
|
||||
|
||||
anchored = TRUE
|
||||
vis_flags = VIS_INHERIT_PLANE
|
||||
// blocks_emissive = EMI
|
||||
|
||||
/obj/effect/fire_act()
|
||||
return
|
||||
@@ -30,22 +25,25 @@
|
||||
/obj/effect/blob_act(obj/structure/blob/B)
|
||||
return
|
||||
|
||||
/obj/effect/legacy_ex_act(severity, target)
|
||||
return FALSE
|
||||
|
||||
/obj/effect/singularity_act()
|
||||
qdel(src)
|
||||
|
||||
/// The abstract effect ignores even more effects and is often typechecked for atoms that should truly not be fucked with.
|
||||
/obj/effect/abstract
|
||||
|
||||
/obj/effect/abstract/singularity_pull()
|
||||
/obj/effect/abstract/singularity_pull(atom/singularity, current_size)
|
||||
return
|
||||
|
||||
/obj/effect/abstract/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/abstract/has_gravity(turf/T)
|
||||
/obj/effect/abstract/has_gravity(turf/gravity_turf)
|
||||
return FALSE
|
||||
|
||||
/obj/effect/dummy/singularity_pull()
|
||||
/obj/effect/dummy/singularity_pull(atom/singularity, current_size)
|
||||
return
|
||||
|
||||
/obj/effect/dummy/singularity_act()
|
||||
|
||||
@@ -1,34 +1,58 @@
|
||||
var/list/obj/effect/bump_teleporter/BUMP_TELEPORTERS = list()
|
||||
|
||||
/// Abstract effect, that when a mob touches it, it will forceMove them to the teleporter-exit point (that matches the ID set map-side).
|
||||
/obj/effect/bump_teleporter
|
||||
name = "bump-teleporter"
|
||||
name = "bump teleporter (forceMove)"
|
||||
desc = "Use me when you want to move every single mob without any exceptions."
|
||||
icon = 'icons/mob/screen1.dmi'
|
||||
icon_state = "x2"
|
||||
var/id = null //id of this bump_teleporter.
|
||||
var/id_target = null //id of bump_teleporter which this moves you to.
|
||||
invisibility = 101 //nope, can't see this
|
||||
anchored = 1
|
||||
density = 1
|
||||
opacity = 0
|
||||
invisibility = INVISIBILITY_ABSTRACT //nope, can't see this
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
opacity = FALSE
|
||||
/// id of this bump_teleporter.
|
||||
var/id = null
|
||||
/// id of bump_teleporter which this moves you to.
|
||||
var/id_target = null
|
||||
/// List of all teleporters in the world.
|
||||
var/static/list/AllTeleporters
|
||||
|
||||
/obj/effect/bump_teleporter/Initialize(mapload)
|
||||
. = ..()
|
||||
BUMP_TELEPORTERS += src
|
||||
LAZYADD(AllTeleporters, src)
|
||||
|
||||
/obj/effect/bump_teleporter/Destroy()
|
||||
BUMP_TELEPORTERS -= src
|
||||
LAZYREMOVE(AllTeleporters, src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/bump_teleporter/Bumped(atom/user)
|
||||
if(!ismob(user))
|
||||
//user.loc = src.loc //Stop at teleporter location
|
||||
/obj/effect/bump_teleporter/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/bump_teleporter/singularity_pull(atom/singularity, current_size)
|
||||
return
|
||||
|
||||
/obj/effect/bump_teleporter/Bumped(atom/movable/bumper)
|
||||
if(!validate_setup(bumper))
|
||||
return
|
||||
|
||||
for(var/obj/effect/bump_teleporter/teleporter in AllTeleporters)
|
||||
if(teleporter.id == id_target)
|
||||
teleport_action(bumper, get_turf(teleporter)) //Teleport to location with correct id.
|
||||
return
|
||||
|
||||
stack_trace("Bump_teleporter [src] could not find a teleporter with id [id_target]!")
|
||||
|
||||
/// Check to see if our teleporter was set up correctly mapside. Return TRUE if everything is fine, FALSE if not.
|
||||
/obj/effect/bump_teleporter/proc/validate_setup(atom/movable/checkable)
|
||||
if(!ismob(checkable))
|
||||
return FALSE
|
||||
|
||||
if(!id_target)
|
||||
//user.loc = src.loc //Stop at teleporter location, there is nowhere to teleport to.
|
||||
return
|
||||
var/message = "Bump teleporter [src] at [AREACOORD(src)] has no id_target set."
|
||||
stack_trace(message)
|
||||
log_mapping(message)
|
||||
return FALSE
|
||||
|
||||
for(var/obj/effect/bump_teleporter/BT in BUMP_TELEPORTERS)
|
||||
if(BT.id == src.id_target)
|
||||
usr.loc = BT.loc //Teleport to location with correct id.
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/// Actually move our target atom from one position to another. Return TRUE if everything is fine. Override this proc on subtypes for specific teleportation methods.
|
||||
/obj/effect/bump_teleporter/proc/teleport_action(atom/movable/target, turf/destination)
|
||||
target.locationTransitForceMove(destination)
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/obj/effect/countdown
|
||||
name = "countdown"
|
||||
desc = "We're leaving together\n\
|
||||
But still it's farewell\n\
|
||||
And maybe we'll come back\n\
|
||||
To Earth, who can tell?"
|
||||
|
||||
invisibility = INVISIBILITY_OBSERVER
|
||||
anchored = TRUE
|
||||
plane = OBSERVER_PLANE
|
||||
color = "#ff0000" // text color
|
||||
var/text_size = 3 // larger values clip when the displayed text is larger than 2 digits.
|
||||
var/started = FALSE
|
||||
var/displayed_text
|
||||
var/atom/attached_to
|
||||
|
||||
/obj/effect/countdown/Initialize(mapload)
|
||||
. = ..()
|
||||
attach(loc)
|
||||
|
||||
/obj/effect/countdown/examine(mob/user)
|
||||
. = ..()
|
||||
. += "This countdown is displaying: [displayed_text]."
|
||||
|
||||
/obj/effect/countdown/proc/attach(atom/A)
|
||||
attached_to = A
|
||||
var/turf/loc_turf = get_turf(A)
|
||||
if(!loc_turf)
|
||||
RegisterSignal(attached_to, COMSIG_MOVABLE_MOVED, PROC_REF(retry_attach), TRUE)
|
||||
else
|
||||
forceMove(loc_turf)
|
||||
|
||||
/obj/effect/countdown/proc/retry_attach()
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/turf/loc_turf = get_turf(attached_to)
|
||||
if(!loc_turf)
|
||||
return
|
||||
forceMove(loc_turf)
|
||||
UnregisterSignal(attached_to, COMSIG_MOVABLE_MOVED)
|
||||
|
||||
/obj/effect/countdown/proc/start()
|
||||
if(!started)
|
||||
START_PROCESSING(SSprocess_5fps, src)
|
||||
started = TRUE
|
||||
|
||||
/obj/effect/countdown/proc/stop()
|
||||
if(started)
|
||||
maptext = null
|
||||
STOP_PROCESSING(SSprocess_5fps, src)
|
||||
started = FALSE
|
||||
|
||||
/obj/effect/countdown/proc/get_value()
|
||||
// Get the value from our atom
|
||||
return
|
||||
|
||||
/obj/effect/countdown/process()
|
||||
if(!attached_to || QDELETED(attached_to))
|
||||
qdel(src)
|
||||
forceMove(get_turf(attached_to))
|
||||
var/new_val = get_value()
|
||||
if(new_val == displayed_text)
|
||||
return
|
||||
displayed_text = new_val
|
||||
|
||||
if(displayed_text)
|
||||
maptext = MAPTEXT("[displayed_text]")
|
||||
else
|
||||
maptext = null
|
||||
|
||||
/obj/effect/countdown/Destroy()
|
||||
attached_to = null
|
||||
STOP_PROCESSING(SSprocess_5fps, src)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/countdown/singularity_pull(atom/singularity, current_size)
|
||||
return
|
||||
|
||||
/obj/effect/countdown/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/countdown/nuclearbomb
|
||||
name = "nuclear bomb countdown"
|
||||
color = "#81FF14"
|
||||
|
||||
// /obj/effect/countdown/nuclearbomb/get_value()
|
||||
// var/obj/machinery/nuclearbomb/N = attached_to
|
||||
// if(!istype(N))
|
||||
// return
|
||||
// else if(N.timing)
|
||||
// return round(N.get_time_left(), 1)
|
||||
|
||||
/obj/effect/countdown/supermatter
|
||||
name = "supermatter damage"
|
||||
color = "#00ff80"
|
||||
pixel_y = 8
|
||||
|
||||
/obj/effect/countdown/supermatter/attach(atom/A)
|
||||
. = ..()
|
||||
if(istype(A, /obj/machinery/power/supermatter))
|
||||
pixel_y = -12
|
||||
|
||||
/obj/effect/countdown/supermatter/get_value()
|
||||
var/obj/machinery/power/supermatter/S = attached_to
|
||||
if(!istype(S))
|
||||
return
|
||||
return "<div align='center' valign='bottom' style='position:relative; top:0px; left:0px'>[round(S.get_integrity())]%</div>"
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
/obj/effect/particle_effect
|
||||
name = "particle effect"
|
||||
pass_flags = ATOM_PASS_TABLE | ATOM_PASS_GRILLE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
anchored = TRUE
|
||||
|
||||
/datum/effect_system
|
||||
var/number = 3
|
||||
var/cardinals = 0
|
||||
var/turf/location
|
||||
var/atom/holder
|
||||
var/setup = 0
|
||||
|
||||
/datum/effect_system/Destroy()
|
||||
holder = null
|
||||
location = null
|
||||
return..()
|
||||
|
||||
/datum/effect_system/proc/set_up(n = 3, c = 0, turf/loc)
|
||||
if(n > 10)
|
||||
n = 10
|
||||
number = n
|
||||
cardinals = c
|
||||
location = loc
|
||||
setup = 1
|
||||
|
||||
/datum/effect_system/proc/attach(atom/atom)
|
||||
holder = atom
|
||||
|
||||
/datum/effect_system/proc/start()
|
||||
|
||||
-110
@@ -1,44 +1,3 @@
|
||||
/* This is an attempt to make some easily reusable "particle" type effect, to stop the code
|
||||
constantly having to be rewritten. An item like the jetpack that uses the ion_trail_follow system, just has one
|
||||
defined, then set up when it is created with New(). Then this same system can just be reused each time
|
||||
it needs to create more trails.A beaker could have a steam_trail_follow system set up, then the steam
|
||||
would spawn and follow the beaker, even if it is carried or thrown.
|
||||
*/
|
||||
|
||||
|
||||
/obj/effect/particle_effect
|
||||
name = "effect"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
integrity_flags = INTEGRITY_INDESTRUCTIBLE | INTEGRITY_ACIDPROOF | INTEGRITY_FIREPROOF | INTEGRITY_LAVAPROOF
|
||||
pass_flags = ATOM_PASS_TABLE | ATOM_PASS_GRILLE
|
||||
|
||||
/datum/effect_system
|
||||
var/number = 3
|
||||
var/cardinals = 0
|
||||
var/turf/location
|
||||
var/atom/holder
|
||||
var/setup = 0
|
||||
|
||||
/datum/effect_system/Destroy()
|
||||
holder = null
|
||||
location = null
|
||||
return..()
|
||||
|
||||
/datum/effect_system/proc/set_up(n = 3, c = 0, turf/loc)
|
||||
if(n > 10)
|
||||
n = 10
|
||||
number = n
|
||||
cardinals = c
|
||||
location = loc
|
||||
setup = 1
|
||||
|
||||
/datum/effect_system/proc/attach(atom/atom)
|
||||
holder = atom
|
||||
|
||||
/datum/effect_system/proc/start()
|
||||
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// GENERIC STEAM SPREAD SYSTEM
|
||||
|
||||
@@ -87,76 +46,7 @@ steam.start() -- spawns the effect
|
||||
spawn(20)
|
||||
qdel(steam)
|
||||
|
||||
/////////////////////////////////////////////
|
||||
//SPARK SYSTEM (like steam system)
|
||||
// The attach(atom/atom) proc is optional, and can be called to attach the effect
|
||||
// to something, like the RCD, so then you can just call start() and the sparks
|
||||
// will always spawn at the items location.
|
||||
/////////////////////////////////////////////
|
||||
|
||||
/obj/effect/particle_effect/sparks
|
||||
name = "sparks"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "sparks"
|
||||
var/amount = 6.0
|
||||
anchored = 1.0
|
||||
mouse_opacity = 0
|
||||
|
||||
/obj/effect/particle_effect/sparks/Initialize(mapload)
|
||||
. = ..()
|
||||
playsound(src, /datum/soundbyte/sparks, 100, 1)
|
||||
var/turf/T = src.loc
|
||||
if (istype(T, /turf))
|
||||
T.hotspot_expose(1000,100)
|
||||
QDEL_IN(src, 5 SECONDS)
|
||||
|
||||
/obj/effect/particle_effect/sparks/Destroy()
|
||||
var/turf/T = src.loc
|
||||
if (istype(T, /turf))
|
||||
T.hotspot_expose(1000,100)
|
||||
return ..()
|
||||
|
||||
/obj/effect/particle_effect/sparks/Move()
|
||||
..()
|
||||
var/turf/T = src.loc
|
||||
if (istype(T, /turf))
|
||||
T.hotspot_expose(1000,100)
|
||||
return
|
||||
|
||||
/datum/effect_system/spark_spread
|
||||
var/total_sparks = 0 // To stop it being spammed and lagging!
|
||||
|
||||
/datum/effect_system/spark_spread/set_up(n = 3, c = 0, loca)
|
||||
if(n > 10)
|
||||
n = 10
|
||||
number = n
|
||||
cardinals = c
|
||||
if(istype(loca, /turf/))
|
||||
location = loca
|
||||
else
|
||||
location = get_turf(loca)
|
||||
|
||||
/datum/effect_system/spark_spread/start()
|
||||
var/i = 0
|
||||
for(i=0, i<src.number, i++)
|
||||
if(src.total_sparks > 20)
|
||||
return
|
||||
spawn(0)
|
||||
if(holder)
|
||||
src.location = get_turf(holder)
|
||||
var/obj/effect/particle_effect/sparks/sparks = new /obj/effect/particle_effect/sparks(src.location)
|
||||
src.total_sparks++
|
||||
var/direction
|
||||
if(src.cardinals)
|
||||
direction = pick(GLOB.cardinal)
|
||||
else
|
||||
direction = pick(GLOB.alldirs)
|
||||
for(i=0, i<pick(1,2,3), i++)
|
||||
sleep(5)
|
||||
if(isloc(sparks.loc) && !QDELETED(sparks))
|
||||
step(sparks,direction)
|
||||
spawn(20)
|
||||
src.total_sparks--
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/////////////////////////////////////////////
|
||||
//SPARK SYSTEM (like steam system)
|
||||
// The attach(atom/atom) proc is optional, and can be called to attach the effect
|
||||
// to something, like the RCD, so then you can just call start() and the sparks
|
||||
// will always spawn at the items location.
|
||||
/////////////////////////////////////////////
|
||||
|
||||
/obj/effect/particle_effect/sparks
|
||||
name = "sparks"
|
||||
icon_state = "sparks"
|
||||
anchored = TRUE
|
||||
light_range = 1.5
|
||||
light_power = 0.8
|
||||
light_color = LIGHT_COLOR_FIRE
|
||||
var/amount = 6.0
|
||||
|
||||
/obj/effect/particle_effect/sparks/Initialize(mapload)
|
||||
..()
|
||||
return INITIALIZE_HINT_LATELOAD
|
||||
|
||||
/obj/effect/particle_effect/sparks/LateInitialize()
|
||||
flick(icon_state, src)
|
||||
playsound(src, /datum/soundbyte/sparks, 100, 1)
|
||||
var/turf/location = loc
|
||||
if(isturf(location))
|
||||
affect_location(location, just_initialized = TRUE)
|
||||
QDEL_IN(src, 2 SECONDS)
|
||||
|
||||
/obj/effect/particle_effect/sparks/Destroy()
|
||||
var/turf/location = loc
|
||||
if(isturf(location))
|
||||
affect_location(location)
|
||||
return ..()
|
||||
|
||||
/obj/effect/particle_effect/sparks/Move()
|
||||
..()
|
||||
var/turf/location = loc
|
||||
if(isturf(location))
|
||||
affect_location(location)
|
||||
|
||||
/*
|
||||
* Apply the effects of this spark to its location.
|
||||
*
|
||||
* When the spark is first created, Cross() and Crossed() don't get called,
|
||||
* so for the first initialization, we make sure to specifically invoke the
|
||||
* behavior of the spark on all the mobs and objects in the location.
|
||||
* turf/location - The place the spark is affectiong
|
||||
* just_initialized - If the spark is just being created, and we need to manually affect everything in the location
|
||||
*/
|
||||
/obj/effect/particle_effect/sparks/proc/affect_location(turf/location, just_initialized = FALSE)
|
||||
location.hotspot_expose(1000,100)
|
||||
// SEND_SIGNAL(location, COMSIG_ATOM_TOUCHED_SPARKS, src) // for plasma floors; other floor types only have to worry about the mysterious HAZARDOUS sparks
|
||||
|
||||
/datum/effect_system/spark_spread
|
||||
var/total_sparks = 0 // To stop it being spammed and lagging!
|
||||
|
||||
/datum/effect_system/spark_spread/set_up(n = 3, c = 0, loca)
|
||||
if(n > 10)
|
||||
n = 10
|
||||
number = n
|
||||
cardinals = c
|
||||
if(istype(loca, /turf/))
|
||||
location = loca
|
||||
else
|
||||
location = get_turf(loca)
|
||||
|
||||
/datum/effect_system/spark_spread/start()
|
||||
var/i = 0
|
||||
for(i=0, i<src.number, i++)
|
||||
if(src.total_sparks > 20)
|
||||
return
|
||||
spawn(0)
|
||||
if(holder)
|
||||
src.location = get_turf(holder)
|
||||
var/obj/effect/particle_effect/sparks/sparks = new /obj/effect/particle_effect/sparks(src.location)
|
||||
src.total_sparks++
|
||||
var/direction
|
||||
if(src.cardinals)
|
||||
direction = pick(GLOB.cardinal)
|
||||
else
|
||||
direction = pick(GLOB.alldirs)
|
||||
for(i=0, i<pick(1,2,3), i++)
|
||||
sleep(5)
|
||||
if(isloc(sparks.loc) && !QDELETED(sparks))
|
||||
step(sparks,direction)
|
||||
spawn(20)
|
||||
src.total_sparks--
|
||||
@@ -1,58 +0,0 @@
|
||||
/proc/gibs(atom/location, var/datum/dna/MobDNA, gibber_type = /obj/effect/gibspawner/generic, var/fleshcolor, var/bloodcolor)
|
||||
new gibber_type(location,MobDNA,fleshcolor,bloodcolor)
|
||||
|
||||
/obj/effect/gibspawner
|
||||
var/sparks = 0 //whether sparks spread on Gib()
|
||||
var/list/gibtypes = list()
|
||||
var/list/gibamounts = list()
|
||||
var/list/gibdirections = list() //of lists
|
||||
var/fleshcolor //Used for gibbed humans.
|
||||
var/bloodcolor //Used for gibbed humans.
|
||||
|
||||
/obj/effect/gibspawner/Initialize(mapload, datum/dna/MobDNA, fleshcolor, bloodcolor)
|
||||
..()
|
||||
|
||||
if(fleshcolor)
|
||||
src.fleshcolor = fleshcolor
|
||||
if(bloodcolor)
|
||||
src.bloodcolor = bloodcolor
|
||||
Gib(loc,MobDNA)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/gibspawner/proc/Gib(atom/location, datum/dna/MobDNA = null)
|
||||
if(gibtypes.len != gibamounts.len || gibamounts.len != gibdirections.len)
|
||||
to_chat(world, SPAN_WARNING("Gib list length mismatch!"))
|
||||
return
|
||||
|
||||
var/obj/effect/debris/cleanable/blood/gibs/gib = null
|
||||
|
||||
if(sparks)
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread()
|
||||
s.set_up(2, 1, get_turf(location)) // Not sure if it's safe to pass an arbitrary object to set_up, todo
|
||||
s.start()
|
||||
|
||||
for(var/i = 1, i<= gibtypes.len, i++)
|
||||
if(gibamounts[i])
|
||||
for(var/j = 1, j<= gibamounts[i], j++)
|
||||
var/gibType = gibtypes[i]
|
||||
gib = new gibType(location)
|
||||
|
||||
// Apply human species colouration to masks.
|
||||
if(fleshcolor)
|
||||
gib.fleshcolor = fleshcolor
|
||||
if(bloodcolor)
|
||||
gib.basecolor = bloodcolor
|
||||
|
||||
gib.update_icon()
|
||||
|
||||
gib.blood_DNA = list()
|
||||
if(MobDNA)
|
||||
gib.blood_DNA[MobDNA.unique_enzymes] = MobDNA.b_type
|
||||
else if(istype(src, /obj/effect/gibspawner/human)) // Probably a monkey
|
||||
gib.blood_DNA["Non-human DNA"] = "A+"
|
||||
if(istype(location,/turf/))
|
||||
var/list/directions = gibdirections[i]
|
||||
if(directions.len)
|
||||
gib.streak(directions)
|
||||
|
||||
qdel(src)
|
||||
@@ -1,6 +1,11 @@
|
||||
/obj/effect/overlay
|
||||
name = "overlay"
|
||||
integrity_flags = INTEGRITY_ACIDPROOF | INTEGRITY_FIREPROOF | INTEGRITY_LAVAPROOF | INTEGRITY_INDESTRUCTIBLE
|
||||
|
||||
/obj/effect/overlay/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/overlay/singularity_pull(atom/singularity, current_size)
|
||||
return
|
||||
|
||||
/obj/effect/overlay/palmtree_r
|
||||
name = "Palm tree"
|
||||
|
||||
@@ -3,10 +3,20 @@
|
||||
* You know, so multiple particle effects can exist at once. Also because some objects do not display particles due to how their visuals are built.
|
||||
*/
|
||||
/obj/effect/abstract/particle_holder
|
||||
anchored = TRUE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
layer = ABOVE_MOB_LAYER
|
||||
name = "particle holder"
|
||||
desc = "How are you reading this? Please make a bug report :)"
|
||||
appearance_flags = KEEP_APART|KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE|LONG_GLIDE|RESET_COLOR //movable appearance_flags plus KEEP_APART and KEEP_TOGETHER
|
||||
vis_flags = VIS_INHERIT_PLANE
|
||||
layer = ABOVE_MOB_LAYER
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
anchored = TRUE
|
||||
|
||||
/// Holds info about how this particle emitter works
|
||||
/// See \code\__DEFINES\particles.dm
|
||||
var/particle_flags = NONE
|
||||
|
||||
var/atom/parent
|
||||
|
||||
/// Typepath of the last location we're in, if it's different when moved then we need to update vis contents.
|
||||
var/last_attached_location_type
|
||||
/// The main item we're attached to at the moment, particle holders hold particles for something.
|
||||
@@ -14,58 +24,57 @@
|
||||
/// Besides the item we're also sometimes attached to other stuff! (items held emitting particles on a mob).
|
||||
var/datum/weakref/weak_additional
|
||||
|
||||
/obj/effect/abstract/particle_holder/Initialize(mapload, particle_path = /particles/smoke)
|
||||
/obj/effect/abstract/particle_holder/Initialize(mapload, particle_path = /particles/smoke, particle_flags = NONE)
|
||||
. = ..()
|
||||
if(!loc)
|
||||
stack_trace("particle holder was created with no loc!")
|
||||
return INITIALIZE_HINT_QDEL
|
||||
if(ismovable(loc))
|
||||
RegisterSignal(loc, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
|
||||
RegisterSignal(loc, COMSIG_PARENT_QDELETING, PROC_REF(on_qdel))
|
||||
weak_attached = WEAKREF(loc)
|
||||
particles = new particle_path
|
||||
update_visual_contents(loc)
|
||||
|
||||
// We nullspace ourselves because some objects use their contents (e.g. storage) and some items may drop everything in their contents on deconstruct.
|
||||
parent = loc
|
||||
loc = null
|
||||
|
||||
// Mouse opacity can get set to opaque by some objects when placed into the object's contents (storage containers).
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
src.particle_flags = particle_flags
|
||||
particles = new particle_path()
|
||||
// /atom doesn't have vis_contents, /turf and /atom/movable do
|
||||
var/atom/movable/lie_about_areas = parent
|
||||
lie_about_areas.vis_contents += src
|
||||
RegisterSignal(parent, COMSIG_PARENT_QDELETING, PROC_REF(parent_deleted))
|
||||
|
||||
if(particle_flags & PARTICLE_ATTACH_MOB)
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
|
||||
on_move(parent, null, NORTH)
|
||||
|
||||
/obj/effect/abstract/particle_holder/Destroy(force)
|
||||
var/atom/movable/attached = weak_attached.resolve()
|
||||
var/atom/movable/additional_attached
|
||||
if(weak_additional)
|
||||
additional_attached = weak_additional.resolve()
|
||||
if(attached)
|
||||
attached.vis_contents -= src
|
||||
UnregisterSignal(loc, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING))
|
||||
if(additional_attached)
|
||||
additional_attached.vis_contents -= src
|
||||
QDEL_NULL(particles)
|
||||
parent = null
|
||||
return ..()
|
||||
|
||||
/// Signal called when parent is moved.
|
||||
/// Non movables don't delete contents on destroy, so we gotta do this
|
||||
/obj/effect/abstract/particle_holder/proc/parent_deleted(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
qdel(src)
|
||||
|
||||
/// signal called when a parent that's been hooked into this moves
|
||||
/// does a variety of checks to ensure overrides work out properly
|
||||
/obj/effect/abstract/particle_holder/proc/on_move(atom/movable/attached, atom/oldloc, direction)
|
||||
SIGNAL_HANDLER
|
||||
if(attached.loc.type != last_attached_location_type)
|
||||
update_visual_contents(attached)
|
||||
|
||||
/// Signal called when parent is deleted.
|
||||
/obj/effect/abstract/particle_holder/proc/on_qdel(atom/movable/attached, force)
|
||||
SIGNAL_HANDLER
|
||||
qdel(src)//our parent is gone and we need to be as well
|
||||
if(!(particle_flags & PARTICLE_ATTACH_MOB))
|
||||
return
|
||||
|
||||
/**
|
||||
* Logic proc for particle holders, aka where they move.
|
||||
* Subtypes of particle holders can override this for particles that should always be turf level or do special things when repositioning.
|
||||
* This base subtype has some logic for items, as the loc of items becomes mobs very often hiding the particles.
|
||||
*/
|
||||
/obj/effect/abstract/particle_holder/proc/update_visual_contents(atom/movable/attached_to)
|
||||
// Remove old.
|
||||
if(weak_additional)
|
||||
var/atom/movable/resolved_location = weak_additional.resolve()
|
||||
if(resolved_location)
|
||||
resolved_location.vis_contents -= src
|
||||
// Add to new.
|
||||
if(isitem(attached_to) && ismob(attached_to.loc)) //special case we want to also be emitting from the mob
|
||||
var/mob/particle_mob = attached_to.loc
|
||||
last_attached_location_type = attached_to.loc
|
||||
weak_additional = WEAKREF(particle_mob)
|
||||
//remove old
|
||||
if(ismob(oldloc))
|
||||
var/mob/particle_mob = oldloc
|
||||
particle_mob.vis_contents -= src
|
||||
|
||||
// If we're sitting in a mob, we want to emit from it too, for vibes and shit
|
||||
if(ismob(attached.loc))
|
||||
var/mob/particle_mob = attached.loc
|
||||
particle_mob.vis_contents += src
|
||||
// Readd to ourselves.
|
||||
attached_to.vis_contents |= src
|
||||
|
||||
/// Sets the particles position to the passed coordinates
|
||||
/obj/effect/abstract/particle_holder/proc/set_particle_position(x = 0, y = 0, z = 0)
|
||||
particles.position = list(x, y, z)
|
||||
|
||||
@@ -14,6 +14,14 @@
|
||||
gravity = list(0, 0.95)
|
||||
grow = 0.05
|
||||
|
||||
/particles/smoke/burning
|
||||
position = list(0, 0, 0)
|
||||
|
||||
/particles/smoke/burning/small
|
||||
spawning = 1
|
||||
scale = list(0.8, 0.8)
|
||||
velocity = list(0, 0.4, 0)
|
||||
|
||||
/particles/smoke/steam
|
||||
icon_state = list("steam_1" = 1, "steam_2" = 1, "steam_3" = 2)
|
||||
fade = 1.5 SECONDS
|
||||
@@ -22,3 +30,40 @@
|
||||
spawning = 1
|
||||
velocity = list(0, 0.3, 0)
|
||||
friction = 0.25
|
||||
|
||||
/particles/smoke/steam/bad
|
||||
icon_state = list("steam_1" = 1, "smoke_1" = 1, "smoke_2" = 1, "smoke_3" = 1)
|
||||
spawning = 2
|
||||
velocity = list(0, 0.25, 0)
|
||||
|
||||
/particles/smoke/steam/mald
|
||||
icon_state = list("steam_1" = 1, "steam_2" = 1, "steam_3" = 2)
|
||||
velocity = list(0, 0.25, 0)
|
||||
lifespan = 1 SECONDS
|
||||
fade = 0.5 SECONDS
|
||||
position = list(-1, 12, 0)
|
||||
|
||||
/particles/smoke/cig
|
||||
icon_state = list("steam_1" = 2, "steam_2" = 1, "steam_3" = 1)
|
||||
count = 1
|
||||
spawning = 0.05 // used to pace it out roughly in time with breath ticks
|
||||
position = list(-6, -2, 0)
|
||||
gravity = list(0, 0.75, 0)
|
||||
lifespan = 0.75 SECONDS
|
||||
fade = 0.75 SECONDS
|
||||
velocity = list(0, 0.2, 0)
|
||||
scale = 0.5
|
||||
grow = 0.01
|
||||
friction = 0.5
|
||||
color = "#d0d0d09d"
|
||||
|
||||
/particles/smoke/cig/big
|
||||
icon_state = list("steam_1" = 1, "steam_2" = 2, "steam_3" = 2)
|
||||
gravity = list(0, 0.5, 0)
|
||||
velocity = list(0, 0.1, 0)
|
||||
lifespan = 1 SECONDS
|
||||
fade = 1 SECONDS
|
||||
grow = 0.1
|
||||
scale = 0.75
|
||||
spawning = 1
|
||||
friction = 0.75
|
||||
|
||||
@@ -5,47 +5,76 @@ GLOBAL_LIST_BOILERPLATE(all_portals, /obj/effect/portal)
|
||||
desc = "Looks unstable. Best to test it with the clown."
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "portal"
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
integrity_flags = INTEGRITY_INDESTRUCTIBLE | INTEGRITY_ACIDPROOF | INTEGRITY_FIREPROOF | INTEGRITY_LAVAPROOF
|
||||
density = TRUE // dense for receiving bumbs
|
||||
light_range = 3
|
||||
light_power = 1
|
||||
light_color = COLOR_BLUE_LIGHT
|
||||
|
||||
var/obj/item/target = null
|
||||
var/creator = null
|
||||
|
||||
/obj/effect/portal/Bumped(mob/M as mob|obj)
|
||||
if(istype(M,/mob) && !(istype(M,/mob/living)))
|
||||
return //do not send ghosts, zshadows, ai eyes, etc
|
||||
teleport(M)
|
||||
/obj/effect/portal/Move(newloc)
|
||||
for(var/T in newloc)
|
||||
if(istype(T, /obj/effect/portal))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/effect/portal/Crossed(AM as mob|obj)
|
||||
// Prevents portals spawned by jaunter/handtele from floating into space when relocated to an adjacent tile.
|
||||
/obj/effect/portal/newtonian_move()
|
||||
return TRUE
|
||||
|
||||
/obj/effect/portal/attackby(obj/item/W, mob/user, list/modifiers)
|
||||
if(user && Adjacent(user))
|
||||
teleport(user)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/portal/Bumped(atom/movable/bumper)
|
||||
teleport(bumper)
|
||||
|
||||
/obj/effect/portal/attack_hand(mob/user,)
|
||||
. = ..()
|
||||
teleport(AM)
|
||||
|
||||
/obj/effect/portal/attack_hand(mob/user, datum/event_args/actor/clickchain/e_args)
|
||||
if(istype(user) && !(istype(user,/mob/living)))
|
||||
return //do not send ghosts, zshadows, ai eyes, etc
|
||||
spawn(0)
|
||||
src.teleport(user)
|
||||
if(.)
|
||||
return
|
||||
return
|
||||
if(Adjacent(user))
|
||||
teleport(user)
|
||||
|
||||
/obj/effect/portal/attack_robot(mob/living/user)
|
||||
if(Adjacent(user))
|
||||
teleport(user)
|
||||
|
||||
/obj/effect/portal/Initialize(mapload, ...)
|
||||
. = ..()
|
||||
QDEL_IN(src, 30 SECONDS)
|
||||
|
||||
/obj/effect/portal/proc/teleport(atom/movable/M as mob|obj)
|
||||
if(istype(M, /obj/effect)) //sparks don't teleport
|
||||
/obj/effect/portal/singularity_pull(atom/singularity, current_size)
|
||||
return
|
||||
|
||||
/obj/effect/portal/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/portal/Destroy()
|
||||
target = null
|
||||
creator = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/portal/attack_ghost(mob/observer/dead/ghost)
|
||||
if(!teleport(ghost, force = TRUE))
|
||||
return ..()
|
||||
return TRUE
|
||||
|
||||
/obj/effect/portal/proc/teleport(atom/movable/moving, force = FALSE)
|
||||
if(!force && (!istype(moving) || iseffect(moving)|| (!isobj(moving) && !ismob(moving)))) //Things that shouldn't teleport.
|
||||
return
|
||||
if (M.anchored&&istype(M, /obj/vehicle/sealed/mecha))
|
||||
|
||||
var/turf/real_target = get_turf(target)
|
||||
if(!istype(real_target))
|
||||
return FALSE
|
||||
|
||||
if(!force && (!ismecha(moving) && moving.anchored))
|
||||
return
|
||||
|
||||
if (icon_state == "portal1")
|
||||
return
|
||||
if (!( target ))
|
||||
qdel(src)
|
||||
return
|
||||
if (istype(M, /atom/movable))
|
||||
do_teleport(M, target, 1) ///You will appear adjacent to the beacon
|
||||
|
||||
/obj/effect/portal/attack_ghost(mob/user)
|
||||
. = ..()
|
||||
if(target)
|
||||
user.forceMove(get_turf(target))
|
||||
do_teleport(moving, real_target, 1) ///You will appear adjacent to the beacon
|
||||
|
||||
@@ -1,3 +1,64 @@
|
||||
/proc/gibs(atom/location, var/datum/dna/MobDNA, gibber_type = /obj/effect/gibspawner/generic, var/fleshcolor, var/bloodcolor)
|
||||
new gibber_type(location,MobDNA,fleshcolor,bloodcolor)
|
||||
|
||||
/obj/effect/gibspawner
|
||||
icon_state = "gibspawner"// For the map editor
|
||||
var/list/gibtypes = list() // Assoc list of typepaths of the gib decals to spawn to amount to spawn
|
||||
var/list/gibdirections = list() // Lists of possible directions to spread each gib decal type towards.
|
||||
var/sparks = 0 //whether sparks spread on Gib()
|
||||
var/list/gibamounts = list()
|
||||
var/fleshcolor //Used for gibbed humans.
|
||||
var/bloodcolor //Used for gibbed humans.
|
||||
|
||||
/obj/effect/gibspawner/Initialize(mapload, datum/dna/MobDNA, fleshcolor, bloodcolor)
|
||||
..()
|
||||
|
||||
if(fleshcolor)
|
||||
src.fleshcolor = fleshcolor
|
||||
if(bloodcolor)
|
||||
src.bloodcolor = bloodcolor
|
||||
Gib(loc,MobDNA)
|
||||
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/gibspawner/proc/Gib(atom/location, datum/dna/MobDNA = null)
|
||||
if(gibtypes.len != gibamounts.len || gibamounts.len != gibdirections.len)
|
||||
to_chat(world, SPAN_WARNING("Gib list length mismatch!"))
|
||||
return
|
||||
|
||||
var/obj/effect/debris/cleanable/blood/gibs/gib = null
|
||||
|
||||
if(sparks)
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread()
|
||||
s.set_up(2, 1, get_turf(location)) // Not sure if it's safe to pass an arbitrary object to set_up, todo
|
||||
s.start()
|
||||
|
||||
for(var/i = 1, i<= gibtypes.len, i++)
|
||||
if(gibamounts[i])
|
||||
for(var/j = 1, j<= gibamounts[i], j++)
|
||||
var/gibType = gibtypes[i]
|
||||
gib = new gibType(location)
|
||||
|
||||
// Apply human species colouration to masks.
|
||||
if(fleshcolor)
|
||||
gib.fleshcolor = fleshcolor
|
||||
if(bloodcolor)
|
||||
gib.basecolor = bloodcolor
|
||||
|
||||
gib.update_icon()
|
||||
|
||||
gib.blood_DNA = list()
|
||||
if(MobDNA)
|
||||
gib.blood_DNA[MobDNA.unique_enzymes] = MobDNA.b_type
|
||||
else if(istype(src, /obj/effect/gibspawner/human)) // Probably a monkey
|
||||
gib.blood_DNA["Non-human DNA"] = "A+"
|
||||
if(istype(location,/turf/))
|
||||
var/list/directions = gibdirections[i]
|
||||
if(directions.len)
|
||||
gib.streak(directions)
|
||||
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/gibspawner/generic
|
||||
gibtypes = list(/obj/effect/debris/cleanable/blood/gibs,/obj/effect/debris/cleanable/blood/gibs,/obj/effect/debris/cleanable/blood/gibs/core)
|
||||
gibamounts = list(2,2,1)
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
icon_state = "arrow"
|
||||
plane = POINT_PLANE
|
||||
duration = (2.5 SECONDS)
|
||||
anchored = TRUE
|
||||
mouse_opacity = 0
|
||||
|
||||
/obj/effect/temp_visual/point/Initialize(mapload, set_invis = 0)
|
||||
. = ..()
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
icon_state = "nothing"
|
||||
layer = ABOVE_MOB_LAYER
|
||||
anchored = TRUE
|
||||
mouse_opacity = 0
|
||||
appearance_flags = 0
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
/obj/effect/projectile/singularity_pull()
|
||||
/obj/effect/projectile/singularity_pull(atom/singularity, current_size)
|
||||
return
|
||||
|
||||
/obj/effect/projectile/singularity_act()
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
//temporary visual effects
|
||||
/obj/effect/temp_visual
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "nothing"
|
||||
anchored = TRUE
|
||||
layer = ABOVE_MOB_LAYER
|
||||
mouse_opacity = 0
|
||||
var/duration = 10 //in deciseconds
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
///time, in deciseconds, that this object will exist
|
||||
var/duration = 10
|
||||
///if true, will pick a random direction when created.
|
||||
var/randomdir = TRUE
|
||||
///id of the deletion timer
|
||||
var/timerid
|
||||
|
||||
/obj/effect/temp_visual/Initialize(mapload)
|
||||
. = ..()
|
||||
if(randomdir)
|
||||
dir = pick(list(NORTH, SOUTH, EAST, WEST))
|
||||
timerid = QDEL_IN(src, duration)
|
||||
setDir(pick(GLOB.cardinal))
|
||||
|
||||
timerid = QDEL_IN_STOPPABLE(src, duration)
|
||||
|
||||
/obj/effect/temp_visual/Destroy()
|
||||
. = ..()
|
||||
@@ -22,17 +25,13 @@
|
||||
/obj/effect/temp_visual/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/temp_visual/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/temp_visual/legacy_ex_act()
|
||||
/obj/effect/temp_visual/singularity_pull(atom/singularity, current_size)
|
||||
return
|
||||
|
||||
/obj/effect/temp_visual/dir_setting
|
||||
randomdir = FALSE
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/Initialize(mapload, setDir)
|
||||
if(setDir)
|
||||
dir = setDir
|
||||
return ..()
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/Initialize(mapload, set_dir)
|
||||
if(set_dir)
|
||||
setDir(set_dir)
|
||||
. = ..()
|
||||
|
||||
Reference in New Issue
Block a user