Merge branch 'master' into Ghommie-cit621
This commit is contained in:
@@ -260,6 +260,11 @@
|
||||
/obj/structure/chair/stool,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/security/prison)
|
||||
"aaK" = (
|
||||
/obj/structure/table/wood,
|
||||
/mob/living/simple_animal/pet/fox/Renault,
|
||||
/turf/open/floor/carpet,
|
||||
/area/crew_quarters/heads/captain)
|
||||
"aaN" = (
|
||||
/obj/structure/chair/sofa/right,
|
||||
/turf/open/floor/plasteel,
|
||||
@@ -21528,10 +21533,6 @@
|
||||
/obj/structure/table,
|
||||
/turf/open/floor/wood,
|
||||
/area/bridge/meeting_room)
|
||||
"bbZ" = (
|
||||
/obj/structure/table/wood,
|
||||
/turf/open/floor/carpet,
|
||||
/area/crew_quarters/heads/captain)
|
||||
"bca" = (
|
||||
/turf/open/floor/carpet,
|
||||
/area/bridge/meeting_room)
|
||||
@@ -90412,7 +90413,7 @@ aYo
|
||||
aZV
|
||||
bao
|
||||
baP
|
||||
bbZ
|
||||
aaK
|
||||
bcP
|
||||
cBo
|
||||
bgS
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,6 @@
|
||||
#define TRAITOR_HUMAN /datum/traitor_class/human/freeform
|
||||
#define TRAITOR_AI /datum/traitor_class/ai
|
||||
|
||||
#define NUKE_RESULT_FLUKE 0
|
||||
#define NUKE_RESULT_NUKE_WIN 1
|
||||
#define NUKE_RESULT_CREW_WIN 2
|
||||
@@ -74,6 +77,7 @@
|
||||
#define MARTIALART_HUNTER "hunter-fu"
|
||||
|
||||
//Blob
|
||||
/// blob gets a free reroll every X time
|
||||
#define BLOB_REROLL_TIME 2400
|
||||
#define BLOB_REROLL_TIME 2400 // blob gets a free reroll every X time
|
||||
#define BLOB_SPREAD_COST 4
|
||||
#define BLOB_ATTACK_REFUND 2 //blob refunds this much if it attacks and doesn't spread
|
||||
#define BLOB_REFLECTOR_COST 15
|
||||
@@ -0,0 +1,41 @@
|
||||
/// 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.
|
||||
/// This will be noted in the runtime logs
|
||||
#define COMPONENT_INCOMPATIBLE 1
|
||||
/// Returned in PostTransfer to prevent transfer, similar to `COMPONENT_INCOMPATIBLE`
|
||||
#define COMPONENT_NOTRANSFER 2
|
||||
|
||||
/// Return value to cancel attaching
|
||||
#define ELEMENT_INCOMPATIBLE 1
|
||||
|
||||
// /datum/element flags
|
||||
/// Causes the detach proc to be called when the host object is being deleted
|
||||
#define ELEMENT_DETACH (1 << 0)
|
||||
/**
|
||||
* Only elements created with the same arguments given after `id_arg_index` share an element instance
|
||||
* The arguments are the same when the text and number values are the same and all other values have the same ref
|
||||
*/
|
||||
#define ELEMENT_BESPOKE (1 << 1)
|
||||
|
||||
// How multiple components of the exact same type are handled in the same datum
|
||||
/// old component is deleted (default)
|
||||
#define COMPONENT_DUPE_HIGHLANDER 0
|
||||
/// duplicates allowed
|
||||
#define COMPONENT_DUPE_ALLOWED 1
|
||||
/// new component is deleted
|
||||
#define COMPONENT_DUPE_UNIQUE 2
|
||||
/// old component is given the initialization args of the new
|
||||
#define COMPONENT_DUPE_UNIQUE_PASSARGS 4
|
||||
/// each component of the same type is consulted as to whether the duplicate should be allowed
|
||||
#define COMPONENT_DUPE_SELECTIVE 5
|
||||
|
||||
//Redirection component init flags
|
||||
#define REDIRECT_TRANSFER_WITH_TURF 1
|
||||
|
||||
//Arch
|
||||
#define ARCH_PROB "probability" //Probability for each item
|
||||
#define ARCH_MAXDROP "max_drop_amount" //each item's max drop amount
|
||||
|
||||
//Ouch my toes!
|
||||
#define CALTROP_BYPASS_SHOES 1
|
||||
#define CALTROP_IGNORE_WALKERS 2
|
||||
@@ -0,0 +1,16 @@
|
||||
/// Used to trigger signals and call procs registered for that signal
|
||||
/// The datum hosting the signal is automaticaly added as the first argument
|
||||
/// Returns a bitfield gathered from all registered procs
|
||||
/// Arguments given here are packaged in a list and given to _SendSignal
|
||||
#define SEND_SIGNAL(target, sigtype, arguments...) ( !target.comp_lookup || !target.comp_lookup[sigtype] ? NONE : target._SendSignal(sigtype, list(target, ##arguments)) )
|
||||
|
||||
#define SEND_GLOBAL_SIGNAL(sigtype, arguments...) ( SEND_SIGNAL(SSdcs, sigtype, ##arguments) )
|
||||
|
||||
/// A wrapper for _AddElement that allows us to pretend we're using normal named arguments
|
||||
#define AddElement(arguments...) _AddElement(list(##arguments))
|
||||
|
||||
/// A wrapper for _RemoveElement that allows us to pretend we're using normal named arguments
|
||||
#define RemoveElement(arguments...) _RemoveElement(list(##arguments))
|
||||
|
||||
/// A wrapper for _AddComponent that allows us to pretend we're using normal named arguments
|
||||
#define AddComponent(arguments...) _AddComponent(list(##arguments))
|
||||
@@ -1,28 +1,3 @@
|
||||
#define SEND_SIGNAL(target, sigtype, arguments...) ( !target.comp_lookup || !target.comp_lookup[sigtype] ? NONE : target._SendSignal(sigtype, list(target, ##arguments)) )
|
||||
|
||||
#define SEND_GLOBAL_SIGNAL(sigtype, arguments...) ( SEND_SIGNAL(SSdcs, sigtype, ##arguments) )
|
||||
|
||||
#define COMPONENT_INCOMPATIBLE 1
|
||||
#define COMPONENT_NOTRANSFER 2
|
||||
|
||||
#define ELEMENT_INCOMPATIBLE 1 // Return value to cancel attaching
|
||||
|
||||
// /datum/element flags
|
||||
/// Causes the detach proc to be called when the host object is being deleted
|
||||
#define ELEMENT_DETACH (1 << 0)
|
||||
/**
|
||||
* Only elements created with the same arguments given after `id_arg_index` share an element instance
|
||||
* The arguments are the same when the text and number values are the same and all other values have the same ref
|
||||
*/
|
||||
#define ELEMENT_BESPOKE (1 << 1)
|
||||
|
||||
// How multiple components of the exact same type are handled in the same datum
|
||||
|
||||
#define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default)
|
||||
#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed
|
||||
#define COMPONENT_DUPE_UNIQUE 2 //new component is deleted
|
||||
#define COMPONENT_DUPE_UNIQUE_PASSARGS 4 //old component is given the initialization args of the new
|
||||
|
||||
// All signals. Format:
|
||||
// When the signal is called: (signal arguments)
|
||||
// All signals send the source datum of the signal as the first argument
|
||||
@@ -359,19 +334,6 @@
|
||||
#define COMSIG_ACTION_TRIGGER "action_trigger" //from base of datum/action/proc/Trigger(): (datum/action)
|
||||
#define COMPONENT_ACTION_BLOCK_TRIGGER 1
|
||||
|
||||
/*******Non-Signal Component Related Defines*******/
|
||||
|
||||
//Redirection component init flags
|
||||
#define REDIRECT_TRANSFER_WITH_TURF 1
|
||||
|
||||
//Arch
|
||||
#define ARCH_PROB "probability" //Probability for each item
|
||||
#define ARCH_MAXDROP "max_drop_amount" //each item's max drop amount
|
||||
|
||||
//Ouch my toes!
|
||||
#define CALTROP_BYPASS_SHOES 1
|
||||
#define CALTROP_IGNORE_WALKERS 2
|
||||
|
||||
//Xenobio hotkeys
|
||||
#define COMSIG_XENO_SLIME_CLICK_CTRL "xeno_slime_click_ctrl" //from slime CtrlClickOn(): (/mob)
|
||||
#define COMSIG_XENO_SLIME_CLICK_ALT "xeno_slime_click_alt" //from slime AltClickOn(): (/mob)
|
||||
@@ -125,11 +125,7 @@
|
||||
if(prob(33))
|
||||
I.add_mob_blood(src)
|
||||
var/turf/location = get_turf(src)
|
||||
if(iscarbon(src))
|
||||
var/mob/living/carbon/C = src
|
||||
C.bleed(totitemdamage)
|
||||
else
|
||||
add_splatter_floor(location)
|
||||
add_splatter_floor(location)
|
||||
if(totitemdamage >= 10 && get_dist(user, src) <= 1) //people with TK won't get smeared with blood
|
||||
user.add_mob_blood(src)
|
||||
return TRUE //successful attack
|
||||
|
||||
@@ -82,17 +82,23 @@
|
||||
config_entry_value = 600
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/number/vote_autotransfer_initial //length of time before the first autotransfer vote is called (deciseconds, default 2 hours)
|
||||
/// Length of time before the first autotransfer vote is called (deciseconds, default 2 hours)
|
||||
/// Set to 0 to disable the subsystem altogether.
|
||||
/datum/config_entry/number/vote_autotransfer_initial
|
||||
config_entry_value = 72000
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/number/vote_autotransfer_interval //length of time to wait before subsequent autotransfer votes (deciseconds, default 30 minutes)
|
||||
///length of time to wait before subsequent autotransfer votes (deciseconds, default 30 minutes)
|
||||
/datum/config_entry/number/vote_autotransfer_interval
|
||||
config_entry_value = 18000
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/number/vote_autotransfer_maximum // maximum extensions until the round autoends
|
||||
/// maximum extensions until the round autoends.
|
||||
/// Set to 0 to force automatic crew transfer after the 'vote_autotransfer_initial' elapsed.
|
||||
/// Set to -1 to disable the maximum extensions cap.
|
||||
/datum/config_entry/number/vote_autotransfer_maximum
|
||||
config_entry_value = 4
|
||||
min_val = 0
|
||||
min_val = -1
|
||||
|
||||
/datum/config_entry/flag/default_no_vote // vote does not default to nochange/norestart
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#define NO_MAXVOTES_CAP -1
|
||||
|
||||
SUBSYSTEM_DEF(autotransfer)
|
||||
name = "Autotransfer Vote"
|
||||
flags = SS_KEEP_TIMING | SS_BACKGROUND
|
||||
@@ -7,21 +9,32 @@ SUBSYSTEM_DEF(autotransfer)
|
||||
var/targettime
|
||||
var/voteinterval
|
||||
var/maxvotes
|
||||
var/curvotes
|
||||
var/curvotes = 0
|
||||
|
||||
/datum/controller/subsystem/autotransfer/Initialize(timeofday)
|
||||
var/init_vote = CONFIG_GET(number/vote_autotransfer_initial)
|
||||
if(!init_vote) //Autotransfer voting disabled.
|
||||
can_fire = FALSE
|
||||
return ..()
|
||||
starttime = world.time
|
||||
targettime = starttime + CONFIG_GET(number/vote_autotransfer_initial)
|
||||
targettime = starttime + init_vote
|
||||
voteinterval = CONFIG_GET(number/vote_autotransfer_interval)
|
||||
maxvotes = CONFIG_GET(number/vote_autotransfer_maximum)
|
||||
curvotes = 0
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/autotransfer/Recover()
|
||||
starttime = SSautotransfer.starttime
|
||||
voteinterval = SSautotransfer.voteinterval
|
||||
curvotes = SSautotransfer.curvotes
|
||||
|
||||
/datum/controller/subsystem/autotransfer/fire()
|
||||
if(maxvotes > curvotes)
|
||||
if(world.time > targettime)
|
||||
SSvote.initiate_vote("transfer","server")
|
||||
targettime = targettime + voteinterval
|
||||
curvotes += 1
|
||||
if(world.time < targettime)
|
||||
return
|
||||
if(maxvotes == NO_MAXVOTES_CAP || maxvotes > curvotes)
|
||||
SSvote.initiate_vote("transfer","server")
|
||||
targettime = targettime + voteinterval
|
||||
curvotes++
|
||||
else
|
||||
SSshuttle.autoEnd()
|
||||
|
||||
#undef NO_MAXVOTES_CAP
|
||||
@@ -1,27 +1,53 @@
|
||||
PROCESSING_SUBSYSTEM_DEF(dcs)
|
||||
name = "Datum Component System"
|
||||
flags = SS_NO_INIT
|
||||
|
||||
var/list/elements_by_type = list()
|
||||
|
||||
/datum/controller/subsystem/processing/dcs/Recover()
|
||||
comp_lookup = SSdcs.comp_lookup
|
||||
|
||||
/datum/controller/subsystem/processing/dcs/proc/GetElement(datum/element/eletype, ...)
|
||||
/datum/controller/subsystem/processing/dcs/proc/GetElement(list/arguments)
|
||||
var/datum/element/eletype = arguments[1]
|
||||
var/element_id = eletype
|
||||
|
||||
if(!ispath(eletype, /datum/element))
|
||||
CRASH("Attempted to instantiate [eletype] as a /datum/element")
|
||||
|
||||
if(initial(eletype.element_flags) & ELEMENT_BESPOKE)
|
||||
var/list/fullid = list("[eletype]")
|
||||
for(var/i in initial(eletype.id_arg_index) to length(args))
|
||||
var/argument = args[i]
|
||||
if(istext(argument) || isnum(argument))
|
||||
fullid += "[argument]"
|
||||
else
|
||||
fullid += "[REF(argument)]"
|
||||
element_id = fullid.Join("&")
|
||||
element_id = GetIdFromArguments(arguments)
|
||||
|
||||
. = elements_by_type[element_id]
|
||||
if(.)
|
||||
return
|
||||
if(!ispath(eletype, /datum/element))
|
||||
CRASH("Attempted to instantiate [eletype] as a /datum/element")
|
||||
. = elements_by_type[element_id] = new eletype
|
||||
. = elements_by_type[element_id] = new eletype
|
||||
|
||||
/****
|
||||
* Generates an id for bespoke elements when given the argument list
|
||||
* Generating the id here is a bit complex because we need to support named arguments
|
||||
* Named arguments can appear in any order and we need them to appear after ordered arguments
|
||||
* We assume that no one will pass in a named argument with a value of null
|
||||
**/
|
||||
/datum/controller/subsystem/processing/dcs/proc/GetIdFromArguments(list/arguments)
|
||||
var/datum/element/eletype = arguments[1]
|
||||
var/list/fullid = list("[eletype]")
|
||||
var/list/named_arguments = list()
|
||||
for(var/i in initial(eletype.id_arg_index) to length(arguments))
|
||||
var/key = arguments[i]
|
||||
var/value
|
||||
if(istext(key))
|
||||
value = arguments[key]
|
||||
if(!(istext(key) || isnum(key)))
|
||||
key = REF(key)
|
||||
key = "[key]" // Key is stringified so numbers dont break things
|
||||
if(!isnull(value))
|
||||
if(!(istext(value) || isnum(value)))
|
||||
value = REF(value)
|
||||
named_arguments["[key]"] = value
|
||||
else
|
||||
fullid += "[key]"
|
||||
|
||||
if(length(named_arguments))
|
||||
named_arguments = sortList(named_arguments)
|
||||
fullid += named_arguments
|
||||
return list2params(fullid)
|
||||
|
||||
@@ -85,7 +85,7 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
|
||||
our_quirks -= i
|
||||
cut += i
|
||||
pointscut += quirk_points_by_name(i)
|
||||
if (pointscut >= 0) //with how it works, it needs to be above zero, not below, as points for positive is positive, and negative is negative, we only want it to break if it's above zero, ie. we cut more positive than negative
|
||||
if (pointscut >= 0)
|
||||
break
|
||||
/* //Code to automatically reduce positive quirks until balance is even.
|
||||
var/points_used = total_points(our_quirks)
|
||||
@@ -102,7 +102,7 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
|
||||
*/
|
||||
|
||||
//Nah, let's null all non-neutrals out.
|
||||
if (pointscut != 0)// only if the pointscutting didn't work.
|
||||
if (pointscut < 0)// only if the pointscutting didn't work.
|
||||
if(cut.len)
|
||||
for(var/i in our_quirks)
|
||||
if(quirk_points_by_name(i) != 0)
|
||||
|
||||
@@ -443,7 +443,7 @@ SUBSYSTEM_DEF(vote)
|
||||
|
||||
var/admin = FALSE
|
||||
var/ckey = ckey(initiator_key)
|
||||
if(GLOB.admin_datums[ckey])
|
||||
if(GLOB.admin_datums[ckey] || initiator_key == "server")
|
||||
admin = TRUE
|
||||
|
||||
if(next_allowed_time > world.time && !admin)
|
||||
|
||||
@@ -4,132 +4,6 @@
|
||||
|
||||
Loosely adapted from /vg/. This is an entity component system for adding behaviours to datums when inheritance doesn't quite cut it. By using signals and events instead of direct inheritance, you can inject behaviours without hacky overloads. It requires a different method of thinking, but is not hard to use correctly. If a behaviour can have application across more than one thing. Make it generic, make it a component. Atom/mob/obj event? Give it a signal, and forward it's arguments with a `SendSignal()` call. Now every component that want's to can also know about this happening.
|
||||
|
||||
### In the code
|
||||
See [this thread](https://tgstation13.org/phpBB/viewtopic.php?f=5&t=22674) for an introduction to the system as a whole.
|
||||
|
||||
#### Slippery things
|
||||
|
||||
At the time of this writing, every object that is slippery overrides atom/Crossed does some checks, then slips the mob. Instead of all those Crossed overrides they could add a slippery component to all these objects. And have the checks in one proc that is run by the Crossed event
|
||||
|
||||
#### Powercells
|
||||
|
||||
A lot of objects have powercells. The `get_cell()` proc was added to give generic access to the cell var if it had one. This is just a specific use case of `GetComponent()`
|
||||
|
||||
#### Radios
|
||||
|
||||
The radio object as it is should not exist, given that more things use the _concept_ of radios rather than the object itself. The actual function of the radio can exist in a component which all the things that use it (Request consoles, actual radios, the SM shard) can add to themselves.
|
||||
|
||||
#### Standos
|
||||
|
||||
Stands have a lot of procs which mimic mob procs. Rather than inserting hooks for all these procs in overrides, the same can be accomplished with signals
|
||||
|
||||
## API
|
||||
|
||||
### Defines
|
||||
|
||||
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. This will be noted in the runtime logs
|
||||
|
||||
### Vars
|
||||
|
||||
1. `/datum/var/list/datum_components` (private)
|
||||
* Lazy associated list of type -> component/list of components.
|
||||
1. `/datum/var/list/comp_lookup` (private)
|
||||
* Lazy associated list of signal -> registree/list of registrees
|
||||
1. `/datum/var/list/signal_procs` (private)
|
||||
* Associated lazy list of signals -> `/datum/callback`s that will be run when the parent datum receives that signal
|
||||
1. `/datum/var/signal_enabled` (protected, boolean)
|
||||
* If the datum is signal enabled. If not, it will not react to signals
|
||||
* `FALSE` by default, set to `TRUE` when a signal is registered
|
||||
1. `/datum/component/var/dupe_mode` (protected, enum)
|
||||
* How duplicate component types are handled when added to the datum.
|
||||
* `COMPONENT_DUPE_HIGHLANDER` (default): Old component will be deleted, new component will first have `/datum/component/proc/InheritComponent(datum/component/old, FALSE)` on it
|
||||
* `COMPONENT_DUPE_ALLOWED`: The components will be treated as separate, `GetComponent()` will return the first added
|
||||
* `COMPONENT_DUPE_UNIQUE`: New component will be deleted, old component will first have `/datum/component/proc/InheritComponent(datum/component/new, TRUE)` on it
|
||||
* `COMPONENT_DUPE_UNIQUE_PASSARGS`: New component will never exist and instead its initialization arguments will be passed on to the old component.
|
||||
1. `/datum/component/var/dupe_type` (protected, type)
|
||||
* Definition of a duplicate component type
|
||||
* `null` means exact match on `type` (default)
|
||||
* Any other type means that and all subtypes
|
||||
1. `/datum/component/var/datum/parent` (protected, read-only)
|
||||
* The datum this component belongs to
|
||||
* Never `null` in child procs
|
||||
1. `report_signal_origin` (protected, boolean)
|
||||
* If `TRUE`, will invoke the callback when signalled with the signal type as the first argument.
|
||||
* `FALSE` by default.
|
||||
|
||||
### Procs
|
||||
|
||||
1. `/datum/proc/GetComponent(component_type(type)) -> datum/component?` (public, final)
|
||||
* Returns a reference to a component of component_type if it exists in the datum, null otherwise
|
||||
1. `/datum/proc/GetComponents(component_type(type)) -> list` (public, final)
|
||||
* Returns a list of references to all components of component_type that exist in the datum
|
||||
1. `/datum/proc/GetExactComponent(component_type(type)) -> datum/component?` (public, final)
|
||||
* Returns a reference to a component whose type MATCHES component_type if that component exists in the datum, null otherwise
|
||||
1. `GET_COMPONENT(varname, component_type)` OR `GET_COMPONENT_FROM(varname, component_type, src)`
|
||||
* Shorthand for `var/component_type/varname = src.GetComponent(component_type)`
|
||||
1. `SEND_SIGNAL(target, sigtype, ...)` (public, final)
|
||||
* Use to send signals to target datum
|
||||
* Extra arguments are to be specified in the signal definition
|
||||
* Returns a bitflag with signal specific information assembled from all activated components
|
||||
* Arguments are packaged in a list and handed off to _SendSignal()
|
||||
1. `/datum/proc/AddComponent(component_type(type), ...) -> datum/component` (public, final)
|
||||
* Creates an instance of `component_type` in the datum and passes `...` to its `Initialize()` call
|
||||
* Sends the `COMSIG_COMPONENT_ADDED` signal to the datum
|
||||
* All components a datum owns are deleted with the datum
|
||||
* Returns the component that was created. Or the old component in a dupe situation where `COMPONENT_DUPE_UNIQUE` was set
|
||||
* If this tries to add an component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
|
||||
* Properly handles duplicate situations based on the `dupe_mode` var
|
||||
1. `/datum/proc/LoadComponent(component_type(type), ...) -> datum/component` (public, final)
|
||||
* Equivalent to calling `GetComponent(component_type)` where, if the result would be `null`, returns `AddComponent(component_type, ...)` instead
|
||||
1. `/datum/proc/ComponentActivated(datum/component/C)` (abstract, async)
|
||||
* Called on a component's `parent` after a signal received causes it to activate. `src` is the parameter
|
||||
* 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
|
||||
* 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, list/arguments)` (private, final)
|
||||
* Handles most of the actual signaling procedure
|
||||
* Will runtime if used on datums with an empty component list
|
||||
1. `/datum/proc/RegisterSignal(datum/target, signal(string/list of strings), proc_ref(type), override(boolean))` (protected, final)
|
||||
* If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments
|
||||
* Makes the datum listen for the specified `signal` on it's `parent` datum.
|
||||
* When that signal is received `proc_ref` will be called on the component, along with associated arguments
|
||||
* Example proc ref: `.proc/OnEvent`
|
||||
* If a previous registration is overwritten by the call, a runtime occurs. Setting `override` to TRUE prevents this
|
||||
* These callbacks run asyncronously
|
||||
* Returning `TRUE` from these callbacks will trigger a `TRUE` return from the `SendSignal()` that initiated it
|
||||
1. `/datum/component/New(datum/parent, ...)` (private, final)
|
||||
* Runs internal setup for the component
|
||||
* Extra arguments are passed to `Initialize()`
|
||||
1. `/datum/component/Initialize(...)` (abstract, no-sleep)
|
||||
* Called by `New()` with the same argments excluding `parent`
|
||||
* Component does not exist in `parent`'s `datum_components` list yet, although `parent` is set and may be used
|
||||
* Signals will not be received 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(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`
|
||||
* `C`'s type will always be the same of the called component
|
||||
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 `new_parent` is assigned to `parent` in `TakeComponent()`
|
||||
* Allows the component to react to ownership transfers
|
||||
1. `/datum/component/proc/_RemoveFromParent()` (private, final)
|
||||
* Clears `parent` and removes the component from it's component list
|
||||
1. `/datum/component/proc/_JoinParent` (private, final)
|
||||
* Tries to add the component to it's `parent`s `datum_components` list
|
||||
1. `/datum/component/proc/RegisterWithParent` (abstract, no-sleep)
|
||||
* Used to register the signals that should be on the `parent` object
|
||||
* Use this if you plan on the component transfering between parents
|
||||
1. `/datum/component/proc/UnregisterFromParent` (abstract, no-sleep)
|
||||
* Counterpart to `RegisterWithParent()`
|
||||
* Used to unregister the signals that should only be on the `parent` object
|
||||
|
||||
### See/Define signals and their arguments in __DEFINES\components.dm
|
||||
### See/Define signals and their arguments in [__DEFINES\components.dm](..\..\__DEFINES\components.dm)
|
||||
|
||||
@@ -1,21 +1,71 @@
|
||||
/**
|
||||
* # Component
|
||||
*
|
||||
* The component datum
|
||||
*
|
||||
* A component should be a single standalone unit
|
||||
* of functionality, that works by receiving signals from it's parent
|
||||
* object to provide some single functionality (i.e a slippery component)
|
||||
* that makes the object it's attached to cause people to slip over.
|
||||
* Useful when you want shared behaviour independent of type inheritance
|
||||
*/
|
||||
/datum/component
|
||||
/// Defines how duplicate existing components are handled when added to a datum
|
||||
/// See `COMPONENT_DUPE_*` definitions for available options
|
||||
var/dupe_mode = COMPONENT_DUPE_HIGHLANDER
|
||||
|
||||
/// The type to check for duplication
|
||||
/// `null` means exact match on `type` (default)
|
||||
/// Any other type means that and all subtypes
|
||||
var/dupe_type
|
||||
|
||||
/// The datum this components belongs to
|
||||
var/datum/parent
|
||||
//only set to true if you are able to properly transfer this component
|
||||
//At a minimum RegisterWithParent and UnregisterFromParent should be used
|
||||
//Make sure you also implement PostTransfer for any post transfer handling
|
||||
|
||||
/// Only set to true if you are able to properly transfer this component
|
||||
/// At a minimum RegisterWithParent and UnregisterFromParent should be used
|
||||
/// Make sure you also implement PostTransfer for any post transfer handling
|
||||
var/can_transfer = FALSE
|
||||
|
||||
/datum/component/New(datum/P, ...)
|
||||
parent = P
|
||||
var/list/arguments = args.Copy(2)
|
||||
/**
|
||||
* Create a new component.
|
||||
* Additional arguments are passed to `Initialize()`
|
||||
*
|
||||
* Arguments:
|
||||
* * datum/P the parent datum this component reacts to signals from
|
||||
*/
|
||||
/datum/component/New(list/raw_args)
|
||||
parent = raw_args[1]
|
||||
var/list/arguments = raw_args.Copy(2)
|
||||
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
|
||||
qdel(src, TRUE, TRUE)
|
||||
CRASH("Incompatible [type] assigned to a [P.type]! args: [json_encode(arguments)]")
|
||||
CRASH("Incompatible [type] assigned to a [parent.type]! args: [json_encode(arguments)]")
|
||||
|
||||
_JoinParent(P)
|
||||
_JoinParent(parent)
|
||||
|
||||
/**
|
||||
* Called during component creation with the same arguments as in new excluding parent.
|
||||
* Do not call `qdel(src)` from this function, `return COMPONENT_INCOMPATIBLE` instead
|
||||
*/
|
||||
/datum/component/proc/Initialize(...)
|
||||
return
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
/datum/component/Destroy(force=FALSE, silent=FALSE)
|
||||
if(!force && parent)
|
||||
_RemoveFromParent()
|
||||
if(!silent)
|
||||
SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src)
|
||||
parent = null
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Internal proc to handle behaviour of components when joining a parent
|
||||
*/
|
||||
/datum/component/proc/_JoinParent()
|
||||
var/datum/P = parent
|
||||
//lazy init the parent's dc list
|
||||
@@ -51,21 +101,9 @@
|
||||
|
||||
RegisterWithParent()
|
||||
|
||||
// If you want/expect to be moving the component around between parents, use this to register on the parent for signals
|
||||
/datum/component/proc/RegisterWithParent()
|
||||
SEND_SIGNAL(src, COMSIG_COMPONENT_REGISTER_PARENT) //CITADEL EDIT
|
||||
|
||||
/datum/component/proc/Initialize(...)
|
||||
return
|
||||
|
||||
/datum/component/Destroy(force=FALSE, silent=FALSE)
|
||||
if(!force && parent)
|
||||
_RemoveFromParent()
|
||||
if(!silent)
|
||||
SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src)
|
||||
parent = null
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Internal proc to handle behaviour when being removed from a parent
|
||||
*/
|
||||
/datum/component/proc/_RemoveFromParent()
|
||||
var/datum/P = parent
|
||||
var/list/dc = P.datum_components
|
||||
@@ -84,9 +122,38 @@
|
||||
|
||||
UnregisterFromParent()
|
||||
|
||||
/datum/component/proc/UnregisterFromParent()
|
||||
SEND_SIGNAL(src, COMSIG_COMPONENT_UNREGISTER_PARENT) //CITADEL EDIT
|
||||
/**
|
||||
* Register the component with the parent object
|
||||
*
|
||||
* Use this proc to register with your parent object
|
||||
* Overridable proc that's called when added to a new parent
|
||||
*/
|
||||
/datum/component/proc/RegisterWithParent()
|
||||
return
|
||||
|
||||
/**
|
||||
* Unregister from our parent object
|
||||
*
|
||||
* Use this proc to unregister from your parent object
|
||||
* Overridable proc that's called when removed from a parent
|
||||
* *
|
||||
*/
|
||||
/datum/component/proc/UnregisterFromParent()
|
||||
return
|
||||
|
||||
/**
|
||||
* Register to listen for a signal from the passed in target
|
||||
*
|
||||
* This sets up a listening relationship such that when the target object emits a signal
|
||||
* the source datum this proc is called upon, will recieve a callback to the given proctype
|
||||
* Return values from procs registered must be a bitfield
|
||||
*
|
||||
* Arguments:
|
||||
* * datum/target The target to listen for signals from
|
||||
* * sig_type_or_types Either a string signal name, or a list of signal names (strings)
|
||||
* * proctype The proc to call back when the signal is emitted
|
||||
* * override If a previous registration exists you must explicitly set this
|
||||
*/
|
||||
/datum/proc/RegisterSignal(datum/target, sig_type_or_types, proctype, override = FALSE)
|
||||
if(QDELETED(src) || QDELETED(target))
|
||||
return
|
||||
@@ -119,6 +186,16 @@
|
||||
|
||||
signal_enabled = TRUE
|
||||
|
||||
/**
|
||||
* Stop listening to a given signal from target
|
||||
*
|
||||
* Breaks the relationship between target and source datum, removing the callback when the signal fires
|
||||
* Doesn't care if a registration exists or not
|
||||
*
|
||||
* Arguments:
|
||||
* * datum/target Datum to stop listening to signals from
|
||||
* * sig_typeor_types Signal string key or list of signal keys to stop listening to specifically
|
||||
*/
|
||||
/datum/proc/UnregisterSignal(datum/target, sig_type_or_types)
|
||||
var/list/lookup = target.comp_lookup
|
||||
if(!signal_procs || !signal_procs[target] || !lookup)
|
||||
@@ -126,6 +203,8 @@
|
||||
if(!islist(sig_type_or_types))
|
||||
sig_type_or_types = list(sig_type_or_types)
|
||||
for(var/sig in sig_type_or_types)
|
||||
if(!signal_procs[target][sig])
|
||||
continue
|
||||
switch(length(lookup[sig]))
|
||||
if(2)
|
||||
lookup[sig] = (lookup[sig]-src)[1]
|
||||
@@ -148,15 +227,47 @@
|
||||
if(!signal_procs[target].len)
|
||||
signal_procs -= target
|
||||
|
||||
/**
|
||||
* Called on a component when a component of the same type was added to the same parent
|
||||
* See `/datum/component/var/dupe_mode`
|
||||
* `C`'s type will always be the same of the called component
|
||||
*/
|
||||
/datum/component/proc/InheritComponent(datum/component/C, i_am_original)
|
||||
return
|
||||
|
||||
|
||||
/**
|
||||
* Called on a component when a component of the same type was added to the same parent with COMPONENT_DUPE_SELECTIVE
|
||||
* See `/datum/component/var/dupe_mode`
|
||||
* `C`'s type will always be the same of the called component
|
||||
* return TRUE if you are absorbing the component, otherwise FALSE if you are fine having it exist as a duplicate component
|
||||
*/
|
||||
/datum/component/proc/CheckDupeComponent(datum/component/C, ...)
|
||||
return
|
||||
|
||||
|
||||
/**
|
||||
* Callback Just before this component is transferred
|
||||
*
|
||||
* Use this to do any special cleanup you might need to do before being deregged from an object
|
||||
*
|
||||
*/
|
||||
/datum/component/proc/PreTransfer()
|
||||
return
|
||||
|
||||
/**
|
||||
* Callback Just after a component is transferred
|
||||
*
|
||||
* Use this to do any special setup you need to do after being moved to a new object
|
||||
* Do not call `qdel(src)` from this function, `return COMPONENT_INCOMPATIBLE` instead
|
||||
*
|
||||
*/
|
||||
/datum/component/proc/PostTransfer()
|
||||
return COMPONENT_INCOMPATIBLE //Do not support transfer by default as you must properly support it
|
||||
|
||||
/**
|
||||
* Internal proc to create a list of our type and all parent types
|
||||
*/
|
||||
/datum/component/proc/_GetInverseTypeList(our_type = type)
|
||||
//we can do this one simple trick
|
||||
var/current_type = parent_type
|
||||
@@ -166,6 +277,11 @@
|
||||
current_type = type2parent(current_type)
|
||||
. += current_type
|
||||
|
||||
/**
|
||||
* Internal proc to handle most all of the signaling procedure
|
||||
* Will runtime if used on datums with an empty component list
|
||||
* Use the `SEND_SIGNAL` define instead
|
||||
*/
|
||||
/datum/proc/_SendSignal(sigtype, list/arguments)
|
||||
var/target = comp_lookup[sigtype]
|
||||
if(!length(target))
|
||||
@@ -183,9 +299,16 @@
|
||||
. |= CallAsync(C, proctype, arguments)
|
||||
|
||||
// The type arg is casted so initial works, you shouldn't be passing a real instance into this
|
||||
/**
|
||||
* Return any component assigned to this datum of the given type
|
||||
* This will throw an error if it's possible to have more than one component of that type on the parent
|
||||
*
|
||||
* Arguments:
|
||||
* * datum/component/c_type The typepath of the component you want to get a reference to
|
||||
*/
|
||||
/datum/proc/GetComponent(datum/component/c_type)
|
||||
RETURN_TYPE(c_type)
|
||||
if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED)
|
||||
if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED || initial(c_type.dupe_mode) == COMPONENT_DUPE_SELECTIVE)
|
||||
stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]")
|
||||
var/list/dc = datum_components
|
||||
if(!dc)
|
||||
@@ -194,7 +317,18 @@
|
||||
if(length(.))
|
||||
return .[1]
|
||||
|
||||
/datum/proc/GetExactComponent(c_type)
|
||||
// The type arg is casted so initial works, you shouldn't be passing a real instance into this
|
||||
/**
|
||||
* Return any component assigned to this datum of the exact given type
|
||||
* This will throw an error if it's possible to have more than one component of that type on the parent
|
||||
*
|
||||
* Arguments:
|
||||
* * datum/component/c_type The typepath of the component you want to get a reference to
|
||||
*/
|
||||
/datum/proc/GetExactComponent(datum/component/c_type)
|
||||
RETURN_TYPE(c_type)
|
||||
if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED || initial(c_type.dupe_mode) == COMPONENT_DUPE_SELECTIVE)
|
||||
stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]")
|
||||
var/list/dc = datum_components
|
||||
if(!dc)
|
||||
return null
|
||||
@@ -206,6 +340,12 @@
|
||||
return C
|
||||
return null
|
||||
|
||||
/**
|
||||
* Get all components of a given type that are attached to this datum
|
||||
*
|
||||
* Arguments:
|
||||
* * c_type The component type path
|
||||
*/
|
||||
/datum/proc/GetComponents(c_type)
|
||||
var/list/dc = datum_components
|
||||
if(!dc)
|
||||
@@ -214,7 +354,15 @@
|
||||
if(!length(.))
|
||||
return list(.)
|
||||
|
||||
/datum/proc/AddComponent(new_type, ...)
|
||||
/**
|
||||
* Creates an instance of `new_type` in the datum and attaches to it as parent
|
||||
* Sends the `COMSIG_COMPONENT_ADDED` signal to the datum
|
||||
* Returns the component that was created. Or the old component in a dupe situation where `COMPONENT_DUPE_UNIQUE` was set
|
||||
* If this tries to add an component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
|
||||
* Properly handles duplicate situations based on the `dupe_mode` var
|
||||
*/
|
||||
/datum/proc/_AddComponent(list/raw_args)
|
||||
var/new_type = raw_args[1]
|
||||
var/datum/component/nt = new_type
|
||||
var/dm = initial(nt.dupe_mode)
|
||||
var/dt = initial(nt.dupe_type)
|
||||
@@ -229,7 +377,7 @@
|
||||
new_comp = nt
|
||||
nt = new_comp.type
|
||||
|
||||
args[1] = src
|
||||
raw_args[1] = src
|
||||
|
||||
if(dm != COMPONENT_DUPE_ALLOWED)
|
||||
if(!dt)
|
||||
@@ -240,37 +388,62 @@
|
||||
switch(dm)
|
||||
if(COMPONENT_DUPE_UNIQUE)
|
||||
if(!new_comp)
|
||||
new_comp = new nt(arglist(args))
|
||||
new_comp = new nt(raw_args)
|
||||
if(!QDELETED(new_comp))
|
||||
old_comp.InheritComponent(new_comp, TRUE)
|
||||
QDEL_NULL(new_comp)
|
||||
if(COMPONENT_DUPE_HIGHLANDER)
|
||||
if(!new_comp)
|
||||
new_comp = new nt(arglist(args))
|
||||
new_comp = new nt(raw_args)
|
||||
if(!QDELETED(new_comp))
|
||||
new_comp.InheritComponent(old_comp, FALSE)
|
||||
QDEL_NULL(old_comp)
|
||||
if(COMPONENT_DUPE_UNIQUE_PASSARGS)
|
||||
if(!new_comp)
|
||||
var/list/arguments = args.Copy(2)
|
||||
old_comp.InheritComponent(null, TRUE, arguments)
|
||||
var/list/arguments = raw_args.Copy(2)
|
||||
arguments.Insert(1, null, TRUE)
|
||||
old_comp.InheritComponent(arglist(arguments))
|
||||
else
|
||||
old_comp.InheritComponent(new_comp, TRUE)
|
||||
if(COMPONENT_DUPE_SELECTIVE)
|
||||
var/list/arguments = raw_args.Copy()
|
||||
arguments[1] = new_comp
|
||||
var/make_new_component = TRUE
|
||||
for(var/i in GetComponents(new_type))
|
||||
var/datum/component/C = i
|
||||
if(C.CheckDupeComponent(arglist(arguments)))
|
||||
make_new_component = FALSE
|
||||
QDEL_NULL(new_comp)
|
||||
break
|
||||
if(!new_comp && make_new_component)
|
||||
new_comp = new nt(raw_args)
|
||||
else if(!new_comp)
|
||||
new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal
|
||||
new_comp = new nt(raw_args) // There's a valid dupe mode but there's no old component, act like normal
|
||||
else if(!new_comp)
|
||||
new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal
|
||||
new_comp = new nt(raw_args) // Dupes are allowed, act like normal
|
||||
|
||||
if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
|
||||
SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_comp)
|
||||
return new_comp
|
||||
return old_comp
|
||||
|
||||
/**
|
||||
* Get existing component of type, or create it and return a reference to it
|
||||
*
|
||||
* Use this if the item needs to exist at the time of this call, but may not have been created before now
|
||||
*
|
||||
* Arguments:
|
||||
* * component_type The typepath of the component to create or return
|
||||
* * ... additional arguments to be passed when creating the component if it does not exist
|
||||
*/
|
||||
/datum/proc/LoadComponent(component_type, ...)
|
||||
. = GetComponent(component_type)
|
||||
if(!.)
|
||||
return AddComponent(arglist(args))
|
||||
return _AddComponent(args)
|
||||
|
||||
/**
|
||||
* Removes the component from parent, ends up with a null parent
|
||||
*/
|
||||
/datum/component/proc/RemoveComponent()
|
||||
if(!parent)
|
||||
return
|
||||
@@ -280,6 +453,14 @@
|
||||
parent = null
|
||||
SEND_SIGNAL(old_parent, COMSIG_COMPONENT_REMOVING, src)
|
||||
|
||||
/**
|
||||
* Transfer this component to another parent
|
||||
*
|
||||
* Component is taken from source datum
|
||||
*
|
||||
* Arguments:
|
||||
* * datum/component/target Target datum to transfer to
|
||||
*/
|
||||
/datum/proc/TakeComponent(datum/component/target)
|
||||
if(!target || target.parent == src)
|
||||
return
|
||||
@@ -296,6 +477,14 @@
|
||||
if(target == AddComponent(target))
|
||||
target._JoinParent()
|
||||
|
||||
/**
|
||||
* Transfer all components to target
|
||||
*
|
||||
* All components from source datum are taken
|
||||
*
|
||||
* Arguments:
|
||||
* * /datum/target the target to move the components to
|
||||
*/
|
||||
/datum/proc/TransferComponents(datum/target)
|
||||
var/list/dc = datum_components
|
||||
if(!dc)
|
||||
@@ -310,5 +499,8 @@
|
||||
if(C.can_transfer)
|
||||
target.TakeComponent(comps)
|
||||
|
||||
/**
|
||||
* Return the object that is the host of any UI's that this component has
|
||||
*/
|
||||
/datum/component/ui_host()
|
||||
return parent
|
||||
|
||||
@@ -30,26 +30,23 @@
|
||||
return ..()
|
||||
|
||||
/datum/component/fantasy/RegisterWithParent()
|
||||
. = ..()
|
||||
var/obj/item/master = parent
|
||||
originalName = master.name
|
||||
modify()
|
||||
|
||||
/datum/component/fantasy/UnregisterFromParent()
|
||||
. = ..()
|
||||
unmodify()
|
||||
|
||||
/datum/component/fantasy/InheritComponent(datum/component/fantasy/newComp, original, list/arguments)
|
||||
/datum/component/fantasy/InheritComponent(datum/component/fantasy/newComp, original, quality, list/affixes, canFail, announce)
|
||||
unmodify()
|
||||
if(newComp)
|
||||
quality += newComp.quality
|
||||
canFail = newComp.canFail
|
||||
announce = newComp.announce
|
||||
src.quality += newComp.quality
|
||||
src.canFail = newComp.canFail
|
||||
src.announce = newComp.announce
|
||||
else
|
||||
arguments.len = 5 // This is done to replicate what happens when an arglist smaller than the necessary arguments is given
|
||||
quality += arguments[1]
|
||||
canFail = arguments[4] || canFail
|
||||
announce = arguments[5] || announce
|
||||
src.quality += quality
|
||||
src.canFail = canFail || src.canFail
|
||||
src.announce = announce || src.announce
|
||||
modify()
|
||||
|
||||
/datum/component/fantasy/proc/randomQuality()
|
||||
|
||||
@@ -101,11 +101,11 @@
|
||||
host_mob = null
|
||||
return ..()
|
||||
|
||||
/datum/component/nanites/InheritComponent(datum/component/nanites/new_nanites, i_am_original, list/arguments)
|
||||
/datum/component/nanites/InheritComponent(datum/component/nanites/new_nanites, i_am_original, amount, cloud)
|
||||
if(new_nanites)
|
||||
adjust_nanites(null, new_nanites.nanite_volume)
|
||||
else
|
||||
adjust_nanites(null, arguments[1]) //just add to the nanite volume
|
||||
adjust_nanites(null, amount) //just add to the nanite volume
|
||||
|
||||
/datum/component/nanites/process()
|
||||
adjust_nanites(null, regen_rate)
|
||||
|
||||
@@ -41,9 +41,9 @@
|
||||
orbiters = null
|
||||
return ..()
|
||||
|
||||
/datum/component/orbiter/InheritComponent(datum/component/orbiter/newcomp, original, list/arguments)
|
||||
if(arguments)
|
||||
begin_orbit(arglist(arguments))
|
||||
/datum/component/orbiter/InheritComponent(datum/component/orbiter/newcomp, original, atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
|
||||
if(!newcomp)
|
||||
begin_orbit(arglist(args.Copy(3)))
|
||||
return
|
||||
// The following only happens on component transfers
|
||||
orbiters += newcomp.orbiters
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
if(strength <= RAD_BACKGROUND_RADIATION)
|
||||
return PROCESS_KILL
|
||||
|
||||
/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original, list/arguments)
|
||||
/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original, _strength, _source, _half_life, _can_contaminate)
|
||||
if(!i_am_original)
|
||||
return
|
||||
if(!hl3_release_date) // Permanently radioactive things don't get to grow stronger
|
||||
@@ -56,7 +56,7 @@
|
||||
var/datum/component/radioactive/other = C
|
||||
strength = max(strength, other.strength)
|
||||
else
|
||||
strength = max(strength, arguments[1])
|
||||
strength = max(strength, _strength)
|
||||
|
||||
/datum/component/radioactive/proc/rad_examine(datum/source, mob/user, list/examine_list)
|
||||
var/atom/master = parent
|
||||
|
||||
@@ -53,11 +53,21 @@ handles linking back and forth.
|
||||
|
||||
/datum/component/remote_materials/proc/_MakeLocal()
|
||||
silo = null
|
||||
mat_container = parent.AddComponent(/datum/component/material_container,
|
||||
list(/datum/material/iron, /datum/material/glass, /datum/material/silver, /datum/material/gold, /datum/material/diamond, /datum/material/plasma, /datum/material/uranium, /datum/material/bananium, /datum/material/titanium, /datum/material/bluespace, /datum/material/plastic),
|
||||
local_size,
|
||||
FALSE,
|
||||
/obj/item/stack)
|
||||
var/static/list/allowed_mats = list(
|
||||
/datum/material/iron,
|
||||
/datum/material/glass,
|
||||
/datum/material/silver,
|
||||
/datum/material/gold,
|
||||
/datum/material/diamond,
|
||||
/datum/material/plasma,
|
||||
/datum/material/uranium,
|
||||
/datum/material/bananium,
|
||||
/datum/material/titanium,
|
||||
/datum/material/bluespace,
|
||||
/datum/material/plastic,
|
||||
)
|
||||
|
||||
mat_container = parent.AddComponent(/datum/component/material_container, allowed_mats, local_size, allowed_types=/obj/item/stack)
|
||||
|
||||
/datum/component/remote_materials/proc/set_local_size(size)
|
||||
local_size = size
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
src.allow_death = allow_death
|
||||
check_in_bounds() // Just in case something is being created outside of station/centcom
|
||||
|
||||
/datum/component/stationloving/InheritComponent(datum/component/stationloving/newc, original, list/arguments)
|
||||
/datum/component/stationloving/InheritComponent(datum/component/stationloving/newc, original, inform_admins, allow_death)
|
||||
if (original)
|
||||
if (istype(newc))
|
||||
if (newc)
|
||||
inform_admins = newc.inform_admins
|
||||
allow_death = newc.allow_death
|
||||
else if (LAZYLEN(arguments))
|
||||
inform_admins = arguments[1]
|
||||
else
|
||||
inform_admins = inform_admins
|
||||
|
||||
/datum/component/stationloving/proc/relocate()
|
||||
var/targetturf = find_safe_turf()
|
||||
|
||||
@@ -43,13 +43,13 @@
|
||||
master.cut_overlay(overlay)
|
||||
return ..()
|
||||
|
||||
/datum/component/thermite/InheritComponent(datum/component/thermite/newC, i_am_original, list/arguments)
|
||||
/datum/component/thermite/InheritComponent(datum/component/thermite/newC, i_am_original, _amount)
|
||||
if(!i_am_original)
|
||||
return
|
||||
if(newC)
|
||||
amount += newC.amount
|
||||
else
|
||||
amount += arguments[1]
|
||||
amount += _amount
|
||||
|
||||
/datum/component/thermite/proc/thermite_melt(mob/user)
|
||||
var/turf/master = parent
|
||||
|
||||
@@ -28,7 +28,7 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
var/compact_mode = FALSE
|
||||
var/debug = FALSE
|
||||
|
||||
/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/ui_state/_checkstate)
|
||||
/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/ui_state/_checkstate, datum/traitor_class/traitor_class)
|
||||
if(!isitem(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
@@ -47,7 +47,11 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
RegisterSignal(parent, COMSIG_PEN_ROTATED, .proc/pen_rotation)
|
||||
|
||||
GLOB.uplinks += src
|
||||
uplink_items = get_uplink_items(gamemode, TRUE, allow_restricted)
|
||||
var/list/filters = list()
|
||||
if(istype(traitor_class))
|
||||
filters = traitor_class.uplink_filters
|
||||
starting_tc = traitor_class.TC
|
||||
uplink_items = get_uplink_items(gamemode, TRUE, allow_restricted, filters)
|
||||
|
||||
if(_owner)
|
||||
owner = _owner
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
var/permanent = FALSE
|
||||
var/last_process = 0
|
||||
|
||||
/datum/component/wet_floor/InheritComponent(datum/newcomp, orig, argslist)
|
||||
/datum/component/wet_floor/InheritComponent(datum/newcomp, orig, strength, duration_minimum, duration_add, duration_maximum, _permanent)
|
||||
if(!newcomp) //We are getting passed the arguments of a would-be new component, but not a new component
|
||||
add_wet(arglist(argslist))
|
||||
add_wet(arglist(args.Copy(3)))
|
||||
else //We are being passed in a full blown component
|
||||
var/datum/component/wet_floor/WF = newcomp //Lets make an assumption
|
||||
if(WF.gc()) //See if it's even valid, still. Also does LAZYLEN and stuff for us.
|
||||
|
||||
+48
-5
@@ -1,12 +1,42 @@
|
||||
/**
|
||||
* The absolute base class for everything
|
||||
*
|
||||
* A datum instantiated has no physical world prescence, use an atom if you want something
|
||||
* that actually lives in the world
|
||||
*
|
||||
* Be very mindful about adding variables to this class, they are inherited by every single
|
||||
* thing in the entire game, and so you can easily cause memory usage to rise a lot with careless
|
||||
* use of variables at this level
|
||||
*/
|
||||
/datum
|
||||
/**
|
||||
* Tick count time when this object was destroyed.
|
||||
*
|
||||
* If this is non zero then the object has been garbage collected and is awaiting either
|
||||
* a hard del by the GC subsystme, or to be autocollected (if it has no references)
|
||||
*/
|
||||
var/gc_destroyed //Time when this object was destroyed.
|
||||
var/list/active_timers //for SStimer
|
||||
var/list/datum_components //for /datum/components
|
||||
|
||||
/// Active timers with this datum as the target
|
||||
var/list/active_timers
|
||||
/// Status traits attached to this datum
|
||||
var/list/status_traits
|
||||
/// Components attached to this datum
|
||||
/// Lazy associated list in the structure of `type:component/list of components`
|
||||
var/list/datum_components
|
||||
/// Any datum registered to receive signals from this datum is in this list
|
||||
/// Lazy associated list in the structure of `signal:registree/list of registrees`
|
||||
var/list/comp_lookup //it used to be for looking up components which had registered a signal but now anything can register
|
||||
/// Lazy associated list in the structure of `signals:proctype` that are run when the datum receives that signal
|
||||
var/list/list/datum/callback/signal_procs
|
||||
/// Is this datum capable of sending signals?
|
||||
/// Set to true when a signal has been registered
|
||||
var/signal_enabled = FALSE
|
||||
|
||||
/// Datum level flags
|
||||
var/datum_flags = NONE
|
||||
|
||||
/// A weak reference to another datum
|
||||
var/datum/weakref/weak_reference
|
||||
|
||||
#ifdef TESTING
|
||||
@@ -18,9 +48,22 @@
|
||||
var/list/cached_vars
|
||||
#endif
|
||||
|
||||
// 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.
|
||||
/**
|
||||
* Default implementation of clean-up code.
|
||||
*
|
||||
* This should be overridden to remove all references pointing to the object being destroyed, if
|
||||
* you do override it, make sure to call the parent and return it's return value by default
|
||||
*
|
||||
* Return an appropriate QDEL_HINT to modify handling of your deletion;
|
||||
* in most cases this is QDEL_HINT_QUEUE.
|
||||
*
|
||||
* The base case is responsible for doing the following
|
||||
* * Erasing timers pointing to this datum
|
||||
* * Erasing compenents on this datum
|
||||
* * Notifying datums listening to signals from this datum that we are going away
|
||||
*
|
||||
* Returns QDEL_HINT_QUEUE
|
||||
*/
|
||||
/datum/proc/Destroy(force=FALSE, ...)
|
||||
tag = null
|
||||
datum_flags &= ~DF_USE_TAG //In case something tries to REF us
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
/**
|
||||
* A holder for simple behaviour that can be attached to many different types
|
||||
*
|
||||
* Only one element of each type is instanced during game init.
|
||||
* Otherwise acts basically like a lightweight component.
|
||||
*/
|
||||
/datum/element
|
||||
/// Option flags for element behaviour
|
||||
var/element_flags = NONE
|
||||
/**
|
||||
* The index of the first attach argument to consider for duplicate elements
|
||||
@@ -7,13 +14,17 @@
|
||||
*/
|
||||
var/id_arg_index = INFINITY
|
||||
|
||||
/// Activates the functionality defined by the element on the given target datum
|
||||
/datum/element/proc/Attach(datum/target)
|
||||
SHOULD_CALL_PARENT(1)
|
||||
if(type == /datum/element)
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
if(element_flags & ELEMENT_DETACH)
|
||||
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/Detach, override = TRUE)
|
||||
|
||||
/// Deactivates the functionality defines by the element on the given datum
|
||||
/datum/element/proc/Detach(datum/source, force)
|
||||
SHOULD_CALL_PARENT(1)
|
||||
UnregisterSignal(source, COMSIG_PARENT_QDELETING)
|
||||
|
||||
/datum/element/Destroy(force)
|
||||
@@ -24,16 +35,17 @@
|
||||
|
||||
//DATUM PROCS
|
||||
|
||||
/datum/proc/AddElement(eletype, ...)
|
||||
var/datum/element/ele = SSdcs.GetElement(arglist(args))
|
||||
args[1] = src
|
||||
if(ele.Attach(arglist(args)) == ELEMENT_INCOMPATIBLE)
|
||||
CRASH("Incompatible [eletype] assigned to a [type]! args: [json_encode(args)]")
|
||||
/// Finds the singleton for the element type given and attaches it to src
|
||||
/datum/proc/_AddElement(list/arguments)
|
||||
var/datum/element/ele = SSdcs.GetElement(arguments)
|
||||
arguments[1] = src
|
||||
if(ele.Attach(arglist(arguments)) == ELEMENT_INCOMPATIBLE)
|
||||
CRASH("Incompatible [arguments[1]] assigned to a [type]! args: [json_encode(args)]")
|
||||
|
||||
/**
|
||||
* Finds the singleton for the element type given and detaches it from src
|
||||
* You only need additional arguments beyond the type if you're using ELEMENT_BESPOKE
|
||||
*/
|
||||
/datum/proc/RemoveElement(eletype, ...)
|
||||
var/datum/element/ele = SSdcs.GetElement(arglist(args))
|
||||
/datum/proc/_RemoveElement(list/arguments)
|
||||
var/datum/element/ele = SSdcs.GetElement(arguments)
|
||||
ele.Detach(src)
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
penalty += roundstart_quit_limit - world.time
|
||||
if(penalty)
|
||||
penalty += world.realtime
|
||||
var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
|
||||
if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
|
||||
penalty = CANT_REENTER_ROUND
|
||||
if(SSautotransfer.can_fire && SSautotransfer.maxvotes)
|
||||
var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
|
||||
if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
|
||||
penalty = CANT_REENTER_ROUND
|
||||
if(!(M.ckey in timeouts))
|
||||
timeouts += M.ckey
|
||||
timeouts[M.ckey] = 0
|
||||
|
||||
@@ -8,18 +8,18 @@
|
||||
var/inv_slots
|
||||
var/proctype //if present, will be invoked on headwear generation.
|
||||
|
||||
/datum/element/mob_holder/Attach(datum/target, _worn_state, _alt_worn, _right_hand, _left_hand, _inv_slots = NONE, _proctype)
|
||||
/datum/element/mob_holder/Attach(datum/target, worn_state, alt_worn, right_hand, left_hand, inv_slots = NONE, proctype)
|
||||
. = ..()
|
||||
|
||||
if(!isliving(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
worn_state = _worn_state
|
||||
alt_worn = _alt_worn
|
||||
right_hand = _right_hand
|
||||
left_hand = _left_hand
|
||||
inv_slots = _inv_slots
|
||||
proctype = _proctype
|
||||
src.worn_state = worn_state
|
||||
src.alt_worn = alt_worn
|
||||
src.right_hand = right_hand
|
||||
src.left_hand = left_hand
|
||||
src.inv_slots = inv_slots
|
||||
src.proctype = proctype
|
||||
|
||||
RegisterSignal(target, COMSIG_CLICK_ALT, .proc/mob_try_pickup)
|
||||
RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/on_examine)
|
||||
|
||||
@@ -93,12 +93,12 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
/datum/material/plasma/on_applied(atom/source, amount, material_flags)
|
||||
. = ..()
|
||||
if(ismovableatom(source))
|
||||
source.AddElement(/datum/element/firestacker)
|
||||
source.AddElement(/datum/element/firestacker, amount=1)
|
||||
source.AddComponent(/datum/component/explodable, 0, 0, amount / 2500, amount / 1250)
|
||||
|
||||
/datum/material/plasma/on_removed(atom/source, material_flags)
|
||||
. = ..()
|
||||
source.RemoveElement(/datum/element/firestacker)
|
||||
source.RemoveElement(/datum/element/firestacker, amount=1)
|
||||
qdel(source.GetComponent(/datum/component/explodable))
|
||||
|
||||
///Can cause bluespace effects on use. (Teleportation) (Not yet implemented)
|
||||
|
||||
+8
-6
@@ -256,9 +256,11 @@
|
||||
remove_rev()
|
||||
SSticker.mode.update_cult_icons_removed(src)
|
||||
|
||||
/datum/mind/proc/equip_traitor(employer = "The Syndicate", silent = FALSE, datum/antagonist/uplink_owner)
|
||||
/datum/mind/proc/equip_traitor(datum/traitor_class/traitor_class, silent = FALSE, datum/antagonist/uplink_owner)
|
||||
if(!current)
|
||||
return
|
||||
if(!traitor_class)
|
||||
traitor_class = GLOB.traitor_classes[TRAITOR_HUMAN]
|
||||
var/mob/living/carbon/human/traitor_mob = current
|
||||
if (!istype(traitor_mob))
|
||||
return
|
||||
@@ -306,21 +308,21 @@
|
||||
|
||||
if (!uplink_loc)
|
||||
if(!silent)
|
||||
to_chat(traitor_mob, "Unfortunately, [employer] wasn't able to get you an Uplink.")
|
||||
to_chat(traitor_mob, "Unfortunately, [traitor_class.employer] wasn't able to get you an Uplink.")
|
||||
. = 0
|
||||
else
|
||||
. = uplink_loc
|
||||
var/datum/component/uplink/U = uplink_loc.AddComponent(/datum/component/uplink, traitor_mob.key)
|
||||
var/datum/component/uplink/U = uplink_loc.AddComponent(/datum/component/uplink, traitor_mob.key,traitor_class)
|
||||
if(!U)
|
||||
CRASH("Uplink creation failed.")
|
||||
U.setup_unlock_code()
|
||||
if(!silent)
|
||||
if(uplink_loc == R)
|
||||
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [R.name]. Simply dial the frequency [format_frequency(U.unlock_code)] to unlock its hidden features.")
|
||||
to_chat(traitor_mob, "[traitor_class.employer] has cunningly disguised a Syndicate Uplink as your [R.name]. Simply dial the frequency [format_frequency(U.unlock_code)] to unlock its hidden features.")
|
||||
else if(uplink_loc == PDA)
|
||||
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [PDA.name]. Simply enter the code \"[U.unlock_code]\" into the ringtone select to unlock its hidden features.")
|
||||
to_chat(traitor_mob, "[traitor_class.employer] has cunningly disguised a Syndicate Uplink as your [PDA.name]. Simply enter the code \"[U.unlock_code]\" into the ringtone select to unlock its hidden features.")
|
||||
else if(uplink_loc == P)
|
||||
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [P.name]. Simply twist the top of the pen [U.unlock_code] from its starting position to unlock its hidden features.")
|
||||
to_chat(traitor_mob, "[traitor_class.employer] has cunningly disguised a Syndicate Uplink as your [P.name]. Simply twist the top of the pen [U.unlock_code] from its starting position to unlock its hidden features.")
|
||||
|
||||
if(uplink_owner)
|
||||
uplink_owner.antag_memory += U.unlock_note + "<br>"
|
||||
|
||||
@@ -273,10 +273,14 @@
|
||||
var/ion_announce = 33
|
||||
var/removeDontImproveChance = 10
|
||||
|
||||
/datum/dynamic_ruleset/midround/malf/ready()
|
||||
if(!candidates || !candidates.len)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/dynamic_ruleset/midround/malf/trim_candidates()
|
||||
..()
|
||||
living_players = candidates[CURRENT_LIVING_PLAYERS]
|
||||
for(var/mob/living/player in candidates)
|
||||
for(var/mob/living/player in living_players)
|
||||
if(!isAI(player))
|
||||
candidates -= player
|
||||
continue
|
||||
@@ -287,8 +291,6 @@
|
||||
candidates -= player
|
||||
|
||||
/datum/dynamic_ruleset/midround/malf/execute()
|
||||
if(!candidates || !candidates.len)
|
||||
return FALSE
|
||||
var/mob/living/silicon/ai/M = pick_n_take(candidates)
|
||||
assigned += M.mind
|
||||
var/datum/antagonist/traitor/AI = new
|
||||
@@ -337,6 +339,7 @@
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/wizard/finish_setup(mob/new_character, index)
|
||||
..()
|
||||
new_character.forceMove(pick(GLOB.wizardstart))
|
||||
wizard = new_character.mind
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/wizard/rule_process() // i can literally copy this from are_special_antags_dead it's great
|
||||
if(isliving(wizard.current) && wizard.current.stat!=DEAD)
|
||||
@@ -447,9 +450,7 @@
|
||||
property_weights = list("story_potential" = -1, "trust" = 1, "chaos" = 2, "extended" = -2, "valid" = 2)
|
||||
var/list/vents = list()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/execute()
|
||||
// 50% chance of being incremented by one
|
||||
required_candidates += prob(50)
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/ready()
|
||||
for(var/obj/machinery/atmospherics/components/unary/vent_pump/temp_vent in GLOB.machines)
|
||||
if(QDELETED(temp_vent))
|
||||
continue
|
||||
@@ -463,6 +464,12 @@
|
||||
vents += temp_vent
|
||||
if(!vents.len)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/execute()
|
||||
// 50% chance of being incremented by one
|
||||
required_candidates += prob(50)
|
||||
. = ..()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/generate_ruleset_body(mob/applicant)
|
||||
@@ -497,7 +504,7 @@
|
||||
property_weights = list("story_potential" = 1, "trust" = 1, "extended" = 1, "valid" = 2, "integrity" = 1)
|
||||
var/list/spawn_locs = list()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/nightmare/execute()
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/nightmare/ready()
|
||||
for(var/X in GLOB.xeno_spawn)
|
||||
var/turf/T = X
|
||||
var/light_amount = T.get_lumcount()
|
||||
@@ -505,7 +512,7 @@
|
||||
spawn_locs += T
|
||||
if(!spawn_locs.len)
|
||||
return FALSE
|
||||
. = ..()
|
||||
return ..()
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/nightmare/generate_ruleset_body(mob/applicant)
|
||||
var/datum/mind/player_mind = new /datum/mind(applicant.key)
|
||||
|
||||
@@ -232,7 +232,7 @@ Property weights are:
|
||||
pop_antag_ratio = 7
|
||||
flags = USE_PREF_WEIGHTS
|
||||
|
||||
/datum/dynamic_storyteller/memes
|
||||
/datum/dynamic_storyteller/story
|
||||
name = "Story"
|
||||
config_tag = "story"
|
||||
desc = "Antags with options for loadouts and gimmicks. Traitor, wizard, nukies."
|
||||
|
||||
@@ -1163,12 +1163,17 @@ GLOBAL_LIST_EMPTY(possible_sabotages)
|
||||
var/payout = 0
|
||||
var/payout_bonus = 0
|
||||
var/area/dropoff = null
|
||||
var/static/list/blacklisted_areas = typecacheof(list(/area/ai_monitored/turret_protected,
|
||||
/area/solar/,
|
||||
/area/ruin/, //thank you station space ruins
|
||||
/area/science/test_area/,
|
||||
/area/shuttle/))
|
||||
|
||||
/datum/objective/contract/proc/generate_dropoff() // Generate a random valid area on the station that the dropoff will happen.
|
||||
var/found = FALSE
|
||||
while(!found)
|
||||
var/area/dropoff_area = pick(GLOB.sortedAreas)
|
||||
if(dropoff_area && is_station_level(dropoff_area.z) && !dropoff_area.outdoors && !istype(dropoff_area, /area/shuttle/))
|
||||
if(dropoff_area && is_station_level(dropoff_area.z) && !dropoff_area.outdoors && !is_type_in_typecache(dropoff_area, blacklisted_areas))
|
||||
dropoff = dropoff_area
|
||||
found = TRUE
|
||||
|
||||
|
||||
@@ -47,8 +47,8 @@
|
||||
)
|
||||
|
||||
/obj/machinery/autolathe/Initialize()
|
||||
AddComponent(/datum/component/material_container,
|
||||
list(/datum/material/iron,
|
||||
var/static/list/allowed_types = list(
|
||||
/datum/material/iron,
|
||||
/datum/material/glass,
|
||||
/datum/material/gold,
|
||||
/datum/material/silver,
|
||||
@@ -62,10 +62,9 @@
|
||||
/datum/material/plastic,
|
||||
/datum/material/adamantine,
|
||||
/datum/material/mythril
|
||||
),
|
||||
0, TRUE, null, null, CALLBACK(src, .proc/AfterMaterialInsert))
|
||||
)
|
||||
AddComponent(/datum/component/material_container, allowed_types, _show_on_examine=TRUE, _after_insert=CALLBACK(src, .proc/AfterMaterialInsert))
|
||||
. = ..()
|
||||
|
||||
wires = new /datum/wires/autolathe(src)
|
||||
stored_research = new /datum/techweb/specialized/autounlocking/autolathe
|
||||
matching_designs = list()
|
||||
|
||||
@@ -46,7 +46,12 @@
|
||||
)
|
||||
|
||||
/obj/machinery/autoylathe/Initialize()
|
||||
AddComponent(/datum/component/material_container, list(/datum/material/iron, /datum/material/glass, /datum/material/plastic), 0, TRUE, null, null, CALLBACK(src, .proc/AfterMaterialInsert))
|
||||
var/static/list/allowed_materials = list(
|
||||
/datum/material/iron,
|
||||
/datum/material/glass,
|
||||
/datum/material/plastic
|
||||
)
|
||||
AddComponent(/datum/component/material_container, allowed_materials, 0, TRUE, null, null, CALLBACK(src, .proc/AfterMaterialInsert))
|
||||
. = ..()
|
||||
|
||||
wires = new /datum/wires/autoylathe(src)
|
||||
|
||||
@@ -35,9 +35,19 @@
|
||||
)
|
||||
|
||||
/obj/machinery/mecha_part_fabricator/Initialize()
|
||||
var/datum/component/material_container/materials = AddComponent(/datum/component/material_container,
|
||||
list(/datum/material/iron, /datum/material/glass, /datum/material/silver, /datum/material/gold, /datum/material/diamond, /datum/material/plasma, /datum/material/uranium, /datum/material/bananium, /datum/material/titanium, /datum/material/bluespace), 0,
|
||||
TRUE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
|
||||
var/static/list/allowed_types = list(
|
||||
/datum/material/iron,
|
||||
/datum/material/glass,
|
||||
/datum/material/silver,
|
||||
/datum/material/gold,
|
||||
/datum/material/diamond,
|
||||
/datum/material/plasma,
|
||||
/datum/material/uranium,
|
||||
/datum/material/bananium,
|
||||
/datum/material/titanium,
|
||||
/datum/material/bluespace
|
||||
)
|
||||
var/datum/component/material_container/materials = AddComponent(/datum/component/material_container, allowed_types, 0, TRUE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
|
||||
materials.precise_insertion = TRUE
|
||||
stored_research = new
|
||||
return ..()
|
||||
|
||||
@@ -462,7 +462,7 @@
|
||||
desc = "An upgrade to the Medical module's hypospray, containing \
|
||||
stronger versions of existing chemicals."
|
||||
additional_reagents = list(/datum/reagent/medicine/oxandrolone, /datum/reagent/medicine/sal_acid,
|
||||
/datum/reagent/medicine/rezadone, /datum/reagent/medicine/pen_acid)
|
||||
/datum/reagent/medicine/rezadone, /datum/reagent/medicine/pen_acid, /datum/reagent/medicine/prussian_blue)
|
||||
|
||||
/obj/item/borg/upgrade/piercing_hypospray
|
||||
name = "cyborg piercing hypospray"
|
||||
|
||||
@@ -525,14 +525,6 @@
|
||||
desc = "A kit containing a Deluxe hypospray and Vials."
|
||||
icon_state = "tactical-mini"
|
||||
|
||||
/obj/item/storage/hypospraykit/cmo/ComponentInitialize()
|
||||
. = ..()
|
||||
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
|
||||
STR.max_items = 6
|
||||
STR.can_hold = typecacheof(list(
|
||||
/obj/item/hypospray/mkii,
|
||||
/obj/item/reagent_containers/glass/bottle/vial))
|
||||
|
||||
/obj/item/storage/hypospraykit/cmo/PopulateContents()
|
||||
if(empty)
|
||||
return
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
/obj/item/melee/baton/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<span class='notice'>Right click attack while in combat mode or attack while in disarm intent to disarm instead of stun.</span>"
|
||||
. += "<span class='notice'>Right click attack while in combat mode to disarm instead of stun.</span>"
|
||||
|
||||
/obj/item/melee/baton/get_cell()
|
||||
. = cell
|
||||
@@ -149,8 +149,6 @@
|
||||
|
||||
//return TRUE to interrupt attack chain.
|
||||
/obj/item/melee/baton/proc/common_baton_melee(mob/M, mob/living/user, disarming = FALSE)
|
||||
if(user.a_intent == INTENT_DISARM)
|
||||
disarming = TRUE //override if they're in disarm intent.
|
||||
if(iscyborg(M) || !isliving(M)) //can't baton cyborgs
|
||||
return FALSE
|
||||
if(status && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
|
||||
|
||||
@@ -315,13 +315,8 @@
|
||||
|
||||
/obj/structure/windoor_assembly/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(
|
||||
/datum/component/simple_rotation,
|
||||
ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS,
|
||||
null,
|
||||
CALLBACK(src, .proc/can_be_rotated),
|
||||
CALLBACK(src,.proc/after_rotation)
|
||||
)
|
||||
var/static/rotation_flags = ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS
|
||||
AddComponent(/datum/component/simple_rotation, rotation_flags, can_be_rotated=CALLBACK(src, .proc/can_be_rotated), after_rotation=CALLBACK(src,.proc/after_rotation))
|
||||
|
||||
/obj/structure/windoor_assembly/proc/can_be_rotated(mob/user,rotation_type)
|
||||
if(anchored)
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
icon_state = "blob_glow"
|
||||
flags_1 = CHECK_RICOCHET_1
|
||||
point_return = 8
|
||||
max_integrity = 50
|
||||
max_integrity = 100
|
||||
brute_resist = 1
|
||||
explosion_block = 2
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
var/list/nodes = list()
|
||||
for(var/i in 1 to GLOB.blob_nodes.len)
|
||||
var/obj/structure/blob/node/B = GLOB.blob_nodes[i]
|
||||
nodes["Blob Node #[i] ([B.overmind ? "[B.overmind.blobstrain.name]":"No Strain"])"] = B
|
||||
nodes["Blob Node #[i] ([get_area_name(B)])"] = B
|
||||
var/node_name = input(src, "Choose a node to jump to.", "Node Jump") in nodes
|
||||
var/obj/structure/blob/node/chosen_node = nodes[node_name]
|
||||
if(chosen_node)
|
||||
@@ -120,13 +120,13 @@
|
||||
/mob/camera/blob/proc/create_shield(turf/T)
|
||||
var/obj/structure/blob/shield/S = locate(/obj/structure/blob/shield) in T
|
||||
if(S)
|
||||
if(!can_buy(15))
|
||||
if(!can_buy(BLOB_REFLECTOR_COST))
|
||||
return
|
||||
if(S.obj_integrity < S.max_integrity * 0.5)
|
||||
add_points(BLOB_REFLECTOR_COST)
|
||||
to_chat(src, "<span class='warning'>This shield blob is too damaged to be modified properly!</span>")
|
||||
return
|
||||
to_chat(src, "<span class='warning'>You secrete a reflective ooze over the shield blob, allowing it to reflect projectiles at the cost of reduced intregrity.</span>")
|
||||
to_chat(src, "<span class='warning'>You secrete a reflective ooze over the shield blob, allowing it to reflect projectiles at the cost of reduced integrity.</span>")
|
||||
S.change_to(/obj/structure/blob/shield/reflective, src)
|
||||
else
|
||||
createSpecial(15, /obj/structure/blob/shield, 0, 0, T)
|
||||
@@ -247,8 +247,8 @@
|
||||
|
||||
/mob/camera/blob/verb/expand_blob_power()
|
||||
set category = "Blob"
|
||||
set name = "Expand/Attack Blob (4)"
|
||||
set desc = "Attempts to create a new blob in this tile. If the tile isn't clear, instead attacks it, damaging mobs and objects."
|
||||
set name = "Expand/Attack Blob ([BLOB_SPREAD_COST])"
|
||||
set desc = "Attempts to create a new blob in this tile. If the tile isn't clear, instead attacks it, damaging mobs and objects and refunding [BLOB_ATTACK_REFUND] points."
|
||||
var/turf/T = get_turf(src)
|
||||
expand_blob(T)
|
||||
|
||||
@@ -261,7 +261,7 @@
|
||||
if(!possibleblobs.len)
|
||||
to_chat(src, "<span class='warning'>There is no blob adjacent to the target tile!</span>")
|
||||
return
|
||||
if(can_buy(4))
|
||||
if(can_buy(BLOB_SPREAD_COST))
|
||||
var/attacksuccess = FALSE
|
||||
for(var/mob/living/L in T)
|
||||
if(ROLE_BLOB in L.faction) //no friendly/dead fire
|
||||
@@ -271,11 +271,11 @@
|
||||
blobstrain.attack_living(L)
|
||||
var/obj/structure/blob/B = locate() in T
|
||||
if(B)
|
||||
if(attacksuccess) //if we successfully attacked a turf with a blob on it, don't refund shit
|
||||
if(attacksuccess) //if we successfully attacked a turf with a blob on it, only give an attack refund
|
||||
B.blob_attack_animation(T, src)
|
||||
else
|
||||
to_chat(src, "<span class='warning'>There is a blob there!</span>")
|
||||
add_points(4) //otherwise, refund all of the cost
|
||||
add_points(BLOB_SPREAD_COST) //otherwise, refund all of the cost
|
||||
else
|
||||
var/list/cardinalblobs = list()
|
||||
var/list/diagonalblobs = list()
|
||||
@@ -288,14 +288,15 @@
|
||||
var/obj/structure/blob/OB
|
||||
if(cardinalblobs.len)
|
||||
OB = pick(cardinalblobs)
|
||||
OB.expand(T, src)
|
||||
if(!OB.expand(T, src))
|
||||
add_points(BLOB_ATTACK_REFUND) //assume it's attacked SOMETHING, possibly a structure
|
||||
else
|
||||
OB = pick(diagonalblobs)
|
||||
if(attacksuccess)
|
||||
OB.blob_attack_animation(T, src)
|
||||
playsound(OB, 'sound/effects/splat.ogg', 50, 1)
|
||||
else
|
||||
add_points(4) //if we're attacking diagonally and didn't hit anything, refund
|
||||
add_points(BLOB_SPREAD_COST) //if we're attacking diagonally and didn't hit anything, refund
|
||||
if(attacksuccess)
|
||||
last_attack = world.time + CLICK_CD_MELEE
|
||||
else
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
// EXPLANATION
|
||||
/datum/objective/bloodsucker/lair/update_explanation_text()
|
||||
explanation_text = "Create a lair by claiming a coffin, and protect it until the end of the shift"// Make sure to keep it safe!"
|
||||
explanation_text = "Create a lair by claiming a coffin, and protect it until the end of the shift."// Make sure to keep it safe!"
|
||||
|
||||
// WIN CONDITIONS?
|
||||
/datum/objective/bloodsucker/lair/check_completion()
|
||||
@@ -228,7 +228,7 @@
|
||||
if (SC && SC.lastgen > 0 && SC.connected_panels.len > 0 && SC.connected_tracker)
|
||||
return FALSE
|
||||
return TRUE
|
||||
*/
|
||||
*/
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -250,15 +250,15 @@
|
||||
// WIN CONDITIONS?
|
||||
/datum/objective/bloodsucker/heartthief/check_completion()
|
||||
// -Must have a body.
|
||||
if (!owner.current)
|
||||
if(!owner.current)
|
||||
return FALSE
|
||||
// Taken from /steal in objective.dm
|
||||
var/list/all_items = owner.current.GetAllContents() // Includes items inside other items.
|
||||
var/itemcount = FALSE
|
||||
for(var/obj/I in all_items) //Check for items
|
||||
if(I == /obj/item/organ/heart)
|
||||
itemcount ++
|
||||
if (itemcount >= target_amount) // Got the right amount?
|
||||
if(istype(I, /obj/item/organ/heart/))
|
||||
itemcount++
|
||||
if(itemcount >= target_amount) // Got the right amount?
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/reinstate_escape_objective()
|
||||
..()
|
||||
var/objtype = traitor_kind == TRAITOR_HUMAN ? /datum/objective/escape : /datum/objective/survive
|
||||
var/objtype = !istype(traitor_kind,TRAITOR_AI) ? /datum/objective/escape : /datum/objective/survive
|
||||
var/datum/objective/escape_objective = new objtype
|
||||
escape_objective.owner = owner
|
||||
add_objective(escape_objective)
|
||||
@@ -215,20 +215,12 @@
|
||||
kill_objective.target = target_mind
|
||||
kill_objective.update_explanation_text()
|
||||
add_objective(kill_objective)
|
||||
|
||||
//Optional traitor objective
|
||||
if(prob(PROB_ACTUAL_TRAITOR))
|
||||
employer = "The Syndicate"
|
||||
owner.special_role = TRAITOR_AGENT_ROLE
|
||||
special_role = TRAITOR_AGENT_ROLE
|
||||
syndicate = TRUE
|
||||
forge_single_objective()
|
||||
return
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/forge_traitor_objectives()
|
||||
forge_iaa_objectives()
|
||||
|
||||
var/objtype = traitor_kind == TRAITOR_HUMAN ? /datum/objective/escape : /datum/objective/survive
|
||||
var/objtype = !istype(traitor_kind,TRAITOR_AI) ? /datum/objective/escape : /datum/objective/survive
|
||||
var/datum/objective/escape_objective = new objtype
|
||||
escape_objective.owner = owner
|
||||
add_objective(escape_objective)
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/datum/traitor_class/ai // this one is special, so has no weight
|
||||
name = "Malfunctioning AI"
|
||||
|
||||
/datum/traitor_class/ai/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/objective_count = 0
|
||||
|
||||
if(prob(30))
|
||||
objective_count += forge_single_objective()
|
||||
|
||||
for(var/i = objective_count, i < CONFIG_GET(number/traitor_objectives_amount), i++)
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
|
||||
var/datum/objective/survive/exist/exist_objective = new
|
||||
exist_objective.owner = T.owner
|
||||
T.add_objective(exist_objective)
|
||||
|
||||
/datum/traitor_class/ai/forge_single_objective(datum/antagonist/traitor/T)
|
||||
.=1
|
||||
var/special_pick = rand(1,4)
|
||||
switch(special_pick)
|
||||
if(1)
|
||||
var/datum/objective/block/block_objective = new
|
||||
block_objective.owner = T.owner
|
||||
T.add_objective(block_objective)
|
||||
if(2)
|
||||
var/datum/objective/purge/purge_objective = new
|
||||
purge_objective.owner = T.owner
|
||||
T.add_objective(purge_objective)
|
||||
if(3)
|
||||
var/datum/objective/robot_army/robot_objective = new
|
||||
robot_objective.owner = T.owner
|
||||
T.add_objective(robot_objective)
|
||||
if(4) //Protect and strand a target
|
||||
var/datum/objective/protect/yandere_one = new
|
||||
yandere_one.owner = T.owner
|
||||
T.add_objective(yandere_one)
|
||||
yandere_one.find_target()
|
||||
var/datum/objective/maroon/yandere_two = new
|
||||
yandere_two.owner = T.owner
|
||||
yandere_two.target = yandere_one.target
|
||||
yandere_two.update_explanation_text() // normally called in find_target()
|
||||
T.add_objective(yandere_two)
|
||||
.=2
|
||||
|
||||
/datum/traitor_class/ai/on_removal(datum/antagonist/traitor/T)
|
||||
var/mob/living/silicon/ai/A = T.owner.current
|
||||
A.set_zeroth_law("")
|
||||
A.verbs -= /mob/living/silicon/ai/proc/choose_modules
|
||||
A.malf_picker.remove_malf_verbs(A)
|
||||
qdel(A.malf_picker)
|
||||
|
||||
|
||||
/datum/traitor_class/ai/apply_innate_effects(mob/living/M)
|
||||
var/mob/living/silicon/ai/A = M
|
||||
A.hack_software = TRUE
|
||||
|
||||
/datum/traitor_class/ai/remove_innate_effects(mob/living/M)
|
||||
var/mob/living/silicon/ai/A = M
|
||||
A.hack_software = FALSE
|
||||
|
||||
/datum/traitor_class/ai/finalize_traitor(datum/antagonist/traitor/T)
|
||||
T.add_law_zero()
|
||||
T.owner.current.playsound_local(get_turf(T.owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
T.owner.current.grant_language(/datum/language/codespeak)
|
||||
return FALSE
|
||||
@@ -0,0 +1,37 @@
|
||||
/datum/traitor_class/human/assassin
|
||||
name = "Donk Co Operative"
|
||||
employer = "Donk Corporation"
|
||||
weight = 0
|
||||
chaos = 1
|
||||
cost = 2
|
||||
|
||||
/datum/traitor_class/human/assassin/forge_single_objective(datum/antagonist/traitor/T)
|
||||
.=1
|
||||
var/permakill_prob = 20
|
||||
var/is_dynamic = FALSE
|
||||
var/datum/game_mode/dynamic/mode
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
is_dynamic = TRUE
|
||||
permakill_prob = max(0,mode.threat_level-50)
|
||||
var/list/active_ais = active_ais()
|
||||
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
|
||||
var/datum/objective/destroy/destroy_objective = new
|
||||
destroy_objective.owner = T.owner
|
||||
destroy_objective.find_target()
|
||||
T.add_objective(destroy_objective)
|
||||
else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN)))
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = T.owner
|
||||
maroon_objective.find_target()
|
||||
T.add_objective(maroon_objective)
|
||||
else if(prob(permakill_prob))
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
else
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
@@ -0,0 +1,12 @@
|
||||
/datum/traitor_class/human/freeform
|
||||
name = "Waffle Co Agent"
|
||||
employer = "Waffle Company"
|
||||
weight = 16
|
||||
chaos = 0
|
||||
|
||||
/datum/traitor_class/human/freeform/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/datum/objective/escape/O = new
|
||||
O.explanation_text = "You have no goals! Whatever you can do do antagonize Nanotrasen, do it! The gimmickier, the better! Make sure to escape alive, though!"
|
||||
O.owner = T.owner
|
||||
T.add_objective(O)
|
||||
return
|
||||
@@ -0,0 +1,18 @@
|
||||
/datum/traitor_class/human/hijack
|
||||
name = "Gorlex Marauder"
|
||||
employer = "The Gorlex Marauders"
|
||||
weight = 3
|
||||
chaos = 5
|
||||
cost = 5
|
||||
uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit)
|
||||
|
||||
/datum/traitor_class/human/hijack/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/datum/objective/hijack/O = new
|
||||
O.explanation_text = "The Gorlex Marauders are letting you do what you want, with one condition: the shuttle must be hijacked by hacking its navigational protocols through the control console (alt click emergency shuttle console)."
|
||||
O.owner = T.owner
|
||||
T.add_objective(O)
|
||||
return
|
||||
|
||||
/datum/traitor_class/human/hijack/finalize_traitor(datum/antagonist/traitor/T)
|
||||
T.hijack_speed=1
|
||||
return TRUE
|
||||
@@ -0,0 +1,82 @@
|
||||
/datum/traitor_class/human
|
||||
name = "Syndicate Agent"
|
||||
chaos = 0
|
||||
|
||||
/datum/traitor_class/human/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/objective_count = 0 //Hijacking counts towards number of objectives
|
||||
if(!SSticker.mode.exchange_blue && SSticker.mode.traitors.len >= 8) //Set up an exchange if there are enough traitors
|
||||
if(!SSticker.mode.exchange_red)
|
||||
SSticker.mode.exchange_red = T.owner
|
||||
else
|
||||
SSticker.mode.exchange_blue = T.owner
|
||||
T.assign_exchange_role(SSticker.mode.exchange_red)
|
||||
T.assign_exchange_role(SSticker.mode.exchange_blue)
|
||||
objective_count += 1 //Exchange counts towards number of objectives
|
||||
var/toa = CONFIG_GET(number/traitor_objectives_amount)
|
||||
for(var/i = objective_count, i < toa, i++)
|
||||
forge_single_objective(T)
|
||||
if(!(locate(/datum/objective/escape) in T.objectives))
|
||||
var/datum/objective/escape/escape_objective = new
|
||||
escape_objective.owner = T.owner
|
||||
T.add_objective(escape_objective)
|
||||
return
|
||||
|
||||
/datum/traitor_class/human/forge_single_objective(datum/antagonist/traitor/T)
|
||||
.=1
|
||||
var/assassin_prob = 50
|
||||
var/is_dynamic = FALSE
|
||||
var/datum/game_mode/dynamic/mode
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
is_dynamic = TRUE
|
||||
assassin_prob = max(0,mode.threat_level-20)
|
||||
if(prob(assassin_prob))
|
||||
if(is_dynamic)
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("[T.owner.name] spent [threat_spent] on an assassination target.")
|
||||
var/list/active_ais = active_ais()
|
||||
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
|
||||
var/datum/objective/destroy/destroy_objective = new
|
||||
destroy_objective.owner = T.owner
|
||||
destroy_objective.find_target()
|
||||
T.add_objective(destroy_objective)
|
||||
else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN)))
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = T.owner
|
||||
maroon_objective.find_target()
|
||||
T.add_objective(maroon_objective)
|
||||
else if(prob(max(0,assassin_prob-20)))
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
else
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
else
|
||||
if(prob(15) && !(locate(/datum/objective/download) in T.objectives) && !(T.owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
|
||||
var/datum/objective/download/download_objective = new
|
||||
download_objective.owner = T.owner
|
||||
download_objective.gen_amount_goal()
|
||||
T.add_objective(download_objective)
|
||||
else if(prob(40)) // cum. not counting download: 40%.
|
||||
var/datum/objective/steal/steal_objective = new
|
||||
steal_objective.owner = T.owner
|
||||
steal_objective.find_target()
|
||||
T.add_objective(steal_objective)
|
||||
else if(prob(100/3)) // cum. not counting download: 20%.
|
||||
var/datum/objective/sabotage/sabotage_objective = new
|
||||
sabotage_objective.owner = T.owner
|
||||
sabotage_objective.find_target()
|
||||
T.add_objective(sabotage_objective)
|
||||
else // cum. not counting download: 40%
|
||||
var/datum/objective/flavor/traitor/flavor_objective = new
|
||||
flavor_objective.owner = T.owner
|
||||
flavor_objective.forge_objective()
|
||||
T.add_objective(flavor_objective)
|
||||
|
||||
/datum/traitor_class/human/greet(datum/antagonist/traitor/T)
|
||||
to_chat(T.owner.current, "<B><font size=2 color=red>You are under contract with [employer]. They have given you your objectives.</font></B>")
|
||||
@@ -0,0 +1,14 @@
|
||||
/datum/traitor_class/human/martyr
|
||||
name = "Tiger Cooperator"
|
||||
employer = "The Tiger Cooperative"
|
||||
weight = 2
|
||||
chaos = 5
|
||||
cost = 5
|
||||
uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit,/datum/uplink_item/bundles_TC/contract_kit)
|
||||
|
||||
/datum/traitor_class/human/martyr/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/datum/objective/martyr/O = new
|
||||
O.explanation_text = "The tiger cooperative have given you free reign. You may do as you wish, as long as you die a glorious death!"
|
||||
O.owner = T.owner
|
||||
T.add_objective(O)
|
||||
return
|
||||
@@ -0,0 +1,40 @@
|
||||
/datum/traitor_class/human/subterfuge
|
||||
name = "MI13 Operative"
|
||||
employer = "MI13"
|
||||
weight = 20
|
||||
chaos = -5
|
||||
|
||||
/datum/traitor_class/human/subterfuge/forge_single_objective(datum/antagonist/traitor/T)
|
||||
.=1
|
||||
var/assassin_prob = 30
|
||||
var/datum/game_mode/dynamic/mode
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
assassin_prob = max(0,mode.threat_level-40)
|
||||
if(prob(assassin_prob))
|
||||
if(prob(assassin_prob))
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
else
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = T.owner
|
||||
maroon_objective.find_target()
|
||||
T.add_objective(maroon_objective)
|
||||
else
|
||||
if(prob(15) && !(locate(/datum/objective/download) in T.objectives) && !(T.owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
|
||||
var/datum/objective/download/download_objective = new
|
||||
download_objective.owner = T.owner
|
||||
download_objective.gen_amount_goal()
|
||||
T.add_objective(download_objective)
|
||||
else if(prob(70)) // cum. not counting download: 40%.
|
||||
var/datum/objective/steal/steal_objective = new
|
||||
steal_objective.owner = T.owner
|
||||
steal_objective.find_target()
|
||||
T.add_objective(steal_objective)
|
||||
else
|
||||
var/datum/objective/sabotage/sabotage_objective = new
|
||||
sabotage_objective.owner = T.owner
|
||||
sabotage_objective.find_target()
|
||||
T.add_objective(sabotage_objective)
|
||||
@@ -0,0 +1,40 @@
|
||||
GLOBAL_LIST_EMPTY(traitor_classes)
|
||||
|
||||
/datum/traitor_class
|
||||
var/name = "Bad Coders Ltd."
|
||||
var/employer = "The Syndicate"
|
||||
var/weight = 0
|
||||
var/chaos = 0
|
||||
var/cost = 0
|
||||
var/TC = 20
|
||||
var/list/uplink_filters
|
||||
|
||||
/datum/traitor_class/New()
|
||||
..()
|
||||
if(src.type in GLOB.traitor_classes)
|
||||
qdel(src)
|
||||
else
|
||||
GLOB.traitor_classes += src.type
|
||||
GLOB.traitor_classes[src.type] = src
|
||||
|
||||
/datum/traitor_class/proc/forge_objectives(datum/antagonist/traitor/T)
|
||||
// Like the old forge_human_objectives. Makes all the objectives for this traitor class.
|
||||
|
||||
/datum/traitor_class/proc/forge_single_objective(datum/antagonist/traitor/T)
|
||||
// As forge_single_objective.
|
||||
|
||||
/datum/traitor_class/proc/on_removal(datum/antagonist/traitor/T)
|
||||
// What this does to the antag datum on removal. Called before proper removal, obviously.
|
||||
|
||||
/datum/traitor_class/proc/apply_innate_effects(mob/living/M)
|
||||
// What innate effects it should have. See: AI.
|
||||
|
||||
/datum/traitor_class/proc/remove_innate_effects(mob/living/M)
|
||||
// Cleaning up the innate effects.
|
||||
|
||||
/datum/traitor_class/proc/greet(datum/antagonist/traitor/T)
|
||||
// Message upon creation. Not necessary, but can be useful.
|
||||
|
||||
/datum/traitor_class/proc/finalize_traitor(datum/antagonist/traitor/T)
|
||||
// Finalization. Return TRUE if should play standard traitor sound/equip, return FALSE if both are special case
|
||||
return TRUE
|
||||
@@ -1,6 +1,3 @@
|
||||
#define TRAITOR_HUMAN "human"
|
||||
#define TRAITOR_AI "AI"
|
||||
|
||||
/datum/antagonist/traitor
|
||||
name = "Traitor"
|
||||
roundend_category = "traitors"
|
||||
@@ -12,43 +9,52 @@
|
||||
var/give_objectives = TRUE
|
||||
var/should_give_codewords = TRUE
|
||||
var/should_equip = TRUE
|
||||
var/traitor_kind = TRAITOR_HUMAN //Set on initial assignment
|
||||
var/datum/traitor_class/traitor_kind
|
||||
var/datum/contractor_hub/contractor_hub
|
||||
hijack_speed = 0.5 //10 seconds per hijack stage by default
|
||||
|
||||
/datum/antagonist/traitor/New()
|
||||
..()
|
||||
if(!GLOB.traitor_classes.len)//Only need to fill the list when it's needed.
|
||||
for(var/I in subtypesof(/datum/traitor_class))
|
||||
new I
|
||||
|
||||
/datum/antagonist/traitor/proc/set_traitor_kind(var/kind)
|
||||
traitor_kind = GLOB.traitor_classes[kind]
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
if(traitor_kind.cost)
|
||||
mode.spend_threat(traitor_kind.cost)
|
||||
mode.log_threat("[traitor_kind.cost] was spent due to [owner.name] being a [traitor_kind.name].")
|
||||
|
||||
/datum/antagonist/traitor/on_gain()
|
||||
if(owner.current && isAI(owner.current))
|
||||
traitor_kind = TRAITOR_AI
|
||||
|
||||
set_traitor_kind(TRAITOR_AI)
|
||||
else
|
||||
var/chaos_weight = 0
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
chaos_weight = (mode.threat - 50)/50
|
||||
var/list/weights = list()
|
||||
for(var/C in GLOB.traitor_classes)
|
||||
var/datum/traitor_class/class = GLOB.traitor_classes[C]
|
||||
var/weight = (1.5*class.weight)/(0.5+NUM_E**(-chaos_weight*class.chaos)) // just a logistic function
|
||||
weights[C] = weight
|
||||
var/choice = pickweightAllowZero(weights)
|
||||
if(!choice)
|
||||
choice = GLOB.traitor_classes[TRAITOR_HUMAN]
|
||||
set_traitor_kind(pickweightAllowZero(weights))
|
||||
traitor_kind.weight *= 0.8 // less likely this round
|
||||
SSticker.mode.traitors += owner
|
||||
owner.special_role = special_role
|
||||
if(give_objectives)
|
||||
forge_traitor_objectives()
|
||||
traitor_kind.forge_objectives(src)
|
||||
finalize_traitor()
|
||||
..()
|
||||
|
||||
/datum/antagonist/traitor/apply_innate_effects()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob && istype(traitor_mob))
|
||||
if(!silent)
|
||||
to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
traitor_mob.dna.remove_mutation(CLOWNMUT)
|
||||
|
||||
/datum/antagonist/traitor/remove_innate_effects()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob && istype(traitor_mob))
|
||||
traitor_mob.dna.add_mutation(CLOWNMUT)
|
||||
|
||||
/datum/antagonist/traitor/on_removal()
|
||||
//Remove malf powers.
|
||||
if(traitor_kind == TRAITOR_AI && owner.current && isAI(owner.current))
|
||||
var/mob/living/silicon/ai/A = owner.current
|
||||
A.set_zeroth_law("")
|
||||
A.verbs -= /mob/living/silicon/ai/proc/choose_modules
|
||||
A.malf_picker.remove_malf_verbs(A)
|
||||
qdel(A.malf_picker)
|
||||
traitor_kind.on_removal(src)
|
||||
SSticker.mode.traitors -= owner
|
||||
if(!silent && owner.current)
|
||||
to_chat(owner.current,"<span class='userdanger'> You are no longer the [special_role]! </span>")
|
||||
@@ -69,192 +75,11 @@
|
||||
objectives -= O
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_traitor_objectives()
|
||||
switch(traitor_kind)
|
||||
if(TRAITOR_AI)
|
||||
forge_ai_objectives()
|
||||
else
|
||||
forge_human_objectives()
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_human_objectives()
|
||||
var/is_hijacker = FALSE
|
||||
var/datum/game_mode/dynamic/mode
|
||||
var/is_dynamic = FALSE
|
||||
var/hijack_prob = 0
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
is_dynamic = TRUE
|
||||
if(mode.threat >= CONFIG_GET(number/dynamic_hijack_cost))
|
||||
hijack_prob = CLAMP(mode.threat_level-50,0,20)
|
||||
if(GLOB.joined_player_list.len>=GLOB.dynamic_high_pop_limit)
|
||||
is_hijacker = (prob(hijack_prob) && mode.threat_level > CONFIG_GET(number/dynamic_hijack_high_population_requirement))
|
||||
else
|
||||
var/indice_pop = min(10,round(GLOB.joined_player_list.len/mode.pop_per_requirement)+1)
|
||||
is_hijacker = (prob(hijack_prob) && (mode.threat_level >= CONFIG_GET(number_list/dynamic_hijack_requirements)[indice_pop]))
|
||||
if(mode.storyteller.flags & NO_ASSASSIN)
|
||||
is_hijacker = FALSE
|
||||
else if (GLOB.joined_player_list.len >= 30) // Less murderboning on lowpop thanks
|
||||
hijack_prob = 10
|
||||
is_hijacker = prob(10)
|
||||
var/martyr_chance = prob(hijack_prob*2)
|
||||
var/objective_count = is_hijacker //Hijacking counts towards number of objectives
|
||||
if(!SSticker.mode.exchange_blue && SSticker.mode.traitors.len >= 8) //Set up an exchange if there are enough traitors
|
||||
if(!SSticker.mode.exchange_red)
|
||||
SSticker.mode.exchange_red = owner
|
||||
else
|
||||
SSticker.mode.exchange_blue = owner
|
||||
assign_exchange_role(SSticker.mode.exchange_red)
|
||||
assign_exchange_role(SSticker.mode.exchange_blue)
|
||||
objective_count += 1 //Exchange counts towards number of objectives
|
||||
var/toa = CONFIG_GET(number/traitor_objectives_amount)
|
||||
for(var/i = objective_count, i < toa, i++)
|
||||
forge_single_objective()
|
||||
|
||||
if(is_hijacker && objective_count <= toa) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount
|
||||
if (!(locate(/datum/objective/hijack) in objectives))
|
||||
var/datum/objective/hijack/hijack_objective = new
|
||||
hijack_objective.owner = owner
|
||||
add_objective(hijack_objective)
|
||||
if(is_dynamic)
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("[owner.name] spent [threat_spent] on hijack.")
|
||||
return
|
||||
|
||||
|
||||
var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead.
|
||||
for(var/datum/objective/O in objectives)
|
||||
if(!O.martyr_compatible)
|
||||
martyr_compatibility = 0
|
||||
break
|
||||
|
||||
if(martyr_compatibility && martyr_chance)
|
||||
var/datum/objective/martyr/martyr_objective = new
|
||||
martyr_objective.owner = owner
|
||||
add_objective(martyr_objective)
|
||||
if(is_dynamic)
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("[owner.name] spent [threat_spent] on glorious death.")
|
||||
return
|
||||
|
||||
else
|
||||
if(!(locate(/datum/objective/escape) in objectives))
|
||||
var/datum/objective/escape/escape_objective = new
|
||||
escape_objective.owner = owner
|
||||
add_objective(escape_objective)
|
||||
return
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_ai_objectives()
|
||||
var/objective_count = 0
|
||||
|
||||
if(prob(30))
|
||||
objective_count += forge_single_objective()
|
||||
|
||||
for(var/i = objective_count, i < CONFIG_GET(number/traitor_objectives_amount), i++)
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.find_target()
|
||||
add_objective(kill_objective)
|
||||
|
||||
var/datum/objective/survive/exist/exist_objective = new
|
||||
exist_objective.owner = owner
|
||||
add_objective(exist_objective)
|
||||
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_single_objective()
|
||||
switch(traitor_kind)
|
||||
if(TRAITOR_AI)
|
||||
return forge_single_AI_objective()
|
||||
else
|
||||
return forge_single_human_objective()
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_single_human_objective() //Returns how many objectives are added
|
||||
.=1
|
||||
var/assassin_prob = 50
|
||||
var/is_dynamic = FALSE
|
||||
var/datum/game_mode/dynamic/mode
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
is_dynamic = TRUE
|
||||
assassin_prob = max(0,mode.threat_level-20)
|
||||
if(prob(assassin_prob))
|
||||
if(is_dynamic)
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("[owner.name] spent [threat_spent] on an assassination target.")
|
||||
var/list/active_ais = active_ais()
|
||||
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
|
||||
var/datum/objective/destroy/destroy_objective = new
|
||||
destroy_objective.owner = owner
|
||||
destroy_objective.find_target()
|
||||
add_objective(destroy_objective)
|
||||
else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN)))
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = owner
|
||||
maroon_objective.find_target()
|
||||
add_objective(maroon_objective)
|
||||
else if(prob(max(0,assassin_prob-20)))
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.find_target()
|
||||
add_objective(kill_objective)
|
||||
else
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.find_target()
|
||||
add_objective(kill_objective)
|
||||
else
|
||||
if(prob(15) && !(locate(/datum/objective/download) in objectives) && !(owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
|
||||
var/datum/objective/download/download_objective = new
|
||||
download_objective.owner = owner
|
||||
download_objective.gen_amount_goal()
|
||||
add_objective(download_objective)
|
||||
else if(prob(40)) // cum. not counting download: 40%.
|
||||
var/datum/objective/steal/steal_objective = new
|
||||
steal_objective.owner = owner
|
||||
steal_objective.find_target()
|
||||
add_objective(steal_objective)
|
||||
else if(prob(100/3)) // cum. not counting download: 20%.
|
||||
var/datum/objective/sabotage/sabotage_objective = new
|
||||
sabotage_objective.owner = owner
|
||||
sabotage_objective.find_target()
|
||||
add_objective(sabotage_objective)
|
||||
else // cum. not counting download: 40%
|
||||
var/datum/objective/flavor/traitor/flavor_objective = new
|
||||
flavor_objective.owner = owner
|
||||
flavor_objective.forge_objective()
|
||||
add_objective(flavor_objective)
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_single_AI_objective()
|
||||
.=1
|
||||
var/special_pick = rand(1,4)
|
||||
switch(special_pick)
|
||||
if(1)
|
||||
var/datum/objective/block/block_objective = new
|
||||
block_objective.owner = owner
|
||||
add_objective(block_objective)
|
||||
if(2)
|
||||
var/datum/objective/purge/purge_objective = new
|
||||
purge_objective.owner = owner
|
||||
add_objective(purge_objective)
|
||||
if(3)
|
||||
var/datum/objective/robot_army/robot_objective = new
|
||||
robot_objective.owner = owner
|
||||
add_objective(robot_objective)
|
||||
if(4) //Protect and strand a target
|
||||
var/datum/objective/protect/yandere_one = new
|
||||
yandere_one.owner = owner
|
||||
add_objective(yandere_one)
|
||||
yandere_one.find_target()
|
||||
var/datum/objective/maroon/yandere_two = new
|
||||
yandere_two.owner = owner
|
||||
yandere_two.target = yandere_one.target
|
||||
yandere_two.update_explanation_text() // normally called in find_target()
|
||||
add_objective(yandere_two)
|
||||
.=2
|
||||
traitor_kind.forge_objectives(src)
|
||||
|
||||
/datum/antagonist/traitor/greet()
|
||||
to_chat(owner.current, "<B><font size=3 color=red>You are the [owner.special_role].</font></B>")
|
||||
traitor_kind.greet(src)
|
||||
owner.announce_objectives()
|
||||
if(should_give_codewords)
|
||||
give_codewords()
|
||||
@@ -270,32 +95,33 @@
|
||||
set_antag_hud(owner.current, null)
|
||||
|
||||
/datum/antagonist/traitor/proc/finalize_traitor()
|
||||
switch(traitor_kind)
|
||||
if(TRAITOR_AI)
|
||||
add_law_zero()
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
owner.current.grant_language(/datum/language/codespeak)
|
||||
if(TRAITOR_HUMAN)
|
||||
if(should_equip)
|
||||
equip(silent)
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
if(traitor_kind.finalize_traitor(src))
|
||||
if(should_equip)
|
||||
equip(silent)
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
|
||||
/datum/antagonist/traitor/apply_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
update_traitor_icons_added()
|
||||
var/mob/M = mob_override || owner.current
|
||||
if(isAI(M) && traitor_kind == TRAITOR_AI)
|
||||
var/mob/living/silicon/ai/A = M
|
||||
A.hack_software = TRUE
|
||||
traitor_kind.apply_innate_effects(M)
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(istype(H))
|
||||
if(!silent)
|
||||
to_chat(H, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
H.dna.remove_mutation(CLOWNMUT)
|
||||
RegisterSignal(M, COMSIG_MOVABLE_HEAR, .proc/handle_hearing)
|
||||
|
||||
/datum/antagonist/traitor/remove_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
update_traitor_icons_removed()
|
||||
var/mob/M = mob_override || owner.current
|
||||
if(isAI(M) && traitor_kind == TRAITOR_AI)
|
||||
var/mob/living/silicon/ai/A = M
|
||||
A.hack_software = FALSE
|
||||
traitor_kind.remove_innate_effects(M)
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(istype(H))
|
||||
H.dna.add_mutation(CLOWNMUT)
|
||||
UnregisterSignal(M, COMSIG_MOVABLE_HEAR)
|
||||
|
||||
/datum/antagonist/traitor/proc/give_codewords()
|
||||
@@ -326,8 +152,7 @@
|
||||
killer.add_malf_picker()
|
||||
|
||||
/datum/antagonist/traitor/proc/equip(var/silent = FALSE)
|
||||
if(traitor_kind == TRAITOR_HUMAN)
|
||||
owner.equip_traitor(employer, silent, src)
|
||||
owner.equip_traitor(traitor_kind, silent, src)
|
||||
|
||||
/datum/antagonist/traitor/proc/assign_exchange_role()
|
||||
//set faction
|
||||
|
||||
@@ -375,6 +375,8 @@
|
||||
desc = "A collection of wands that allow for a wide variety of utility. Wands have a limited number of charges, so be conservative in use. Comes in a handy belt."
|
||||
item_path = /obj/item/storage/belt/wands/full
|
||||
category = "Defensive"
|
||||
dynamic_requirement = 60
|
||||
dynamic_cost = 10
|
||||
|
||||
/datum/spellbook_entry/item/armor
|
||||
name = "Mastercrafted Armor Set"
|
||||
|
||||
@@ -20,13 +20,8 @@
|
||||
|
||||
/obj/item/assembly/infra/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(
|
||||
/datum/component/simple_rotation,
|
||||
ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_FLIP | ROTATION_VERBS,
|
||||
null,
|
||||
null,
|
||||
CALLBACK(src,.proc/after_rotation)
|
||||
)
|
||||
var/static/rotation_flags = ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_FLIP | ROTATION_VERBS
|
||||
AddComponent(/datum/component/simple_rotation, rotation_flags, after_rotation=CALLBACK(src,.proc/after_rotation))
|
||||
|
||||
/obj/item/assembly/infra/proc/after_rotation()
|
||||
refreshBeam()
|
||||
|
||||
@@ -89,32 +89,17 @@
|
||||
|
||||
/datum/supply_pack/misc/paper_work
|
||||
name = "Freelance Paper work"
|
||||
desc = "The Nanotrasen Primary Bureaucratic Database Intelligence (PDBI) reports that the station has not completed its funding and grant paperwork this solar cycle. In order to gain further funding, your station is required to fill out (20) ten of these forms or no additional capital will be disbursed. We have sent you ten copies of the following form and we expect every one to be up to Nanotrasen Standards." // Disbursement. It's not a typo, look it up.
|
||||
cost = 700 // Net of 0 credits but makes (120 x 20 = 2400)
|
||||
desc = "The Nanotrasen Primary Bureaucratic Database Intelligence (PDBI) reports that the station has not completed its funding and grant paperwork this solar cycle. In order to gain further funding, your station is required to fill out (10) ten of these forms or no additional capital will be disbursed. We have sent you ten copies of the following form and we expect every one to be up to Nanotrasen Standards." // Disbursement. It's not a typo, look it up.
|
||||
cost = 700 // Net of 0 credits but makes (120 x 10 = 1200)
|
||||
contains = list(/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/pen/fountain
|
||||
)
|
||||
crate_name = "Paperwork"
|
||||
|
||||
/datum/supply_pack/misc/paper_work/generate()
|
||||
. = ..()
|
||||
for(var/i in 1 to 9)
|
||||
new /obj/item/folder/paperwork(.)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////// Entertainment ///////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -123,16 +108,14 @@
|
||||
name = "Bedsheet Crate (R)"
|
||||
desc = "Snuggle up in some sweet sheets with this assorted bedsheet crate. Each set comes with eight random bedsheets for your slumbering pleasure!"
|
||||
cost = 2000
|
||||
contains = list(/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random) //I'm lazy, and I copy paste stuff.
|
||||
contains = list(/obj/item/bedsheet/random)
|
||||
crate_name = "random bedsheet crate"
|
||||
|
||||
/datum/supply_pack/misc/randombedsheets/generate()
|
||||
. = ..()
|
||||
for(var/i in 1 to 7)
|
||||
new /obj/item/bedsheet/random(.)
|
||||
|
||||
/datum/supply_pack/misc/coloredsheets
|
||||
name = "Bedsheet Crate (C)"
|
||||
desc = "Give your night life a splash of color with this crate filled with bedsheets! Contains a total of nine different-colored sheets."
|
||||
@@ -208,13 +191,14 @@
|
||||
name = "Dueling Pistols"
|
||||
desc = "Resolve all your quarrels with some nonlethal fun."
|
||||
cost = 2000
|
||||
contains = list(/obj/item/storage/lockbox/dueling/hugbox/stamina,
|
||||
/obj/item/storage/lockbox/dueling/hugbox/stamina,
|
||||
/obj/item/storage/lockbox/dueling/hugbox/stamina,
|
||||
/obj/item/storage/lockbox/dueling/hugbox/stamina,
|
||||
/obj/item/storage/lockbox/dueling/hugbox/stamina)
|
||||
contains = list(/obj/item/storage/lockbox/dueling/hugbox/stamina)
|
||||
crate_name = "dueling pistols"
|
||||
|
||||
/datum/supply_pack/misc/dueling_stam/generate()
|
||||
. = ..()
|
||||
for(var/i in 1 to 3)
|
||||
new /obj/item/storage/lockbox/dueling/hugbox/stamina(.)
|
||||
|
||||
/datum/supply_pack/misc/dueling_lethal
|
||||
name = "Lethal Dueling Pistols"
|
||||
desc = "Settle your differences the true spaceman way."
|
||||
@@ -240,12 +224,7 @@
|
||||
cost = 12000
|
||||
var/num_contained = 3
|
||||
contains = list(/obj/item/ammo_box/a357,
|
||||
/obj/item/ammo_box/a357,
|
||||
/obj/item/ammo_box/a357,
|
||||
/obj/item/ammo_box/magazine/pistolm9mm,
|
||||
/obj/item/ammo_box/magazine/pistolm9mm,
|
||||
/obj/item/ammo_box/magazine/pistolm9mm,
|
||||
/obj/item/ammo_box/magazine/m45/kitchengun,
|
||||
/obj/item/ammo_box/magazine/m45/kitchengun)
|
||||
crate_name = "crate"
|
||||
|
||||
|
||||
@@ -247,6 +247,30 @@
|
||||
/obj/item/clothing/mask/bandana/attack_self(mob/user)
|
||||
adjustmask(user)
|
||||
|
||||
/obj/item/clothing/mask/bandana/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
if((C.get_item_by_slot(SLOT_HEAD == src)) || (C.get_item_by_slot(SLOT_WEAR_MASK) == src))
|
||||
to_chat(user, "<span class='warning'>You can't tie [src] while wearing it!</span>")
|
||||
return
|
||||
if(slot_flags & ITEM_SLOT_HEAD)
|
||||
to_chat(user, "<span class='warning'>You must undo [src] before you can tie it into a neckerchief!</span>")
|
||||
else
|
||||
if(user.is_holding(src))
|
||||
var/obj/item/clothing/neck/neckerchief/nk = new(src)
|
||||
nk.name = "[name] neckerchief"
|
||||
nk.desc = "[desc] It's tied up like a neckerchief."
|
||||
nk.icon_state = icon_state
|
||||
nk.sourceBandanaType = src.type
|
||||
var/currentHandIndex = user.get_held_index_of_item(src)
|
||||
user.transferItemToLoc(src, null)
|
||||
user.put_in_hand(nk, currentHandIndex)
|
||||
user.visible_message("<span class='notice'>You tie [src] up like a neckerchief.</span>", "<span class='notice'>[user] ties [src] up like a neckerchief.</span>")
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You must be holding [src] in order to tie it!")
|
||||
|
||||
/obj/item/clothing/mask/bandana/red
|
||||
name = "red bandana"
|
||||
desc = "A fine red bandana with nanotech lining."
|
||||
|
||||
@@ -291,3 +291,36 @@
|
||||
icon = 'icons/obj/clothing/neck.dmi'
|
||||
icon_state = "bling"
|
||||
item_color = "bling"
|
||||
|
||||
//////////////////////////////////
|
||||
//VERY SUPER BADASS NECKERCHIEFS//
|
||||
//////////////////////////////////
|
||||
|
||||
obj/item/clothing/neck/neckerchief
|
||||
icon = 'icons/obj/clothing/masks.dmi' //In order to reuse the bandana sprite
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/sourceBandanaType
|
||||
|
||||
/obj/item/clothing/neck/neckerchief/worn_overlays(isinhands)
|
||||
. = ..()
|
||||
if(!isinhands)
|
||||
var/mutable_appearance/realOverlay = mutable_appearance('icons/mob/mask.dmi', icon_state)
|
||||
realOverlay.pixel_y = -3
|
||||
. += realOverlay
|
||||
|
||||
/obj/item/clothing/neck/neckerchief/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
if(C.get_item_by_slot(SLOT_NECK) == src)
|
||||
to_chat(user, "<span class='warning'>You can't untie [src] while wearing it!</span>")
|
||||
return
|
||||
if(user.is_holding(src))
|
||||
var/obj/item/clothing/mask/bandana/newBand = new sourceBandanaType(user)
|
||||
var/currentHandIndex = user.get_held_index_of_item(src)
|
||||
var/oldName = src.name
|
||||
qdel(src)
|
||||
user.put_in_hand(newBand, currentHandIndex)
|
||||
user.visible_message("You untie [oldName] back into a [newBand.name]", "[user] unties [oldName] back into a [newBand.name]")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You must be holding [src] in order to untie it!")
|
||||
|
||||
@@ -402,11 +402,22 @@
|
||||
power_draw_per_use = 40
|
||||
ext_cooldown = 1
|
||||
cooldown_per_use = 10
|
||||
var/list/mtypes = list(/datum/material/iron, /datum/material/glass, /datum/material/silver, /datum/material/gold, /datum/material/diamond, /datum/material/uranium, /datum/material/plasma, /datum/material/bluespace, /datum/material/bananium, /datum/material/titanium, /datum/material/plastic)
|
||||
var/static/list/mtypes = list(
|
||||
/datum/material/iron,
|
||||
/datum/material/glass,
|
||||
/datum/material/silver,
|
||||
/datum/material/gold,
|
||||
/datum/material/diamond,
|
||||
/datum/material/uranium,
|
||||
/datum/material/plasma,
|
||||
/datum/material/bluespace,
|
||||
/datum/material/bananium,
|
||||
/datum/material/titanium,
|
||||
/datum/material/plastic
|
||||
)
|
||||
|
||||
/obj/item/integrated_circuit/manipulation/matman/Initialize()
|
||||
var/datum/component/material_container/materials = AddComponent(/datum/component/material_container,
|
||||
mtypes, 100000, FALSE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
|
||||
/obj/item/integrated_circuit/manipulation/matman/ComponentInitialize()
|
||||
var/datum/component/material_container/materials = AddComponent(/datum/component/material_container, mtypes, 100000, FALSE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
|
||||
materials.precise_insertion = TRUE
|
||||
.=..()
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
|
||||
if(target_type && !istype(A,target_type))
|
||||
continue
|
||||
var/cargs = build_args()
|
||||
A.AddComponent(arglist(cargs))
|
||||
A._AddComponent(cargs)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
|
||||
@@ -15,14 +15,20 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
|
||||
|
||||
/obj/machinery/ore_silo/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/material_container,
|
||||
list(/datum/material/iron, /datum/material/glass, /datum/material/silver, /datum/material/gold, /datum/material/diamond, /datum/material/plasma, /datum/material/uranium, /datum/material/bananium, /datum/material/titanium, /datum/material/bluespace, /datum/material/plastic),
|
||||
INFINITY,
|
||||
FALSE,
|
||||
/obj/item/stack,
|
||||
null,
|
||||
null,
|
||||
TRUE)
|
||||
var/static/list/materials_list = list(
|
||||
/datum/material/iron,
|
||||
/datum/material/glass,
|
||||
/datum/material/silver,
|
||||
/datum/material/gold,
|
||||
/datum/material/diamond,
|
||||
/datum/material/plasma,
|
||||
/datum/material/uranium,
|
||||
/datum/material/bananium,
|
||||
/datum/material/titanium,
|
||||
/datum/material/bluespace,
|
||||
/datum/material/plastic,
|
||||
)
|
||||
AddComponent(/datum/component/material_container, materials_list, INFINITY, allowed_types=/obj/item/stack, _disable_attackby=TRUE)
|
||||
if (!GLOB.ore_silo_default && mapload && is_station_level(z))
|
||||
GLOB.ore_silo_default = src
|
||||
|
||||
|
||||
@@ -292,9 +292,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES
|
||||
if(world.time < roundstart_quit_limit)
|
||||
penalty += roundstart_quit_limit - world.time
|
||||
var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
|
||||
if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
|
||||
penalty = CANT_REENTER_ROUND
|
||||
if(SSautotransfer.can_fire && SSautotransfer.maxvotes)
|
||||
var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
|
||||
if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
|
||||
penalty = CANT_REENTER_ROUND
|
||||
|
||||
if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, (stat == DEAD) ? TRUE : FALSE, FALSE, (stat == DEAD)? penalty : 0, (stat == DEAD)? TRUE : FALSE) & COMPONENT_BLOCK_GHOSTING)
|
||||
return
|
||||
@@ -327,9 +328,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES
|
||||
if(world.time < roundstart_quit_limit)
|
||||
penalty += roundstart_quit_limit - world.time
|
||||
var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
|
||||
if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
|
||||
penalty = CANT_REENTER_ROUND
|
||||
if(SSautotransfer.can_fire && SSautotransfer.maxvotes)
|
||||
var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
|
||||
if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
|
||||
penalty = CANT_REENTER_ROUND
|
||||
|
||||
var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles [penalty == CANT_REENTER_ROUND ? "until the round is over" : "for the next [DisplayTimeText(penalty)]"]" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
|
||||
if(response != "Ghost")
|
||||
|
||||
@@ -105,7 +105,8 @@
|
||||
var/basebloodychance = affecting.brute_dam + totitemdamage
|
||||
if(prob(basebloodychance))
|
||||
I.add_mob_blood(src)
|
||||
bleed(totitemdamage)
|
||||
var/turf/location = get_turf(src)
|
||||
add_splatter_floor(location)
|
||||
if(totitemdamage >= 10 && get_dist(user, src) <= 1) //people with TK won't get smeared with blood
|
||||
user.add_mob_blood(src)
|
||||
|
||||
@@ -263,11 +264,11 @@
|
||||
jitteriness += 1000 //High numbers for violent convulsions
|
||||
do_jitter_animation(jitteriness)
|
||||
stuttering += 2
|
||||
if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && (flags & SHOCK_NOSTUN))
|
||||
if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN))
|
||||
Stun(40)
|
||||
spawn(20)
|
||||
jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
|
||||
if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && (flags & SHOCK_NOSTUN))
|
||||
if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN))
|
||||
DefaultCombatKnockdown(60)
|
||||
return shock_damage
|
||||
|
||||
|
||||
@@ -1719,7 +1719,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
bloody = 1
|
||||
var/turf/location = H.loc
|
||||
if(istype(location))
|
||||
H.bleed(totitemdamage)
|
||||
H.add_splatter_floor(location)
|
||||
if(get_dist(user, H) <= 1) //people with TK won't get smeared with blood
|
||||
user.add_mob_blood(H)
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
/mob/living/carbon/monkey/ComponentInitialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/mob_holder, "monkey", null, null, null, ITEM_SLOT_HEAD)
|
||||
AddElement(/datum/element/mob_holder, worn_state = "monkey", inv_slots = ITEM_SLOT_HEAD)
|
||||
|
||||
|
||||
/mob/living/carbon/monkey/Destroy()
|
||||
|
||||
@@ -97,8 +97,7 @@
|
||||
resist_a_rest(FALSE, TRUE)
|
||||
update_icon()
|
||||
if(possible_chassis[old_chassis])
|
||||
var/datum/element/mob_holder/M = SSdcs.GetElement(/datum/element/mob_holder, old_chassis, 'icons/mob/pai_item_head.dmi', 'icons/mob/pai_item_rh.dmi', 'icons/mob/pai_item_lh.dmi', ITEM_SLOT_HEAD)
|
||||
M.Detach(src)
|
||||
RemoveElement(/datum/element/mob_holder, old_chassis, 'icons/mob/pai_item_head.dmi', 'icons/mob/pai_item_rh.dmi', 'icons/mob/pai_item_lh.dmi', ITEM_SLOT_HEAD)
|
||||
if(possible_chassis[chassis])
|
||||
AddElement(/datum/element/mob_holder, chassis, 'icons/mob/pai_item_head.dmi', 'icons/mob/pai_item_rh.dmi', 'icons/mob/pai_item_lh.dmi', ITEM_SLOT_HEAD)
|
||||
to_chat(src, "<span class='boldnotice'>You switch your holochassis projection composite to [chassis]</span>")
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/lizard/ComponentInitialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/mob_holder, "lizard", null, null, null, ITEM_SLOT_HEAD) //you can hold lizards now.
|
||||
AddElement(/datum/element/mob_holder, worn_state = "lizard", inv_slots = ITEM_SLOT_HEAD) //you can hold lizards now.
|
||||
|
||||
/mob/living/simple_animal/hostile/lizard/CanAttack(atom/the_target)//Can we actually attack a possible target?
|
||||
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
|
||||
|
||||
@@ -64,21 +64,22 @@
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/mouse/handle_automated_action()
|
||||
if(!prob(chew_probability) || !isturf(loc))
|
||||
if(!isturf(loc))
|
||||
return
|
||||
|
||||
var/turf/open/floor/F = get_turf(src)
|
||||
if(istype(F) && !F.intact)
|
||||
var/obj/structure/cable/C = locate() in F
|
||||
if(C && prob(15))
|
||||
if(C.avail())
|
||||
visible_message("<span class='warning'>[src] chews through the [C]. It's toast!</span>")
|
||||
playsound(src, 'sound/effects/sparks2.ogg', 100, 1)
|
||||
C.deconstruct()
|
||||
death(toast=1)
|
||||
else
|
||||
C.deconstruct()
|
||||
visible_message("<span class='warning'>[src] chews through the [C].</span>")
|
||||
if(prob(chew_probability))
|
||||
var/turf/open/floor/F = get_turf(src)
|
||||
if(istype(F) && !F.intact)
|
||||
var/obj/structure/cable/C = locate() in F
|
||||
if(C && prob(15))
|
||||
if(C.avail())
|
||||
visible_message("<span class='warning'>[src] chews through the [C]. It's toast!</span>")
|
||||
playsound(src, 'sound/effects/sparks2.ogg', 100, 1)
|
||||
C.deconstruct()
|
||||
death(toast=TRUE)
|
||||
else
|
||||
C.deconstruct()
|
||||
visible_message("<span class='warning'>[src] chews through the [C].</span>")
|
||||
|
||||
/*
|
||||
* Mouse types
|
||||
|
||||
@@ -28,7 +28,7 @@ Borg Hypospray
|
||||
|
||||
var/list/datum/reagents/reagent_list = list()
|
||||
var/list/reagent_ids = list(/datum/reagent/medicine/dexalin, /datum/reagent/medicine/kelotane, /datum/reagent/medicine/bicaridine, /datum/reagent/medicine/antitoxin,
|
||||
/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/spaceacillin, /datum/reagent/medicine/salglu_solution, /datum/reagent/medicine/insulin)
|
||||
/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/spaceacillin, /datum/reagent/medicine/salglu_solution, /datum/reagent/medicine/insulin, /datum/reagent/medicine/potass_iodide)
|
||||
var/accepts_reagent_upgrades = TRUE //If upgrades can increase number of reagents dispensed.
|
||||
var/list/modes = list() //Basically the inverse of reagent_ids. Instead of having numbers as "keys" and strings as values it has strings as keys and numbers as values.
|
||||
//Used as list for input() in shakers.
|
||||
@@ -164,7 +164,7 @@ Borg Hypospray
|
||||
icon_state = "borghypo_s"
|
||||
charge_cost = 20
|
||||
recharge_time = 2
|
||||
reagent_ids = list(/datum/reagent/medicine/syndicate_nanites, /datum/reagent/medicine/potass_iodide, /datum/reagent/medicine/morphine, /datum/reagent/medicine/insulin)
|
||||
reagent_ids = list(/datum/reagent/medicine/syndicate_nanites, /datum/reagent/medicine/prussian_blue, /datum/reagent/medicine/morphine, /datum/reagent/medicine/insulin)
|
||||
bypass_protection = 1
|
||||
accepts_reagent_upgrades = FALSE
|
||||
|
||||
@@ -261,5 +261,5 @@ Borg Shaker
|
||||
/obj/item/reagent_containers/borghypo/epi
|
||||
name = "Stabilizer injector"
|
||||
desc = "An advanced chemical synthesizer and injection system, designed to stabilize patients."
|
||||
reagent_ids = list(/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/insulin)
|
||||
reagent_ids = list(/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/insulin, /datum/reagent/medicine/potass_iodide)
|
||||
accepts_reagent_upgrades = FALSE
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
return
|
||||
|
||||
var/datum/nanite_cloud_backup/backup = new(src)
|
||||
var/datum/component/nanites/cloud_copy = new(backup)
|
||||
var/datum/component/nanites/cloud_copy = backup.AddComponent(/datum/component/nanites)
|
||||
backup.cloud_id = cloud_id
|
||||
backup.nanites = cloud_copy
|
||||
investigate_log("[key_name(user)] created a new nanite cloud backup with id #[cloud_id]", INVESTIGATE_NANITES)
|
||||
@@ -213,7 +213,7 @@
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
|
||||
var/datum/nanite_rule/rule = rule_template.make_rule(P)
|
||||
|
||||
|
||||
investigate_log("[key_name(usr)] added rule [rule.display()] to program [P.name] in cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("remove_rule")
|
||||
@@ -224,7 +224,7 @@
|
||||
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
|
||||
var/datum/nanite_rule/rule = P.rules[text2num(params["rule_id"])]
|
||||
rule.remove()
|
||||
|
||||
|
||||
investigate_log("[key_name(usr)] removed rule [rule.display()] from program [P.name] in cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/proc/get_uplink_items(datum/game_mode/gamemode, allow_sales = TRUE, allow_restricted = TRUE)
|
||||
/proc/get_uplink_items(datum/game_mode/gamemode, allow_sales = TRUE, allow_restricted = TRUE, other_filter = list())
|
||||
var/list/filtered_uplink_items = GLOB.uplink_categories.Copy() // list of uplink categories without associated values.
|
||||
var/list/sale_items = list()
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
continue
|
||||
if (I.restricted && !allow_restricted)
|
||||
continue
|
||||
|
||||
if (I.type in other_filter)
|
||||
continue
|
||||
LAZYSET(filtered_uplink_items[I.category], I.name, I)
|
||||
|
||||
if(I.limited_stock < 0 && !I.cant_discount && I.item && I.cost > 1)
|
||||
|
||||
+4
-1
@@ -185,12 +185,15 @@ VOTE_DELAY 6000
|
||||
VOTE_PERIOD 600
|
||||
|
||||
## autovote initial delay (deciseconds) before first automatic transfer vote call (default 120 minutes)
|
||||
## Set to 0 to disable the subsystem altogether.
|
||||
VOTE_AUTOTRANSFER_INITIAL 72000
|
||||
|
||||
## autovote delay (deciseconds) before sequential automatic transfer votes are called (default 30 minutes)
|
||||
VOTE_AUTOTRANSFER_INTERVAL 18000
|
||||
|
||||
## autovote maximum votes until automatic transfer call (default 4)
|
||||
## autovote maximum votes until automatic transfer call. (default 4)
|
||||
## Set to 0 to force automatic crew transfer after the 'vote_autotransfer_initial' elapsed.
|
||||
## Set to -1 to disable the maximum votes cap.
|
||||
VOTE_AUTOTRANSFER_MAXIMUM 4
|
||||
|
||||
## prevents dead players from voting or starting votes
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Putnam3145"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Traitor classes for traitors: a new way for traitors to have objectives assigned."
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "MrJWhit"
|
||||
delete-after: True
|
||||
changes:
|
||||
- tweak: "Removed egun in every head locker, replaces RPD with air pump in science, fixes a computer in sec, moves hand teleporter, and removes decals under lockers."
|
||||
@@ -0,0 +1,8 @@
|
||||
author: "keronshb"
|
||||
delete-after: True
|
||||
changes:
|
||||
- balance: "blobs now receive a 50% cost refund on attacks that don't spread"
|
||||
- balance: "reflector blobs are considerably tougher"
|
||||
- bugfix: "fixed an integrity"
|
||||
- bugfix: "attempting to turn a damaged strong blob into a reflector blob now refunds points"
|
||||
- bugfix: "also fixes blob node camera jump (from another PR)"
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "spookydonut"
|
||||
delete-after: True
|
||||
changes:
|
||||
- code_imp: "adds selective duplicate component mode"
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Ghommie"
|
||||
delete-after: True
|
||||
changes:
|
||||
- bugfix: "The autotransfer subsystem is slightly more modulable now."
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "zeroisthebiggay"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Space Fashion has discovered a new way to wear bandannas. With some simple minor adjustments and ties, bandannas can be made into fashionable neckerchiefs!"
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Putnam3145"
|
||||
delete-after: True
|
||||
changes:
|
||||
- bugfix: "More dynamic fixes"
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Linzolle"
|
||||
delete-after: True
|
||||
changes:
|
||||
- tweak: "cmo hypokit now holds the same amount of items as normal kits"
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "necromanceranne"
|
||||
delete-after: True
|
||||
changes:
|
||||
- bugfix: "Bleeding out all your blood from getting love tapped by a toolbox."
|
||||
@@ -0,0 +1,5 @@
|
||||
author: "Trilbyspaceclone"
|
||||
delete-after: True
|
||||
changes:
|
||||
- tweak: "Number of paper work in the crate \"freelance paperwork\" is half"
|
||||
- code_imp: "A few cases were something their is unneeded copy past replaced with many 1 in spawns"
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "bunny232"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Box station captain office now has a standard issue renault"
|
||||
@@ -0,0 +1,5 @@
|
||||
author: "Trilbyspaceclone"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Potass Iodide has been fitted into standered borgs as well as medical ones. Upgraded hypos now have Prussian Blue as well."
|
||||
- tweak: "Syndi borgs Potass Iodide has been swapped for Prussian Blue"
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Kraseo"
|
||||
delete-after: True
|
||||
changes:
|
||||
- bugfix: "Mice don't chew on wires anymore while they're on your person."
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Kraseo"
|
||||
delete-after: True
|
||||
changes:
|
||||
- bugfix: "Bloodsucker heart theft objective now completes successfully."
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Putnam3145"
|
||||
delete-after: True
|
||||
changes:
|
||||
- bugfix: "Server-run votes aren't subject to vote cooldown"
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Seris02"
|
||||
delete-after: True
|
||||
changes:
|
||||
- bugfix: "quirk blacklist fixing"
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Kraseo"
|
||||
delete-after: True
|
||||
changes:
|
||||
- tweak: "Blacklists turret protected areas, the toxins test range, asteroid ruins, and solars from being valid dropoff locations for contracts."
|
||||
Executable → Regular
+11
-1
@@ -36,7 +36,6 @@
|
||||
#include "code\__DEFINES\clockcult.dm"
|
||||
#include "code\__DEFINES\colors.dm"
|
||||
#include "code\__DEFINES\combat.dm"
|
||||
#include "code\__DEFINES\components.dm"
|
||||
#include "code\__DEFINES\configuration.dm"
|
||||
#include "code\__DEFINES\construction.dm"
|
||||
#include "code\__DEFINES\contracts.dm"
|
||||
@@ -118,6 +117,9 @@
|
||||
#include "code\__DEFINES\vv.dm"
|
||||
#include "code\__DEFINES\wall_dents.dm"
|
||||
#include "code\__DEFINES\wires.dm"
|
||||
#include "code\__DEFINES\dcs\flags.dm"
|
||||
#include "code\__DEFINES\dcs\helpers.dm"
|
||||
#include "code\__DEFINES\dcs\signals.dm"
|
||||
#include "code\__HELPERS\_cit_helpers.dm"
|
||||
#include "code\__HELPERS\_lists.dm"
|
||||
#include "code\__HELPERS\_logging.dm"
|
||||
@@ -1496,6 +1498,14 @@
|
||||
#include "code\modules\antagonists\swarmer\swarmer.dm"
|
||||
#include "code\modules\antagonists\swarmer\swarmer_event.dm"
|
||||
#include "code\modules\antagonists\traitor\datum_traitor.dm"
|
||||
#include "code\modules\antagonists\traitor\classes\ai.dm"
|
||||
#include "code\modules\antagonists\traitor\classes\assassin.dm"
|
||||
#include "code\modules\antagonists\traitor\classes\freeform.dm"
|
||||
#include "code\modules\antagonists\traitor\classes\hijack.dm"
|
||||
#include "code\modules\antagonists\traitor\classes\human.dm"
|
||||
#include "code\modules\antagonists\traitor\classes\martyr.dm"
|
||||
#include "code\modules\antagonists\traitor\classes\subterfuge.dm"
|
||||
#include "code\modules\antagonists\traitor\classes\traitor_class.dm"
|
||||
#include "code\modules\antagonists\traitor\syndicate_contract.dm"
|
||||
#include "code\modules\antagonists\traitor\equipment\contractor.dm"
|
||||
#include "code\modules\antagonists\traitor\equipment\Malf_Modules.dm"
|
||||
|
||||
Generated
+3
-3
@@ -5480,9 +5480,9 @@
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.2.tgz",
|
||||
"integrity": "sha512-rIqbOrKb8GJmx/5bc2M0QchhUouMXSpd1RTclXsB41JdL+VtnojfaJR+h7F9k18/4kHUsBFgk80Uk+q569vjPA=="
|
||||
},
|
||||
"mixin-deep": {
|
||||
"version": "1.3.2",
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
"html5shiv": "3.7.3",
|
||||
"ie8": "0.8.1",
|
||||
"lodash": "^4.17.15",
|
||||
"minimist": "1.2.0",
|
||||
"minimist": "1.2.2",
|
||||
"paths-js": "0.4.10",
|
||||
"pleeease-filters": "2.0.0",
|
||||
"postcss": "7.0.18",
|
||||
|
||||
Reference in New Issue
Block a user