Merge branch 'master' into upstream-merge-32161
This commit is contained in:
@@ -35,7 +35,7 @@ GLOBAL_LIST_INIT(lawlorify, list (
|
||||
BAN_CHAPEL = "This devil avoids holy ground.",
|
||||
BAN_HURTPRIEST = "The annointed clergy appear to be immune to his powers.",
|
||||
BAN_AVOIDWATER = "The devil seems to have some sort of aversion to water, though it does not appear to harm him.",
|
||||
BAN_STRIKEUNCONCIOUS = "This devil only shows interest in those who are awake.",
|
||||
BAN_STRIKEUNCONSCIOUS = "This devil only shows interest in those who are awake.",
|
||||
BAN_HURTLIZARD = "This devil will not strike a lizardman first.",
|
||||
BAN_HURTANIMAL = "This devil avoids hurting animals.",
|
||||
BANISH_WATER = "To banish the devil, you must infuse its body with holy water.",
|
||||
@@ -59,7 +59,7 @@ GLOBAL_LIST_INIT(lawlorify, list (
|
||||
BAN_CHAPEL = "You must never attempt to enter the chapel.",
|
||||
BAN_HURTPRIEST = "You must never attack a priest.",
|
||||
BAN_AVOIDWATER = "You must never willingly touch a wet surface.",
|
||||
BAN_STRIKEUNCONCIOUS = "You must never strike an unconscious person.",
|
||||
BAN_STRIKEUNCONSCIOUS = "You must never strike an unconscious person.",
|
||||
BAN_HURTLIZARD = "You must never harm a lizardman outside of self defense.",
|
||||
BAN_HURTANIMAL = "You must never harm a non-sentient creature or robot outside of self defense.",
|
||||
BANE_SILVER = "Silver, in all of its forms shall be your downfall.",
|
||||
@@ -148,7 +148,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
|
||||
return pick(OBLIGATION_FOOD, OBLIGATION_FIDDLE, OBLIGATION_DANCEOFF, OBLIGATION_GREET, OBLIGATION_PRESENCEKNOWN, OBLIGATION_SAYNAME, OBLIGATION_ANNOUNCEKILL, OBLIGATION_ANSWERTONAME)
|
||||
|
||||
/proc/randomdevilban()
|
||||
return pick(BAN_HURTWOMAN, BAN_CHAPEL, BAN_HURTPRIEST, BAN_AVOIDWATER, BAN_STRIKEUNCONCIOUS, BAN_HURTLIZARD, BAN_HURTANIMAL)
|
||||
return pick(BAN_HURTWOMAN, BAN_CHAPEL, BAN_HURTPRIEST, BAN_AVOIDWATER, BAN_STRIKEUNCONSCIOUS, BAN_HURTLIZARD, BAN_HURTANIMAL)
|
||||
|
||||
/proc/randomdevilbane()
|
||||
return pick(BANE_SALT, BANE_LIGHT, BANE_IRON, BANE_WHITECLOTHES, BANE_SILVER, BANE_HARVEST, BANE_TOOLBOX)
|
||||
|
||||
@@ -26,7 +26,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
|
||||
|
||||
### Defines
|
||||
|
||||
1. `COMPONENT_INCOMPATIBLE` Return this from `/datum/component/Initialize` to have the component be deleted if it's applied to an incorrect type. `parent` must not be modified if this is to be returned.
|
||||
1. `COMPONENT_INCOMPATIBLE` Return this from `/datum/component/Initialize` or `datum/component/OnTransfer` to have the component be deleted if it's applied to an incorrect type. `parent` must not be modified if this is to be returned.
|
||||
|
||||
### Vars
|
||||
|
||||
@@ -42,12 +42,13 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
|
||||
* `COMPONENT_DUPE_UNIQUE`: New component will be deleted, old component will first have `/datum/component/proc/InheritComponent(datum/component/new, TRUE)` on it
|
||||
1. `/datum/component/var/dupe_type` (protected, type)
|
||||
* Definition of a duplicate component type
|
||||
* `null` means exact match on `type`
|
||||
* `null` means exact match on `type` (default)
|
||||
* Any other type means that and all subtypes
|
||||
1. `/datum/component/var/list/signal_procs` (private)
|
||||
* Associated lazy list of signals -> `/datum/callback`s that will be run when the parent datum recieves that signal
|
||||
1. `/datum/component/var/datum/parent` (protected, read-only)
|
||||
* The datum this component belongs to
|
||||
* Never `null` in child procs
|
||||
|
||||
### Procs
|
||||
|
||||
@@ -72,7 +73,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
|
||||
* Will only be called if a component's callback returns `TRUE`
|
||||
1. `/datum/proc/TakeComponent(datum/component/C)` (public, final)
|
||||
* Properly transfers ownership of a component from one datum to another
|
||||
* Singals `COMSIG_COMPONENT_REMOVING` on the parent
|
||||
* Signals `COMSIG_COMPONENT_REMOVING` on the parent
|
||||
* Called on the datum you want to own the component with another datum's component
|
||||
1. `/datum/proc/SendSignal(signal, ...)` (public, final)
|
||||
* Call to send a signal to the components of the target datum
|
||||
@@ -86,9 +87,11 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
|
||||
* Signals will not be recieved while this function is running
|
||||
* Component may be deleted after this function completes without being attached
|
||||
* Do not call `qdel(src)` from this function
|
||||
1. `/datum/component/Destroy()` (virtual, no-sleep)
|
||||
1. `/datum/component/Destroy(force(bool), silent(bool))` (virtual, no-sleep)
|
||||
* Sends the `COMSIG_COMPONENT_REMOVING` signal to the parent datum if the `parent` isn't being qdeleted
|
||||
* Properly removes the component from `parent` and cleans up references
|
||||
* Setting `force` makes it not check for and remove the component from the parent
|
||||
* Setting `silent` deletes the component without sending a `COMSIG_COMPONENT_REMOVING` signal
|
||||
1. `/datum/component/proc/InheritComponent(datum/component/C, i_am_original(boolean))` (abstract, no-sleep)
|
||||
* Called on a component when a component of the same type was added to the same parent
|
||||
* See `/datum/component/var/dupe_mode`
|
||||
@@ -96,10 +99,13 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
|
||||
1. `/datum/component/proc/AfterComponentActivated()` (abstract, async)
|
||||
* Called on a component that was activated after it's `parent`'s `ComponentActivated()` is called
|
||||
1. `/datum/component/proc/OnTransfer(datum/new_parent)` (abstract, no-sleep)
|
||||
* Called before the new `parent` is assigned in `TakeComponent()`, after the remove signal, before the added signal
|
||||
* Called before `new_parent` is assigned to `parent` in `TakeComponent()`
|
||||
* Allows the component to react to ownership transfers
|
||||
1. `/datum/component/proc/_RemoveNoSignal()` (private, final)
|
||||
* Internal, clears the parent var and removes the component from the parents component list
|
||||
1. `/datum/component/proc/_RemoveFromParent()` (private, final)
|
||||
* Clears `parent` and removes the component from it's component list
|
||||
1. `/datum/component/proc/_CheckDupesAndJoinParent` (private, final)
|
||||
* Tries to add the component to it's `parent`s `datum_components` list
|
||||
* Properly handles duplicate situations based on the `dupe_mode` var
|
||||
1. `/datum/component/proc/RegisterSignal(signal(string/list of strings), proc_ref(type), override(boolean))` (protected, final) (Consider removing for performance gainz)
|
||||
* If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments
|
||||
* Makes a component listen for the specified `signal` on it's `parent` datum.
|
||||
|
||||
@@ -6,35 +6,45 @@
|
||||
var/datum/parent
|
||||
|
||||
/datum/component/New(datum/P, ...)
|
||||
if(type == /datum/component)
|
||||
qdel(src)
|
||||
CRASH("[type] instantiated!")
|
||||
|
||||
parent = P
|
||||
var/list/arguments = args.Copy()
|
||||
arguments.Cut(1, 2)
|
||||
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
|
||||
parent = null
|
||||
qdel(src)
|
||||
qdel(src, TRUE, TRUE)
|
||||
return
|
||||
|
||||
_CheckDupesAndJoinParent(P)
|
||||
|
||||
/datum/component/proc/_CheckDupesAndJoinParent()
|
||||
var/datum/P = parent
|
||||
var/dm = dupe_mode
|
||||
|
||||
var/datum/component/old
|
||||
if(dm != COMPONENT_DUPE_ALLOWED)
|
||||
var/dt = dupe_type
|
||||
var/datum/component/old
|
||||
if(!dt)
|
||||
old = P.GetExactComponent(type)
|
||||
else
|
||||
old = P.GetComponent(dt)
|
||||
if(old)
|
||||
//One or the other has to die
|
||||
switch(dm)
|
||||
if(COMPONENT_DUPE_UNIQUE)
|
||||
old.InheritComponent(src, TRUE)
|
||||
parent = null //prevent COMPONENT_REMOVING signal
|
||||
qdel(src)
|
||||
qdel(src, TRUE, TRUE)
|
||||
return
|
||||
if(COMPONENT_DUPE_HIGHLANDER)
|
||||
InheritComponent(old, FALSE)
|
||||
qdel(old)
|
||||
|
||||
//let the others know
|
||||
P.SendSignal(COMSIG_COMPONENT_ADDED, src)
|
||||
qdel(old, FALSE, TRUE)
|
||||
|
||||
//provided we didn't eat someone
|
||||
if(!old)
|
||||
//let the others know
|
||||
P.SendSignal(COMSIG_COMPONENT_ADDED, src)
|
||||
|
||||
//lazy init the parent's dc list
|
||||
var/list/dc = P.datum_components
|
||||
@@ -47,7 +57,7 @@
|
||||
var/test = dc[I]
|
||||
if(test) //already another component of this type here
|
||||
var/list/components_of_type
|
||||
if(!islist(test))
|
||||
if(!length(test))
|
||||
components_of_type = list(test)
|
||||
dc[I] = components_of_type
|
||||
else
|
||||
@@ -70,35 +80,34 @@
|
||||
/datum/component/proc/Initialize(...)
|
||||
return
|
||||
|
||||
/datum/component/Destroy()
|
||||
/datum/component/Destroy(force=FALSE, silent=FALSE)
|
||||
enabled = FALSE
|
||||
var/datum/P = parent
|
||||
if(P)
|
||||
_RemoveNoSignal()
|
||||
if(!force)
|
||||
_RemoveFromParent()
|
||||
if(!silent)
|
||||
P.SendSignal(COMSIG_COMPONENT_REMOVING, src)
|
||||
parent = null
|
||||
LAZYCLEARLIST(signal_procs)
|
||||
return ..()
|
||||
|
||||
/datum/component/proc/_RemoveNoSignal()
|
||||
/datum/component/proc/_RemoveFromParent()
|
||||
var/datum/P = parent
|
||||
if(P)
|
||||
var/list/dc = P.datum_components
|
||||
var/our_type = type
|
||||
for(var/I in _GetInverseTypeList(our_type))
|
||||
var/list/components_of_type = dc[I]
|
||||
if(islist(components_of_type)) //
|
||||
var/list/subtracted = components_of_type - src
|
||||
if(subtracted.len == 1) //only 1 guy left
|
||||
dc[I] = subtracted[1] //make him special
|
||||
else
|
||||
dc[I] = subtracted
|
||||
else //just us
|
||||
dc -= I
|
||||
if(!dc.len)
|
||||
P.datum_components = null
|
||||
parent = null
|
||||
var/list/dc = P.datum_components
|
||||
for(var/I in _GetInverseTypeList())
|
||||
var/list/components_of_type = dc[I]
|
||||
if(length(components_of_type)) //
|
||||
var/list/subtracted = components_of_type - src
|
||||
if(subtracted.len == 1) //only 1 guy left
|
||||
dc[I] = subtracted[1] //make him special
|
||||
else
|
||||
dc[I] = subtracted
|
||||
else //just us
|
||||
dc -= I
|
||||
if(!dc.len)
|
||||
P.datum_components = null
|
||||
|
||||
/datum/component/proc/RegisterSignal(sig_type_or_types, proc_on_self, override = FALSE)
|
||||
/datum/component/proc/RegisterSignal(sig_type_or_types, proc_or_callback, override = FALSE)
|
||||
if(QDELETED(src))
|
||||
return
|
||||
var/list/procs = signal_procs
|
||||
@@ -112,8 +121,10 @@
|
||||
. = procs[sig_type]
|
||||
if(.)
|
||||
stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
|
||||
|
||||
procs[sig_type] = CALLBACK(src, proc_on_self)
|
||||
|
||||
if(!istype(proc_or_callback, /datum/callback)) //if it wasnt a callback before, it is now
|
||||
proc_or_callback = CALLBACK(src, proc_or_callback)
|
||||
procs[sig_type] = proc_or_callback
|
||||
|
||||
/datum/component/proc/InheritComponent(datum/component/C, i_am_original)
|
||||
return
|
||||
@@ -125,8 +136,15 @@
|
||||
set waitfor = FALSE
|
||||
return
|
||||
|
||||
/datum/component/proc/_GetInverseTypeList(current_type)
|
||||
. = list(current_type)
|
||||
/datum/component/proc/_GetInverseTypeList(our_type = type)
|
||||
#if DM_VERSION > 511
|
||||
#warning Remove this hack for http://www.byond.com/forum/?post=73469
|
||||
#endif
|
||||
set invisibility = 101
|
||||
//we can do this one simple trick
|
||||
var/current_type = parent_type
|
||||
. = list(our_type, current_type)
|
||||
//and since most components are root level + 1, this won't even have to run
|
||||
while (current_type != /datum/component)
|
||||
current_type = type2parent(current_type)
|
||||
. += current_type
|
||||
@@ -138,7 +156,7 @@
|
||||
var/list/arguments = args.Copy()
|
||||
arguments.Cut(1, 2)
|
||||
var/target = comps[/datum/component]
|
||||
if(!islist(target))
|
||||
if(!length(target))
|
||||
var/datum/component/C = target
|
||||
if(!C.enabled)
|
||||
return FALSE
|
||||
@@ -174,7 +192,7 @@
|
||||
if(!dc)
|
||||
return null
|
||||
. = dc[c_type]
|
||||
if(islist(.))
|
||||
if(length(.))
|
||||
return .[1]
|
||||
|
||||
/datum/proc/GetExactComponent(c_type)
|
||||
@@ -183,7 +201,7 @@
|
||||
return null
|
||||
var/datum/component/C = dc[c_type]
|
||||
if(C)
|
||||
if(islist(C))
|
||||
if(length(C))
|
||||
C = C[1]
|
||||
if(C.type == c_type)
|
||||
return C
|
||||
@@ -194,14 +212,14 @@
|
||||
if(!dc)
|
||||
return null
|
||||
. = dc[c_type]
|
||||
if(!islist(.))
|
||||
if(!length(.))
|
||||
return list(.)
|
||||
|
||||
/datum/proc/AddComponent(new_type, ...)
|
||||
var/nt = new_type
|
||||
args[1] = src
|
||||
var/datum/component/C = new nt(arglist(args))
|
||||
return QDELING(C) ? GetComponent(new_type) : C
|
||||
return QDELING(C) ? GetExactComponent(new_type) : C
|
||||
|
||||
/datum/proc/LoadComponent(component_type, ...)
|
||||
. = GetComponent(component_type)
|
||||
@@ -213,13 +231,15 @@
|
||||
return
|
||||
var/datum/helicopter = C.parent
|
||||
if(helicopter == src)
|
||||
//wat
|
||||
//if we're taking to the same thing no need for anything
|
||||
return
|
||||
C._RemoveNoSignal()
|
||||
if(C.OnTransfer(src) == COMPONENT_INCOMPATIBLE)
|
||||
qdel(C)
|
||||
return
|
||||
C._RemoveFromParent()
|
||||
helicopter.SendSignal(COMSIG_COMPONENT_REMOVING, C)
|
||||
C.OnTransfer(src)
|
||||
C.parent = src
|
||||
SendSignal(COMSIG_COMPONENT_ADDED, C)
|
||||
C._CheckDupesAndJoinParent()
|
||||
|
||||
/datum/proc/TransferComponents(datum/target)
|
||||
var/list/dc = datum_components
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/datum/component/decal
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
|
||||
var/cleanable
|
||||
var/mutable_appearance/pic
|
||||
|
||||
/datum/component/decal/Initialize(_icon, _icon_state, _dir, _cleanable=CLEAN_GOD, _color, _layer=TURF_LAYER)
|
||||
if(!isatom(parent) || !_icon || !_icon_state)
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("A turf decal was applied incorrectly to [parent.type]: icon:[_icon ? _icon : "none"] icon_state:[_icon_state ? _icon_state : "none"]")
|
||||
|
||||
// It has to be made from an image or dir breaks because of a byond bug
|
||||
var/temp_image = image(_icon, null, _icon_state, _layer, _dir)
|
||||
pic = new(temp_image)
|
||||
pic.color = _color
|
||||
|
||||
cleanable = _cleanable
|
||||
|
||||
apply()
|
||||
|
||||
if(_dir) // If no dir is assigned at start then it follows the atom's dir
|
||||
RegisterSignal(COMSIG_ATOM_DIR_CHANGE, .proc/rotate_react)
|
||||
if(_cleanable)
|
||||
RegisterSignal(COMSIG_COMPONENT_CLEAN_ACT, .proc/clean_react)
|
||||
|
||||
/datum/component/decal/Destroy()
|
||||
remove()
|
||||
return ..()
|
||||
|
||||
/datum/component/decal/OnTransfer(atom/thing)
|
||||
remove()
|
||||
remove(thing)
|
||||
apply(thing)
|
||||
|
||||
/datum/component/decal/proc/apply(atom/thing)
|
||||
var/atom/master = thing || parent
|
||||
master.add_overlay(pic, TRUE)
|
||||
|
||||
/datum/component/decal/proc/remove(atom/thing)
|
||||
var/atom/master = thing || parent
|
||||
master.cut_overlay(pic, TRUE)
|
||||
|
||||
/datum/component/decal/proc/rotate_react(old_dir, new_dir)
|
||||
if(old_dir == new_dir)
|
||||
return
|
||||
remove()
|
||||
var/rotation = SimplifyDegrees(dir2angle(new_dir)-dir2angle(old_dir))
|
||||
pic.dir = turn(pic.dir, rotation)
|
||||
apply()
|
||||
|
||||
/datum/component/decal/proc/clean_react(strength)
|
||||
if(strength >= cleanable)
|
||||
qdel(src)
|
||||
@@ -37,11 +37,15 @@
|
||||
return ..()
|
||||
|
||||
/datum/component/radioactive/process()
|
||||
if(hl3_release_date && prob(50))
|
||||
radiation_pulse(parent, strength, RAD_DISTANCE_COEFFICIENT*2, FALSE, can_contaminate)
|
||||
strength -= strength / hl3_release_date
|
||||
if(strength <= RAD_BACKGROUND_RADIATION)
|
||||
qdel(src)
|
||||
if(!prob(50))
|
||||
return
|
||||
radiation_pulse(parent, strength, RAD_DISTANCE_COEFFICIENT*2, FALSE, can_contaminate)
|
||||
|
||||
if(!hl3_release_date)
|
||||
return
|
||||
strength -= strength / hl3_release_date
|
||||
if(strength <= RAD_BACKGROUND_RADIATION)
|
||||
return PROCESS_KILL
|
||||
|
||||
/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original)
|
||||
if(!i_am_original)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/datum/component/redirect
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
|
||||
/datum/component/redirect/Initialize(list/signals, datum/callback/_callback)
|
||||
//It's not our job to verify the right signals are registered here, just do it.
|
||||
if(!LAZYLEN(signals) || !istype(_callback))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("A redirection component was initialized with incorrect args.")
|
||||
RegisterSignal(signals, _callback)
|
||||
@@ -0,0 +1,60 @@
|
||||
/datum/component/spooky
|
||||
var/too_spooky = TRUE //will it spawn a new instrument?
|
||||
|
||||
/datum/component/spooky/Initialize()
|
||||
RegisterSignal(COMSIG_ITEM_ATTACK, .proc/spectral_attack)
|
||||
|
||||
/datum/component/spooky/proc/spectral_attack(mob/living/carbon/C, mob/user)
|
||||
if(ishuman(user)) //this weapon wasn't meant for mortals.
|
||||
var/mob/living/carbon/human/U = user
|
||||
if(!istype(U.dna.species, /datum/species/skeleton))
|
||||
U.adjustStaminaLoss(35) //Extra Damage
|
||||
U.Jitter(35)
|
||||
U.stuttering = 20
|
||||
if(U.getStaminaLoss() > 95)
|
||||
to_chat(U, "<font color ='red', size ='4'><B>Your ears weren't meant for this spectral sound.</B></font>")
|
||||
spectral_change(U)
|
||||
return
|
||||
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(istype(H.dna.species, /datum/species/skeleton))
|
||||
return ..() //undeads are unaffected by the spook-pocalypse.
|
||||
if(istype(H.dna.species, /datum/species/zombie))
|
||||
H.adjustStaminaLoss(25)
|
||||
H.Knockdown(15) //zombies can't resist the doot
|
||||
C.Jitter(35)
|
||||
C.stuttering = 20
|
||||
if((!istype(H.dna.species, /datum/species/skeleton)) && (!istype(H.dna.species, /datum/species/golem)) && (!istype(H.dna.species, /datum/species/android)) && (!istype(H.dna.species, /datum/species/jelly)))
|
||||
C.adjustStaminaLoss(25) //boneless humanoids don't lose the will to live
|
||||
to_chat(C, "<font color='red' size='4'><B>DOOT</B></span>")
|
||||
spectral_change(H)
|
||||
|
||||
else //the sound will spook monkeys.
|
||||
C.Jitter(15)
|
||||
C.stuttering = 20
|
||||
|
||||
/datum/component/spooky/proc/spectral_change(mob/living/carbon/human/H, mob/user)
|
||||
if((H.getStaminaLoss() > 95) && (!istype(H.dna.species, /datum/species/skeleton)) && (!istype(H.dna.species, /datum/species/golem)) && (!istype(H.dna.species, /datum/species/android)) && (!istype(H.dna.species, /datum/species/jelly)))
|
||||
H.Knockdown(20)
|
||||
H.set_species(/datum/species/skeleton)
|
||||
H.visible_message("<span class='warning'>[H] has given up on life as a mortal.</span>")
|
||||
var/T = get_turf(H)
|
||||
if(too_spooky)
|
||||
if(prob(30))
|
||||
new/obj/item/device/instrument/saxophone/spectral(T)
|
||||
else if(prob(30))
|
||||
new/obj/item/device/instrument/trumpet/spectral(T)
|
||||
else if(prob(30))
|
||||
new/obj/item/device/instrument/trombone/spectral(T)
|
||||
else
|
||||
to_chat(H, "The spooky gods forgot to ship your instrument. Better luck next unlife.")
|
||||
to_chat(H, "<B>You are the spooky skeleton!</B>")
|
||||
to_chat(H, "A new life and identity has begun. Help your fellow skeletons into bringing out the spooky-pocalypse. You haven't forgotten your past life, and are still beholden to past loyalties.")
|
||||
change_name(H) //time for a new name!
|
||||
|
||||
/datum/component/spooky/proc/change_name(mob/living/carbon/human/H)
|
||||
var/t = stripped_input(H, "Enter your new skeleton name", H.real_name, null, MAX_NAME_LEN)
|
||||
if(!t)
|
||||
t = "spooky skeleton"
|
||||
H.fully_replace_character_name(H.real_name, t)
|
||||
@@ -0,0 +1,51 @@
|
||||
/datum/component/turf_decal
|
||||
var/dir
|
||||
var/icon
|
||||
var/icon_state
|
||||
var/layer
|
||||
var/group
|
||||
|
||||
/datum/component/turf_decal/Initialize(_dir, _icon, _icon_state, _layer=TURF_DECAL_LAYER, _group=TURF_DECAL_PAINT)
|
||||
if(!isturf(parent) || !_icon || !_icon_state)
|
||||
WARNING("A turf decal was applied incorrectly to [parent]: icon:[_icon ? _icon : "none"] icon_state:[_icon_state ? _icon_state : "none"]")
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
dir = _dir
|
||||
icon = _icon
|
||||
icon_state = _icon_state
|
||||
layer = _layer
|
||||
group = _group
|
||||
apply_decal()
|
||||
|
||||
RegisterSignal(COMSIG_ATOM_ROTATE, .proc/rotate_react)
|
||||
RegisterSignal(COMSIG_COMPONENT_CLEAN_ACT, .proc/clean_react)
|
||||
|
||||
/datum/component/turf_decal/Destroy()
|
||||
remove_decal()
|
||||
return ..()
|
||||
|
||||
/datum/component/turf_decal/OnTransfer(turf/newT)
|
||||
remove_decal()
|
||||
remove_decal(newT)
|
||||
apply_decal(newT)
|
||||
|
||||
/datum/component/turf_decal/proc/get_decal()
|
||||
return image(icon, null, icon_state, layer, dir)
|
||||
|
||||
/datum/component/turf_decal/proc/apply_decal(turf/overT)
|
||||
var/turf/master = overT || parent
|
||||
master.add_decal(get_decal(), group)
|
||||
|
||||
/datum/component/turf_decal/proc/remove_decal(turf/overT)
|
||||
var/turf/master = overT || parent
|
||||
master.remove_decal(group)
|
||||
|
||||
/datum/component/turf_decal/proc/rotate_react(rotation, params)
|
||||
if(params & ROTATE_DIR)
|
||||
dir = angle2dir(rotation+dir2angle(dir))
|
||||
remove_decal()
|
||||
apply_decal()
|
||||
|
||||
/datum/component/turf_decal/proc/clean_react(strength)
|
||||
if(strength >= CLEAN_IMPRESSIVE)
|
||||
qdel(src)
|
||||
@@ -13,7 +13,7 @@
|
||||
// Default implementation of clean-up code.
|
||||
// This should be overridden to remove all references pointing to the object being destroyed.
|
||||
// Return the appropriate QDEL_HINT; in most cases this is QDEL_HINT_QUEUE.
|
||||
/datum/proc/Destroy(force=FALSE)
|
||||
/datum/proc/Destroy(force=FALSE, ...)
|
||||
tag = null
|
||||
var/list/timers = active_timers
|
||||
active_timers = null
|
||||
@@ -25,14 +25,12 @@
|
||||
var/list/dc = datum_components
|
||||
if(dc)
|
||||
var/all_components = dc[/datum/component]
|
||||
if(islist(all_components))
|
||||
if(length(all_components))
|
||||
for(var/I in all_components)
|
||||
var/datum/component/C = I
|
||||
C._RemoveNoSignal()
|
||||
qdel(C)
|
||||
qdel(C, FALSE, TRUE)
|
||||
else
|
||||
var/datum/component/C = all_components
|
||||
C._RemoveNoSignal()
|
||||
qdel(C)
|
||||
qdel(C, FALSE, TRUE)
|
||||
dc.Cut()
|
||||
return QDEL_HINT_QUEUE
|
||||
|
||||
+19
-17
@@ -1,5 +1,6 @@
|
||||
#define EXPLOSION_THROW_SPEED 4
|
||||
#define REEBE_HUGBOX_COEFFICIENT 0.5
|
||||
#define CITYOFCOGS_CAP_MULTIPLIER 0.5
|
||||
#define MINING_CAP_MULTIPLIER 3
|
||||
|
||||
GLOBAL_LIST_EMPTY(explosions)
|
||||
//Against my better judgement, I will return the explosion datum
|
||||
@@ -53,21 +54,21 @@ GLOBAL_LIST_EMPTY(explosions)
|
||||
var/orig_dev_range = devastation_range
|
||||
var/orig_heavy_range = heavy_impact_range
|
||||
var/orig_light_range = light_impact_range
|
||||
|
||||
if(!ignorecap && epicenter.z != ZLEVEL_MINING)
|
||||
//Clamp all values to MAX_EXPLOSION_RANGE
|
||||
devastation_range = min(GLOB.MAX_EX_DEVESTATION_RANGE, devastation_range)
|
||||
heavy_impact_range = min(GLOB.MAX_EX_HEAVY_RANGE, heavy_impact_range)
|
||||
light_impact_range = min(GLOB.MAX_EX_LIGHT_RANGE, light_impact_range)
|
||||
flash_range = min(GLOB.MAX_EX_FLASH_RANGE, flash_range)
|
||||
flame_range = min(GLOB.MAX_EX_FLAME_RANGE, flame_range)
|
||||
|
||||
if(!ignorecap && epicenter.z == ZLEVEL_CITYOFCOGS)
|
||||
devastation_range = min(GLOB.MAX_EX_DEVESTATION_RANGE * REEBE_HUGBOX_COEFFICIENT, devastation_range)
|
||||
heavy_impact_range = min(GLOB.MAX_EX_HEAVY_RANGE * REEBE_HUGBOX_COEFFICIENT, heavy_impact_range)
|
||||
light_impact_range = min(GLOB.MAX_EX_LIGHT_RANGE * REEBE_HUGBOX_COEFFICIENT, light_impact_range)
|
||||
flash_range = min(GLOB.MAX_EX_FLASH_RANGE * REEBE_HUGBOX_COEFFICIENT, flash_range)
|
||||
flame_range = min(GLOB.MAX_EX_FLAME_RANGE * REEBE_HUGBOX_COEFFICIENT, flame_range)
|
||||
|
||||
//Zlevel specific bomb cap multiplier
|
||||
var/cap_multiplier = 1
|
||||
switch(epicenter.z)
|
||||
if(ZLEVEL_CITYOFCOGS)
|
||||
cap_multiplier = CITYOFCOGS_CAP_MULTIPLIER
|
||||
if(ZLEVEL_MINING)
|
||||
cap_multiplier = MINING_CAP_MULTIPLIER
|
||||
|
||||
if(!ignorecap)
|
||||
devastation_range = min(GLOB.MAX_EX_DEVESTATION_RANGE * cap_multiplier, devastation_range)
|
||||
heavy_impact_range = min(GLOB.MAX_EX_HEAVY_RANGE * cap_multiplier, heavy_impact_range)
|
||||
light_impact_range = min(GLOB.MAX_EX_LIGHT_RANGE * cap_multiplier, light_impact_range)
|
||||
flash_range = min(GLOB.MAX_EX_FLASH_RANGE * cap_multiplier, flash_range)
|
||||
flame_range = min(GLOB.MAX_EX_FLAME_RANGE * cap_multiplier, flame_range)
|
||||
|
||||
//DO NOT REMOVE THIS STOPLAG, IT BREAKS THINGS
|
||||
//not sleeping causes us to ex_act() the thing that triggered the explosion
|
||||
@@ -397,4 +398,5 @@ GLOBAL_LIST_EMPTY(explosions)
|
||||
// 5 explosion power is a (0, 1, 3) explosion.
|
||||
// 1 explosion power is a (0, 0, 1) explosion.
|
||||
|
||||
#undef REEBE_HUGBOX_COEFFICIENT
|
||||
#undef CITYOFCOGS_CAP_MULTIPLIER
|
||||
#undef MINING_CAP_MULTIPLIER
|
||||
|
||||
@@ -152,13 +152,14 @@
|
||||
if(istype(teleatom, /obj/item/storage/backpack/holding))
|
||||
precision = rand(1,100)
|
||||
|
||||
var/list/bagholding = teleatom.search_contents_for(/obj/item/storage/backpack/holding)
|
||||
var/static/list/bag_cache = typecacheof(/obj/item/storage/backpack/holding)
|
||||
var/list/bagholding = typecache_filter_list(teleatom.GetAllContents(), bag_cache)
|
||||
if(bagholding.len)
|
||||
precision = max(rand(1,100)*bagholding.len,100)
|
||||
if(isliving(teleatom))
|
||||
var/mob/living/MM = teleatom
|
||||
to_chat(MM, "<span class='warning'>The bluespace interface on your bag of holding interferes with the teleport!</span>")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
// Safe location finder
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/datum/looping_sound/active_outside_ashstorm
|
||||
mid_sounds = list(
|
||||
'sound/weather/ashstorm/outside/active_mid1.ogg'=1,
|
||||
'sound/weather/ashstorm/outside/active_mid1.ogg'=1,
|
||||
'sound/weather/ashstorm/outside/active_mid1.ogg'=1
|
||||
)
|
||||
mid_length = 80
|
||||
start_sound = 'sound/weather/ashstorm/outside/active_start.ogg'
|
||||
start_length = 130
|
||||
end_sound = 'sound/weather/ashstorm/outside/active_end.ogg'
|
||||
volume = 80
|
||||
|
||||
/datum/looping_sound/active_inside_ashstorm
|
||||
mid_sounds = list(
|
||||
'sound/weather/ashstorm/inside/active_mid1.ogg'=1,
|
||||
'sound/weather/ashstorm/inside/active_mid2.ogg'=1,
|
||||
'sound/weather/ashstorm/inside/active_mid3.ogg'=1
|
||||
)
|
||||
mid_length = 80
|
||||
start_sound = 'sound/weather/ashstorm/inside/active_start.ogg'
|
||||
start_length = 130
|
||||
end_sound = 'sound/weather/ashstorm/inside/active_end.ogg'
|
||||
volume = 80
|
||||
|
||||
/datum/looping_sound/weak_outside_ashstorm
|
||||
mid_sounds = list(
|
||||
'sound/weather/ashstorm/outside/weak_mid1.ogg'=1,
|
||||
'sound/weather/ashstorm/outside/weak_mid2.ogg'=1,
|
||||
'sound/weather/ashstorm/outside/weak_mid3.ogg'=1
|
||||
)
|
||||
mid_length = 80
|
||||
start_sound = 'sound/weather/ashstorm/outside/weak_start.ogg'
|
||||
start_length = 130
|
||||
end_sound = 'sound/weather/ashstorm/outside/weak_end.ogg'
|
||||
volume = 50
|
||||
|
||||
/datum/looping_sound/weak_inside_ashstorm
|
||||
mid_sounds = list(
|
||||
'sound/weather/ashstorm/inside/weak_mid1.ogg'=1,
|
||||
'sound/weather/ashstorm/inside/weak_mid2.ogg'=1,
|
||||
'sound/weather/ashstorm/inside/weak_mid3.ogg'=1
|
||||
)
|
||||
mid_length = 80
|
||||
start_sound = 'sound/weather/ashstorm/inside/weak_start.ogg'
|
||||
start_length = 130
|
||||
end_sound = 'sound/weather/ashstorm/inside/weak_end.ogg'
|
||||
volume = 50
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
//Order matters here.
|
||||
var/list/transition_config = list(CENTCOM = SELFLOOPING,
|
||||
CITY_OF_COGS = SELFLOOPING,
|
||||
MAIN_STATION = CROSSLINKED,
|
||||
EMPTY_AREA_1 = CROSSLINKED,
|
||||
EMPTY_AREA_2 = CROSSLINKED,
|
||||
@@ -69,12 +68,11 @@
|
||||
map_path = json["map_path"]
|
||||
map_file = json["map_file"]
|
||||
|
||||
minetype = json["minetype"]
|
||||
allow_custom_shuttles = json["allow_custom_shuttles"]
|
||||
minetype = json["minetype"] || minetype
|
||||
allow_custom_shuttles = json["allow_custom_shuttles"] == TRUE
|
||||
|
||||
var/list/jtcl = json["transition_config"]
|
||||
|
||||
if(jtcl != "default")
|
||||
var/jtcl = json["transition_config"]
|
||||
if(jtcl && jtcl != "default")
|
||||
transition_config.Cut()
|
||||
|
||||
for(var/I in jtcl)
|
||||
@@ -87,25 +85,22 @@
|
||||
CHECK_EXISTS("map_name")
|
||||
CHECK_EXISTS("map_path")
|
||||
CHECK_EXISTS("map_file")
|
||||
CHECK_EXISTS("minetype")
|
||||
CHECK_EXISTS("transition_config")
|
||||
CHECK_EXISTS("allow_custom_shuttles")
|
||||
|
||||
var/path = GetFullMapPath(json["map_path"], json["map_file"])
|
||||
if(!fexists(path))
|
||||
log_world("Map file ([path]) does not exist!")
|
||||
return
|
||||
|
||||
if(json["transition_config"] != "default")
|
||||
if(!islist(json["transition_config"]))
|
||||
var/tc = json["transition_config"]
|
||||
if(tc != null && tc != "default")
|
||||
if(!islist(tc))
|
||||
log_world("transition_config is not a list!")
|
||||
return
|
||||
|
||||
var/list/jtcl = json["transition_config"]
|
||||
for(var/I in jtcl)
|
||||
for(var/I in tc)
|
||||
if(isnull(TransitionStringToEnum(I)))
|
||||
log_world("Invalid transition_config option: [I]!")
|
||||
if(isnull(TransitionStringToEnum(jtcl[I])))
|
||||
if(isnull(TransitionStringToEnum(tc[I])))
|
||||
log_world("Invalid transition_config option: [I]!")
|
||||
|
||||
return TRUE
|
||||
|
||||
+1
-1
@@ -1039,7 +1039,7 @@
|
||||
remove_wizard()
|
||||
log_admin("[key_name(usr)] has de-wizard'ed [current].")
|
||||
if("wizard")
|
||||
if(has_antag_datum(/datum/antagonist/wizard))
|
||||
if(!has_antag_datum(/datum/antagonist/wizard))
|
||||
special_role = "Wizard"
|
||||
add_antag_datum(/datum/antagonist/wizard)
|
||||
message_admins("[key_name_admin(usr)] has wizard'ed [current].")
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
//these are real globals so you can use profiling to profile early world init stuff.
|
||||
GLOBAL_REAL_VAR(list/PROFILE_STORE)
|
||||
GLOBAL_REAL_VAR(PROFILE_LINE)
|
||||
GLOBAL_REAL_VAR(PROFILE_FILE)
|
||||
GLOBAL_REAL_VAR(PROFILE_SLEEPCHECK)
|
||||
GLOBAL_REAL_VAR(PROFILE_TIME)
|
||||
|
||||
|
||||
/proc/profile_show(user, sort = /proc/cmp_profile_avg_time_dsc)
|
||||
sortTim(PROFILE_STORE, sort, TRUE)
|
||||
|
||||
var/list/lines = list()
|
||||
|
||||
for (var/entry in PROFILE_STORE)
|
||||
var/list/data = PROFILE_STORE[entry]
|
||||
lines += "[entry] => [num2text(data[PROFILE_ITEM_TIME], 10)]ms ([data[PROFILE_ITEM_COUNT]]) (avg:[num2text(data[PROFILE_ITEM_TIME]/(data[PROFILE_ITEM_COUNT] || 1), 99)])"
|
||||
|
||||
user << browse("<ol><li>[lines.Join("</li><li>")]</li></ol>", "window=[url_encode(GUID())]")
|
||||
@@ -142,7 +142,7 @@
|
||||
/datum/map_template/ruin/lavaland/ufo_crash
|
||||
name = "UFO Crash"
|
||||
id = "ufo-crash"
|
||||
description = "Turns out that keeping your abductees unconcious is really important. Who knew?"
|
||||
description = "Turns out that keeping your abductees unconscious is really important. Who knew?"
|
||||
suffix = "lavaland_surface_ufo_crash.dmm"
|
||||
cost = 5
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
suffix = "mini"
|
||||
name = "Ministation emergency shuttle"
|
||||
credit_cost = 1000
|
||||
description = "Despite it's namesake, this shuttle is actually only slightly smaller than standard, and still complete with a brig and medbay."
|
||||
description = "Despite its namesake, this shuttle is actually only slightly smaller than standard, and still complete with a brig and medbay."
|
||||
|
||||
/datum/map_template/shuttle/emergency/scrapheap
|
||||
suffix = "scrapheap"
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
|
||||
var/spawner_ref = pick(GLOB.mob_spawners[params["name"]])
|
||||
var/obj/effect/mob_spawn/MS = locate(spawner_ref) in GLOB.poi_list
|
||||
if(!MS)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("jump")
|
||||
|
||||
@@ -5,18 +5,15 @@
|
||||
|
||||
telegraph_message = "<span class='boldwarning'>An eerie moan rises on the wind. Sheets of burning ash blacken the horizon. Seek shelter.</span>"
|
||||
telegraph_duration = 300
|
||||
telegraph_sound = 'sound/lavaland/ash_storm_windup.ogg'
|
||||
telegraph_overlay = "light_ash"
|
||||
|
||||
weather_message = "<span class='userdanger'><i>Smoldering clouds of scorching ash billow down around you! Get inside!</i></span>"
|
||||
weather_duration_lower = 600
|
||||
weather_duration_upper = 1200
|
||||
weather_sound = 'sound/lavaland/ash_storm_start.ogg'
|
||||
weather_overlay = "ash_storm"
|
||||
|
||||
end_message = "<span class='boldannounce'>The shrieking wind whips away the last of the ash and falls to its usual murmur. It should be safe to go outside now.</span>"
|
||||
end_duration = 300
|
||||
end_sound = 'sound/lavaland/ash_storm_end.ogg'
|
||||
end_overlay = "light_ash"
|
||||
|
||||
area_type = /area/lavaland/surface/outdoors
|
||||
@@ -26,6 +23,53 @@
|
||||
|
||||
probability = 90
|
||||
|
||||
var/datum/looping_sound/active_outside_ashstorm/sound_ao = new(list(), FALSE, TRUE)
|
||||
var/datum/looping_sound/active_inside_ashstorm/sound_ai = new(list(), FALSE, TRUE)
|
||||
var/datum/looping_sound/weak_outside_ashstorm/sound_wo = new(list(), FALSE, TRUE)
|
||||
var/datum/looping_sound/weak_inside_ashstorm/sound_wi = new(list(), FALSE, TRUE)
|
||||
|
||||
/datum/weather/ash_storm/telegraph()
|
||||
. = ..()
|
||||
var/list/inside_areas = list()
|
||||
var/list/outside_areas = list()
|
||||
var/list/eligible_areas = SSmapping.areas_in_z["[target_z]"]
|
||||
for(var/i in 1 to eligible_areas.len)
|
||||
var/area/place = eligible_areas[i]
|
||||
if(place.outdoors)
|
||||
outside_areas += place
|
||||
else
|
||||
inside_areas += place
|
||||
CHECK_TICK
|
||||
|
||||
sound_ao.output_atoms = outside_areas
|
||||
sound_ai.output_atoms = inside_areas
|
||||
sound_wo.output_atoms = outside_areas
|
||||
sound_wi.output_atoms = inside_areas
|
||||
|
||||
sound_wo.start()
|
||||
sound_wi.start()
|
||||
|
||||
/datum/weather/ash_storm/start()
|
||||
. = ..()
|
||||
sound_wo.stop()
|
||||
sound_wi.stop()
|
||||
|
||||
sound_ao.start()
|
||||
sound_ai.start()
|
||||
|
||||
/datum/weather/ash_storm/wind_down()
|
||||
. = ..()
|
||||
sound_ao.stop()
|
||||
sound_ai.stop()
|
||||
|
||||
sound_wo.start()
|
||||
sound_wi.start()
|
||||
|
||||
/datum/weather/ash_storm/end()
|
||||
. = ..()
|
||||
sound_wo.stop()
|
||||
sound_wi.stop()
|
||||
|
||||
/datum/weather/ash_storm/proc/is_ash_immune(mob/living/L)
|
||||
if(ismecha(L.loc)) //Mechs are immune
|
||||
return TRUE
|
||||
@@ -50,7 +94,6 @@
|
||||
desc = "A passing ash storm blankets the area in harmless embers."
|
||||
|
||||
weather_message = "<span class='notice'>Gentle embers waft down around you like grotesque snow. The storm seems to have passed you by...</span>"
|
||||
weather_sound = 'sound/lavaland/ash_storm_windup.ogg'
|
||||
weather_overlay = "light_ash"
|
||||
|
||||
end_message = "<span class='notice'>The emberfall slows, stops. Another layer of hardened soot to the basalt beneath your feet.</span>"
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
"white",
|
||||
"yellow"
|
||||
)
|
||||
|
||||
|
||||
var/list/my_possible_colors = possible_colors.Copy()
|
||||
|
||||
for(var/wire in shuffle(wires))
|
||||
@@ -163,9 +163,9 @@
|
||||
for(var/wire in possible_wires)
|
||||
if(prob(33))
|
||||
pulse(wire)
|
||||
remaining_pulses--
|
||||
if(remaining_pulses >= 0)
|
||||
break
|
||||
remaining_pulses--
|
||||
if(!remaining_pulses)
|
||||
break
|
||||
|
||||
// Overridable Procs
|
||||
/datum/wires/proc/interactable(mob/user)
|
||||
|
||||
Reference in New Issue
Block a user