update
This commit is contained in:
@@ -312,6 +312,7 @@
|
||||
#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled)
|
||||
#define COMSIG_OBJ_BREAK "obj_break" //from base of /obj/obj_break(): (damage_flag)
|
||||
#define COMSIG_OBJ_SETANCHORED "obj_setanchored" //called in /obj/structure/setAnchored(): (value)
|
||||
#define COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH "obj_default_unfasten_wrench" //called exclusively in plumbing, for now
|
||||
#define COMSIG_OBJ_ATTACK_GENERIC "obj_attack_generic" //from base of atom/animal_attack(): (/mob/user)
|
||||
#define COMPONENT_STOP_GENERIC_ATTACK 1
|
||||
|
||||
|
||||
@@ -64,7 +64,6 @@
|
||||
#define DEFAULT_BODYPART_ICON 'icons/mob/human_parts.dmi'
|
||||
#define DEFAULT_BODYPART_ICON_ORGANIC 'icons/mob/human_parts_greyscale.dmi'
|
||||
#define DEFAULT_BODYPART_ICON_ROBOTIC 'icons/mob/augmentation/augments.dmi'
|
||||
#define DEFAULT_BODYPART_ICON_CITADEL 'modular_citadel/icons/mob/mutant_bodyparts.dmi'
|
||||
|
||||
#define MONKEY_BODYPART "monkey"
|
||||
#define ALIEN_BODYPART "alien"
|
||||
@@ -333,4 +332,4 @@
|
||||
/// If you examine the same atom twice in this timeframe, we call examine_more() instead of examine()
|
||||
#define EXAMINE_MORE_TIME 1 SECONDS
|
||||
|
||||
#define SILENCE_RANGED_MESSAGE (1<<0)
|
||||
#define SILENCE_RANGED_MESSAGE (1<<0)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#define FIRST_DUCT_LAYER 1
|
||||
#define SECOND_DUCT_LAYER 2
|
||||
#define THIRD_DUCT_LAYER 4
|
||||
#define FOURTH_DUCT_LAYER 8
|
||||
#define FIFTH_DUCT_LAYER 16
|
||||
|
||||
#define DUCT_LAYER_DEFAULT THIRD_DUCT_LAYER
|
||||
|
||||
#define MACHINE_REAGENT_TRANSFER 10
|
||||
+11
-4
@@ -6,10 +6,17 @@
|
||||
#define QDEL_HINT_IWILLGC 2 //functionally the same as the above. qdel should assume the object will gc on its own, and not check it.
|
||||
#define QDEL_HINT_HARDDEL 3 //qdel should assume this object won't gc, and queue a hard delete using a hard reference.
|
||||
#define QDEL_HINT_HARDDEL_NOW 4 //qdel should assume this object won't gc, and hard del it post haste.
|
||||
#define QDEL_HINT_FINDREFERENCE 5 //functionally identical to QDEL_HINT_QUEUE if TESTING is not enabled in _compiler_options.dm.
|
||||
//if TESTING is enabled, qdel will call this object's find_references() verb.
|
||||
#define QDEL_HINT_IFFAIL_FINDREFERENCE 6 //Above but only if gc fails.
|
||||
//defines for the gc_destroyed var
|
||||
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
/** If LEGACY_REFERENCE_TRACKING is enabled, qdel will call this object's find_references() verb.
|
||||
*
|
||||
* Functionally identical to QDEL_HINT_QUEUE if GC_FAILURE_HARD_LOOKUP is not enabled in _compiler_options.dm.
|
||||
*/
|
||||
#define QDEL_HINT_FINDREFERENCE 5
|
||||
/// Behavior as QDEL_HINT_FINDREFERENCE, but only if the GC fails and a hard delete is forced.
|
||||
#define QDEL_HINT_IFFAIL_FINDREFERENCE 6
|
||||
#endif
|
||||
|
||||
|
||||
#define GC_QUEUE_CHECK 1
|
||||
#define GC_QUEUE_HARDDELETE 2
|
||||
|
||||
@@ -57,6 +57,10 @@
|
||||
#define ADD_REAGENT 2 // reagent added
|
||||
#define REM_REAGENT 3 // reagent removed (may still exist)
|
||||
|
||||
|
||||
#define PILL_STYLE_COUNT 22 //Update this if you add more pill icons or you die (literally, we'll toss a nuke at whever your ip turns up)
|
||||
#define RANDOM_PILL_STYLE 22 //Dont change this one though
|
||||
|
||||
#define THRESHOLD_UNHUSK 50 // health threshold for synthflesh/rezadone to unhusk someone
|
||||
|
||||
//reagent bitflags, used for altering how they works
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#define ROCKPAPERSCISSORS_RANGE 3
|
||||
#define ROCKPAPERSCISSORS_TIME_LIMIT 20 SECONDS
|
||||
|
||||
#define ROCKPAPERSCISSORS_LOSE "lose"
|
||||
#define ROCKPAPERSCISSORS_WIN "win"
|
||||
#define ROCKPAPERSCISSORS_TIE "tie"
|
||||
#define ROCKPAPERSCISSORS_NOT_DECIDED "not_decided"
|
||||
@@ -24,7 +24,10 @@ GLOBAL_LIST_INIT(default_weight_class_to_volume, list(
|
||||
// Let's keep all of this in one place. given what we put above anyways..
|
||||
|
||||
// volume amount for items
|
||||
/// volume for a data disk
|
||||
#define ITEM_VOLUME_DISK 1
|
||||
/// volume for a shotgun stripper clip holding 4 shells
|
||||
#define ITEM_VOLUME_STRIPPER_CLIP (DEFAULT_VOLUME_NORMAL * 0.5)
|
||||
|
||||
// #define SAMPLE_VOLUME_AMOUNT 2
|
||||
|
||||
|
||||
@@ -146,11 +146,11 @@
|
||||
#define SSAIR_EQUALIZE 8
|
||||
#define SSAIR_ACTIVETURFS 9
|
||||
|
||||
// |= on overlays is not actually guaranteed to not add same appearances but we're optimistically using it anyway.
|
||||
#define COMPILE_OVERLAYS(A)\
|
||||
if (TRUE) {\
|
||||
var/list/ad = A.add_overlays;\
|
||||
var/list/rm = A.remove_overlays;\
|
||||
var/list/po = A.priority_overlays;\
|
||||
if(LAZYLEN(rm)){\
|
||||
A.overlays -= rm;\
|
||||
A.remove_overlays = null;\
|
||||
@@ -159,11 +159,5 @@
|
||||
A.overlays |= ad;\
|
||||
A.add_overlays = null;\
|
||||
}\
|
||||
if(LAZYLEN(po)){\
|
||||
A.overlays |= po;\
|
||||
}\
|
||||
else{\
|
||||
A.priority_overlays = null;\
|
||||
}\
|
||||
A.flags_1 &= ~OVERLAY_QUEUED_1;\
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
#define VV_HK_MARK "mark"
|
||||
#define VV_HK_ADDCOMPONENT "addcomponent"
|
||||
#define VV_HK_MODIFY_TRAITS "modtraits"
|
||||
#define VV_HK_VIEW_REFERENCES "viewreferences"
|
||||
|
||||
// /datum/gas_mixture
|
||||
#define VV_HK_SET_MOLES "set_moles"
|
||||
|
||||
@@ -17,9 +17,9 @@ For fast lookups, this is generated using regenerate_donator_grouping_list()
|
||||
/proc/regenerate_donator_grouping_list()
|
||||
GLOB.donators_by_group = list() //reinit everything
|
||||
var/list/donator_list = GLOB.donators_by_group //cache
|
||||
var/list/tier_1 = TIER_1_DONATORS
|
||||
donator_list[DONATOR_GROUP_TIER_1] = tier_1.Copy() //The .Copy() is to "decouple"/make a new list, rather than letting the global list impact the config list.
|
||||
var/list/tier_2 = tier_1 + TIER_2_DONATORS //Using + on lists implies making new lists, so we don't need to manually Copy().
|
||||
var/list/tier_3 = TIER_3_DONATORS
|
||||
donator_list[DONATOR_GROUP_TIER_3] = tier_3.Copy() //The .Copy() is to "decouple"/make a new list, rather than letting the global list impact the config list.
|
||||
var/list/tier_2 = tier_3 + TIER_2_DONATORS //Using + on lists implies making new lists, so we don't need to manually Copy().
|
||||
donator_list[DONATOR_GROUP_TIER_2] = tier_2
|
||||
var/list/tier_3 = tier_2 + TIER_3_DONATORS
|
||||
donator_list[DONATOR_GROUP_TIER_3] = tier_3
|
||||
var/list/tier_1 = tier_2 + TIER_1_DONATORS
|
||||
donator_list[DONATOR_GROUP_TIER_1] = tier_1
|
||||
|
||||
@@ -11,15 +11,28 @@
|
||||
#ifdef TESTING
|
||||
#define DATUMVAR_DEBUGGING_MODE
|
||||
|
||||
//#define GC_FAILURE_HARD_LOOKUP //makes paths that fail to GC call find_references before del'ing.
|
||||
//implies FIND_REF_NO_CHECK_TICK
|
||||
/*
|
||||
* Enables extools-powered reference tracking system, letting you see what is referencing objects that refuse to hard delete.
|
||||
*
|
||||
* * Requires TESTING to be defined to work.
|
||||
*/
|
||||
//#define REFERENCE_TRACKING
|
||||
|
||||
//#define FIND_REF_NO_CHECK_TICK //Sets world.loop_checks to false and prevents find references from sleeping
|
||||
///Method of tracking references without using extools. Slower, kept to avoid over-reliance on extools.
|
||||
//#define LEGACY_REFERENCE_TRACKING
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
|
||||
///Use the legacy reference on things hard deleting by default.
|
||||
//#define GC_FAILURE_HARD_LOOKUP
|
||||
#ifdef GC_FAILURE_HARD_LOOKUP
|
||||
#define FIND_REF_NO_CHECK_TICK
|
||||
#endif //ifdef GC_FAILURE_HARD_LOOKUP
|
||||
|
||||
#endif //ifdef LEGACY_REFERENCE_TRACKING
|
||||
|
||||
//#define VISUALIZE_ACTIVE_TURFS //Highlights atmos active turfs in green
|
||||
#endif
|
||||
|
||||
#endif //ifdef TESTING
|
||||
//#define UNIT_TESTS //Enables unit tests via TEST_RUN_PARAMETER
|
||||
|
||||
#ifndef PRELOAD_RSC //set to:
|
||||
|
||||
@@ -278,3 +278,8 @@ GLOBAL_LIST_INIT(all_mutant_parts, list("tail_lizard" = "Tail", "mam_tail" = "Ta
|
||||
GLOBAL_LIST_INIT(unlocked_mutant_parts, list("horns", "insect_fluff"))
|
||||
//parts in either of the above two lists that require a second option that allows them to be coloured
|
||||
GLOBAL_LIST_INIT(colored_mutant_parts, list("insect_wings" = "wings_color", "deco_wings" = "wings_color", "horns" = "horns_color"))
|
||||
|
||||
//species ids that have greyscale sprites
|
||||
GLOBAL_LIST_INIT(greyscale_limb_types, list("human","moth","lizard","pod","plant","jelly","slime","golem","lum","stargazer","mush","ethereal","snail","c_golem","b_golem","mammal","xeno","ipc","insect","synthliz","avian","aquatic"))
|
||||
|
||||
//species ids that need snowflake coloring applied
|
||||
|
||||
@@ -41,3 +41,6 @@ GLOBAL_LIST_EMPTY(ai_status_displays)
|
||||
|
||||
GLOBAL_LIST_EMPTY(mob_spawners) // All mob_spawn objects
|
||||
GLOBAL_LIST_EMPTY(alert_consoles) // Station alert consoles, /obj/machinery/computer/station_alert
|
||||
|
||||
//list of everyone playing rock paper scissors
|
||||
GLOBAL_LIST_EMPTY(rockpaperscissors_players)
|
||||
|
||||
@@ -122,13 +122,13 @@
|
||||
if(pixel_size == pixels)
|
||||
return
|
||||
pixel_size = pixels
|
||||
cut_overlays(TRUE)
|
||||
cut_overlays()
|
||||
//our icon size is 32 pixels.
|
||||
transform = matrix((pixels - (VOLUMETRIC_STORAGE_BOX_BORDER_SIZE * 2)) / VOLUMETRIC_STORAGE_BOX_ICON_SIZE, 0, 0, 0, 1, 0)
|
||||
left.pixel_x = -((pixels - VOLUMETRIC_STORAGE_BOX_ICON_SIZE) * 0.5) - VOLUMETRIC_STORAGE_BOX_BORDER_SIZE
|
||||
right.pixel_x = ((pixels - VOLUMETRIC_STORAGE_BOX_ICON_SIZE) * 0.5) + VOLUMETRIC_STORAGE_BOX_BORDER_SIZE
|
||||
add_overlay(left, TRUE)
|
||||
add_overlay(right, TRUE)
|
||||
add_overlay(left)
|
||||
add_overlay(right)
|
||||
|
||||
/obj/screen/storage/volumetric_edge
|
||||
layer = VOLUMETRIC_STORAGE_BOX_LAYER
|
||||
|
||||
@@ -32,4 +32,4 @@
|
||||
/mob/camera/blob/AltClickOn(atom/A) //Remove a blob
|
||||
var/turf/T = get_turf(A)
|
||||
if(T)
|
||||
remove_blob(T)
|
||||
remove_blob(T)
|
||||
|
||||
@@ -534,4 +534,4 @@
|
||||
config_entry_value = 6
|
||||
|
||||
/datum/config_entry/number/max_shuttle_size
|
||||
config_entry_value = 250
|
||||
config_entry_value = 500
|
||||
|
||||
@@ -29,7 +29,7 @@ SUBSYSTEM_DEF(acid)
|
||||
|
||||
if(O.acid_level && O.acid_processing())
|
||||
else
|
||||
O.cut_overlay(GLOB.acid_overlay, TRUE)
|
||||
O.update_icon()
|
||||
processing -= O
|
||||
|
||||
if (MC_TICK_CHECK)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
PROCESSING_SUBSYSTEM_DEF(fluids)
|
||||
name = "Fluids"
|
||||
wait = 20
|
||||
stat_tag = "FD" //its actually Fluid Ducts
|
||||
flags = SS_NO_INIT | SS_TICKER
|
||||
@@ -25,7 +25,7 @@ SUBSYSTEM_DEF(garbage)
|
||||
//Queue
|
||||
var/list/queues
|
||||
|
||||
#ifdef TESTING
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
var/list/reference_find_on_fail = list()
|
||||
var/list/reference_find_on_fail_types = list()
|
||||
#endif
|
||||
@@ -134,7 +134,7 @@ SUBSYSTEM_DEF(garbage)
|
||||
++gcedlasttick
|
||||
++totalgcs
|
||||
pass_counts[level]++
|
||||
#ifdef TESTING
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
reference_find_on_fail -= refID //It's deleted we don't care anymore.
|
||||
#endif
|
||||
if (MC_TICK_CHECK)
|
||||
@@ -145,7 +145,9 @@ SUBSYSTEM_DEF(garbage)
|
||||
fail_counts[level]++
|
||||
switch (level)
|
||||
if (GC_QUEUE_CHECK)
|
||||
#ifdef TESTING
|
||||
#ifdef REFERENCE_TRACKING
|
||||
D.find_references()
|
||||
#elif defined(LEGACY_REFERENCE_TRACKING)
|
||||
if(reference_find_on_fail[refID])
|
||||
D.find_references()
|
||||
#ifdef GC_FAILURE_HARD_LOOKUP
|
||||
@@ -156,7 +158,19 @@ SUBSYSTEM_DEF(garbage)
|
||||
#endif
|
||||
var/type = D.type
|
||||
var/datum/qdel_item/I = items[type]
|
||||
#ifdef TESTING
|
||||
log_world("## TESTING: GC: -- \ref[D] | [type] was unable to be GC'd --")
|
||||
for(var/c in GLOB.admins) //Using testing() here would fill the logs with ADMIN_VV garbage
|
||||
var/client/admin = c
|
||||
if(!check_rights_for(admin, R_ADMIN))
|
||||
continue
|
||||
to_chat(admin, "## TESTING: GC: -- [ADMIN_VV(D)] | [type] was unable to be GC'd --")
|
||||
testing("GC: -- \ref[src] | [type] was unable to be GC'd --")
|
||||
#endif
|
||||
#ifdef REFERENCE_TRACKING
|
||||
GLOB.deletion_failures += D //It should no longer be bothered by the GC, manual deletion only.
|
||||
continue
|
||||
#endif
|
||||
I.failures++
|
||||
if (GC_QUEUE_HARDDELETE)
|
||||
HardDelete(D)
|
||||
@@ -181,7 +195,7 @@ SUBSYSTEM_DEF(garbage)
|
||||
var/gctime = world.time
|
||||
var/refid = "\ref[D]"
|
||||
|
||||
#ifdef TESTING
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
if(reference_find_on_fail_types[D.type])
|
||||
reference_find_on_fail["\ref[D]"] = TRUE
|
||||
#endif
|
||||
@@ -193,7 +207,7 @@ SUBSYSTEM_DEF(garbage)
|
||||
|
||||
queue[refid] = gctime
|
||||
|
||||
#ifdef TESTING
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
/datum/controller/subsystem/garbage/proc/add_type_to_findref(type)
|
||||
if(!ispath(type))
|
||||
return "NOT A VAILD PATH"
|
||||
@@ -260,12 +274,6 @@ SUBSYSTEM_DEF(garbage)
|
||||
/datum/qdel_item/New(mytype)
|
||||
name = "[mytype]"
|
||||
|
||||
#ifdef TESTING
|
||||
/proc/qdel_and_find_ref_if_fail(datum/D, force = FALSE)
|
||||
SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE
|
||||
qdel(D, force)
|
||||
#endif
|
||||
|
||||
// Should be treated as a replacement for the 'del' keyword.
|
||||
// Datums passed to this will be given a chance to clean up references to allow the GC to collect them.
|
||||
/proc/qdel(datum/D, force=FALSE, ...)
|
||||
@@ -319,16 +327,13 @@ SUBSYSTEM_DEF(garbage)
|
||||
SSgarbage.Queue(D, GC_QUEUE_HARDDELETE)
|
||||
if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste.
|
||||
SSgarbage.HardDelete(D)
|
||||
if (QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion.
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
if (QDEL_HINT_FINDREFERENCE) //qdel will, if LEGACY_REFERENCE_TRACKING is enabled, display all references to this object, then queue the object for deletion.
|
||||
SSgarbage.Queue(D)
|
||||
#ifdef TESTING
|
||||
D.find_references()
|
||||
#endif
|
||||
if (QDEL_HINT_IFFAIL_FINDREFERENCE)
|
||||
SSgarbage.Queue(D)
|
||||
#ifdef TESTING
|
||||
SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE
|
||||
#endif
|
||||
#endif
|
||||
else
|
||||
#ifdef TESTING
|
||||
if(!I.no_hint)
|
||||
@@ -339,119 +344,6 @@ SUBSYSTEM_DEF(garbage)
|
||||
else if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||
CRASH("[D.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic")
|
||||
|
||||
#ifdef TESTING
|
||||
|
||||
/datum/verb/find_refs()
|
||||
set category = "Debug"
|
||||
set name = "Find References"
|
||||
set src in world
|
||||
|
||||
find_references(FALSE)
|
||||
|
||||
/datum/proc/find_references(skip_alert)
|
||||
running_find_references = type
|
||||
if(usr && usr.client)
|
||||
if(usr.client.running_find_references)
|
||||
testing("CANCELLED search for references to a [usr.client.running_find_references].")
|
||||
usr.client.running_find_references = null
|
||||
running_find_references = null
|
||||
//restart the garbage collector
|
||||
SSgarbage.can_fire = 1
|
||||
SSgarbage.next_fire = world.time + world.tick_lag
|
||||
return
|
||||
|
||||
if(!skip_alert)
|
||||
if(alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "Yes", "No") == "No")
|
||||
running_find_references = null
|
||||
return
|
||||
|
||||
//this keeps the garbage collector from failing to collect objects being searched for in here
|
||||
SSgarbage.can_fire = 0
|
||||
|
||||
if(usr && usr.client)
|
||||
usr.client.running_find_references = type
|
||||
|
||||
testing("Beginning search for references to a [type].")
|
||||
last_find_references = world.time
|
||||
|
||||
DoSearchVar(GLOB) //globals
|
||||
for(var/datum/thing in world) //atoms (don't beleive it's lies)
|
||||
DoSearchVar(thing, "World -> [thing]")
|
||||
|
||||
for (var/datum/thing) //datums
|
||||
DoSearchVar(thing, "World -> [thing]")
|
||||
|
||||
for (var/client/thing) //clients
|
||||
DoSearchVar(thing, "World -> [thing]")
|
||||
|
||||
testing("Completed search for references to a [type].")
|
||||
if(usr && usr.client)
|
||||
usr.client.running_find_references = null
|
||||
running_find_references = null
|
||||
|
||||
//restart the garbage collector
|
||||
SSgarbage.can_fire = 1
|
||||
SSgarbage.next_fire = world.time + world.tick_lag
|
||||
|
||||
/datum/verb/qdel_then_find_references()
|
||||
set category = "Debug"
|
||||
set name = "qdel() then Find References"
|
||||
set src in world
|
||||
|
||||
qdel(src, TRUE) //Force.
|
||||
if(!running_find_references)
|
||||
find_references(TRUE)
|
||||
|
||||
/datum/verb/qdel_then_if_fail_find_references()
|
||||
set category = "Debug"
|
||||
set name = "qdel() then Find References if GC failure"
|
||||
set src in world
|
||||
|
||||
qdel_and_find_ref_if_fail(src, TRUE)
|
||||
|
||||
/datum/proc/DoSearchVar(X, Xname, recursive_limit = 64)
|
||||
if(usr && usr.client && !usr.client.running_find_references)
|
||||
return
|
||||
if (!recursive_limit)
|
||||
return
|
||||
|
||||
if(istype(X, /datum))
|
||||
var/datum/D = X
|
||||
if(D.last_find_references == last_find_references)
|
||||
return
|
||||
|
||||
D.last_find_references = last_find_references
|
||||
var/list/L = D.vars
|
||||
|
||||
for(var/varname in L)
|
||||
if (varname == "vars")
|
||||
continue
|
||||
var/variable = L[varname]
|
||||
|
||||
if(variable == src)
|
||||
testing("Found [src.type] \ref[src] in [D.type]'s [varname] var. [Xname]")
|
||||
|
||||
else if(islist(variable))
|
||||
DoSearchVar(variable, "[Xname] -> list", recursive_limit-1)
|
||||
|
||||
else if(islist(X))
|
||||
var/normal = IS_NORMAL_LIST(X)
|
||||
for(var/I in X)
|
||||
if (I == src)
|
||||
testing("Found [src.type] \ref[src] in list [Xname].")
|
||||
|
||||
else if (I && !isnum(I) && normal && X[I] == src)
|
||||
testing("Found [src.type] \ref[src] in list [Xname]\[[I]\]")
|
||||
|
||||
else if (islist(I))
|
||||
DoSearchVar(I, "[Xname] -> list", recursive_limit-1)
|
||||
|
||||
#ifndef FIND_REF_NO_CHECK_TICK
|
||||
CHECK_TICK
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TESTING
|
||||
/proc/writeDatumCount()
|
||||
var/list/datums = list()
|
||||
|
||||
@@ -114,67 +114,47 @@ SUBSYSTEM_DEF(overlays)
|
||||
|
||||
#define NOT_QUEUED_ALREADY (!(flags_1 & OVERLAY_QUEUED_1))
|
||||
#define QUEUE_FOR_COMPILE flags_1 |= OVERLAY_QUEUED_1; SSoverlays.queue += src;
|
||||
/atom/proc/cut_overlays(priority = FALSE)
|
||||
LAZYINITLIST(priority_overlays)
|
||||
/atom/proc/cut_overlays()
|
||||
LAZYINITLIST(remove_overlays)
|
||||
LAZYINITLIST(add_overlays)
|
||||
remove_overlays = overlays.Copy()
|
||||
add_overlays.Cut()
|
||||
|
||||
if(priority)
|
||||
priority_overlays.Cut()
|
||||
|
||||
//If not already queued for work and there are overlays to remove
|
||||
if(NOT_QUEUED_ALREADY && remove_overlays.len)
|
||||
QUEUE_FOR_COMPILE
|
||||
|
||||
/atom/proc/cut_overlay(list/overlays, priority)
|
||||
/atom/proc/cut_overlay(list/overlays)
|
||||
if(!overlays)
|
||||
return
|
||||
overlays = build_appearance_list(overlays)
|
||||
LAZYINITLIST(add_overlays) //always initialized after this point
|
||||
LAZYINITLIST(priority_overlays)
|
||||
LAZYINITLIST(remove_overlays)
|
||||
var/a_len = add_overlays.len
|
||||
var/r_len = remove_overlays.len
|
||||
var/p_len = priority_overlays.len
|
||||
remove_overlays += overlays
|
||||
add_overlays -= overlays
|
||||
|
||||
|
||||
if(priority)
|
||||
var/list/cached_priority = priority_overlays
|
||||
LAZYREMOVE(cached_priority, overlays)
|
||||
|
||||
var/fa_len = add_overlays.len
|
||||
var/fr_len = remove_overlays.len
|
||||
var/fp_len = priority_overlays.len
|
||||
|
||||
//If not already queued and there is work to be done
|
||||
if(NOT_QUEUED_ALREADY && (fa_len != a_len || fr_len != r_len || fp_len != p_len))
|
||||
if(NOT_QUEUED_ALREADY && (fa_len != a_len || fr_len != r_len))
|
||||
QUEUE_FOR_COMPILE
|
||||
|
||||
/atom/proc/add_overlay(list/overlays, priority = FALSE)
|
||||
/atom/proc/add_overlay(list/overlays)
|
||||
if(!overlays)
|
||||
return
|
||||
|
||||
overlays = build_appearance_list(overlays)
|
||||
|
||||
LAZYINITLIST(add_overlays) //always initialized after this point
|
||||
LAZYINITLIST(priority_overlays)
|
||||
var/a_len = add_overlays.len
|
||||
var/p_len = priority_overlays.len
|
||||
|
||||
if(priority)
|
||||
priority_overlays += overlays //or in the image. Can we use [image] = image?
|
||||
var/fp_len = priority_overlays.len
|
||||
if(NOT_QUEUED_ALREADY && fp_len != p_len)
|
||||
QUEUE_FOR_COMPILE
|
||||
else
|
||||
add_overlays += overlays
|
||||
var/fa_len = add_overlays.len
|
||||
if(NOT_QUEUED_ALREADY && fa_len != a_len)
|
||||
QUEUE_FOR_COMPILE
|
||||
add_overlays += overlays
|
||||
var/fa_len = add_overlays.len
|
||||
if(NOT_QUEUED_ALREADY && fa_len != a_len)
|
||||
QUEUE_FOR_COMPILE
|
||||
|
||||
/atom/proc/copy_overlays(atom/other, cut_old) //copys our_overlays from another atom
|
||||
if(!other)
|
||||
|
||||
@@ -4,16 +4,26 @@ PROCESSING_SUBSYSTEM_DEF(instruments)
|
||||
init_order = INIT_ORDER_INSTRUMENTS
|
||||
flags = SS_KEEP_TIMING
|
||||
priority = FIRE_PRIORITY_INSTRUMENTS
|
||||
var/static/list/datum/instrument/instrument_data = list() //id = datum
|
||||
/// List of all instrument data, associative id = datum
|
||||
var/static/list/datum/instrument/instrument_data = list()
|
||||
/// List of all song datums.
|
||||
var/static/list/datum/song/songs = list()
|
||||
/// Max lines in songs
|
||||
var/static/musician_maxlines = 600
|
||||
/// Max characters per line in songs
|
||||
var/static/musician_maxlinechars = 300
|
||||
/// Deciseconds between hearchecks. Too high and instruments seem to lag when people are moving around in terms of who can hear it. Too low and the server lags from this.
|
||||
var/static/musician_hearcheck_mindelay = 5
|
||||
/// Maximum instrument channels total instruments are allowed to use. This is so you don't have instruments deadlocking all sound channels.
|
||||
var/static/max_instrument_channels = MAX_INSTRUMENT_CHANNELS
|
||||
/// Current number of channels allocated for instruments
|
||||
var/static/current_instrument_channels = 0
|
||||
/// Single cached list for synthesizer instrument ids, so you don't have to have a new list with every synthesizer.
|
||||
var/static/list/synthesizer_instrument_ids
|
||||
|
||||
/datum/controller/subsystem/processing/instruments/Initialize()
|
||||
initialize_instrument_data()
|
||||
synthesizer_instrument_ids = get_allowed_instrument_ids()
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/processing/instruments/proc/on_song_new(datum/song/S)
|
||||
@@ -29,7 +39,10 @@ PROCESSING_SUBSYSTEM_DEF(instruments)
|
||||
continue
|
||||
I = new path
|
||||
I.Initialize()
|
||||
instrument_data[I.id || "[I.type]"] = I
|
||||
if(!I.id)
|
||||
qdel(I)
|
||||
continue
|
||||
instrument_data[I.id] = I
|
||||
CHECK_TICK
|
||||
|
||||
/datum/controller/subsystem/processing/instruments/proc/get_instrument(id_or_path)
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
|
||||
/datum/action/proc/ApplyIcon(obj/screen/movable/action_button/current_button, force = FALSE)
|
||||
if(icon_icon && button_icon_state && ((current_button.button_icon_state != button_icon_state) || force))
|
||||
current_button.cut_overlays(TRUE)
|
||||
current_button.cut_overlays()
|
||||
current_button.add_overlay(mutable_appearance(icon_icon, button_icon_state))
|
||||
current_button.button_icon_state = button_icon_state
|
||||
|
||||
|
||||
@@ -40,13 +40,23 @@
|
||||
reqs = list(/obj/item/paper = 20)
|
||||
category = CAT_CLOTHING
|
||||
|
||||
/datum/crafting_recipe/balaclavabreath
|
||||
name = "Breathaclava"
|
||||
result = /obj/item/clothing/mask/balaclava/breath
|
||||
time = 10
|
||||
reqs = list(/obj/item/clothing/mask/balaclava = 1,
|
||||
/obj/item/clothing/mask/breath = 1)
|
||||
category = CAT_CLOTHING
|
||||
|
||||
|
||||
|
||||
/datum/crafting_recipe/armwraps
|
||||
name = "Armwraps"
|
||||
result = /obj/item/clothing/gloves/fingerless/pugilist
|
||||
time = 60
|
||||
tools = list(TOOL_WIRECUTTER)
|
||||
reqs = list(/obj/item/stack/sheet/cloth = 4,
|
||||
/obj/item/stack/sheet/durathread = 2,
|
||||
/obj/item/stack/sticky_tape = 2,
|
||||
/obj/item/stack/sheet/leather = 2)
|
||||
category = CAT_CLOTHING
|
||||
|
||||
|
||||
@@ -2,6 +2,15 @@
|
||||
//Large Objects//
|
||||
/////////////////
|
||||
|
||||
/datum/crafting_recipe/plunger
|
||||
name = "Plunger"
|
||||
result = /obj/item/plunger
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/sheet/plastic = 1,
|
||||
/obj/item/stack/sheet/mineral/wood = 1)
|
||||
category = CAT_MISC
|
||||
subcategory = CAT_TOOL
|
||||
|
||||
/datum/crafting_recipe/showercurtain
|
||||
name = "Shower Curtains"
|
||||
reqs = list(/obj/item/stack/sheet/cloth = 2,
|
||||
@@ -337,7 +346,7 @@
|
||||
result = /obj/item/toy/sword/cx
|
||||
subcategory = CAT_MISCELLANEOUS
|
||||
category = CAT_MISC
|
||||
|
||||
|
||||
/datum/crafting_recipe/catgirlplushie
|
||||
name = "Catgirl Plushie"
|
||||
reqs = list(/obj/item/toy/plush/hairball = 3)
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING))
|
||||
if(overlay)
|
||||
var/atom/A = parent
|
||||
A.cut_overlay(overlay, TRUE)
|
||||
UnregisterSignal(A,COMSIG_ATOM_UPDATE_OVERLAYS)
|
||||
qdel(overlay)
|
||||
|
||||
return ..()
|
||||
@@ -326,7 +326,8 @@
|
||||
var/matrix/M = matrix()
|
||||
M.Translate(pixelX, pixelY)
|
||||
overlay.transform = M
|
||||
hit.add_overlay(overlay, TRUE)
|
||||
RegisterSignal(hit,COMSIG_ATOM_UPDATE_OVERLAYS,.proc/apply_overlay)
|
||||
hit.update_icon()
|
||||
|
||||
if(harmful)
|
||||
hit.visible_message("<span class='danger'>[weapon] embeds itself in [hit]!</span>")
|
||||
@@ -339,6 +340,8 @@
|
||||
else
|
||||
hit.visible_message("<span class='danger'>[weapon] sticks itself to [hit]!</span>")
|
||||
|
||||
/datum/component/embedded/proc/apply_overlay(atom/source, list/overlay_list)
|
||||
overlay_list += overlay
|
||||
|
||||
/datum/component/embedded/proc/examineTurf(datum/source, mob/user, list/examine_list)
|
||||
if(harmful)
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
/datum/component/plumbing
|
||||
///Index with "1" = /datum/ductnet/theductpointingnorth etc. "1" being the num2text from NORTH define
|
||||
var/list/datum/ductnet/ducts = list()
|
||||
///shortcut to our parents' reagent holder
|
||||
var/datum/reagents/reagents
|
||||
///TRUE if we wanna add proper pipe outless under our parent object. this is pretty good if i may so so myself
|
||||
var/use_overlays = TRUE
|
||||
///We can't just cut all of the parents' overlays, so we'll track them here
|
||||
var/list/image/ducterlays
|
||||
///directions in wich we act as a supplier
|
||||
var/supply_connects
|
||||
///direction in wich we act as a demander
|
||||
var/demand_connects
|
||||
///FALSE to pretty much just not exist in the plumbing world so we can be moved, TRUE to go plumbo mode
|
||||
var/active = FALSE
|
||||
///if TRUE connects will spin with the parent object visually and codually, so you can have it work in any direction. FALSE if you want it to be static
|
||||
var/turn_connects = TRUE
|
||||
|
||||
/datum/component/plumbing/Initialize(start=TRUE, _turn_connects=TRUE) //turn_connects for wheter or not we spin with the object to change our pipes
|
||||
if(parent && !istype(parent, /atom/movable))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
var/atom/movable/AM = parent
|
||||
if(!AM.reagents)
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
reagents = AM.reagents
|
||||
turn_connects = _turn_connects
|
||||
|
||||
RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED,COMSIG_PARENT_PREQDELETED), .proc/disable)
|
||||
RegisterSignal(parent, list(COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH), .proc/toggle_active)
|
||||
|
||||
if(start)
|
||||
enable()
|
||||
|
||||
if(use_overlays)
|
||||
create_overlays()
|
||||
|
||||
/datum/component/plumbing/process()
|
||||
if(!demand_connects || !reagents)
|
||||
STOP_PROCESSING(SSfluids, src)
|
||||
return
|
||||
if(reagents.total_volume < reagents.maximum_volume)
|
||||
for(var/D in GLOB.cardinals)
|
||||
if(D & demand_connects)
|
||||
send_request(D)
|
||||
///Can we be added to the ductnet?
|
||||
/datum/component/plumbing/proc/can_add(datum/ductnet/D, dir)
|
||||
if(!active)
|
||||
return
|
||||
if(!dir || !D)
|
||||
return FALSE
|
||||
if(num2text(dir) in ducts)
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
///called from in process(). only calls process_request(), but can be overwritten for children with special behaviour
|
||||
/datum/component/plumbing/proc/send_request(dir)
|
||||
process_request(amount = MACHINE_REAGENT_TRANSFER, reagent = null, dir = dir)
|
||||
///check who can give us what we want, and how many each of them will give us
|
||||
/datum/component/plumbing/proc/process_request(amount, reagent, dir)
|
||||
var/list/valid_suppliers = list()
|
||||
var/datum/ductnet/net
|
||||
if(!ducts.Find(num2text(dir)))
|
||||
return
|
||||
net = ducts[num2text(dir)]
|
||||
for(var/A in net.suppliers)
|
||||
var/datum/component/plumbing/supplier = A
|
||||
if(supplier.can_give(amount, reagent, net))
|
||||
valid_suppliers += supplier
|
||||
for(var/A in valid_suppliers)
|
||||
var/datum/component/plumbing/give = A
|
||||
give.transfer_to(src, amount / valid_suppliers.len, reagent, net)
|
||||
///returns TRUE when they can give the specified amount and reagent. called by process request
|
||||
/datum/component/plumbing/proc/can_give(amount, reagent, datum/ductnet/net)
|
||||
if(amount <= 0)
|
||||
return
|
||||
|
||||
if(reagent) //only asked for one type of reagent
|
||||
for(var/A in reagents.reagent_list)
|
||||
var/datum/reagent/R = A
|
||||
if(R.type == reagent)
|
||||
return TRUE
|
||||
else if(reagents.total_volume > 0) //take whatever
|
||||
return TRUE
|
||||
///this is where the reagent is actually transferred and is thus the finish point of our process()
|
||||
/datum/component/plumbing/proc/transfer_to(datum/component/plumbing/target, amount, reagent, datum/ductnet/net)
|
||||
if(!reagents || !target || !target.reagents)
|
||||
return FALSE
|
||||
if(reagent)
|
||||
reagents.trans_id_to(target.parent, reagent, amount)
|
||||
else
|
||||
reagents.trans_to(target.parent, amount)
|
||||
///We create our luxurious piping overlays/underlays, to indicate where we do what. only called once if use_overlays = TRUE in Initialize()
|
||||
/datum/component/plumbing/proc/create_overlays()
|
||||
var/atom/movable/AM = parent
|
||||
for(var/image/I in ducterlays)
|
||||
AM.overlays.Remove(I)
|
||||
qdel(I)
|
||||
ducterlays = list()
|
||||
for(var/D in GLOB.cardinals)
|
||||
var/color
|
||||
var/direction
|
||||
if(D & demand_connects)
|
||||
color = "red" //red because red is mean and it takes
|
||||
else if(D & supply_connects)
|
||||
color = "blue" //blue is nice and gives
|
||||
else
|
||||
continue
|
||||
var/image/I
|
||||
if(turn_connects)
|
||||
switch(D)
|
||||
if(NORTH)
|
||||
direction = "north"
|
||||
if(SOUTH)
|
||||
direction = "south"
|
||||
if(EAST)
|
||||
direction = "east"
|
||||
if(WEST)
|
||||
direction = "west"
|
||||
I = image('icons/obj/plumbing/plumbers.dmi', "[direction]-[color]", layer = AM.layer - 1)
|
||||
else
|
||||
I = image('icons/obj/plumbing/plumbers.dmi', color, layer = AM.layer - 1) //color is not color as in the var, it's just the name
|
||||
I.dir = D
|
||||
AM.add_overlay(I)
|
||||
ducterlays += I
|
||||
///we stop acting like a plumbing thing and disconnect if we are, so we can safely be moved and stuff
|
||||
/datum/component/plumbing/proc/disable()
|
||||
if(!active)
|
||||
return
|
||||
STOP_PROCESSING(SSfluids, src)
|
||||
for(var/A in ducts)
|
||||
var/datum/ductnet/D = ducts[A]
|
||||
D.remove_plumber(src)
|
||||
active = FALSE
|
||||
for(var/D in GLOB.cardinals)
|
||||
if(D & (demand_connects | supply_connects))
|
||||
for(var/obj/machinery/duct/duct in get_step(parent, D))
|
||||
duct.attempt_connect()
|
||||
|
||||
///settle wherever we are, and start behaving like a piece of plumbing
|
||||
/datum/component/plumbing/proc/enable()
|
||||
if(active)
|
||||
return
|
||||
update_dir()
|
||||
active = TRUE
|
||||
var/atom/movable/AM = parent
|
||||
for(var/obj/machinery/duct/D in AM.loc) //Destroy any ducts under us. Ducts also self destruct if placed under a plumbing machine. machines disable when they get moved
|
||||
if(D.anchored) //that should cover everything
|
||||
D.disconnect_duct()
|
||||
|
||||
if(demand_connects)
|
||||
START_PROCESSING(SSfluids, src)
|
||||
|
||||
for(var/D in GLOB.cardinals)
|
||||
if(D & (demand_connects | supply_connects))
|
||||
for(var/atom/movable/A in get_step(parent, D))
|
||||
if(istype(A, /obj/machinery/duct))
|
||||
var/obj/machinery/duct/duct = A
|
||||
duct.attempt_connect()
|
||||
else
|
||||
var/datum/component/plumbing/P = A.GetComponent(/datum/component/plumbing)
|
||||
if(P)
|
||||
direct_connect(P, D)
|
||||
|
||||
/// Toggle our machinery on or off. This is called by a hook from default_unfasten_wrench with anchored as only param, so we dont have to copypaste this on every object that can move
|
||||
/datum/component/plumbing/proc/toggle_active(obj/O, new_state)
|
||||
if(new_state)
|
||||
enable()
|
||||
else
|
||||
disable()
|
||||
/** We update our connects only when we settle down by taking our current and original direction to find our new connects
|
||||
* If someone wants it to fucking spin while connected to something go actually knock yourself out
|
||||
*/
|
||||
/datum/component/plumbing/proc/update_dir()
|
||||
if(!turn_connects)
|
||||
return
|
||||
var/atom/movable/AM = parent
|
||||
var/new_demand_connects
|
||||
var/new_supply_connects
|
||||
var/new_dir = AM.dir
|
||||
var/angle = 180 - dir2angle(new_dir)
|
||||
if(new_dir == SOUTH)
|
||||
demand_connects = initial(demand_connects)
|
||||
supply_connects = initial(supply_connects)
|
||||
else
|
||||
for(var/D in GLOB.cardinals)
|
||||
if(D & initial(demand_connects))
|
||||
new_demand_connects += turn(D, angle)
|
||||
if(D & initial(supply_connects))
|
||||
new_supply_connects += turn(D, angle)
|
||||
demand_connects = new_demand_connects
|
||||
supply_connects = new_supply_connects
|
||||
///Give the direction of a pipe, and it'll return wich direction it originally was when it's object pointed SOUTH
|
||||
/datum/component/plumbing/proc/get_original_direction(dir)
|
||||
var/atom/movable/AM = parent
|
||||
return turn(dir, dir2angle(AM.dir) - 180)
|
||||
//special case in-case we want to connect directly with another machine without a duct
|
||||
/datum/component/plumbing/proc/direct_connect(datum/component/plumbing/P, dir)
|
||||
if(!P.active)
|
||||
return
|
||||
var/opposite_dir = turn(dir, 180)
|
||||
if(P.demand_connects & opposite_dir && supply_connects & dir || P.supply_connects & opposite_dir && demand_connects & dir) //make sure we arent connecting two supplies or demands
|
||||
var/datum/ductnet/net = new()
|
||||
net.add_plumber(src, dir)
|
||||
net.add_plumber(P, opposite_dir)
|
||||
|
||||
///has one pipe input that only takes, example is manual output pipe
|
||||
/datum/component/plumbing/simple_demand
|
||||
demand_connects = NORTH
|
||||
///has one pipe output that only supplies. example is liquid pump and manual input pipe
|
||||
/datum/component/plumbing/simple_supply
|
||||
supply_connects = NORTH
|
||||
///input and output, like a holding tank
|
||||
/datum/component/plumbing/tank
|
||||
demand_connects = WEST
|
||||
supply_connects = EAST
|
||||
@@ -0,0 +1,21 @@
|
||||
/datum/component/plumbing/acclimator
|
||||
demand_connects = WEST
|
||||
supply_connects = EAST
|
||||
var/obj/machinery/plumbing/acclimator/AC
|
||||
|
||||
/datum/component/plumbing/acclimator/Initialize(start=TRUE, _turn_connects=TRUE)
|
||||
. = ..()
|
||||
if(!istype(parent, /obj/machinery/plumbing/acclimator))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
AC = parent
|
||||
|
||||
/datum/component/plumbing/acclimator/can_give(amount, reagent)
|
||||
. = ..()
|
||||
if(. && AC.emptying)
|
||||
return TRUE
|
||||
return FALSE
|
||||
///We're overriding process and not send_request, because all process does is do the requests, so we might aswell cut out the middle man and save some code from running
|
||||
/datum/component/plumbing/acclimator/process()
|
||||
if(AC.emptying)
|
||||
return
|
||||
. = ..()
|
||||
@@ -0,0 +1,59 @@
|
||||
///The magical plumbing component used by the chemical filters. The different supply connects behave differently depending on the filters set on the chemical filter
|
||||
/datum/component/plumbing/filter
|
||||
demand_connects = NORTH
|
||||
supply_connects = SOUTH | EAST | WEST //SOUTH is straight, EAST is left and WEST is right. We look from the perspective of the insert
|
||||
|
||||
/datum/component/plumbing/filter/Initialize()
|
||||
. = ..()
|
||||
if(!istype(parent, /obj/machinery/plumbing/filter))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
/datum/component/plumbing/filter/can_give(amount, reagent, datum/ductnet/net)
|
||||
. = ..()
|
||||
if(.)
|
||||
var/direction
|
||||
for(var/A in ducts)
|
||||
if(ducts[A] == net)
|
||||
direction = get_original_direction(text2num(A)) //we need it relative to the direction, so filters don't change when we turn the filter
|
||||
break
|
||||
if(!direction)
|
||||
return FALSE
|
||||
if(reagent)
|
||||
if(!can_give_in_direction(direction, reagent))
|
||||
return FALSE
|
||||
|
||||
/datum/component/plumbing/filter/transfer_to(datum/component/plumbing/target, amount, reagent, datum/ductnet/net)
|
||||
if(!reagents || !target || !target.reagents)
|
||||
return FALSE
|
||||
var/direction
|
||||
for(var/A in ducts)
|
||||
if(ducts[A] == net)
|
||||
direction = get_original_direction(text2num(A))
|
||||
break
|
||||
if(reagent)
|
||||
reagents.trans_id_to(target.parent, reagent, amount)
|
||||
else
|
||||
for(var/A in reagents.reagent_list)
|
||||
var/datum/reagent/R = A
|
||||
if(!can_give_in_direction(direction, R.type))
|
||||
continue
|
||||
var/new_amount
|
||||
if(R.volume < amount)
|
||||
new_amount = amount - R.volume
|
||||
reagents.trans_id_to(target.parent, R.type, amount)
|
||||
amount = new_amount
|
||||
if(amount <= 0)
|
||||
break
|
||||
///We check if the direction and reagent are valid to give. Needed for filters since different outputs have different behaviours
|
||||
/datum/component/plumbing/filter/proc/can_give_in_direction(dir, reagent)
|
||||
var/obj/machinery/plumbing/filter/F = parent
|
||||
switch(dir)
|
||||
if(SOUTH) //straight
|
||||
if(!F.left.Find(reagent) && !F.right.Find(reagent))
|
||||
return TRUE
|
||||
if(WEST) //right
|
||||
if(F.right.Find(reagent))
|
||||
return TRUE
|
||||
if(EAST) //left
|
||||
if(F.left.Find(reagent))
|
||||
return TRUE
|
||||
@@ -0,0 +1,38 @@
|
||||
/datum/component/plumbing/reaction_chamber
|
||||
demand_connects = WEST
|
||||
supply_connects = EAST
|
||||
|
||||
/datum/component/plumbing/reaction_chamber/Initialize(start=TRUE, _turn_connects=TRUE)
|
||||
. = ..()
|
||||
if(!istype(parent, /obj/machinery/plumbing/reaction_chamber))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
/datum/component/plumbing/reaction_chamber/can_give(amount, reagent, datum/ductnet/net)
|
||||
. = ..()
|
||||
var/obj/machinery/plumbing/reaction_chamber/RC = parent
|
||||
if(!. || !RC.emptying)
|
||||
return FALSE
|
||||
|
||||
/datum/component/plumbing/reaction_chamber/send_request(dir)
|
||||
var/obj/machinery/plumbing/reaction_chamber/RC = parent
|
||||
if(RC.emptying || !LAZYLEN(RC.required_reagents))
|
||||
return
|
||||
for(var/RT in RC.required_reagents)
|
||||
var/has_reagent = FALSE
|
||||
for(var/A in reagents.reagent_list)
|
||||
var/datum/reagent/RD = A
|
||||
if(RT == RD.type)
|
||||
has_reagent = TRUE
|
||||
if(RD.volume < RC.required_reagents[RT])
|
||||
process_request(min(RC.required_reagents[RT] - RD.volume, MACHINE_REAGENT_TRANSFER) , RT, dir)
|
||||
return
|
||||
if(!has_reagent)
|
||||
process_request(min(RC.required_reagents[RT], MACHINE_REAGENT_TRANSFER), RT, dir)
|
||||
return
|
||||
|
||||
RC.reagent_flags &= ~NO_REACT
|
||||
reagents.handle_reactions()
|
||||
|
||||
RC.emptying = TRUE //If we move this up, it'll instantly get turned off since any reaction always sets the reagent_total to zero. Other option is make the reaction update
|
||||
//everything for every chemical removed, wich isn't a good option either.
|
||||
RC.on_reagent_change() //We need to check it now, because some reactions leave nothing left.
|
||||
@@ -0,0 +1,45 @@
|
||||
/datum/component/plumbing/splitter
|
||||
demand_connects = NORTH
|
||||
supply_connects = SOUTH | EAST
|
||||
|
||||
/datum/component/plumbing/splitter/Initialize()
|
||||
. = ..()
|
||||
if(. && !istype(parent, /obj/machinery/plumbing/splitter))
|
||||
return FALSE
|
||||
|
||||
/datum/component/plumbing/splitter/can_give(amount, reagent, datum/ductnet/net)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
. = FALSE
|
||||
var/direction
|
||||
for(var/A in ducts)
|
||||
if(ducts[A] == net)
|
||||
direction = get_original_direction(text2num(A))
|
||||
break
|
||||
var/obj/machinery/plumbing/splitter/S = parent
|
||||
switch(direction)
|
||||
if(SOUTH)
|
||||
if(S.turn_straight && S.transfer_straight <= amount)
|
||||
S.turn_straight = FALSE
|
||||
return TRUE
|
||||
if(EAST)
|
||||
if(!S.turn_straight && S.transfer_side <= amount)
|
||||
S.turn_straight = TRUE
|
||||
return TRUE
|
||||
|
||||
/datum/component/plumbing/splitter/transfer_to(datum/component/plumbing/target, amount, reagent, datum/ductnet/net)
|
||||
var/direction
|
||||
for(var/A in ducts)
|
||||
if(ducts[A] == net)
|
||||
direction = get_original_direction(text2num(A))
|
||||
break
|
||||
var/obj/machinery/plumbing/splitter/S = parent
|
||||
switch(direction)
|
||||
if(SOUTH)
|
||||
if(amount >= S.transfer_straight)
|
||||
amount = S.transfer_straight
|
||||
if(EAST)
|
||||
if(amount >= S.transfer_side)
|
||||
amount = S.transfer_side
|
||||
. = ..()
|
||||
@@ -14,6 +14,7 @@
|
||||
var/mob/living/holder //who is currently benefiting from the shield.
|
||||
var/dissipating = FALSE //Is this shield meant to dissipate over time instead of recharging.
|
||||
var/del_on_overload = FALSE //will delete itself once it has no charges left.
|
||||
var/cached_vis_overlay //text identifier of the visual overlay.
|
||||
|
||||
/datum/component/shielded/Initialize(current, max = 3, delay = 20 SECONDS, rate = 1, slots, state = "shield-old", broken, \
|
||||
sound = 'sound/magic/charge.ogg', end_sound = 'sound/machines/ding.ogg', diss = FALSE, del_overload = FALSE)
|
||||
@@ -47,9 +48,8 @@
|
||||
holder = L
|
||||
var/to_add = charges >= 1 ? shield_state : broken_state
|
||||
if(to_add)
|
||||
var/mutable_appearance/M = mutable_appearance('icons/effects/effects.dmi', to_add)
|
||||
M.layer = (L.layer > MOB_LAYER ? L.layer : MOB_LAYER) + 0.01
|
||||
holder.add_overlay(M, TRUE)
|
||||
var/layer = (L.layer > MOB_LAYER ? L.layer : MOB_LAYER) + 0.01
|
||||
SSvis_overlays.add_vis_overlay(L, 'icons/effects/effects.dmi', to_add, layer, GAME_PLANE, L.dir)
|
||||
|
||||
/datum/component/shielded/UnregisterFromParent()
|
||||
. = ..()
|
||||
@@ -57,9 +57,9 @@
|
||||
UnregisterSignal(parent, list(COMSIG_ITEM_RUN_BLOCK,COMSIG_ITEM_CHECK_BLOCK,COMSIG_ITEM_EQUIPPED,COMSIG_ITEM_DROPPED))
|
||||
if(holder)
|
||||
UnregisterSignal(holder, list(COMSIG_LIVING_RUN_BLOCK, COMSIG_LIVING_GET_BLOCKING_ITEMS))
|
||||
var/to_remove = charges >= 1 ? shield_state : broken_state
|
||||
if(to_remove)
|
||||
holder.cut_overlay(mutable_appearance('icons/effects/effects.dmi', to_remove), TRUE)
|
||||
if(cached_vis_overlay)
|
||||
SSvis_overlays.remove_vis_overlay(holder, cached_vis_overlay)
|
||||
cached_vis_overlay = null
|
||||
holder = null
|
||||
|
||||
/datum/component/shielded/process()
|
||||
@@ -80,7 +80,7 @@
|
||||
holder.visible_message("[holder]'s shield overloads!")
|
||||
qdel(src)
|
||||
return
|
||||
if(holder && (old_charges < 1 && charges >= 1) || (!del_on_overload && old_charges >= 1 && charges < 1))
|
||||
if(holder && ((old_charges < 1 && charges >= 1) || (!del_on_overload && old_charges >= 1 && charges < 1)))
|
||||
update_shield_overlay(charges < 1)
|
||||
|
||||
/datum/component/shielded/proc/adjust_charges(amount)
|
||||
@@ -93,20 +93,19 @@
|
||||
holder.visible_message("[holder]'s shield overloads!")
|
||||
qdel(src)
|
||||
return
|
||||
if(holder && (old_charges < 1 && charges >= 1) || (!del_on_overload && old_charges >= 1 && charges < 1))
|
||||
if(holder && ((old_charges < 1 && charges >= 1) || (!del_on_overload && old_charges >= 1 && charges < 1)))
|
||||
update_shield_overlay(charges < 1)
|
||||
|
||||
/datum/component/shielded/proc/update_shield_overlay(broken)
|
||||
if(!holder)
|
||||
return
|
||||
var/to_remove = broken ? shield_state : broken_state
|
||||
var/to_add = broken ? broken_state : shield_state
|
||||
if(to_remove)
|
||||
holder.cut_overlay(mutable_appearance('icons/effects/effects.dmi', to_remove), TRUE)
|
||||
if(cached_vis_overlay)
|
||||
SSvis_overlays.remove_vis_overlay(holder, cached_vis_overlay)
|
||||
cached_vis_overlay = null
|
||||
if(to_add)
|
||||
var/mutable_appearance/M = mutable_appearance('icons/effects/effects.dmi', to_add)
|
||||
M.layer = (holder.layer > MOB_LAYER ? holder.layer : MOB_LAYER) + 0.01
|
||||
holder.add_overlay(M, TRUE)
|
||||
var/layer = (holder.layer > MOB_LAYER ? holder.layer : MOB_LAYER) + 0.01
|
||||
SSvis_overlays.add_vis_overlay(holder, 'icons/effects/effects.dmi', to_add, layer, GAME_PLANE, holder.dir)
|
||||
|
||||
/datum/component/shielded/proc/on_equip(obj/item/source, mob/living/equipper, slot)
|
||||
if(!(accepted_slots & slotdefine2slotbit(slot)))
|
||||
@@ -117,17 +116,16 @@
|
||||
RegisterSignal(equipper, COMSIG_LIVING_GET_BLOCKING_ITEMS, .proc/include_shield)
|
||||
var/to_add = charges >= 1 ? shield_state : broken_state
|
||||
if(to_add)
|
||||
var/mutable_appearance/M = mutable_appearance('icons/effects/effects.dmi', to_add)
|
||||
M.layer = (holder.layer > MOB_LAYER ? holder.layer : MOB_LAYER) + 0.01
|
||||
equipper.add_overlay(M, TRUE)
|
||||
var/layer = (holder.layer > MOB_LAYER ? holder.layer : MOB_LAYER) + 0.01
|
||||
cached_vis_overlay = SSvis_overlays.add_vis_overlay(holder, 'icons/effects/effects.dmi', to_add, layer, GAME_PLANE, holder.dir)
|
||||
|
||||
/datum/component/shielded/proc/on_drop(obj/item/source, mob/dropper)
|
||||
if(holder == dropper)
|
||||
UnregisterSignal(holder, COMSIG_LIVING_GET_BLOCKING_ITEMS)
|
||||
UnregisterSignal(parent, list(COMSIG_ITEM_RUN_BLOCK, COMSIG_ITEM_CHECK_BLOCK))
|
||||
var/to_remove = charges >= 1 ? shield_state : broken_state
|
||||
if(to_remove)
|
||||
holder.cut_overlay(mutable_appearance('icons/effects/effects.dmi', to_remove), TRUE)
|
||||
if(cached_vis_overlay)
|
||||
SSvis_overlays.remove_vis_overlay(holder, cached_vis_overlay)
|
||||
cached_vis_overlay = null
|
||||
holder = null
|
||||
|
||||
/datum/component/shielded/proc/include_shield(mob/source, list/items)
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
VV_DROPDOWN_OPTION(VV_HK_EXPOSE, "Show VV To Player")
|
||||
VV_DROPDOWN_OPTION(VV_HK_ADDCOMPONENT, "Add Component/Element")
|
||||
VV_DROPDOWN_OPTION(VV_HK_MODIFY_TRAITS, "Modify Traits")
|
||||
#ifdef REFERENCE_TRACKING
|
||||
VV_DROPDOWN_OPTION(VV_HK_VIEW_REFERENCES, "View References")
|
||||
#endif
|
||||
|
||||
//This proc is only called if everything topic-wise is verified. The only verifications that should happen here is things like permission checks!
|
||||
//href_list is a reference, modifying it in these procs WILL change the rest of the proc in topic.dm of admin/view_variables!
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
///We handle the unity part of plumbing. We track who is connected to who.
|
||||
/datum/ductnet
|
||||
var/list/suppliers = list()
|
||||
var/list/demanders = list()
|
||||
var/list/obj/machinery/duct/ducts = list()
|
||||
|
||||
var/capacity
|
||||
///Add a duct to our network
|
||||
/datum/ductnet/proc/add_duct(obj/machinery/duct/D)
|
||||
if(!D || (D in ducts))
|
||||
return
|
||||
ducts += D
|
||||
D.duct = src
|
||||
///Remove a duct from our network and commit suicide, because this is probably easier than to check who that duct was connected to and what part of us was lost
|
||||
/datum/ductnet/proc/remove_duct(obj/machinery/duct/ducting)
|
||||
destroy_network(FALSE)
|
||||
for(var/obj/machinery/duct/D in ducting.neighbours)
|
||||
addtimer(CALLBACK(D, /obj/machinery/duct/proc/reconnect), 0) //all needs to happen after the original duct that was destroyed finishes destroying itself
|
||||
addtimer(CALLBACK(D, /obj/machinery/duct/proc/generate_connects), 0)
|
||||
qdel(src)
|
||||
///add a plumbing object to either demanders or suppliers
|
||||
/datum/ductnet/proc/add_plumber(datum/component/plumbing/P, dir)
|
||||
if(!P.can_add(src, dir))
|
||||
return FALSE
|
||||
P.ducts[num2text(dir)] = src
|
||||
if(dir & P.supply_connects)
|
||||
suppliers += P
|
||||
else if(dir & P.demand_connects)
|
||||
demanders += P
|
||||
return TRUE
|
||||
///remove a plumber. we dont delete ourselves because ductnets dont persist through plumbing objects
|
||||
/datum/ductnet/proc/remove_plumber(datum/component/plumbing/P)
|
||||
suppliers.Remove(P) //we're probably only in one of these, but Remove() is inherently sane so this is fine
|
||||
demanders.Remove(P)
|
||||
|
||||
for(var/dir in P.ducts)
|
||||
if(P.ducts[dir] == src)
|
||||
P.ducts -= dir
|
||||
if(!ducts.len) //there were no ducts, so it was a direct connection. we destroy ourselves since a ductnet with only one plumber and no ducts is worthless
|
||||
destroy_network()
|
||||
///we combine ductnets. this occurs when someone connects to seperate sets of fluid ducts
|
||||
/datum/ductnet/proc/assimilate(datum/ductnet/D)
|
||||
ducts.Add(D.ducts)
|
||||
suppliers.Add(D.suppliers)
|
||||
demanders.Add(D.demanders)
|
||||
for(var/A in D.suppliers + D.demanders)
|
||||
var/datum/component/plumbing/P = A
|
||||
for(var/s in P.ducts)
|
||||
if(P.ducts[s] != D)
|
||||
continue
|
||||
P.ducts[s] = src //all your ducts are belong to us
|
||||
for(var/A in D.ducts)
|
||||
var/obj/machinery/duct/M = A
|
||||
M.duct = src //forget your old master
|
||||
|
||||
destroy_network()
|
||||
///destroy the network and tell all our ducts and plumbers we are gone
|
||||
/datum/ductnet/proc/destroy_network(delete=TRUE)
|
||||
for(var/A in suppliers + demanders)
|
||||
remove_plumber(A)
|
||||
for(var/A in ducts)
|
||||
var/obj/machinery/duct/D = A
|
||||
D.duct = null
|
||||
if(delete) //I don't want code to run with qdeleted objects because that can never be good, so keep this in-case the ductnet has some business left to attend to before commiting suicide
|
||||
qdel(src)
|
||||
@@ -33,39 +33,34 @@
|
||||
if(description)
|
||||
RegisterSignal(A, COMSIG_PARENT_EXAMINE, .proc/examine)
|
||||
|
||||
apply(A, TRUE)
|
||||
|
||||
num_decals_per_atom[A]++
|
||||
apply(A)
|
||||
|
||||
/datum/element/decal/Detach(datum/target)
|
||||
var/atom/A = target
|
||||
remove(A, A.dir)
|
||||
UnregisterSignal(A, list(COMSIG_ATOM_DIR_CHANGE, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_PARENT_EXAMINE))
|
||||
LAZYREMOVE(num_decals_per_atom, A)
|
||||
num_decals_per_atom[A]--
|
||||
apply(A, TRUE)
|
||||
if(!num_decals_per_atom[A])
|
||||
UnregisterSignal(A, list(COMSIG_ATOM_DIR_CHANGE, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_PARENT_EXAMINE, COMSIG_ATOM_UPDATE_OVERLAYS))
|
||||
LAZYREMOVE(num_decals_per_atom, A)
|
||||
return ..()
|
||||
|
||||
/datum/element/decal/proc/remove(atom/target, old_dir)
|
||||
pic.dir = first_dir == NORTH ? target.dir : turn(first_dir, dir2angle(old_dir))
|
||||
for(var/i in 1 to num_decals_per_atom[target])
|
||||
target.cut_overlay(pic, TRUE)
|
||||
/datum/element/decal/proc/apply(atom/target, removing = FALSE)
|
||||
if(num_decals_per_atom[target] == 1 && !removing)
|
||||
RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_overlay, TRUE)
|
||||
target.update_icon()
|
||||
if(isitem(target))
|
||||
addtimer(CALLBACK(target, /obj/item/.proc/update_slot_icon), 0, TIMER_UNIQUE)
|
||||
|
||||
/datum/element/decal/proc/apply(atom/target, init = FALSE)
|
||||
pic.dir = first_dir == NORTH ? target.dir : turn(first_dir, dir2angle(target.dir))
|
||||
if(init)
|
||||
target.add_overlay(pic, TRUE)
|
||||
else
|
||||
for(var/i in 1 to num_decals_per_atom[target])
|
||||
target.add_overlay(pic, TRUE)
|
||||
if(isitem(target))
|
||||
addtimer(CALLBACK(target, /obj/item/.proc/update_slot_icon), 0, TIMER_UNIQUE)
|
||||
/datum/element/decal/proc/apply_overlay(atom/source, list/overlay_list)
|
||||
pic.dir = first_dir == NORTH ? source.dir : turn(first_dir, dir2angle(source.dir))
|
||||
for(var/i in 1 to num_decals_per_atom[source])
|
||||
overlay_list += pic
|
||||
|
||||
/datum/element/decal/proc/rotate_react(datum/source, old_dir, new_dir)
|
||||
/datum/element/decal/proc/rotate_react(atom/source, old_dir, new_dir)
|
||||
if(old_dir == new_dir)
|
||||
return
|
||||
remove(source, old_dir)
|
||||
apply(source)
|
||||
source.update_icon()
|
||||
|
||||
/datum/element/decal/proc/clean_react(datum/source, strength)
|
||||
if(strength >= cleanable)
|
||||
|
||||
@@ -90,6 +90,8 @@
|
||||
to_chat(user, "<span class='boldnotice'>You catch some drifting memories of their past conversations...</span>")
|
||||
for(var/spoken_memory in recent_speech)
|
||||
to_chat(user, "<span class='notice'>[recent_speech[spoken_memory]]</span>")
|
||||
if(usr in GLOB.rockpaperscissors_players)
|
||||
to_chat(user, "<span class='notice'>They're planning on playing [GLOB.rockpaperscissors_players[usr][1]]</span>")
|
||||
if(iscarbon(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
to_chat(user, "<span class='boldnotice'>You find that their intent is to [H.a_intent]...</span>")
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
|
||||
/datum/wires/airlock/interactable(mob/user)
|
||||
var/obj/machinery/door/airlock/A = holder
|
||||
if(!A.hasSiliconAccessInArea(user) && A.isElectrified() && A.shock(user, 100))
|
||||
return FALSE
|
||||
if(A.panel_open)
|
||||
return TRUE
|
||||
|
||||
@@ -73,6 +71,8 @@
|
||||
/datum/wires/airlock/on_pulse(wire)
|
||||
set waitfor = FALSE
|
||||
var/obj/machinery/door/airlock/A = holder
|
||||
if(!A.hasSiliconAccessInArea(usr) && A.isElectrified() && A.shock(usr, 100))
|
||||
return FALSE
|
||||
switch(wire)
|
||||
if(WIRE_POWER1, WIRE_POWER2) // Pulse to loose power.
|
||||
A.loseMainPower()
|
||||
@@ -127,6 +127,8 @@
|
||||
|
||||
/datum/wires/airlock/on_cut(wire, mend)
|
||||
var/obj/machinery/door/airlock/A = holder
|
||||
if(!A.hasSiliconAccessInArea(usr) && A.isElectrified() && A.shock(usr, 100))
|
||||
return FALSE
|
||||
switch(wire)
|
||||
if(WIRE_POWER1, WIRE_POWER2) // Cut to loose power, repair all to gain power.
|
||||
if(mend && !is_cut(WIRE_POWER1) && !is_cut(WIRE_POWER2))
|
||||
@@ -174,4 +176,4 @@
|
||||
A.update_icon()
|
||||
if(WIRE_ZAP1, WIRE_ZAP2) // Ouch.
|
||||
if(isliving(usr))
|
||||
A.shock(usr, 50)
|
||||
A.shock(usr, 50)
|
||||
|
||||
+1
-3
@@ -26,7 +26,6 @@
|
||||
var/list/atom_colours //used to store the different colors on an atom
|
||||
//its inherent color, the colored paint applied on it, special color effect etc...
|
||||
|
||||
var/list/priority_overlays //overlays that should remain on top and not normally removed when using cut_overlay functions, like c4.
|
||||
var/list/remove_overlays // a very temporary list of overlays to remove
|
||||
var/list/add_overlays // a very temporary list of overlays to add
|
||||
|
||||
@@ -145,7 +144,6 @@
|
||||
qdel(reagents)
|
||||
|
||||
LAZYCLEARLIST(overlays)
|
||||
LAZYCLEARLIST(priority_overlays)
|
||||
|
||||
for(var/i in targeted_by)
|
||||
var/mob/M = i
|
||||
@@ -1128,4 +1126,4 @@
|
||||
* Override this if you want custom behaviour in whatever gets hit by the rust
|
||||
*/
|
||||
/atom/proc/rust_heretic_act()
|
||||
return
|
||||
return
|
||||
|
||||
@@ -646,3 +646,10 @@
|
||||
animate(I, alpha = 175, pixel_x = to_x, pixel_y = to_y, time = 3, transform = M, easing = CUBIC_EASING)
|
||||
sleep(1)
|
||||
animate(I, alpha = 0, transform = matrix(), time = 1)
|
||||
|
||||
/atom/movable/proc/set_anchored(anchorvalue) //literally only for plumbing ran
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(anchored == anchorvalue)
|
||||
return
|
||||
. = anchored
|
||||
anchored = anchorvalue
|
||||
|
||||
@@ -50,10 +50,6 @@ Property weights are:
|
||||
for(var/r in SSevents.running)
|
||||
var/datum/round_event/R = r
|
||||
threat += R.threat()
|
||||
for(var/mob/living/simple_animal/hostile/H in GLOB.mob_living_list)
|
||||
var/turf/T = get_turf(H)
|
||||
if(H.stat != DEAD && is_station_level(T.z) && !("Station" in H.faction))
|
||||
threat += H.threat()
|
||||
for(var/obj/item/phylactery/P in GLOB.poi_list)
|
||||
threat += 25 // can't be giving them too much of a break
|
||||
for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS])
|
||||
@@ -91,6 +87,8 @@ Property weights are:
|
||||
mean += 2.5
|
||||
if(CHAOS_MAX)
|
||||
mean += 5
|
||||
else
|
||||
voters += 0.5
|
||||
if(voters)
|
||||
GLOB.dynamic_curve_centre += (mean/voters)
|
||||
if(flags & USE_PREV_ROUND_WEIGHTS)
|
||||
@@ -128,7 +126,8 @@ Property weights are:
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights) // just treat it as 0 if it's not in there
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
drafted_rules[rule] = (rule.get_weight() * property_weight)*rule.weight_mult
|
||||
if(property_weight > 0)
|
||||
drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/proc/midround_draft()
|
||||
@@ -140,25 +139,26 @@ Property weights are:
|
||||
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
|
||||
continue
|
||||
rule.trim_candidates()
|
||||
var/threat_weight = 1
|
||||
if(!(rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway
|
||||
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
|
||||
/* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to
|
||||
pick this particular ruleset.
|
||||
Let's use a toy example: there's 60 threat level and 10 threat spent.
|
||||
We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets.
|
||||
Ruleset 1 has 30 cost, ruleset 2 has 5 cost.
|
||||
When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1
|
||||
is 2.26 times as likely to be picked, all other things considered.
|
||||
Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight.
|
||||
*/
|
||||
threat_weight = abs(1-abs(1-LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
|
||||
if (rule.ready())
|
||||
var/property_weight = 0
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights)
|
||||
if(property in rule.property_weights) // just treat it as 0 if it's not in there
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
drafted_rules[rule] = round(((rule.get_weight() * property_weight)*rule.weight_mult*threat_weight)*1000,1)
|
||||
if(property_weight > 0)
|
||||
var/threat_weight = 1
|
||||
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway
|
||||
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
|
||||
/* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to
|
||||
pick this particular ruleset.
|
||||
Let's use a toy example: there's 60 threat level and 10 threat spent.
|
||||
We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets.
|
||||
Ruleset 1 has 30 cost, ruleset 2 has 5 cost.
|
||||
When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1
|
||||
is 2.26 times as likely to be picked, all other things considered.
|
||||
Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight.
|
||||
*/
|
||||
threat_weight = abs(1-abs(1-LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
|
||||
drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult * threat_weight
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/proc/latejoin_draft(mob/living/carbon/human/newPlayer)
|
||||
@@ -175,28 +175,29 @@ Property weights are:
|
||||
|
||||
rule.candidates = list(newPlayer)
|
||||
rule.trim_candidates()
|
||||
var/threat_weight = 1
|
||||
if(!(rule.flags & MINOR_RULESET))
|
||||
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
|
||||
threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
|
||||
if (rule.ready())
|
||||
var/property_weight = 0
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights)
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
drafted_rules[rule] = round(((rule.get_weight() * property_weight)*rule.weight_mult*threat_weight)*1000,1)
|
||||
if(property_weight > 0)
|
||||
var/threat_weight = 1
|
||||
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))
|
||||
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
|
||||
threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
|
||||
drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult * threat_weight
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/proc/event_draft()
|
||||
var/list/drafted_rules = list()
|
||||
for(var/datum/dynamic_ruleset/event/rule in mode.events)
|
||||
if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && (mode.threat_level - mode.threat) >= rule.cost)
|
||||
if(rule.ready())
|
||||
var/property_weight = 0
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights)
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
drafted_rules[rule] = (rule.get_weight() + property_weight)*rule.weight_mult
|
||||
if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && (mode.threat_level + 20 - mode.threat) >= rule.cost && rule.ready())
|
||||
var/property_weight = 0
|
||||
for(var/property in property_weights)
|
||||
if(property in rule.property_weights)
|
||||
property_weight += rule.property_weights[property] * property_weights[property]
|
||||
if(property_weight > 0)
|
||||
drafted_rules[rule] = rule.get_weight() + property_weight * rule.weight_mult
|
||||
return drafted_rules
|
||||
|
||||
|
||||
@@ -313,9 +314,8 @@ Property weights are:
|
||||
/datum/dynamic_storyteller/random/event_draft()
|
||||
var/list/drafted_rules = list()
|
||||
for(var/datum/dynamic_ruleset/event/rule in mode.events)
|
||||
if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level))
|
||||
if(rule.ready())
|
||||
drafted_rules[rule] = 1
|
||||
if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && rule.ready())
|
||||
drafted_rules[rule] = 1
|
||||
return drafted_rules
|
||||
|
||||
/datum/dynamic_storyteller/story
|
||||
@@ -330,7 +330,7 @@ Property weights are:
|
||||
|
||||
/datum/dynamic_storyteller/story/calculate_threat()
|
||||
var/current_time = (world.time / SSautotransfer.targettime)*180
|
||||
mode.threat_level = round(mode.initial_threat_level*(sin(current_time)+0.25),0.1)
|
||||
mode.threat_level = round((mode.initial_threat_level*(sin(current_time)/2)+0.75),0.1)
|
||||
return ..()
|
||||
|
||||
/datum/dynamic_storyteller/classic
|
||||
|
||||
@@ -117,6 +117,7 @@ Class Procs:
|
||||
var/new_occupant_dir = SOUTH //The direction the occupant will be set to look at when entering the machine.
|
||||
var/speed_process = FALSE // Process as fast as possible?
|
||||
var/obj/item/circuitboard/circuit // Circuit to be created and inserted when the machinery is created
|
||||
var/wire_compatible = FALSE
|
||||
// For storing and overriding ui id and dimensions
|
||||
var/tgui_id // ID of TGUI interface
|
||||
var/ui_style // ID of custom TGUI style (optional)
|
||||
@@ -433,6 +434,7 @@ Class Procs:
|
||||
to_chat(user, "<span class='notice'>You [anchored ? "un" : ""]secure [src].</span>")
|
||||
setAnchored(!anchored)
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
SEND_SIGNAL(src, COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH, anchored)
|
||||
return SUCCESSFUL_UNFASTEN
|
||||
return FAILED_UNFASTEN
|
||||
return CANT_UNFASTEN
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
|
||||
/obj/machinery/iv_drip
|
||||
name = "\improper IV drip"
|
||||
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate."
|
||||
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. Alt-Click to change the transfer rate."
|
||||
icon = 'icons/obj/iv_drip.dmi'
|
||||
icon_state = "iv_drip"
|
||||
anchored = FALSE
|
||||
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
|
||||
var/mob/living/carbon/attached
|
||||
var/mode = IV_INJECTING
|
||||
var/dripfeed = FALSE
|
||||
var/obj/item/reagent_containers/beaker
|
||||
var/static/list/drip_containers = typecacheof(list(/obj/item/reagent_containers/blood,
|
||||
/obj/item/reagent_containers/food,
|
||||
@@ -132,9 +133,11 @@
|
||||
if(mode)
|
||||
if(beaker.reagents.total_volume)
|
||||
var/transfer_amount = 5
|
||||
if (dripfeed)
|
||||
transfer_amount = 1
|
||||
if(istype(beaker, /obj/item/reagent_containers/blood))
|
||||
// speed up transfer on blood packs
|
||||
transfer_amount = 10
|
||||
transfer_amount *= 2
|
||||
var/fraction = min(transfer_amount/beaker.reagents.total_volume, 1) //the fraction that is transfered of the total volume
|
||||
beaker.reagents.reaction(attached, INJECT, fraction, FALSE) //make reagents reacts, but don't spam messages
|
||||
beaker.reagents.trans_to(attached, transfer_amount)
|
||||
@@ -169,6 +172,16 @@
|
||||
else
|
||||
toggle_mode()
|
||||
|
||||
/obj/machinery/iv_drip/AltClick(mob/living/user)
|
||||
if(!user.canUseTopic(src, be_close=TRUE))
|
||||
return
|
||||
if(dripfeed)
|
||||
dripfeed = FALSE
|
||||
to_chat(usr, "<span class='notice'>You loosen the valve to speed up the [src].</span>")
|
||||
else
|
||||
dripfeed = TRUE
|
||||
to_chat(usr, "<span class='notice'>You tighten the valve to slowly drip-feed the contents of [src].</span>")
|
||||
|
||||
/obj/machinery/iv_drip/attack_robot(mob/user)
|
||||
if(Adjacent(user))
|
||||
attack_hand(user)
|
||||
@@ -227,7 +240,7 @@
|
||||
|
||||
/obj/machinery/iv_drip/telescopic
|
||||
name = "telescopic IV drip"
|
||||
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. This one is telescopic, and can be picked up and put down."
|
||||
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. This one is telescopic, and can be picked up and put down.Alt-Click with a beaker attached to change the transfer rate."
|
||||
icon_state = "iv_drip"
|
||||
|
||||
/obj/machinery/iv_drip/telescopic/update_icon_state()
|
||||
|
||||
@@ -63,3 +63,23 @@
|
||||
|
||||
/datum/effect_system/lightning_spread
|
||||
effect_type = /obj/effect/particle_effect/sparks/electricity
|
||||
|
||||
//fake sparks, not subtyped because we don't want light/heat, nor checks inside an often used proc for a rare subcase for saving like 10 lines of code
|
||||
/obj/effect/particle_effect/fake_sparks
|
||||
name = "lightning"
|
||||
icon_state = "electricity"
|
||||
|
||||
/obj/effect/particle_effect/fake_sparks/Initialize()
|
||||
. = ..()
|
||||
flick(icon_state, src) // replay the animation
|
||||
playsound(src, "sparks", 100, TRUE)
|
||||
QDEL_IN(src, 20)
|
||||
|
||||
/datum/effect_system/fake_spark_spread
|
||||
effect_type = /obj/effect/particle_effect/fake_sparks
|
||||
|
||||
/proc/do_fake_sparks(n, c, source)
|
||||
var/datum/effect_system/fake_spark_spread/sparks = new
|
||||
sparks.set_up(n, c, source)
|
||||
sparks.autocleanup = TRUE
|
||||
sparks.start()
|
||||
|
||||
@@ -135,6 +135,14 @@ RLD
|
||||
flick("[icon_state]_empty", src) //somewhat hacky thing to make RCDs with ammo counters actually have a blinking yellow light
|
||||
return .
|
||||
|
||||
|
||||
/obj/item/construction/proc/check_menu(mob/living/user)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(user.incapacitated() || !user.Adjacent(src))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/construction/proc/range_check(atom/A, mob/user)
|
||||
if(!(A in range(custom_range, get_turf(user))))
|
||||
to_chat(user, "<span class='warning'>The \'Out of Range\' light on [src] blinks red.</span>")
|
||||
@@ -276,13 +284,6 @@ RLD
|
||||
//Not scaling these down to button size because they look horrible then, instead just bumping up radius.
|
||||
return MA
|
||||
|
||||
/obj/item/construction/rcd/proc/check_menu(mob/living/user)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(user.incapacitated() || !user.Adjacent(src))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/construction/rcd/proc/change_computer_dir(mob/user)
|
||||
if(!user)
|
||||
return
|
||||
@@ -856,6 +857,82 @@ RLD
|
||||
desc = "It contains the design for firelock, air alarm, fire alarm, apc circuits and crap power cells."
|
||||
upgrade = RCD_UPGRADE_SIMPLE_CIRCUITS
|
||||
|
||||
/obj/item/construction/plumbing
|
||||
name = "Plumbing Constructor"
|
||||
desc = "An expertly modified RCD outfitted to construct plumbing machinery. Reload with compressed matter cartridges."
|
||||
icon = 'icons/obj/tools.dmi'
|
||||
icon_state = "arcd"
|
||||
item_state = "oldrcd"
|
||||
has_ammobar = FALSE
|
||||
matter = 200
|
||||
max_matter = 200
|
||||
|
||||
///type of the plumbing machine
|
||||
var/blueprint = null
|
||||
///index, used in the attack self to get the type. stored here since it doesnt change
|
||||
var/list/choices = list()
|
||||
///index, used in the attack self to get the type. stored here since it doesnt change
|
||||
var/list/name_to_type = list()
|
||||
///
|
||||
var/list/machinery_data = list("cost" = list(), "delay" = list())
|
||||
|
||||
/obj/item/construction/plumbing/attack_self(mob/user)
|
||||
..()
|
||||
if(!choices.len)
|
||||
for(var/A in subtypesof(/obj/machinery/plumbing))
|
||||
var/obj/machinery/plumbing/M = A
|
||||
if(initial(M.rcd_constructable))
|
||||
choices += list(initial(M.name) = image(icon = initial(M.icon), icon_state = initial(M.icon_state)))
|
||||
name_to_type[initial(M.name)] = M
|
||||
machinery_data["cost"][A] = initial(M.rcd_cost)
|
||||
machinery_data["delay"][A] = initial(M.rcd_delay)
|
||||
|
||||
var/choice = show_radial_menu(user, src, choices, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE)
|
||||
if(!check_menu(user))
|
||||
return
|
||||
|
||||
blueprint = name_to_type[choice]
|
||||
playsound(src, 'sound/effects/pop.ogg', 50, FALSE)
|
||||
to_chat(user, "<span class='notice'>You change [name]s blueprint to '[choice]'.</span>")
|
||||
|
||||
///pretty much rcd_create, but named differently to make myself feel less bad for copypasting from a sibling-type
|
||||
/obj/item/construction/plumbing/proc/create_machine(atom/A, mob/user)
|
||||
if(!machinery_data || !isopenturf(A))
|
||||
return FALSE
|
||||
|
||||
if(checkResource(machinery_data["cost"][blueprint], user) && blueprint)
|
||||
if(do_after(user, machinery_data["delay"][blueprint], target = A))
|
||||
if(checkResource(machinery_data["cost"][blueprint], user) && canPlace(A))
|
||||
useResource(machinery_data["cost"][blueprint], user)
|
||||
activate()
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
|
||||
new blueprint (A, FALSE, FALSE)
|
||||
return TRUE
|
||||
|
||||
/obj/item/construction/plumbing/proc/canPlace(turf/T)
|
||||
if(!isopenturf(T))
|
||||
return FALSE
|
||||
. = TRUE
|
||||
for(var/obj/O in T.contents)
|
||||
if(O.density) //let's not built ontop of dense stuff, like big machines and other obstacles, it kills my immershion
|
||||
return FALSE
|
||||
|
||||
/obj/item/construction/plumbing/afterattack(atom/A, mob/user)
|
||||
. = ..()
|
||||
if(!range_check(A, user))
|
||||
return
|
||||
if(istype(A, /obj/machinery/plumbing))
|
||||
var/obj/machinery/plumbing/P = A
|
||||
if(P.anchored)
|
||||
to_chat(user, "<span class='warning'>The [P.name] needs to be unanchored!</span>")
|
||||
return
|
||||
if(do_after(user, 20, target = P))
|
||||
P.deconstruct() //Let's not substract matter
|
||||
playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE) //this is just such a great sound effect
|
||||
else
|
||||
create_machine(A, user)
|
||||
|
||||
|
||||
#undef GLOW_MODE
|
||||
#undef LIGHT_MODE
|
||||
#undef REMOVE_MODE
|
||||
|
||||
@@ -6,6 +6,7 @@ RPD
|
||||
#define ATMOS_CATEGORY 0
|
||||
#define DISPOSALS_CATEGORY 1
|
||||
#define TRANSIT_CATEGORY 2
|
||||
#define PLUMBING_CATEGORY 3
|
||||
|
||||
#define BUILD_MODE (1<<0)
|
||||
#define WRENCH_MODE (1<<1)
|
||||
@@ -75,6 +76,13 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
|
||||
)
|
||||
))
|
||||
|
||||
GLOBAL_LIST_INIT(fluid_duct_recipes, list(
|
||||
"Fluid Ducts" = list(
|
||||
new /datum/pipe_info/plumbing("Duct", /obj/machinery/duct, PIPE_ONEDIR),
|
||||
new /datum/pipe_info/plumbing/multilayer("Duct Layer-Manifold",/obj/machinery/duct/multilayered, PIPE_STRAIGHT)
|
||||
)
|
||||
))
|
||||
|
||||
/datum/pipe_info
|
||||
var/name
|
||||
var/icon_state
|
||||
@@ -175,6 +183,15 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
|
||||
if(dt == PIPE_UNARY_FLIPPABLE)
|
||||
icon_state = "[icon_state]_preview"
|
||||
|
||||
/datum/pipe_info/plumbing/New(label, obj/path, dt=PIPE_UNARY)
|
||||
name = label
|
||||
id = path
|
||||
icon_state = initial(path.icon_state)
|
||||
dirtype = dt
|
||||
|
||||
/datum/pipe_info/plumbing/multilayer //exists as identifier so we can see the difference between multi_layer and just ducts properly later on
|
||||
|
||||
|
||||
/obj/item/pipe_dispenser
|
||||
name = "Rapid Piping Device (RPD)"
|
||||
desc = "A device used to rapidly pipe things."
|
||||
@@ -200,15 +217,19 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
|
||||
var/atmos_build_speed = 5 //deciseconds (500ms)
|
||||
var/disposal_build_speed = 5
|
||||
var/transit_build_speed = 5
|
||||
var/plumbing_build_speed = 5
|
||||
var/destroy_speed = 5
|
||||
var/paint_speed = 5
|
||||
var/category = ATMOS_CATEGORY
|
||||
var/piping_layer = PIPING_LAYER_DEFAULT
|
||||
var/ducting_layer = DUCT_LAYER_DEFAULT
|
||||
var/datum/pipe_info/recipe
|
||||
var/static/datum/pipe_info/first_atmos
|
||||
var/static/datum/pipe_info/first_disposal
|
||||
var/static/datum/pipe_info/first_transit
|
||||
var/mode = BUILD_MODE | DESTROY_MODE | WRENCH_MODE
|
||||
var/static/datum/pipe_info/first_plumbing
|
||||
var/locked = FALSE //wheter we can change categories. Useful for the plumber
|
||||
|
||||
/obj/item/pipe_dispenser/New()
|
||||
. = ..()
|
||||
@@ -253,12 +274,15 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
|
||||
var/list/data = list(
|
||||
"category" = category,
|
||||
"piping_layer" = piping_layer,
|
||||
// "ducting_layer" = ducting_layer, //uhh is this for chem thing?
|
||||
|
||||
"ducting_layer" = ducting_layer,
|
||||
|
||||
"preview_rows" = recipe.get_preview(p_dir),
|
||||
"categories" = list(),
|
||||
"selected_color" = paint_color,
|
||||
"paint_colors" = GLOB.pipe_paint_colors,
|
||||
"mode" = mode
|
||||
"mode" = mode,
|
||||
"locked" = locked
|
||||
)
|
||||
|
||||
var/list/recipes
|
||||
@@ -269,6 +293,8 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
|
||||
recipes = GLOB.disposal_pipe_recipes
|
||||
if(TRANSIT_CATEGORY)
|
||||
recipes = GLOB.transit_tube_recipes
|
||||
if(PLUMBING_CATEGORY)
|
||||
recipes = GLOB.fluid_duct_recipes
|
||||
for(var/c in recipes)
|
||||
var/list/cat = recipes[c]
|
||||
var/list/r = list()
|
||||
@@ -297,6 +323,8 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
|
||||
recipe = first_atmos
|
||||
if(TRANSIT_CATEGORY)
|
||||
recipe = first_transit
|
||||
if(PLUMBING_CATEGORY)
|
||||
recipe = first_plumbing
|
||||
p_dir = NORTH
|
||||
playeffect = FALSE
|
||||
if("piping_layer")
|
||||
@@ -468,16 +496,56 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
|
||||
if(mode & WRENCH_MODE)
|
||||
tube.wrench_act(user, src)
|
||||
return
|
||||
|
||||
if(PLUMBING_CATEGORY) //Plumbing.
|
||||
if(!can_make_pipe)
|
||||
return ..()
|
||||
A = get_turf(A)
|
||||
if(isclosedturf(A))
|
||||
to_chat(user, "<span class='warning'>[src]'s error light flickers; there's something in the way!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You start building a fluid duct...</span>")
|
||||
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
|
||||
if(do_after(user, plumbing_build_speed, target = A))
|
||||
var/obj/machinery/duct/D
|
||||
if(recipe.type == /datum/pipe_info/plumbing/multilayer)
|
||||
var/temp_connects = NORTH + SOUTH
|
||||
if(queued_p_dir == EAST)
|
||||
temp_connects = EAST + WEST
|
||||
D = new queued_p_type (A, TRUE, GLOB.pipe_paint_colors[paint_color], ducting_layer, temp_connects)
|
||||
else
|
||||
D = new queued_p_type (A, TRUE, GLOB.pipe_paint_colors[paint_color], ducting_layer)
|
||||
D.add_fingerprint(usr)
|
||||
if(mode & WRENCH_MODE)
|
||||
D.wrench_act(user, src)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/pipe_dispenser/proc/activate()
|
||||
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, 1)
|
||||
/* unneeded, you can craft ducts from plastic
|
||||
/obj/item/pipe_dispenser/plumbing
|
||||
name = "Plumberinator"
|
||||
desc = "A crude device to rapidly plumb things."
|
||||
icon_state = "plumberer"
|
||||
category = PLUMBING_CATEGORY
|
||||
locked = TRUE
|
||||
|
||||
/obj/item/pipe_dispenser/plumbing/Initialize()
|
||||
. = ..()
|
||||
spark_system = new
|
||||
spark_system.set_up(5, 0, src)
|
||||
spark_system.attach(src)
|
||||
if(!first_plumbing)
|
||||
first_plumbing = GLOB.fluid_duct_recipes[GLOB.fluid_duct_recipes[1]][1]
|
||||
|
||||
recipe = first_plumbing
|
||||
|
||||
*/
|
||||
|
||||
#undef ATMOS_CATEGORY
|
||||
#undef DISPOSALS_CATEGORY
|
||||
#undef TRANSIT_CATEGORY
|
||||
#undef PLUMBING_CATEGORY
|
||||
|
||||
#undef BUILD_MODE
|
||||
#undef DESTROY_MODE
|
||||
|
||||
@@ -48,6 +48,13 @@
|
||||
/obj/item/stack/cable_coil = 5,
|
||||
/obj/item/stack/sheet/glass = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/medipen_refiller
|
||||
name = "Medipen Refiller (Machine Board)"
|
||||
icon_state = "medical"
|
||||
build_path = /obj/machinery/medipen_refiller
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/clonepod
|
||||
name = "Clone Pod (Machine Board)"
|
||||
build_path = /obj/machinery/clonepod
|
||||
@@ -512,6 +519,10 @@
|
||||
/obj/item/stack/sheet/glass = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/hydroponics/automagic
|
||||
name = "Automatic Hydroponics Tray (Machine Board)"
|
||||
build_path = /obj/machinery/hydroponics/constructable/automagic
|
||||
|
||||
/obj/item/circuitboard/machine/seed_extractor
|
||||
name = "Seed Extractor (Machine Board)"
|
||||
build_path = /obj/machinery/seed_extractor
|
||||
|
||||
@@ -60,7 +60,8 @@
|
||||
if(target)
|
||||
if(!QDELETED(target))
|
||||
location = get_turf(target)
|
||||
target.cut_overlay(plastic_overlay, TRUE)
|
||||
target.cut_overlay(plastic_overlay)
|
||||
UnregisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/add_plastic_overlay)
|
||||
if(!ismob(target) || full_damage_on_mobs)
|
||||
target.ex_act(EXPLODE_HEAVY, target)
|
||||
else
|
||||
@@ -126,13 +127,17 @@
|
||||
I.embedding["embed_chance"] = 0
|
||||
I.updateEmbedding()
|
||||
|
||||
target.add_overlay(plastic_overlay, TRUE)
|
||||
RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/add_plastic_overlay)
|
||||
target.update_icon()
|
||||
if(!nadeassembly)
|
||||
to_chat(user, "<span class='notice'>You plant the bomb. Timer counting down from [det_time].</span>")
|
||||
addtimer(CALLBACK(src, .proc/prime), det_time*10)
|
||||
else
|
||||
qdel(src) //How?
|
||||
|
||||
/obj/item/grenade/plastic/proc/add_plastic_overlay(atom/source, list/overlay_list)
|
||||
overlay_list += plastic_overlay
|
||||
|
||||
/obj/item/grenade/plastic/proc/shout_syndicate_crap(mob/M)
|
||||
if(!M)
|
||||
return
|
||||
|
||||
@@ -47,8 +47,11 @@
|
||||
spawn_option(stored_options[choice],M)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/choice_beacon/proc/spawn_option(obj/choice,mob/living/M)
|
||||
var/obj/new_item = new choice()
|
||||
/obj/item/choice_beacon/proc/create_choice_atom(atom/choice, mob/owner)
|
||||
return new choice()
|
||||
|
||||
/obj/item/choice_beacon/proc/spawn_option(atom/choice,mob/living/M)
|
||||
var/obj/new_item = create_choice_atom(choice, M)
|
||||
var/obj/structure/closet/supplypod/bluespacepod/pod = new()
|
||||
pod.explosionSize = list(0,0,0,0)
|
||||
new_item.forceMove(pod)
|
||||
@@ -152,10 +155,50 @@
|
||||
augment_list[initial(A.name)] = A
|
||||
return augment_list
|
||||
|
||||
/obj/item/choice_beacon/augments/spawn_option(obj/choice,mob/living/M)
|
||||
/obj/item/choice_beacon/augments/spawn_option(atom/choice,mob/living/M)
|
||||
new choice(get_turf(M))
|
||||
to_chat(M, "<span class='hear'>You hear something crackle from the beacon for a moment before a voice speaks. \"Please stand by for a message from S.E.L.F. Message as follows: <b>Item request received. Your package has been transported, use the autosurgeon supplied to apply the upgrade.</b> Message ends.\"</span>")
|
||||
|
||||
/obj/item/choice_beacon/pet //donator beacon that summons a small friendly animal
|
||||
name = "pet beacon"
|
||||
desc = "Straight from the outerspace pet shop to your feet."
|
||||
var/static/list/pets = list("Crab" = /mob/living/simple_animal/crab,
|
||||
"Cat" = /mob/living/simple_animal/pet/cat,
|
||||
"Space cat" = /mob/living/simple_animal/pet/cat/space,
|
||||
"Kitten" = /mob/living/simple_animal/pet/cat/kitten,
|
||||
"Dog" = /mob/living/simple_animal/pet/dog,
|
||||
"Corgi" = /mob/living/simple_animal/pet/dog/corgi,
|
||||
"Pug" = /mob/living/simple_animal/pet/dog/pug,
|
||||
"Exotic Corgi" = /mob/living/simple_animal/pet/dog/corgi/exoticcorgi,
|
||||
"Fox" = /mob/living/simple_animal/pet/fox,
|
||||
"Red Panda" = /mob/living/simple_animal/pet/redpanda,
|
||||
"Possum" = /mob/living/simple_animal/opossum)
|
||||
var/pet_name
|
||||
|
||||
/obj/item/choice_beacon/pet/generate_display_names()
|
||||
return pets
|
||||
|
||||
/obj/item/choice_beacon/pet/create_choice_atom(atom/choice, mob/owner)
|
||||
var/mob/living/simple_animal/new_choice = new choice()
|
||||
new_choice.butcher_results = null //please don't eat your pet, chef
|
||||
var/obj/item/pet_carrier/donator/carrier = new() //a donator pet carrier is just a carrier that can't be shoved in an autolathe for metal
|
||||
carrier.add_occupant(new_choice)
|
||||
new_choice.mob_size = MOB_SIZE_TINY //yeah we're not letting you use this roundstart pet to hurt people / knock them down
|
||||
new_choice.pass_flags = PASSTABLE | PASSMOB //your pet is not a bullet/person shield
|
||||
new_choice.density = FALSE
|
||||
new_choice.blood_volume = 0 //your pet cannot be used to drain blood from for a bloodsucker
|
||||
new_choice.desc = "A pet [initial(choice.name)], owned by [owner]!"
|
||||
new_choice.can_have_ai = FALSE //no it cant be sentient damnit
|
||||
if(pet_name)
|
||||
new_choice.name = pet_name
|
||||
new_choice.unique_name = TRUE
|
||||
return carrier
|
||||
|
||||
/obj/item/choice_beacon/pet/spawn_option(atom/choice,mob/living/M)
|
||||
pet_name = input(M, "What would you like to name the pet? (leave blank for default name)", "Pet Name")
|
||||
..()
|
||||
|
||||
//choice boxes (they just open in your hand instead of making a pod)
|
||||
/obj/item/choice_beacon/box
|
||||
name = "choice box (default)"
|
||||
desc = "Think really hard about what you want, and then rip it open!"
|
||||
@@ -163,21 +206,17 @@
|
||||
icon_state = "deliverypackage3"
|
||||
item_state = "deliverypackage3"
|
||||
|
||||
/obj/item/choice_beacon/box/spawn_option(obj/choice,mob/living/M)
|
||||
to_chat(M, "<span class='hear'>The box opens, revealing the [choice]!</span>")
|
||||
/obj/item/choice_beacon/box/spawn_option(atom/choice,mob/living/M)
|
||||
var/choice_text = choice
|
||||
if(ispath(choice_text))
|
||||
choice_text = initial(choice.name)
|
||||
to_chat(M, "<span class='hear'>The box opens, revealing the [choice_text]!</span>")
|
||||
playsound(src.loc, 'sound/items/poster_ripped.ogg', 50, 1)
|
||||
M.temporarilyRemoveItemFromInventory(src, TRUE)
|
||||
M.put_in_hands(new choice)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/choice_beacon/box/plushie
|
||||
name = "choice box (plushie)"
|
||||
desc = "Using the power of quantum entanglement, this box contains every plush, until the moment it is opened!"
|
||||
icon = 'icons/obj/plushes.dmi'
|
||||
icon_state = "box"
|
||||
item_state = "box"
|
||||
|
||||
/obj/item/choice_beacon/box/spawn_option(choice,mob/living/M)
|
||||
/obj/item/choice_beacon/box/plushie/spawn_option(choice,mob/living/M)
|
||||
if(ispath(choice, /obj/item/toy/plush))
|
||||
..() //regular plush, spawn it naturally
|
||||
else
|
||||
@@ -188,6 +227,31 @@
|
||||
M.put_in_hands(new choice)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/choice_beacon/box/carpet //donator carpet beacon
|
||||
name = "choice box (carpet)"
|
||||
desc = "Contains 50 of a selected carpet inside!"
|
||||
var/static/list/carpet_list = list(/obj/item/stack/tile/carpet/black/fifty = "Black Carpet",
|
||||
"Black & Red Carpet" = /obj/item/stack/tile/carpet/blackred/fifty,
|
||||
"Monochrome Carpet" = /obj/item/stack/tile/carpet/monochrome/fifty,
|
||||
"Blue Carpet" = /obj/item/stack/tile/carpet/blue/fifty,
|
||||
"Cyan Carpet" = /obj/item/stack/tile/carpet/cyan/fifty,
|
||||
"Green Carpet" = /obj/item/stack/tile/carpet/green/fifty,
|
||||
"Orange Carpet" = /obj/item/stack/tile/carpet/orange/fifty,
|
||||
"Purple Carpet" = /obj/item/stack/tile/carpet/purple/fifty,
|
||||
"Red Carpet" = /obj/item/stack/tile/carpet/red/fifty,
|
||||
"Royal Black Carpet" = /obj/item/stack/tile/carpet/royalblack/fifty,
|
||||
"Royal Blue Carpet" = /obj/item/stack/tile/carpet/royalblue/fifty)
|
||||
|
||||
/obj/item/choice_beacon/box/carpet/generate_display_names()
|
||||
return carpet_list
|
||||
|
||||
/obj/item/choice_beacon/box/plushie
|
||||
name = "choice box (plushie)"
|
||||
desc = "Using the power of quantum entanglement, this box contains every plush, until the moment it is opened!"
|
||||
icon = 'icons/obj/plushes.dmi'
|
||||
icon_state = "box"
|
||||
item_state = "box"
|
||||
|
||||
/obj/item/choice_beacon/box/plushie/generate_display_names()
|
||||
var/list/plushie_list = list()
|
||||
//plushie set 1: just subtypes of /obj/item/toy/plush
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
var/has_lock_sprites = TRUE //whether to load the lock overlays or not
|
||||
var/allows_hostiles = FALSE //does the pet carrier allow hostile entities to be held within it?
|
||||
|
||||
/obj/item/pet_carrier/donator
|
||||
custom_materials = null //you cant just use the loadout item to get free metal!
|
||||
|
||||
/obj/item/pet_carrier/Destroy()
|
||||
if(occupants.len)
|
||||
for(var/V in occupants)
|
||||
|
||||
@@ -128,6 +128,7 @@
|
||||
absorption_capacity = 5
|
||||
splint_factor = 0.35
|
||||
custom_price = PRICE_REALLY_CHEAP
|
||||
grind_results = list(/datum/reagent/cellulose = 2)
|
||||
|
||||
// gauze is only relevant for wounds, which are handled in the wounds themselves
|
||||
/obj/item/stack/medical/gauze/try_heal(mob/living/M, mob/user, silent)
|
||||
|
||||
@@ -412,6 +412,7 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
|
||||
force = 0
|
||||
throwforce = 0
|
||||
merge_type = /obj/item/stack/sheet/cloth
|
||||
grind_results = list(/datum/reagent/cellulose = 2)
|
||||
|
||||
/obj/item/stack/sheet/cloth/get_main_recipes()
|
||||
. = ..()
|
||||
@@ -773,6 +774,7 @@ GLOBAL_LIST_INIT(plastic_recipes, list(
|
||||
new /datum/stack_recipe("water bottle", /obj/item/reagent_containers/glass/beaker/waterbottle/empty), \
|
||||
new /datum/stack_recipe("large water bottle", /obj/item/reagent_containers/glass/beaker/waterbottle/large/empty,3), \
|
||||
new /datum/stack_recipe("shower curtain", /obj/structure/curtain, 10, time = 10, one_per_turf = 1, on_floor = 1), \
|
||||
new /datum/stack_recipe("duct", /obj/item/stack/ducts,1), \
|
||||
new /datum/stack_recipe("laser pointer case", /obj/item/glasswork/glass_base/laserpointer_shell, 30), \
|
||||
new /datum/stack_recipe("wet floor sign", /obj/item/caution, 2)))
|
||||
|
||||
@@ -841,6 +843,7 @@ new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperfra
|
||||
merge_type = /obj/item/stack/sheet/cotton
|
||||
var/pull_effort = 30
|
||||
var/loom_result = /obj/item/stack/sheet/cloth
|
||||
grind_results = list(/datum/reagent/cellulose = 5)
|
||||
|
||||
/obj/item/stack/sheet/cotton/ten
|
||||
amount = 10
|
||||
@@ -856,6 +859,7 @@ new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperfra
|
||||
merge_type = /obj/item/stack/sheet/cotton/durathread
|
||||
pull_effort = 70
|
||||
loom_result = /obj/item/stack/sheet/durathread
|
||||
grind_results = list(/datum/reagent/cellulose = 10)
|
||||
|
||||
/obj/item/stack/sheet/meat
|
||||
name = "meat sheets"
|
||||
|
||||
@@ -478,7 +478,7 @@
|
||||
/obj/item/assembly/signaler,
|
||||
/obj/item/lightreplacer,
|
||||
/obj/item/rcd_ammo,
|
||||
/obj/item/construction/rcd,
|
||||
/obj/item/construction,
|
||||
/obj/item/pipe_dispenser,
|
||||
/obj/item/stack/rods,
|
||||
/obj/item/stack/tile/plasteel,
|
||||
@@ -492,7 +492,7 @@
|
||||
icon_state = "grenadebeltnew"
|
||||
item_state = "security"
|
||||
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
|
||||
|
||||
|
||||
/obj/item/storage/belt/grenade/ComponentInitialize()
|
||||
. = ..()
|
||||
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
|
||||
|
||||
@@ -281,6 +281,7 @@ GLOBAL_LIST_EMPTY(rubber_toolbox_icons)
|
||||
/obj/item/clothing/suit/armor/vest/infiltrator,
|
||||
/obj/item/clothing/under/syndicate/bloodred,
|
||||
/obj/item/clothing/gloves/color/latex/nitrile/infiltrator,
|
||||
/obj/item/clothing/gloves/tackler/combat/insulated/infiltrator,
|
||||
/obj/item/clothing/mask/infiltrator,
|
||||
/obj/item/clothing/shoes/combat/sneakboots,
|
||||
/obj/item/gun/ballistic/automatic/pistol,
|
||||
@@ -292,7 +293,7 @@ GLOBAL_LIST_EMPTY(rubber_toolbox_icons)
|
||||
new /obj/item/clothing/head/helmet/infiltrator(src)
|
||||
new /obj/item/clothing/suit/armor/vest/infiltrator(src)
|
||||
new /obj/item/clothing/under/syndicate/bloodred(src)
|
||||
new /obj/item/clothing/gloves/color/latex/nitrile/infiltrator(src)
|
||||
new /obj/item/clothing/gloves/tackler/combat/insulated/infiltrator(src)
|
||||
new /obj/item/clothing/mask/infiltrator(src)
|
||||
new /obj/item/clothing/shoes/combat/sneakboots(src)
|
||||
|
||||
|
||||
@@ -252,6 +252,10 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
/obj/item/katana/timestop
|
||||
name = "temporal katana"
|
||||
desc = "Delicately balanced, this finely-crafted blade hums with barely-restrained potential."
|
||||
icon_state = "temporalkatana"
|
||||
item_state = "temporalkatana"
|
||||
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
||||
block_chance = 0 // oops
|
||||
force = 27.5 // oops
|
||||
item_flags = ITEM_CAN_PARRY
|
||||
@@ -263,6 +267,21 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
flynn.emote("smirk")
|
||||
new /obj/effect/timestop/magic(get_turf(owner), 1, 50, list(owner)) // null roddies counter
|
||||
|
||||
/obj/item/katana/timestop/suicide_act(mob/living/user) // stolen from hierophant staff
|
||||
new /obj/effect/timestop/magic(get_turf(user), 1, 50, list(user)) // free usage for dying
|
||||
user.visible_message("<span class='suicide'>[user] poses menacingly with the [src]! It looks like [user.p_theyre()] trying to teleport behind someone!</span>")
|
||||
user.say("Heh.. Nothing personnel, kid..", forced = "temporal katana suicide")
|
||||
sleep(20)
|
||||
if(!user)
|
||||
return
|
||||
user.visible_message("<span class='hierophant_warning'>[user] vanishes into a cloud of falling dust and burning embers, likely off to style on some poor sod in the distance!</span>")
|
||||
playsound(user,'sound/magic/blink.ogg', 75, TRUE)
|
||||
for(var/obj/item/I in user)
|
||||
if(I != src)
|
||||
user.dropItemToGround(I)
|
||||
user.dropItemToGround(src) //Drop us last, so it goes on top of their stuff
|
||||
qdel(user)
|
||||
|
||||
/obj/item/melee/bokken // parrying stick
|
||||
name = "bokken"
|
||||
desc = "A space-Japanese training sword made of wood and shaped like a katana."
|
||||
@@ -272,7 +291,8 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
||||
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
force = 9
|
||||
force = 7 //how much harm mode damage we do
|
||||
var/stamina_damage_increment = 4 //how much extra damage do we do when in non-harm mode
|
||||
throwforce = 10
|
||||
damtype = STAMINA
|
||||
attack_verb = list("whacked", "smacked", "struck")
|
||||
@@ -323,17 +343,19 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
||||
/obj/item/melee/bokken/Initialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/sword_point)
|
||||
if(!harm) //if initialised in non-harm mode, setup force accordingly
|
||||
force = force + stamina_damage_increment
|
||||
|
||||
/obj/item/melee/bokken/attack_self(mob/user)
|
||||
harm = !harm
|
||||
if(harm)
|
||||
force -= 2
|
||||
force -= stamina_damage_increment
|
||||
damtype = BRUTE
|
||||
attack_verb = list("bashed", "smashed", "attacked")
|
||||
bare_wound_bonus = 15 // having your leg smacked by a wooden stick is probably not great for it if it's naked
|
||||
wound_bonus = 0
|
||||
else
|
||||
force += 2
|
||||
force += stamina_damage_increment
|
||||
damtype = STAMINA
|
||||
attack_verb = list("whacked", "smacked", "struck")
|
||||
bare_wound_bonus = 0
|
||||
|
||||
@@ -186,7 +186,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
|
||||
|
||||
if(!acid_level)
|
||||
SSacid.processing[src] = src
|
||||
add_overlay(GLOB.acid_overlay, TRUE)
|
||||
update_icon()
|
||||
var/acid_cap = acidpwr * 300 //so we cannot use huge amounts of weak acids to do as well as strong acids.
|
||||
if(acid_level < acid_cap)
|
||||
acid_level = min(acid_level + acidpwr * acid_volume, acid_cap)
|
||||
@@ -224,7 +224,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
|
||||
if(!(resistance_flags & ON_FIRE) && (resistance_flags & FLAMMABLE))
|
||||
resistance_flags |= ON_FIRE
|
||||
SSfire_burning.processing[src] = src
|
||||
add_overlay(GLOB.fire_overlay, TRUE)
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
//called when the obj is destroyed by fire
|
||||
@@ -236,7 +236,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
|
||||
/obj/proc/extinguish()
|
||||
if(resistance_flags & ON_FIRE)
|
||||
resistance_flags &= ~ON_FIRE
|
||||
cut_overlay(GLOB.fire_overlay, TRUE)
|
||||
update_icon()
|
||||
SSfire_burning.processing -= src
|
||||
|
||||
/obj/zap_act(power, zap_flags, shocked_targets)
|
||||
|
||||
@@ -317,6 +317,13 @@
|
||||
icon_state = unique_reskin[choice]
|
||||
to_chat(M, "[src] is now skinned as '[choice]'.")
|
||||
|
||||
/obj/update_overlays()
|
||||
. = ..()
|
||||
if(acid_level)
|
||||
. += GLOB.acid_overlay
|
||||
if(resistance_flags & ON_FIRE)
|
||||
. += GLOB.fire_overlay
|
||||
|
||||
//Called when the object is constructed by an autolathe
|
||||
//Has a reference to the autolathe so you can do !!FUN!! things with hacked lathes
|
||||
/obj/proc/autolathe_crafted(obj/machinery/autolathe/A)
|
||||
@@ -329,3 +336,6 @@
|
||||
. = ..()
|
||||
if(. && ricochet_damage_mod)
|
||||
take_damage(P.damage * ricochet_damage_mod, P.damage_type, P.flag, 0, turn(P.dir, 180), P.armour_penetration) // pass along ricochet_damage_mod damage to the structure for the ricochet
|
||||
|
||||
/obj/proc/plunger_act(obj/item/plunger/P, mob/living/user, reinforced)
|
||||
return
|
||||
|
||||
@@ -243,10 +243,24 @@ LINEN BINS
|
||||
|
||||
/obj/item/bedsheet/random/Initialize()
|
||||
..()
|
||||
var/type = pick(typesof(/obj/item/bedsheet) - /obj/item/bedsheet/random)
|
||||
var/type = pick(typesof(/obj/item/bedsheet) - list(/obj/item/bedsheet/random, /obj/item/bedsheet/chameleon))
|
||||
new type(loc)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/item/bedsheet/chameleon //donator chameleon bedsheet
|
||||
name = "chameleon bedsheet"
|
||||
desc = "Bedsheet technology has truly gone too far."
|
||||
var/datum/action/item_action/chameleon/change/chameleon_action
|
||||
|
||||
/obj/item/bedsheet/chameleon/New()
|
||||
..()
|
||||
chameleon_action = new(src)
|
||||
chameleon_action.chameleon_type = /obj/item/bedsheet
|
||||
chameleon_action.chameleon_name = "Bedsheet"
|
||||
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/bedsheet/chameleon, /obj/item/bedsheet/random), only_root_path = TRUE)
|
||||
chameleon_action.initialize_disguises()
|
||||
|
||||
//bedsheet bin
|
||||
/obj/structure/bedsheetbin
|
||||
name = "linen bin"
|
||||
desc = "It looks rather cosy."
|
||||
|
||||
@@ -86,6 +86,10 @@
|
||||
|
||||
/obj/structure/grille/attack_animal(mob/user)
|
||||
. = ..()
|
||||
if(!user.CheckActionCooldown(CLICK_CD_MELEE))
|
||||
return
|
||||
user.DelayNextAction(flush = TRUE)
|
||||
user.do_attack_animation(src)
|
||||
if(!shock(user, 70) && !QDELETED(src)) //Last hit still shocks but shouldn't deal damage to the grille)
|
||||
take_damage(rand(5,10), BRUTE, "melee", 1)
|
||||
|
||||
@@ -114,12 +118,12 @@
|
||||
/obj/structure/grille/attack_alien(mob/living/user)
|
||||
if(!user.CheckActionCooldown(CLICK_CD_MELEE))
|
||||
return
|
||||
user.DelayNextAction(flush = TRUE)
|
||||
user.do_attack_animation(src)
|
||||
user.visible_message("<span class='warning'>[user] mangles [src].</span>", null, null, COMBAT_MESSAGE_RANGE)
|
||||
if(!shock(user, 70))
|
||||
take_damage(20, BRUTE, "melee", 1)
|
||||
|
||||
|
||||
/obj/structure/grille/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover) && (mover.pass_flags & PASSGRILLE))
|
||||
return TRUE
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
var/erupting_state = null //set to null to get it greyscaled from "[icon_state]_soup". Not very usable with the whole random thing, but more types can be added if you change the spawn prob
|
||||
var/activated = FALSE //whether we are active and generating chems
|
||||
var/reagent_id = /datum/reagent/fuel/oil
|
||||
var/reagent_id = /datum/reagent/oil
|
||||
var/potency = 2 //how much reagents we add every process (2 seconds)
|
||||
var/max_volume = 500
|
||||
var/start_volume = 50
|
||||
@@ -77,10 +77,10 @@
|
||||
|
||||
/obj/item/plunger/reinforced
|
||||
name = "reinforced plunger"
|
||||
desc = "It's an M. 7 Reinforced Plunger© for heavy duty plunging."
|
||||
desc = "It's an M. 7 Reinforced Plunger� for heavy duty plunging."
|
||||
icon_state = "reinforced_plunger"
|
||||
|
||||
reinforced = TRUE
|
||||
plunge_mod = 0.8
|
||||
|
||||
custom_premium_price = 1200
|
||||
custom_premium_price = 600
|
||||
|
||||
@@ -149,6 +149,8 @@
|
||||
var/list/megafauna_spawn_list
|
||||
/// Flora that can spawn in the tunnel, weighted list
|
||||
var/list/flora_spawn_list
|
||||
//terrain to spawn weighted list
|
||||
var/list/terrain_spawn_list
|
||||
/// Turf type to choose when spawning in tunnel at 1% chance, weighted list
|
||||
var/list/choose_turf_type
|
||||
/// if the tunnel should keep being created
|
||||
@@ -230,7 +232,8 @@
|
||||
megafauna_spawn_list = list(/mob/living/simple_animal/hostile/megafauna/dragon = 4, /mob/living/simple_animal/hostile/megafauna/colossus = 2, /mob/living/simple_animal/hostile/megafauna/bubblegum = SPAWN_BUBBLEGUM)
|
||||
if (!flora_spawn_list)
|
||||
flora_spawn_list = list(/obj/structure/flora/ash/leaf_shroom = 2 , /obj/structure/flora/ash/cap_shroom = 2 , /obj/structure/flora/ash/stem_shroom = 2 , /obj/structure/flora/ash/cacti = 1, /obj/structure/flora/ash/tall_shroom = 2)
|
||||
|
||||
if(!terrain_spawn_list)
|
||||
terrain_spawn_list = list(/obj/structure/geyser/random = 1)
|
||||
. = ..()
|
||||
if(!has_data)
|
||||
produce_tunnel_from_data()
|
||||
@@ -334,8 +337,19 @@
|
||||
spawned_flora = SpawnFlora(T)
|
||||
if(!spawned_flora) // no rocks beneath mob spawners / mobs.
|
||||
SpawnMonster(T)
|
||||
SpawnTerrain(T)
|
||||
T.ChangeTurf(turf_type, null, CHANGETURF_IGNORE_AIR)
|
||||
|
||||
/turf/open/floor/plating/asteroid/airless/cave/proc/SpawnTerrain(turf/T)
|
||||
if(prob(1))
|
||||
if(istype(loc, /area/mine/explored) || istype(loc, /area/lavaland/surface/outdoors/explored))
|
||||
return
|
||||
var/randumb = pickweight(terrain_spawn_list)
|
||||
for(var/obj/structure/geyser/F in range(7, T))
|
||||
if(istype(F, randumb))
|
||||
return
|
||||
new randumb(T)
|
||||
|
||||
/// Spawns a random mob or megafauna in the tunnel
|
||||
/turf/open/floor/plating/asteroid/airless/cave/proc/SpawnMonster(turf/T)
|
||||
if(!isarea(loc))
|
||||
|
||||
@@ -12,6 +12,9 @@ GLOBAL_LIST(topic_status_cache)
|
||||
if (fexists(EXTOOLS))
|
||||
call(EXTOOLS, "maptick_initialize")()
|
||||
enable_debugger()
|
||||
#ifdef REFERENCE_TRACKING
|
||||
enable_reference_tracking()
|
||||
#endif
|
||||
|
||||
world.Profile(PROFILE_START)
|
||||
|
||||
|
||||
@@ -171,7 +171,11 @@ GLOBAL_LIST_INIT(admin_verbs_debug, world.AVerbsDebug())
|
||||
/client/proc/cmd_display_overlay_log,
|
||||
/client/proc/reload_configuration,
|
||||
/datum/admins/proc/create_or_modify_area,
|
||||
/client/proc/generate_wikichem_list //DO NOT PRESS UNLESS YOU WANT SUPERLAG
|
||||
#ifdef REFERENCE_TRACKING
|
||||
/datum/admins/proc/view_refs,
|
||||
/datum/admins/proc/view_del_failures,
|
||||
#endif
|
||||
/client/proc/generate_wikichem_list, //DO NOT PRESS UNLESS YOU WANT SUPERLAG
|
||||
)
|
||||
GLOBAL_PROTECT(admin_verbs_debug)
|
||||
GLOBAL_LIST_INIT(admin_verbs_possess, list(/proc/possess, /proc/release))
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
#ifdef REFERENCE_TRACKING
|
||||
|
||||
GLOBAL_LIST_EMPTY(deletion_failures)
|
||||
|
||||
/world/proc/enable_reference_tracking()
|
||||
if (fexists(EXTOOLS))
|
||||
call(EXTOOLS, "ref_tracking_initialize")()
|
||||
|
||||
/proc/get_back_references(datum/D)
|
||||
CRASH("/proc/get_back_references not hooked by extools, reference tracking will not function!")
|
||||
|
||||
/proc/get_forward_references(datum/D)
|
||||
CRASH("/proc/get_forward_references not hooked by extools, reference tracking will not function!")
|
||||
|
||||
/proc/clear_references(datum/D)
|
||||
return
|
||||
|
||||
/datum/admins/proc/view_refs(atom/D in world) //it actually supports datums as well but byond no likey
|
||||
set category = "Debug"
|
||||
set name = "View References"
|
||||
|
||||
if(!check_rights(R_DEBUG) || !D)
|
||||
return
|
||||
|
||||
var/list/backrefs = get_back_references(D)
|
||||
if(isnull(backrefs))
|
||||
var/datum/browser/popup = new(usr, "ref_view", "<div align='center'>Error</div>")
|
||||
popup.set_content("Reference tracking not enabled")
|
||||
popup.open(FALSE)
|
||||
return
|
||||
|
||||
var/list/frontrefs = get_forward_references(D)
|
||||
var/list/dat = list()
|
||||
dat += "<h1>References of \ref[D] - [D]</h1><br><a href='?_src_=vars;[HrefToken()];[VV_HK_VIEW_REFERENCES]=TRUE;[VV_HK_TARGET]=[REF(D)]'>\[Refresh\]</a><hr>"
|
||||
dat += "<h3>Back references - these things hold references to this object.</h3>"
|
||||
dat += "<table>"
|
||||
dat += "<tr><th>Ref</th><th>Type</th><th>Variable Name</th><th>Follow</th>"
|
||||
for(var/ref in backrefs)
|
||||
var/datum/backreference = ref
|
||||
if(isnull(backreference))
|
||||
dat += "<tr><td>GC'd Reference</td></tr>"
|
||||
if(istype(backreference))
|
||||
dat += "<tr><td><a href='?_src_=vars;[HrefToken()];Vars=[REF(backreference)]'>[REF(backreference)]</td><td>[backreference.type]</td><td>[backrefs[backreference]]</td><td><a href='?_src_=vars;[HrefToken()];[VV_HK_VIEW_REFERENCES]=TRUE;[VV_HK_TARGET]=[REF(backreference)]'>\[Follow\]</a></td></tr>"
|
||||
else if(islist(backreference))
|
||||
dat += "<tr><td><a href='?_src_=vars;[HrefToken()];Vars=[REF(backreference)]'>[REF(backreference)]</td><td>list</td><td>[backrefs[backreference]]</td><td><a href='?_src_=vars;[HrefToken()];[VV_HK_VIEW_REFERENCES]=TRUE;[VV_HK_TARGET]=[REF(backreference)]'>\[Follow\]</a></td></tr>"
|
||||
else
|
||||
dat += "<tr><td>Weird reference type. Add more debugging checks.</td></tr>"
|
||||
dat += "</table><hr>"
|
||||
dat += "<h3>Forward references - this object is referencing those things.</h3>"
|
||||
dat += "<table>"
|
||||
dat += "<tr><th>Variable name</th><th>Ref</th><th>Type</th><th>Follow</th>"
|
||||
for(var/ref in frontrefs)
|
||||
var/datum/backreference = frontrefs[ref]
|
||||
dat += "<tr><td>[ref]</td><td><a href='?_src_=vars;[HrefToken()];Vars=[REF(backreference)]'>[REF(backreference)]</a></td><td>[backreference.type]</td><td><a href='?_src_=vars;[HrefToken()];[VV_HK_VIEW_REFERENCES]=TRUE;[VV_HK_TARGET]=[REF(backreference)]'>\[Follow\]</a></td></tr>"
|
||||
dat += "</table><hr>"
|
||||
dat = dat.Join()
|
||||
|
||||
var/datum/browser/popup = new(usr, "ref_view", "<div align='center'>References of \ref[D]</div>")
|
||||
popup.set_content(dat)
|
||||
popup.open(FALSE)
|
||||
|
||||
|
||||
/datum/admins/proc/view_del_failures()
|
||||
set category = "Debug"
|
||||
set name = "View Deletion Failures"
|
||||
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
|
||||
var/list/dat = list("<table>")
|
||||
for(var/t in GLOB.deletion_failures)
|
||||
if(isnull(t))
|
||||
dat += "<tr><td>GC'd Reference | <a href='byond://?src=[REF(src)];[HrefToken(TRUE)];delfail_clearnulls=TRUE'>Clear Nulls</a></td></tr>"
|
||||
continue
|
||||
var/datum/thing = t
|
||||
dat += "<tr><td>\ref[thing] | [thing.type][thing.gc_destroyed ? " (destroyed)" : ""] [ADMIN_VV(thing)]</td></tr>"
|
||||
dat += "</table><hr>"
|
||||
dat = dat.Join()
|
||||
|
||||
var/datum/browser/popup = new(usr, "del_failures", "<div align='center'>Deletion Failures</div>")
|
||||
popup.set_content(dat)
|
||||
popup.open(FALSE)
|
||||
|
||||
|
||||
/datum/proc/find_references()
|
||||
testing("Beginning search for references to a [type].")
|
||||
var/list/backrefs = get_back_references(src)
|
||||
for(var/ref in backrefs)
|
||||
if(isnull(ref))
|
||||
log_world("## TESTING: Datum reference found, but gone now.")
|
||||
continue
|
||||
if(islist(ref))
|
||||
log_world("## TESTING: Found [type] \ref[src] in list.")
|
||||
continue
|
||||
var/datum/datum_ref = ref
|
||||
if(!istype(datum_ref))
|
||||
log_world("## TESTING: Found [type] \ref[src] in unknown type reference: [datum_ref].")
|
||||
return
|
||||
log_world("## TESTING: Found [type] \ref[src] in [datum_ref.type][datum_ref.gc_destroyed ? " (destroyed)" : ""]")
|
||||
message_admins("Found [type] \ref[src] [ADMIN_VV(src)] in [datum_ref.type][datum_ref.gc_destroyed ? " (destroyed)" : ""] [ADMIN_VV(datum_ref)]")
|
||||
testing("Completed search for references to a [type].")
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef LEGACY_REFERENCE_TRACKING
|
||||
|
||||
/datum/verb/legacy_find_refs()
|
||||
set category = "Debug"
|
||||
set name = "Find References"
|
||||
set src in world
|
||||
|
||||
find_references(FALSE)
|
||||
|
||||
|
||||
/datum/proc/find_references_legacy(skip_alert)
|
||||
running_find_references = type
|
||||
if(usr?.client)
|
||||
if(usr.client.running_find_references)
|
||||
testing("CANCELLED search for references to a [usr.client.running_find_references].")
|
||||
usr.client.running_find_references = null
|
||||
running_find_references = null
|
||||
//restart the garbage collector
|
||||
SSgarbage.can_fire = TRUE
|
||||
SSgarbage.next_fire = world.time + world.tick_lag
|
||||
return
|
||||
|
||||
if(!skip_alert && alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "Yes", "No") != "Yes")
|
||||
running_find_references = null
|
||||
return
|
||||
|
||||
//this keeps the garbage collector from failing to collect objects being searched for in here
|
||||
SSgarbage.can_fire = FALSE
|
||||
|
||||
if(usr?.client)
|
||||
usr.client.running_find_references = type
|
||||
|
||||
testing("Beginning search for references to a [type].")
|
||||
last_find_references = world.time
|
||||
|
||||
DoSearchVar(GLOB) //globals
|
||||
for(var/datum/thing in world) //atoms (don't beleive its lies)
|
||||
DoSearchVar(thing, "World -> [thing]")
|
||||
|
||||
for(var/datum/thing) //datums
|
||||
DoSearchVar(thing, "World -> [thing]")
|
||||
|
||||
for(var/client/thing) //clients
|
||||
DoSearchVar(thing, "World -> [thing]")
|
||||
|
||||
testing("Completed search for references to a [type].")
|
||||
if(usr?.client)
|
||||
usr.client.running_find_references = null
|
||||
running_find_references = null
|
||||
|
||||
//restart the garbage collector
|
||||
SSgarbage.can_fire = TRUE
|
||||
SSgarbage.next_fire = world.time + world.tick_lag
|
||||
|
||||
|
||||
/datum/verb/qdel_then_find_references()
|
||||
set category = "Debug"
|
||||
set name = "qdel() then Find References"
|
||||
set src in world
|
||||
|
||||
qdel(src, TRUE) //force a qdel
|
||||
if(!running_find_references)
|
||||
find_references(TRUE)
|
||||
|
||||
|
||||
/datum/verb/qdel_then_if_fail_find_references()
|
||||
set category = "Debug"
|
||||
set name = "qdel() then Find References if GC failure"
|
||||
set src in world
|
||||
|
||||
qdel_and_find_ref_if_fail(src, TRUE)
|
||||
|
||||
|
||||
/datum/proc/DoSearchVar(potential_container, container_name, recursive_limit = 64)
|
||||
if(usr?.client && !usr.client.running_find_references)
|
||||
return
|
||||
|
||||
if(!recursive_limit)
|
||||
return
|
||||
|
||||
if(istype(potential_container, /datum))
|
||||
var/datum/datum_container = potential_container
|
||||
if(datum_container.last_find_references == last_find_references)
|
||||
return
|
||||
|
||||
datum_container.last_find_references = last_find_references
|
||||
var/list/vars_list = datum_container.vars
|
||||
|
||||
for(var/varname in vars_list)
|
||||
if (varname == "vars")
|
||||
continue
|
||||
var/variable = vars_list[varname]
|
||||
|
||||
if(variable == src)
|
||||
testing("Found [type] \ref[src] in [datum_container.type]'s [varname] var. [container_name]")
|
||||
|
||||
else if(islist(variable))
|
||||
DoSearchVar(variable, "[container_name] -> list", recursive_limit - 1)
|
||||
|
||||
else if(islist(potential_container))
|
||||
var/normal = IS_NORMAL_LIST(potential_container)
|
||||
for(var/element_in_list in potential_container)
|
||||
if(element_in_list == src)
|
||||
testing("Found [type] \ref[src] in list [container_name].")
|
||||
|
||||
else if(element_in_list && !isnum(element_in_list) && normal && potential_container[element_in_list] == src)
|
||||
testing("Found [type] \ref[src] in list [container_name]\[[element_in_list]\]")
|
||||
|
||||
else if(islist(element_in_list))
|
||||
DoSearchVar(element_in_list, "[container_name] -> list", recursive_limit - 1)
|
||||
|
||||
#ifndef FIND_REF_NO_CHECK_TICK
|
||||
CHECK_TICK
|
||||
#endif
|
||||
|
||||
|
||||
/proc/qdel_and_find_ref_if_fail(datum/thing_to_del, force = FALSE)
|
||||
SSgarbage.reference_find_on_fail[REF(thing_to_del)] = TRUE
|
||||
qdel(thing_to_del, force)
|
||||
|
||||
#endif
|
||||
@@ -45,6 +45,16 @@
|
||||
usr.client.admin_delete(target)
|
||||
if (isturf(src)) // show the turf that took its place
|
||||
usr.client.debug_variables(src)
|
||||
return
|
||||
#ifdef REFERENCE_TRACKING
|
||||
if(href_list[VV_HK_VIEW_REFERENCES])
|
||||
var/datum/D = locate(href_list[VV_HK_TARGET])
|
||||
if(!D)
|
||||
to_chat(usr, "<span class='warning'>Unable to locate item.</span>")
|
||||
return
|
||||
usr.client.holder.view_refs(target)
|
||||
return
|
||||
#endif
|
||||
if(href_list[VV_HK_MARK])
|
||||
usr.client.mark_datum(target)
|
||||
if(href_list[VV_HK_ADDCOMPONENT])
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
"Set len" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SET_LENGTH),
|
||||
"Shuffle" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SHUFFLE),
|
||||
"Show VV To Player" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_EXPOSE),
|
||||
"View References" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_VIEW_REFERENCES),
|
||||
"---"
|
||||
)
|
||||
for(var/i in 1 to length(dropdownoptions))
|
||||
|
||||
@@ -281,7 +281,6 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
. = CONFIG_GET(keyed_list/antag_threat)[lowertext(name)]
|
||||
if(. == null)
|
||||
return threat
|
||||
return threat
|
||||
|
||||
//This one is created by admin tools for custom objectives
|
||||
/datum/antagonist/custom
|
||||
|
||||
@@ -4,11 +4,17 @@
|
||||
antagpanel_category = "Blob"
|
||||
show_to_ghosts = TRUE
|
||||
job_rank = ROLE_BLOB
|
||||
threat = 20
|
||||
threat = 50
|
||||
var/datum/action/innate/blobpop/pop_action
|
||||
var/starting_points_human_blob = 60
|
||||
var/point_rate_human_blob = 2
|
||||
|
||||
/datum/antagonist/blob/threat()
|
||||
. = ..()
|
||||
if(isovermind(owner.current))
|
||||
var/mob/camera/blob/overmind = owner.current
|
||||
. *= (overmind.blobs_legit.len / overmind.max_count)
|
||||
|
||||
/datum/antagonist/blob/roundend_report()
|
||||
var/basic_report = ..()
|
||||
//Display max blobpoints for blebs that lost
|
||||
|
||||
@@ -75,7 +75,6 @@
|
||||
desc = "A floating, fragile spore."
|
||||
icon_state = "blobpod"
|
||||
icon_living = "blobpod"
|
||||
threat = 0.2
|
||||
health = 30
|
||||
maxHealth = 30
|
||||
verb_say = "psychically pulses"
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
REMOVE_TRAIT(user, TRAIT_PIERCEIMMUNE, "fortitude")
|
||||
REMOVE_TRAIT(user, TRAIT_NODISMEMBER, "fortitude")
|
||||
REMOVE_TRAIT(user, TRAIT_STUNIMMUNE, "fortitude")
|
||||
REMOVE_TRAIT(user, TRAIT_STUNIMMUNE, "fortitude")
|
||||
REMOVE_TRAIT(user, TRAIT_NORUNNING, "fortitude")
|
||||
if(!ishuman(owner))
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
unique_name = 1
|
||||
minbodytemp = 0
|
||||
unsuitable_atmos_damage = 0
|
||||
threat = 1
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) //Robotic
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
healable = FALSE
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
desc = "The stalwart apparition of a soldier, blazing with crimson flames. It's armed with a gladius and shield."
|
||||
icon_state = "clockwork_marauder"
|
||||
mob_biotypes = MOB_HUMANOID
|
||||
threat = 3
|
||||
health = 120
|
||||
maxHealth = 120
|
||||
force_threshold = 8
|
||||
|
||||
@@ -70,7 +70,6 @@
|
||||
icon_living = "swarmer"
|
||||
icon_dead = "swarmer_unactivated"
|
||||
icon_gib = null
|
||||
threat = 0.5
|
||||
wander = 0
|
||||
harm_intent_damage = 5
|
||||
minbodytemp = 0
|
||||
|
||||
@@ -16,6 +16,18 @@
|
||||
var/datum/team/xeno/xeno_team
|
||||
threat = 3
|
||||
|
||||
/datum/antagonist/xeno/threat()
|
||||
. = 1
|
||||
if(isalienhunter(owner))
|
||||
. = 2
|
||||
else if(isaliensentinel(owner))
|
||||
. = 4
|
||||
else if(isalienroyal(owner))
|
||||
if(isalienqueen(owner))
|
||||
. = 8
|
||||
else
|
||||
. = 6
|
||||
|
||||
/datum/antagonist/xeno/create_team(datum/team/xeno/new_team)
|
||||
if(!new_team)
|
||||
for(var/datum/antagonist/xeno/X in GLOB.antagonists)
|
||||
|
||||
@@ -264,7 +264,7 @@
|
||||
name = "pipes"
|
||||
|
||||
/datum/asset/spritesheet/pipes/register()
|
||||
for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi'))
|
||||
for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi', 'icons/obj/plumbing/fluid_ducts.dmi'))
|
||||
InsertAll("", each, GLOB.alldirs)
|
||||
..()
|
||||
|
||||
@@ -388,9 +388,11 @@
|
||||
Insert("polycrystal", 'icons/obj/telescience.dmi', "polycrystal")
|
||||
..()
|
||||
|
||||
|
||||
/datum/asset/spritesheet/mafia
|
||||
name = "mafia"
|
||||
|
||||
/datum/asset/spritesheet/mafia/register()
|
||||
InsertAll("", 'icons/obj/mafia.dmi')
|
||||
..()
|
||||
|
||||
|
||||
@@ -246,6 +246,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
/// Which of the 5 persistent scar slots we randomly roll to load for this round, if enabled. Actually rolled in [/datum/preferences/proc/load_character(slot)]
|
||||
var/scars_index = 1
|
||||
|
||||
var/chosen_limb_id //body sprite selected to load for the users limbs, null means default, is sanitized when loaded
|
||||
|
||||
/datum/preferences/New(client/C)
|
||||
parent = C
|
||||
|
||||
@@ -521,6 +523,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
dat += "</td>"
|
||||
mutant_category = 0
|
||||
|
||||
if(length(pref_species.allowed_limb_ids))
|
||||
if(!chosen_limb_id || !(chosen_limb_id in pref_species.allowed_limb_ids))
|
||||
chosen_limb_id = pref_species.id
|
||||
dat += "<h3>Body sprite</h3>"
|
||||
dat += "<a style='display:block;width:100px' href='?_src_=prefs;preference=bodysprite;task=input'>[chosen_limb_id]</a>"
|
||||
|
||||
if(mutant_category)
|
||||
dat += "</td>"
|
||||
mutant_category = 0
|
||||
@@ -801,7 +809,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
if(!subcategories.Find(gear_subcategory))
|
||||
gear_subcategory = subcategories[1]
|
||||
|
||||
var/firstsubcat = FALSE
|
||||
var/firstsubcat = TRUE
|
||||
for(var/subcategory in subcategories)
|
||||
if(firstsubcat)
|
||||
firstsubcat = FALSE
|
||||
@@ -2092,8 +2100,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
else
|
||||
features["body_model"] = chosengender
|
||||
gender = chosengender
|
||||
facial_hair_style = random_facial_hair_style(gender)
|
||||
hair_style = random_hair_style(gender)
|
||||
|
||||
if("body_size")
|
||||
var/min = CONFIG_GET(number/body_size_min)
|
||||
@@ -2119,6 +2125,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/selected_custom_speech_verb = input(user, "Choose your desired speech verb (none means your species speech verb)", "Character Preference") as null|anything in GLOB.speech_verbs
|
||||
if(selected_custom_speech_verb)
|
||||
custom_speech_verb = selected_custom_speech_verb
|
||||
|
||||
if("bodysprite")
|
||||
var/selected_body_sprite = input(user, "Choose your desired body sprite", "Character Preference") as null|anything in pref_species.allowed_limb_ids
|
||||
if(selected_body_sprite)
|
||||
chosen_limb_id = selected_body_sprite //this gets sanitized before loading
|
||||
else
|
||||
switch(href_list["preference"])
|
||||
//CITADEL PREFERENCES EDIT - I can't figure out how to modularize these, so they have to go here. :c -Pooj
|
||||
@@ -2510,6 +2521,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
|
||||
character.dna.features = features.Copy()
|
||||
character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE)
|
||||
if(chosen_limb_id && (chosen_limb_id in character.dna.species.allowed_limb_ids))
|
||||
character.dna.species.mutant_bodyparts["limbs_id"] = chosen_limb_id
|
||||
character.dna.real_name = character.real_name
|
||||
character.dna.nameless = character.nameless
|
||||
character.dna.custom_species = character.custom_species
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// You do not need to raise this if you are adding new values that have sane defaults.
|
||||
// Only raise this value when changing the meaning/format/name/layout of an existing value
|
||||
// where you would want the updater procs below to run
|
||||
#define SAVEFILE_VERSION_MAX 34
|
||||
#define SAVEFILE_VERSION_MAX 35
|
||||
|
||||
/*
|
||||
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
|
||||
@@ -200,6 +200,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
features["silicon_flavor_text"] = html_encode(features["silicon_flavor_text"])
|
||||
features["ooc_notes"] = html_encode(features["ooc_notes"])
|
||||
|
||||
if(current_version < 35)
|
||||
if(S["species"] == "lizard")
|
||||
features["mam_snouts"] = features["snout"]
|
||||
|
||||
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
|
||||
if(!ckey)
|
||||
return
|
||||
@@ -510,6 +514,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
S["scars3"] >> scars_list["3"]
|
||||
S["scars4"] >> scars_list["4"]
|
||||
S["scars5"] >> scars_list["5"]
|
||||
S["chosen_limb_id"] >> chosen_limb_id
|
||||
|
||||
|
||||
//Custom names
|
||||
@@ -840,6 +845,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
|
||||
WRITE_FILE(S["feature_ooc_notes"], features["ooc_notes"])
|
||||
|
||||
WRITE_FILE(S["chosen_limb_id"], chosen_limb_id)
|
||||
|
||||
//Custom names
|
||||
for(var/custom_name_id in GLOB.preferences_custom_names)
|
||||
var/savefile_slot_name = custom_name_id + "_name" //TODO remove this
|
||||
|
||||
@@ -118,8 +118,7 @@
|
||||
|
||||
// Set the clothing's integrity back to 100%, remove all damage to bodyparts, and generally fix it up
|
||||
/obj/item/clothing/proc/repair(mob/user, params)
|
||||
damaged_clothes = CLOTHING_PRISTINE
|
||||
update_clothes_damaged_state(FALSE)
|
||||
update_clothes_damaged_state(CLOTHING_PRISTINE)
|
||||
obj_integrity = max_integrity
|
||||
name = initial(name) // remove "tattered" or "shredded" if there's a prefix
|
||||
body_parts_covered = initial(body_parts_covered)
|
||||
@@ -196,7 +195,7 @@
|
||||
if(3 to INFINITY) // take better care of your shit, dude
|
||||
name = "tattered [initial(name)]"
|
||||
|
||||
update_clothes_damaged_state()
|
||||
update_clothes_damaged_state(CLOTHING_DAMAGED)
|
||||
|
||||
/obj/item/clothing/Destroy()
|
||||
user_vars_remembered = null //Oh god somebody put REFERENCES in here? not to worry, we'll clean it up
|
||||
@@ -257,7 +256,7 @@
|
||||
how_cool_are_your_threads += "Adding or removing items from [src] makes no noise.\n"
|
||||
how_cool_are_your_threads += "</span>"
|
||||
. += how_cool_are_your_threads.Join()
|
||||
|
||||
|
||||
if(LAZYLEN(armor_list))
|
||||
armor_list.Cut()
|
||||
if(armor.bio)
|
||||
@@ -346,10 +345,16 @@
|
||||
var/mob/M = loc
|
||||
to_chat(M, "<span class='warning'>Your [name] starts to fall apart!</span>")
|
||||
|
||||
/obj/item/clothing/proc/update_clothes_damaged_state(damaging = TRUE)
|
||||
var/index = "[REF(initial(icon))]-[initial(icon_state)]"
|
||||
var/static/list/damaged_clothes_icons = list()
|
||||
if(damaging)
|
||||
//This mostly exists so subtypes can call appriopriate update icon calls on the wearer.
|
||||
/obj/item/clothing/proc/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED)
|
||||
damaged_clothes = damaged_state
|
||||
update_icon()
|
||||
|
||||
/obj/item/clothing/update_overlays()
|
||||
. = ..()
|
||||
if(damaged_clothes)
|
||||
var/index = "[REF(initial(icon))]-[initial(icon_state)]"
|
||||
var/static/list/damaged_clothes_icons = list()
|
||||
var/icon/damaged_clothes_icon = damaged_clothes_icons[index]
|
||||
if(!damaged_clothes_icon)
|
||||
damaged_clothes_icon = icon(initial(icon), initial(icon_state), , 1) //we only want to apply damaged effect to the initial icon_state for each object
|
||||
@@ -357,9 +362,7 @@
|
||||
damaged_clothes_icon.Blend(icon('icons/effects/item_damage.dmi', "itemdamaged"), ICON_MULTIPLY) //adds damage effect and the remaining white areas become transparant
|
||||
damaged_clothes_icon = fcopy_rsc(damaged_clothes_icon)
|
||||
damaged_clothes_icons[index] = damaged_clothes_icon
|
||||
add_overlay(damaged_clothes_icon, TRUE)
|
||||
else
|
||||
cut_overlay(damaged_clothes_icons[index], TRUE)
|
||||
. += damaged_clothes_icon
|
||||
|
||||
/*
|
||||
SEE_SELF // can see self, no matter what
|
||||
|
||||
@@ -199,12 +199,16 @@
|
||||
|
||||
/obj/item/clothing/gloves/evening
|
||||
name = "evening gloves"
|
||||
desc = "Thin, pretty gloves intended for use in regal feminine attire, but knowing Space China these are just for some maid fetish."
|
||||
desc = "Thin, pretty gloves intended for use in regal feminine attire. A tag on the hem claims they were 'maid' in Space China, these were probably intended for use in some maid fetish."
|
||||
icon_state = "evening"
|
||||
item_state = "evening"
|
||||
strip_delay = 40
|
||||
equip_delay_other = 20
|
||||
transfer_prints = TRUE
|
||||
cold_protection = HANDS
|
||||
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
|
||||
strip_mod = 0.9
|
||||
custom_price = PRICE_ALMOST_CHEAP
|
||||
|
||||
/obj/item/clothing/gloves/evening/black
|
||||
name = "midnight gloves"
|
||||
desc = "Thin, pretty gloves intended for use in sexy feminine attire. A tag on the hem claims they pair great with black stockings."
|
||||
icon_state = "eveningblack"
|
||||
item_state = "eveningblack"
|
||||
|
||||
@@ -74,6 +74,25 @@
|
||||
permeability_coefficient = 0.05
|
||||
strip_mod = 1.5 // and combat gloves had this??
|
||||
|
||||
/obj/item/clothing/gloves/tackler/combat/insulated/infiltrator
|
||||
name = "insidious guerrilla gloves"
|
||||
desc = "Specialized combat gloves for carrying people around. Transfers tactical kidnapping and tackling knowledge to the user via the use of nanochips."
|
||||
icon_state = "infiltrator"
|
||||
item_state = "infiltrator"
|
||||
siemens_coefficient = 0
|
||||
permeability_coefficient = 0.05
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
var/carrytrait = TRAIT_QUICKER_CARRY
|
||||
|
||||
/obj/item/clothing/gloves/tackler/combat/insulated/infiltrator/equipped(mob/user, slot)
|
||||
. = ..()
|
||||
if(slot == SLOT_GLOVES)
|
||||
ADD_TRAIT(user, carrytrait, GLOVE_TRAIT)
|
||||
|
||||
/obj/item/clothing/gloves/tackler/combat/insulated/infiltrator/dropped(mob/user)
|
||||
. = ..()
|
||||
REMOVE_TRAIT(user, carrytrait, GLOVE_TRAIT)
|
||||
|
||||
/obj/item/clothing/gloves/tackler/rocket
|
||||
name = "rocket gloves"
|
||||
desc = "The ultimate in high risk, high reward, perfect for when you need to stop a criminal from fifty feet away or die trying. Banned in most Spinward gridiron football and rugby leagues."
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
/obj/item/clothing/mask/balaclava/attack_self(mob/user)
|
||||
adjustmask(user)
|
||||
|
||||
/obj/item/clothing/mask/balaclava/breath
|
||||
name = "breathaclava"
|
||||
clothing_flags = ALLOWINTERNALS
|
||||
|
||||
/obj/item/clothing/mask/infiltrator
|
||||
name = "insidious balaclava"
|
||||
desc = "An incredibly suspicious balaclava made with Syndicate nanofibers to absorb impacts slightly while obfuscating the voice and face using a garbled vocoder."
|
||||
|
||||
@@ -625,7 +625,7 @@
|
||||
desc = "An arctic white winter coat with a small blue caduceus instead of a plastic zipper tab. Snazzy."
|
||||
icon_state = "coatmedical"
|
||||
item_state = "coatmedical"
|
||||
allowed = list(/obj/item/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
allowed = list(/obj/item/analyzer, /obj/item/sensor_device, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 50, "rad" = 0, "fire" = 0, "acid" = 45)
|
||||
hoodtype = /obj/item/clothing/head/hooded/winterhood/medical
|
||||
|
||||
@@ -638,7 +638,7 @@
|
||||
desc = "An arctic white winter coat with a small blue caduceus instead of a plastic zipper tab. The normal liner is replaced with an exceptionally thick, soft layer of fur."
|
||||
icon_state = "coatcmo"
|
||||
item_state = "coatcmo"
|
||||
allowed = list(/obj/item/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
allowed = list(/obj/item/analyzer, /obj/item/sensor_device, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
armor = list("melee" = 5, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 50, "rad" = 0, "fire" = 0, "acid" = 0)
|
||||
hoodtype = /obj/item/clothing/head/hooded/winterhood/cmo
|
||||
|
||||
@@ -651,7 +651,7 @@
|
||||
desc = "A lab-grade winter coat made with acid resistant polymers. For the enterprising chemist who was exiled to a frozen wasteland on the go."
|
||||
icon_state = "coatchemistry"
|
||||
item_state = "coatchemistry"
|
||||
allowed = list(/obj/item/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
allowed = list(/obj/item/analyzer, /obj/item/sensor_device, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 30, "rad" = 0, "fire" = 30, "acid" = 45)
|
||||
hoodtype = /obj/item/clothing/head/hooded/winterhood/chemistry
|
||||
|
||||
@@ -664,7 +664,7 @@
|
||||
desc = "A white winter coat with green markings. Warm, but wont fight off the common cold or any other disease. Might make people stand far away from you in the hallway. The zipper tab looks like an oversized bacteriophage."
|
||||
icon_state = "coatviro"
|
||||
item_state = "coatviro"
|
||||
allowed = list(/obj/item/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
allowed = list(/obj/item/analyzer, /obj/item/sensor_device, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 30, "rad" = 0, "fire" = 0, "acid" = 0)
|
||||
hoodtype = /obj/item/clothing/head/hooded/winterhood/viro
|
||||
|
||||
@@ -677,7 +677,7 @@
|
||||
desc = "A winter coat with blue markings. Warm, but probably won't protect from biological agents. For the cozy doctor on the go."
|
||||
icon_state = "coatparamed"
|
||||
item_state = "coatparamed"
|
||||
allowed = list(/obj/item/analyzer, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
allowed = list(/obj/item/analyzer, /obj/item/sensor_device, /obj/item/stack/medical, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray, /obj/item/healthanalyzer, /obj/item/flashlight/pen, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/pill, /obj/item/storage/pill_bottle, /obj/item/paper, /obj/item/melee/classic_baton/telescopic, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman)
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 50, "rad" = 0, "fire" = 0, "acid" = 45)
|
||||
hoodtype = /obj/item/clothing/head/hooded/winterhood/paramedic
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
typepath = /datum/round_event/ghost_role/alien_infestation
|
||||
weight = 5
|
||||
gamemode_blacklist = list("dynamic")
|
||||
min_players = 10
|
||||
min_players = 25
|
||||
max_occurrences = 1
|
||||
|
||||
/datum/round_event/ghost_role/alien_infestation
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
"How do I vore people?",
|
||||
"ERP?",
|
||||
"Not epic bros...")
|
||||
threat = 5
|
||||
|
||||
|
||||
/datum/round_event/brand_intelligence/announce(fake)
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
ship_name = pick(strings(PIRATE_NAMES_FILE, "ship_names"))
|
||||
|
||||
/datum/round_event/pirates/announce(fake)
|
||||
priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", "commandreport") // CITADEL EDIT metabreak
|
||||
priority_announce("A business proposition has been downloaded and printed out at all communication consoles.", "Incoming Business Proposition", "commandreport")
|
||||
if(fake)
|
||||
return
|
||||
threat_message = new
|
||||
@@ -49,6 +49,7 @@
|
||||
else
|
||||
priority_announce("Trying to cheat us? You'll regret this!",sender_override = ship_name)
|
||||
if(!shuttle_spawned)
|
||||
priority_announce("You won't listen to reason? Then we'll take what's yours or die trying!",sender_override = ship_name)
|
||||
spawn_shuttle()
|
||||
|
||||
/datum/round_event/pirates/start()
|
||||
@@ -83,8 +84,7 @@
|
||||
announce_to_ghosts(M)
|
||||
else
|
||||
announce_to_ghosts(spawner)
|
||||
|
||||
priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", "commandreport") //CITADEL EDIT also metabreak here too
|
||||
priority_announce("Unidentified ship detected near the station.")
|
||||
|
||||
//Shuttle equipment
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
icon_dead = "magicarp_dead"
|
||||
icon_gib = "magicarp_gib"
|
||||
ranged = 1
|
||||
threat = 4
|
||||
retreat_distance = 2
|
||||
minimum_distance = 0 //Between shots they can and will close in to nash
|
||||
projectiletype = /obj/item/projectile/magic
|
||||
@@ -52,7 +51,6 @@
|
||||
color = "#00FFFF"
|
||||
maxHealth = 75
|
||||
health = 75
|
||||
threat = 7
|
||||
|
||||
/mob/living/simple_animal/hostile/carp/ranged/chaos/Shoot()
|
||||
projectiletype = pick(allowed_projectile_types)
|
||||
|
||||
@@ -97,9 +97,12 @@ All foods are distributed among various categories. Use common sense.
|
||||
return
|
||||
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/attack(mob/living/M, mob/living/user, def_zone)
|
||||
/obj/item/reagent_containers/food/snacks/attack(mob/living/M, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
return ..()
|
||||
INVOKE_ASYNC(src, .proc/attempt_forcefeed, M, user)
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/proc/attempt_forcefeed(mob/living/M, mob/living/user)
|
||||
if(!eatverb)
|
||||
eatverb = pick("bite","chew","nibble","gnaw","gobble","chomp")
|
||||
if(!reagents.total_volume) //Shouldn't be needed but it checks to see if it has anything left in it.
|
||||
|
||||
@@ -190,7 +190,6 @@
|
||||
icon_dead = "scary_clown"
|
||||
icon_gib = "scary_clown"
|
||||
speak = list("...", ". . .")
|
||||
threat = 3
|
||||
maxHealth = 120
|
||||
health = 120
|
||||
emote_see = list("silently stares")
|
||||
|
||||
@@ -103,6 +103,7 @@
|
||||
throwforce = 5
|
||||
throw_speed = 2
|
||||
throw_range = 3
|
||||
attack_speed = CLICK_CD_MELEE
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
flags_1 = CONDUCT_1
|
||||
armour_penetration = 20
|
||||
@@ -125,9 +126,12 @@
|
||||
playsound(src,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1)
|
||||
return (BRUTELOSS)
|
||||
|
||||
/obj/item/scythe/pre_attack(atom/A, mob/living/user, params)
|
||||
/obj/item/scythe/pre_attack(atom/A, mob/living/user, params, attackchain_flags, damage_multiplier)
|
||||
. = ..()
|
||||
if(. & STOP_ATTACK_PROC_CHAIN)
|
||||
return
|
||||
if(swiping || !istype(A, /obj/structure/spacevine) || get_turf(A) == get_turf(user))
|
||||
return ..()
|
||||
return
|
||||
else
|
||||
var/turf/user_turf = get_turf(user)
|
||||
var/dir_to_target = get_dir(user_turf, get_turf(A))
|
||||
@@ -138,11 +142,12 @@
|
||||
var/turf/T = get_step(user_turf, turn(dir_to_target, i))
|
||||
for(var/obj/structure/spacevine/V in T)
|
||||
if(user.Adjacent(V))
|
||||
melee_attack_chain(user, V)
|
||||
melee_attack_chain(user, V, attackchain_flags = ATTACK_IGNORE_CLICKDELAY)
|
||||
stam_gain += 5 //should be hitcost
|
||||
swiping = FALSE
|
||||
stam_gain += 2 //Initial hitcost
|
||||
user.adjustStaminaLoss(-stam_gain)
|
||||
user.DelayNextAction()
|
||||
|
||||
// *************************************
|
||||
// Nutrient defines for hydroponics
|
||||
@@ -192,4 +197,4 @@
|
||||
/obj/item/reagent_containers/glass/bottle/killer/pestkiller
|
||||
name = "bottle of pest spray"
|
||||
desc = "Contains a pesticide."
|
||||
list_reagents = list(/datum/reagent/toxin/pestkiller = 50)
|
||||
list_reagents = list(/datum/reagent/toxin/pestkiller = 50)
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
var/self_sufficiency_req = 20 //Required total dose to make a self-sufficient hydro tray. 1:1 with earthsblood.
|
||||
var/self_sufficiency_progress = 0
|
||||
var/self_sustaining = FALSE //If the tray generates nutrients and water on its own
|
||||
|
||||
var/canirrigate = TRUE //tin
|
||||
|
||||
/obj/machinery/hydroponics/constructable
|
||||
name = "hydroponics tray"
|
||||
@@ -847,12 +847,13 @@
|
||||
if (!anchored)
|
||||
to_chat(user, "<span class='warning'>Anchor the tray first!</span>")
|
||||
return
|
||||
using_irrigation = !using_irrigation
|
||||
O.play_tool_sound(src)
|
||||
user.visible_message("<span class='notice'>[user] [using_irrigation ? "" : "dis"]connects [src]'s irrigation hoses.</span>", \
|
||||
"<span class='notice'>You [using_irrigation ? "" : "dis"]connect [src]'s irrigation hoses.</span>")
|
||||
for(var/obj/machinery/hydroponics/h in range(1,src))
|
||||
h.update_icon()
|
||||
if(canirrigate)
|
||||
using_irrigation = !using_irrigation
|
||||
O.play_tool_sound(src)
|
||||
user.visible_message("<span class='notice'>[user] [using_irrigation ? "" : "dis"]connects [src]'s irrigation hoses.</span>", \
|
||||
"<span class='notice'>You [using_irrigation ? "" : "dis"]connect [src]'s irrigation hoses.</span>")
|
||||
for(var/obj/machinery/hydroponics/h in range(1,src))
|
||||
h.update_icon()
|
||||
|
||||
else if(istype(O, /obj/item/shovel/spade))
|
||||
if(!myseed && !weedlevel)
|
||||
@@ -910,11 +911,14 @@
|
||||
harvest = 0
|
||||
lastproduce = age
|
||||
if(istype(myseed, /obj/item/seeds/replicapod))
|
||||
to_chat(user, "<span class='notice'>You harvest from the [myseed.plantname].</span>")
|
||||
if(user)//runtimes
|
||||
to_chat(user, "<span class='notice'>You harvest from the [myseed.plantname].</span>")
|
||||
else if(myseed.getYield() <= 0)
|
||||
to_chat(user, "<span class='warning'>You fail to harvest anything useful!</span>")
|
||||
if(user)
|
||||
to_chat(user, "<span class='warning'>You fail to harvest anything useful!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You harvest [myseed.getYield()] items from the [myseed.plantname].</span>")
|
||||
if(user)
|
||||
to_chat(user, "<span class='notice'>You harvest [myseed.getYield()] items from the [myseed.plantname].</span>")
|
||||
if(!myseed.get_gene(/datum/plant_gene/trait/repeated_harvest))
|
||||
qdel(myseed)
|
||||
myseed = null
|
||||
|
||||
@@ -190,6 +190,31 @@ obj/item/seeds/proc/is_gene_forbidden(typepath)
|
||||
parent.update_tray(user)
|
||||
return result
|
||||
|
||||
/obj/item/seeds/proc/harvest_userless()
|
||||
var/obj/machinery/hydroponics/parent = loc //for ease of access
|
||||
var/t_amount = 0
|
||||
var/list/result = list()
|
||||
var/output_loc = parent.loc
|
||||
var/product_name
|
||||
while(t_amount < getYield())
|
||||
var/obj/item/reagent_containers/food/snacks/grown/t_prod = new product(output_loc, src)
|
||||
if(parent.myseed.plantname != initial(parent.myseed.plantname))
|
||||
t_prod.name = lowertext(parent.myseed.plantname)
|
||||
if(productdesc)
|
||||
t_prod.desc = productdesc
|
||||
t_prod.seed.name = parent.myseed.name
|
||||
t_prod.seed.desc = parent.myseed.desc
|
||||
t_prod.seed.plantname = parent.myseed.plantname
|
||||
result.Add(t_prod) // User gets a consumable
|
||||
if(!t_prod)
|
||||
return
|
||||
t_amount++
|
||||
product_name = parent.myseed.plantname
|
||||
if(getYield() >= 1)
|
||||
SSblackbox.record_feedback("tally", "food_harvested", getYield(), product_name)
|
||||
parent.investigate_log("autmoatic harvest of [getYield()] of [src], with seed traits [english_list(genes)] and reagents_add [english_list(reagents_add)] and potency [potency].", INVESTIGATE_BOTANY)
|
||||
parent.update_tray()
|
||||
return result
|
||||
|
||||
/obj/item/seeds/proc/prepare_result(var/obj/item/reagent_containers/food/snacks/grown/T)
|
||||
if(!T.reagents)
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
#define MUSIC_MAXLINES 1000
|
||||
#define MUSIC_MAXLINECHARS 300
|
||||
|
||||
/**
|
||||
* # Song datum
|
||||
*
|
||||
* These are the actual backend behind instruments.
|
||||
* They attach to an atom and provide the editor + playback functionality.
|
||||
*/
|
||||
/datum/song
|
||||
/// Name of the song
|
||||
var/name = "Untitled"
|
||||
@@ -15,6 +21,9 @@
|
||||
/// delay between notes in deciseconds
|
||||
var/tempo = 5
|
||||
|
||||
/// How far we can be heard
|
||||
var/instrument_range = 15
|
||||
|
||||
/// Are we currently playing?
|
||||
var/playing = FALSE
|
||||
|
||||
@@ -53,17 +62,24 @@
|
||||
|
||||
/////////////////// Playing variables ////////////////
|
||||
/**
|
||||
* Only used in synthesized playback - The chords we compiled. Non assoc list of lists:
|
||||
* list(list(key1, key2, key3..., tempo_divisor), list(key1, key2..., tempo_divisor), ...)
|
||||
* tempo_divisor always exists
|
||||
* if key1 (and so if there's no keys) doesn't exist it's a rest
|
||||
* Build by compile_chords()
|
||||
* Must be rebuilt on instrument switch.
|
||||
* Compilation happens when we start playing and is cleared after we finish playing.
|
||||
* Format: list of chord lists, with chordlists having (key1, key2, key3, tempodiv)
|
||||
*/
|
||||
var/list/compiled_chords
|
||||
/// Current section of a long chord we're on, so we don't need to make a billion chords, one for every unit ticklag.
|
||||
var/elapsed_delay
|
||||
/// Amount of delay to wait before playing the next chord
|
||||
var/delay_by
|
||||
/// Current chord we're on.
|
||||
var/current_chord
|
||||
/// Channel as text = current volume percentage but it's 0 to 100 instead of 0 to 1.
|
||||
var/list/channels_playing = list()
|
||||
/// List of channels that aren't being used, as text. This is to prevent unnecessary freeing and reallocations from SSsounds/SSinstruments.
|
||||
var/list/channels_idle = list()
|
||||
/// Person playing us
|
||||
var/mob/user_playing
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
/// Last world.time we checked for who can hear us
|
||||
@@ -72,8 +88,6 @@
|
||||
var/list/hearing_mobs
|
||||
/// If this is enabled, some things won't be strictly cleared when they usually are (liked compiled_chords on play stop)
|
||||
var/debug_mode = FALSE
|
||||
/// Last time we processed decay
|
||||
var/last_process_decay
|
||||
/// Max sound channels to occupy
|
||||
var/max_sound_channels = CHANNELS_PER_INSTRUMENT
|
||||
/// Current channels, so we can save a length() call.
|
||||
@@ -113,7 +127,7 @@
|
||||
var/cached_exponential_dropoff = 1.045
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/song/New(atom/parent, list/instrument_ids)
|
||||
/datum/song/New(atom/parent, list/instrument_ids, new_range)
|
||||
SSinstruments.on_song_new(src)
|
||||
lines = list()
|
||||
tempo = sanitize_tempo(tempo)
|
||||
@@ -125,6 +139,8 @@
|
||||
hearing_mobs = list()
|
||||
volume = clamp(volume, min_volume, max_volume)
|
||||
update_sustain()
|
||||
if(new_range)
|
||||
instrument_range = new_range
|
||||
|
||||
/datum/song/Destroy()
|
||||
stop_playing()
|
||||
@@ -135,12 +151,15 @@
|
||||
parent = null
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Checks and stores which mobs can hear us. Terminates sounds for mobs that leave our range.
|
||||
*/
|
||||
/datum/song/proc/do_hearcheck()
|
||||
last_hearcheck = world.time
|
||||
var/list/old = hearing_mobs.Copy()
|
||||
hearing_mobs.len = 0
|
||||
var/turf/source = get_turf(parent)
|
||||
for(var/mob/M in get_hearers_in_view(15, source))
|
||||
for(var/mob/M in get_hearers_in_view(instrument_range, source))
|
||||
if(!(M?.client?.prefs?.toggles & SOUND_INSTRUMENTS))
|
||||
continue
|
||||
hearing_mobs[M] = get_dist(M, source)
|
||||
@@ -148,10 +167,15 @@
|
||||
for(var/i in exited)
|
||||
terminate_sound_mob(i)
|
||||
|
||||
/// I can either be a datum, id, or path (if the instrument has no id).
|
||||
/**
|
||||
* Sets our instrument, caching anything necessary for faster accessing. Accepts an ID, typepath, or instantiated instrument datum.
|
||||
*/
|
||||
/datum/song/proc/set_instrument(datum/instrument/I)
|
||||
terminate_all_sounds()
|
||||
var/old_legacy
|
||||
if(using_instrument)
|
||||
using_instrument.songs_using -= src
|
||||
old_legacy = (using_instrument.instrument_flags & INSTRUMENT_LEGACY)
|
||||
using_instrument = null
|
||||
cached_samples = null
|
||||
cached_legacy_ext = null
|
||||
@@ -162,7 +186,7 @@
|
||||
if(istype(I))
|
||||
using_instrument = I
|
||||
I.songs_using += src
|
||||
var/instrument_legacy = CHECK_BITFIELD(I.instrument_flags, INSTRUMENT_LEGACY)
|
||||
var/instrument_legacy = (I.instrument_flags & INSTRUMENT_LEGACY)
|
||||
if(instrument_legacy)
|
||||
cached_legacy_ext = I.legacy_instrument_ext
|
||||
cached_legacy_dir = I.legacy_instrument_path
|
||||
@@ -170,23 +194,37 @@
|
||||
else
|
||||
cached_samples = I.samples
|
||||
legacy = FALSE
|
||||
if(isnull(old_legacy) || (old_legacy != instrument_legacy))
|
||||
if(playing)
|
||||
compile_chords()
|
||||
|
||||
/// THIS IS A BLOCKING CALL.
|
||||
/**
|
||||
* Attempts to start playing our song.
|
||||
*/
|
||||
/datum/song/proc/start_playing(mob/user)
|
||||
if(playing)
|
||||
return
|
||||
if(!using_instrument?.ready())
|
||||
to_chat(user, "<span class='warning'>An error has occured with [src]. Please reset the instrument.</span>")
|
||||
return
|
||||
compile_chords()
|
||||
if(!length(compiled_chords))
|
||||
to_chat(user, "<span class='warning'>Song is empty.</span>")
|
||||
return
|
||||
playing = TRUE
|
||||
updateDialog()
|
||||
updateDialog(user_playing)
|
||||
//we can not afford to runtime, since we are going to be doing sound channel reservations and if we runtime it means we have a channel allocation leak.
|
||||
//wrap the rest of the stuff to ensure stop_playing() is called.
|
||||
last_process_decay = world.time
|
||||
do_hearcheck()
|
||||
elapsed_delay = 0
|
||||
delay_by = 0
|
||||
current_chord = 1
|
||||
user_playing = user
|
||||
START_PROCESSING(SSinstruments, src)
|
||||
. = do_play_lines(user)
|
||||
stop_playing()
|
||||
|
||||
/**
|
||||
* Stops playing, terminating all sounds if in synthesized mode. Clears hearing_mobs.
|
||||
*/
|
||||
/datum/song/proc/stop_playing()
|
||||
if(!playing)
|
||||
return
|
||||
@@ -196,42 +234,93 @@
|
||||
STOP_PROCESSING(SSinstruments, src)
|
||||
terminate_all_sounds(TRUE)
|
||||
hearing_mobs.len = 0
|
||||
updateDialog()
|
||||
user_playing = null
|
||||
|
||||
/// THIS IS A BLOCKING CALL.
|
||||
/datum/song/proc/do_play_lines(user)
|
||||
if(!playing)
|
||||
/**
|
||||
* Processes our song.
|
||||
*/
|
||||
/datum/song/proc/process_song(wait)
|
||||
if(!length(compiled_chords) || should_stop_playing(user_playing))
|
||||
stop_playing()
|
||||
return
|
||||
do_hearcheck()
|
||||
if(legacy)
|
||||
do_play_lines_legacy(user)
|
||||
else
|
||||
do_play_lines_synthesized(user)
|
||||
var/list/chord = compiled_chords[current_chord]
|
||||
if(++elapsed_delay >= delay_by)
|
||||
play_chord(chord)
|
||||
elapsed_delay = 0
|
||||
delay_by = tempodiv_to_delay(chord[length(chord)])
|
||||
current_chord++
|
||||
if(current_chord > length(compiled_chords))
|
||||
if(repeat)
|
||||
repeat--
|
||||
current_chord = 1
|
||||
return
|
||||
else
|
||||
stop_playing()
|
||||
return
|
||||
|
||||
/**
|
||||
* Converts a tempodiv to ticks to elapse before playing the next chord, taking into account our tempo.
|
||||
*/
|
||||
/datum/song/proc/tempodiv_to_delay(tempodiv)
|
||||
if(!tempodiv)
|
||||
tempodiv = 1 // no division by 0. some song converters tend to use 0 for when it wants to have no div, for whatever reason.
|
||||
return max(1, round((tempo/tempodiv) / world.tick_lag, 1))
|
||||
|
||||
/**
|
||||
* Compiles chords.
|
||||
*/
|
||||
/datum/song/proc/compile_chords()
|
||||
legacy? compile_legacy() : compile_synthesized()
|
||||
|
||||
/**
|
||||
* Plays a chord.
|
||||
*/
|
||||
/datum/song/proc/play_chord(list/chord)
|
||||
// last value is timing information
|
||||
for(var/i in 1 to (length(chord) - 1))
|
||||
legacy? playkey_legacy(chord[i][1], chord[i][2], chord[i][3], user_playing) : playkey_synth(chord[i], user_playing)
|
||||
|
||||
/**
|
||||
* Checks if we should halt playback.
|
||||
*/
|
||||
/datum/song/proc/should_stop_playing(mob/user)
|
||||
return QDELETED(parent) || !using_instrument || !playing
|
||||
|
||||
/**
|
||||
* Sanitizes tempo to a value that makes sense and fits the current world.tick_lag.
|
||||
*/
|
||||
/datum/song/proc/sanitize_tempo(new_tempo)
|
||||
new_tempo = abs(new_tempo)
|
||||
return clamp(round(new_tempo, world.tick_lag), world.tick_lag, 5 SECONDS)
|
||||
|
||||
/**
|
||||
* Gets our beats per minute based on our tempo.
|
||||
*/
|
||||
/datum/song/proc/get_bpm()
|
||||
return 600 / tempo
|
||||
|
||||
/**
|
||||
* Sets our tempo from a beats-per-minute, sanitizing it to a valid number first.
|
||||
*/
|
||||
/datum/song/proc/set_bpm(bpm)
|
||||
tempo = sanitize_tempo(600 / bpm)
|
||||
|
||||
/// Updates the window for our user. Override in subtypes.
|
||||
/datum/song/proc/updateDialog(mob/user = usr)
|
||||
/**
|
||||
* Updates the window for our users. Override down the line.
|
||||
*/
|
||||
/datum/song/proc/updateDialog(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/datum/song/process(wait)
|
||||
if(!playing)
|
||||
return PROCESS_KILL
|
||||
var/delay = world.time - last_process_decay
|
||||
process_decay(delay)
|
||||
last_process_decay = world.time
|
||||
// it's expected this ticks at every world.tick_lag. if it lags, do not attempt to catch up.
|
||||
process_song(world.tick_lag)
|
||||
process_decay(world.tick_lag)
|
||||
|
||||
/**
|
||||
* Updates our cached linear/exponential falloff stuff, saving calculations down the line.
|
||||
*/
|
||||
/datum/song/proc/update_sustain()
|
||||
// Exponential is easy
|
||||
cached_exponential_dropoff = sustain_exponential_dropoff
|
||||
@@ -241,21 +330,33 @@
|
||||
var/volume_decrease_per_decisecond = volume_diff / target_duration
|
||||
cached_linear_dropoff = volume_decrease_per_decisecond
|
||||
|
||||
/**
|
||||
* Setter for setting output volume.
|
||||
*/
|
||||
/datum/song/proc/set_volume(volume)
|
||||
src.volume = clamp(volume, max(0, min_volume), min(100, max_volume))
|
||||
update_sustain()
|
||||
updateDialog()
|
||||
|
||||
/**
|
||||
* Setter for setting how low the volume has to get before a note is considered "dead" and dropped
|
||||
*/
|
||||
/datum/song/proc/set_dropoff_volume(volume)
|
||||
sustain_dropoff_volume = clamp(volume, INSTRUMENT_MIN_SUSTAIN_DROPOFF, 100)
|
||||
update_sustain()
|
||||
updateDialog()
|
||||
|
||||
/**
|
||||
* Setter for setting exponential falloff factor.
|
||||
*/
|
||||
/datum/song/proc/set_exponential_drop_rate(drop)
|
||||
sustain_exponential_dropoff = clamp(drop, INSTRUMENT_EXP_FALLOFF_MIN, INSTRUMENT_EXP_FALLOFF_MAX)
|
||||
update_sustain()
|
||||
updateDialog()
|
||||
|
||||
/**
|
||||
* Setter for setting linear falloff duration.
|
||||
*/
|
||||
/datum/song/proc/set_linear_falloff_duration(duration)
|
||||
sustain_linear_duration = clamp(duration, 0.1, INSTRUMENT_MAX_TOTAL_SUSTAIN)
|
||||
update_sustain()
|
||||
@@ -277,10 +378,8 @@
|
||||
// subtype for handheld instruments, like violin
|
||||
/datum/song/handheld
|
||||
|
||||
/datum/song/handheld/updateDialog(mob/user = usr)
|
||||
if(user.machine != src)
|
||||
return
|
||||
parent.ui_interact(user)
|
||||
/datum/song/handheld/updateDialog(mob/user)
|
||||
parent.ui_interact(user || usr)
|
||||
|
||||
/datum/song/handheld/should_stop_playing(mob/user)
|
||||
. = ..()
|
||||
@@ -292,10 +391,8 @@
|
||||
// subtype for stationary structures, like pianos
|
||||
/datum/song/stationary
|
||||
|
||||
/datum/song/stationary/updateDialog(mob/user = usr)
|
||||
if(user.machine != src)
|
||||
return
|
||||
parent.ui_interact(user)
|
||||
/datum/song/stationary/updateDialog(mob/user)
|
||||
parent.ui_interact(user || usr)
|
||||
|
||||
/datum/song/stationary/should_stop_playing(mob/user)
|
||||
. = ..()
|
||||
|
||||
@@ -1,48 +1,52 @@
|
||||
/// Playing legacy instruments - None of the "advanced" like sound reservations and decay are invoked.
|
||||
/datum/song/proc/do_play_lines_legacy(mob/user)
|
||||
while(repeat >= 0)
|
||||
var/cur_oct[7]
|
||||
var/cur_acc[7]
|
||||
for(var/i = 1 to 7)
|
||||
cur_oct[i] = 3
|
||||
cur_acc[i] = "n"
|
||||
/**
|
||||
* Compiles our lines into "chords" with filenames for legacy playback. This makes there have to be a bit of lag at the beginning of the song, but repeats will not have to parse it again, and overall playback won't be impacted by as much lag.
|
||||
*/
|
||||
/datum/song/proc/compile_legacy()
|
||||
if(!length(src.lines))
|
||||
return
|
||||
var/list/lines = src.lines //cache for hyepr speed!
|
||||
compiled_chords = list()
|
||||
var/list/octaves = list(3, 3, 3, 3, 3, 3, 3)
|
||||
var/list/accents = list("n", "n", "n", "n", "n", "n", "n")
|
||||
for(var/line in lines)
|
||||
var/list/chords = splittext(lowertext(line), ",")
|
||||
for(var/chord in chords)
|
||||
var/list/compiled_chord = list()
|
||||
var/tempodiv = 1
|
||||
var/list/notes_tempodiv = splittext(chord, "/")
|
||||
var/len = length(notes_tempodiv)
|
||||
if(len >= 2)
|
||||
tempodiv = text2num(notes_tempodiv[2])
|
||||
if(len) //some dunkass is going to do ,,,, to make 3 rests instead of ,/1 because there's no standardization so let's be prepared for that.
|
||||
var/list/notes = splittext(notes_tempodiv[1], "-")
|
||||
for(var/note in notes)
|
||||
if(length(note) == 0)
|
||||
continue
|
||||
// 1-7, A-G
|
||||
var/key = text2ascii(note) - 96
|
||||
if((key < 1) || (key > 7))
|
||||
continue
|
||||
for(var/i in 2 to length(note))
|
||||
var/oct_acc = copytext(note, i, i + 1)
|
||||
var/num = text2num(oct_acc)
|
||||
if(!num) //it's an accidental
|
||||
accents[key] = oct_acc //if they misspelled it/fucked up that's on them lmao, no safety checks.
|
||||
else //octave
|
||||
octaves[key] = clamp(num, octave_min, octave_max)
|
||||
compiled_chord[++compiled_chord.len] = list(key, accents[key], octaves[key])
|
||||
compiled_chord += tempodiv //this goes last
|
||||
if(length(compiled_chord))
|
||||
compiled_chords[++compiled_chords.len] = compiled_chord
|
||||
|
||||
for(var/line in lines)
|
||||
for(var/beat in splittext(lowertext(line), ","))
|
||||
if(should_stop_playing(user))
|
||||
return
|
||||
var/list/notes = splittext(beat, "/")
|
||||
if(length(notes)) //because some jack-butts are going to do ,,,, to symbolize 3 rests instead of something reasonable like ,/1.
|
||||
for(var/note in splittext(notes[1], "-"))
|
||||
if(length(note) == 0)
|
||||
continue
|
||||
var/cur_note = text2ascii(note) - 96
|
||||
if(cur_note < 1 || cur_note > 7)
|
||||
continue
|
||||
for(var/i=2 to length(note))
|
||||
var/ni = copytext(note,i,i+1)
|
||||
if(!text2num(ni))
|
||||
if(ni == "#" || ni == "b" || ni == "n")
|
||||
cur_acc[cur_note] = ni
|
||||
else if(ni == "s")
|
||||
cur_acc[cur_note] = "#" // so shift is never required
|
||||
else
|
||||
cur_oct[cur_note] = text2num(ni)
|
||||
playnote_legacy(cur_note, cur_acc[cur_note], cur_oct[cur_note])
|
||||
if(notes.len >= 2 && text2num(notes[2]))
|
||||
sleep(sanitize_tempo(tempo / text2num(notes[2])))
|
||||
else
|
||||
sleep(tempo)
|
||||
if(should_stop_playing(user))
|
||||
return
|
||||
repeat--
|
||||
updateDialog()
|
||||
repeat = 0
|
||||
|
||||
// note is a number from 1-7 for A-G
|
||||
// acc is either "b", "n", or "#"
|
||||
// oct is 1-8 (or 9 for C)
|
||||
/datum/song/proc/playnote_legacy(note, acc as text, oct)
|
||||
/**
|
||||
* Proc to play a legacy note. Just plays the sound to hearing mobs (and does hearcheck if necessary), no fancy channel/sustain/management.
|
||||
*
|
||||
* Arguments:
|
||||
* * note is a number from 1-7 for A-G
|
||||
* * acc is either "b", "n", or "#"
|
||||
* * oct is 1-8 (or 9 for C)
|
||||
*/
|
||||
/datum/song/proc/playkey_legacy(note, acc as text, oct, mob/user)
|
||||
// handle accidental -> B<>C of E<>F
|
||||
if(acc == "b" && (note == 3 || note == 6)) // C or F
|
||||
if(note == 3)
|
||||
|
||||
@@ -1,27 +1,7 @@
|
||||
/datum/song/proc/do_play_lines_synthesized(mob/user)
|
||||
compile_lines()
|
||||
while(repeat >= 0)
|
||||
if(should_stop_playing(user))
|
||||
return
|
||||
var/warned = FALSE
|
||||
for(var/_chord in compiled_chords)
|
||||
if(should_stop_playing(user))
|
||||
return
|
||||
var/list/chord = _chord
|
||||
var/tempodiv = chord[chord.len]
|
||||
for(var/i in 1 to chord.len - 1)
|
||||
var/key = chord[i]
|
||||
if(!playkey_synth(key))
|
||||
if(!warned)
|
||||
warned = TRUE
|
||||
to_chat(user, "<span class='boldwarning'>Your instrument has ran out of channels. You might be playing your song too fast or be setting sustain to too high of a value. This warning will be suppressed for the rest of this cycle.</span>")
|
||||
sleep(sanitize_tempo(tempo / (tempodiv || 1)))
|
||||
repeat--
|
||||
updateDialog()
|
||||
repeat = 0
|
||||
|
||||
/// C-Db2-A-A4/2,A-B#4-C/3,/4,A,A-B-C as an example
|
||||
/datum/song/proc/compile_lines()
|
||||
/**
|
||||
* Compiles our lines into "chords" with numbers. This makes there have to be a bit of lag at the beginning of the song, but repeats will not have to parse it again, and overall playback won't be impacted by as much lag.
|
||||
*/
|
||||
/datum/song/proc/compile_synthesized()
|
||||
if(!length(src.lines))
|
||||
return
|
||||
var/list/lines = src.lines //cache for hyepr speed!
|
||||
@@ -57,10 +37,12 @@
|
||||
compiled_chord += tempodiv //this goes last
|
||||
if(length(compiled_chord))
|
||||
compiled_chords[++compiled_chords.len] = compiled_chord
|
||||
CHECK_TICK
|
||||
return compiled_chords
|
||||
|
||||
/datum/song/proc/playkey_synth(key)
|
||||
/**
|
||||
* Plays a specific numerical key from our instrument to anyone who can hear us.
|
||||
* Does a hearing check if enough time has passed.
|
||||
*/
|
||||
/datum/song/proc/playkey_synth(key, mob/user)
|
||||
if(can_noteshift)
|
||||
key = clamp(key + note_shift, key_min, key_max)
|
||||
if((world.time - MUSICIAN_HEARCHECK_MINDELAY) > last_hearcheck)
|
||||
@@ -83,6 +65,9 @@
|
||||
M.playsound_local(get_turf(parent), null, volume, FALSE, K.frequency, INSTRUMENT_DISTANCE_NO_FALLOFF, channel, null, copy, distance_multiplier = INSTRUMENT_DISTANCE_FALLOFF_BUFF)
|
||||
// Could do environment and echo later but not for now
|
||||
|
||||
/**
|
||||
* Stops all sounds we are "responsible" for. Only works in synthesized mode.
|
||||
*/
|
||||
/datum/song/proc/terminate_all_sounds(clear_channels = TRUE)
|
||||
for(var/i in hearing_mobs)
|
||||
terminate_sound_mob(i)
|
||||
@@ -93,10 +78,16 @@
|
||||
using_sound_channels = 0
|
||||
SSsounds.free_datum_channels(src)
|
||||
|
||||
/**
|
||||
* Stops all sounds we are responsible for in a given person. Only works in synthesized mode.
|
||||
*/
|
||||
/datum/song/proc/terminate_sound_mob(mob/M)
|
||||
for(var/channel in channels_playing)
|
||||
M.stop_sound_channel(text2num(channel))
|
||||
|
||||
/**
|
||||
* Pops a channel we have reserved so we don't have to release and re-request them from SSsounds every time we play a note. This is faster.
|
||||
*/
|
||||
/datum/song/proc/pop_channel()
|
||||
if(length(channels_idle)) //just pop one off of here if we have one available
|
||||
. = text2num(channels_idle[1])
|
||||
@@ -108,6 +99,12 @@
|
||||
if(!isnull(.))
|
||||
using_sound_channels++
|
||||
|
||||
/**
|
||||
* Decays our channels and updates their volumes to mobs who can hear us.
|
||||
*
|
||||
* Arguments:
|
||||
* * wait_ds - the deciseconds we should decay by. This is to compensate for any lag, as otherwise songs would get pretty nasty during high time dilation.
|
||||
*/
|
||||
/datum/song/proc/process_decay(wait_ds)
|
||||
var/linear_dropoff = cached_linear_dropoff * wait_ds
|
||||
var/exponential_dropoff = cached_exponential_dropoff ** wait_ds
|
||||
|
||||
@@ -35,18 +35,20 @@
|
||||
|
||||
return destinations
|
||||
|
||||
/obj/item/wormhole_jaunter/proc/activate(mob/user, adjacent)
|
||||
/obj/item/wormhole_jaunter/proc/activate(mob/user, adjacent, force_entry = FALSE)
|
||||
if(!turf_check(user))
|
||||
return
|
||||
|
||||
var/list/L = get_destinations(user)
|
||||
if(!L.len)
|
||||
to_chat(user, "<span class='notice'>The [src.name] found no beacons in the world to anchor a wormhole to.</span>")
|
||||
to_chat(user, "<span class='notice'>The [name] found no beacons in the world to anchor a wormhole to.</span>")
|
||||
return
|
||||
var/chosen_beacon = pick(L)
|
||||
var/obj/effect/portal/jaunt_tunnel/J = new (get_turf(src), src, 100, null, FALSE, get_turf(chosen_beacon))
|
||||
var/obj/effect/portal/jaunt_tunnel/J = new (get_turf(src), 100, null, FALSE, get_turf(chosen_beacon))
|
||||
if(adjacent)
|
||||
try_move_adjacent(J)
|
||||
if(force_entry)
|
||||
J.teleport(user, force = TRUE)
|
||||
playsound(src,'sound/effects/sparks4.ogg',50,1)
|
||||
qdel(src)
|
||||
|
||||
@@ -73,7 +75,7 @@
|
||||
if(user.get_item_by_slot(SLOT_BELT) == src)
|
||||
to_chat(user, "Your [name] activates, saving you from the chasm!</span>")
|
||||
SSblackbox.record_feedback("tally", "jaunter", 1, "Chasm") // chasm automatic activation
|
||||
activate(user, FALSE)
|
||||
activate(user, FALSE, TRUE)
|
||||
else
|
||||
to_chat(user, "[src] is not attached to your belt, preventing it from saving you from the chasm. RIP.</span>")
|
||||
|
||||
@@ -84,9 +86,10 @@
|
||||
icon_state = "bhole3"
|
||||
desc = "A stable hole in the universe made by a wormhole jaunter. Turbulent doesn't even begin to describe how rough passage through one of these is, but at least it will always get you somewhere near a beacon."
|
||||
mech_sized = TRUE //save your ripley
|
||||
teleport_channel = TELEPORT_CHANNEL_WORMHOLE
|
||||
innate_accuracy_penalty = 6
|
||||
|
||||
/obj/effect/portal/jaunt_tunnel/teleport(atom/movable/M)
|
||||
/obj/effect/portal/jaunt_tunnel/teleport(atom/movable/M, force = FALSE)
|
||||
. = ..()
|
||||
if(.)
|
||||
// KERPLUNK
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
name = "Standard"
|
||||
icon_state = "standard"
|
||||
|
||||
/datum/sprite_accessory/xeno_dorsal/royal
|
||||
name = "Royal"
|
||||
icon_state = "royal"
|
||||
|
||||
/datum/sprite_accessory/xeno_dorsal/down
|
||||
name = "Dorsal Down"
|
||||
icon_state = "down"
|
||||
|
||||
/datum/sprite_accessory/xeno_dorsal/royal
|
||||
name = "Royal"
|
||||
icon_state = "royal"
|
||||
|
||||
/******************************************
|
||||
************* Xeno Tails ******************
|
||||
*******************************************/
|
||||
@@ -57,14 +57,14 @@
|
||||
name = "Standard"
|
||||
icon_state = "standard"
|
||||
|
||||
/datum/sprite_accessory/xeno_head/royal
|
||||
name = "royal"
|
||||
icon_state = "royal"
|
||||
|
||||
/datum/sprite_accessory/xeno_head/hollywood
|
||||
name = "hollywood"
|
||||
icon_state = "hollywood"
|
||||
|
||||
/datum/sprite_accessory/xeno_head/royal
|
||||
name = "royal"
|
||||
icon_state = "royal"
|
||||
|
||||
/datum/sprite_accessory/xeno_head/warrior
|
||||
name = "warrior"
|
||||
icon_state = "warrior"
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
icon_state = "dtiger"
|
||||
gender_specific = 1
|
||||
|
||||
/datum/sprite_accessory/body_markings/guilmon
|
||||
name = "Guilmon"
|
||||
icon_state = "guilmon"
|
||||
color_src = MATRIXED
|
||||
icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
|
||||
|
||||
/datum/sprite_accessory/body_markings/ltiger
|
||||
name = "Light Tiger Body"
|
||||
icon_state = "ltiger"
|
||||
@@ -49,11 +55,6 @@
|
||||
icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
|
||||
relevant_layers = null
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/plain
|
||||
name = "Plain"
|
||||
icon_state = "plain"
|
||||
icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/redpanda
|
||||
name = "Redpanda"
|
||||
icon_state = "redpanda"
|
||||
@@ -77,14 +78,14 @@
|
||||
icon_state = "bellyslim"
|
||||
icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/corgi
|
||||
name = "Corgi"
|
||||
icon_state = "corgi"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/cow
|
||||
name = "Bovine"
|
||||
icon_state = "bovine"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/corgi
|
||||
name = "Corgi"
|
||||
icon_state = "corgi"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/corvid
|
||||
name = "Corvid"
|
||||
icon_state = "corvid"
|
||||
@@ -139,15 +140,19 @@
|
||||
name = "Hyena"
|
||||
icon_state = "hyena"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/lab
|
||||
name = "Lab"
|
||||
icon_state = "lab"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/insect
|
||||
name = "Insect"
|
||||
icon_state = "insect"
|
||||
icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/lab
|
||||
name = "Lab"
|
||||
icon_state = "lab"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/orca
|
||||
name = "Orca"
|
||||
icon_state = "orca"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/otie
|
||||
name = "Otie"
|
||||
icon_state = "otie"
|
||||
@@ -156,14 +161,15 @@
|
||||
name = "Otter"
|
||||
icon_state = "otter"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/orca
|
||||
name = "Orca"
|
||||
icon_state = "orca"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/panther
|
||||
name = "Panther"
|
||||
icon_state = "panther"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/plain
|
||||
name = "Plain"
|
||||
icon_state = "plain"
|
||||
icon = 'modular_citadel/icons/mob/markings_notmammals.dmi'
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/possum
|
||||
name = "Possum"
|
||||
icon_state = "possum"
|
||||
@@ -172,6 +178,10 @@
|
||||
name = "Raccoon"
|
||||
icon_state = "raccoon"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/sergal
|
||||
name = "Sergal"
|
||||
icon_state = "sergal"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/pede
|
||||
name = "Scolipede"
|
||||
icon_state = "scolipede"
|
||||
@@ -181,18 +191,14 @@
|
||||
name = "Shark"
|
||||
icon_state = "shark"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/skunk
|
||||
name = "Skunk"
|
||||
icon_state = "skunk"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/sergal
|
||||
name = "Sergal"
|
||||
icon_state = "sergal"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/shepherd
|
||||
name = "Shepherd"
|
||||
icon_state = "shepherd"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/skunk
|
||||
name = "Skunk"
|
||||
icon_state = "skunk"
|
||||
|
||||
/datum/sprite_accessory/mam_body_markings/tajaran
|
||||
name = "Tajaran"
|
||||
icon_state = "tajaran"
|
||||
@@ -232,75 +238,10 @@
|
||||
icon_state = "none"
|
||||
relevant_layers = null
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/plain
|
||||
name = "Plain"
|
||||
icon_state = "plain"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/reddish
|
||||
name = "Reddish"
|
||||
icon_state = "redish"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/royal
|
||||
name = "Royal"
|
||||
icon_state = "royal"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/gothic
|
||||
name = "Gothic"
|
||||
icon_state = "gothic"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/lovers
|
||||
name = "Lovers"
|
||||
icon_state = "lovers"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/whitefly
|
||||
name = "White Fly"
|
||||
icon_state = "whitefly"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/punished
|
||||
name = "Burnt Off"
|
||||
icon_state = "punished"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/firewatch
|
||||
name = "Firewatch"
|
||||
icon_state = "firewatch"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/deathhead
|
||||
name = "Deathshead"
|
||||
icon_state = "deathhead"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/poison
|
||||
name = "Poison"
|
||||
icon_state = "poison"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/ragged
|
||||
name = "Ragged"
|
||||
icon_state = "ragged"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/moonfly
|
||||
name = "Moon Fly"
|
||||
icon_state = "moonfly"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/snow
|
||||
name = "Snow"
|
||||
icon_state = "snow"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/oakworm
|
||||
name = "Oak Worm"
|
||||
icon_state = "oakworm"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/jungle
|
||||
name = "Jungle"
|
||||
icon_state = "jungle"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/witchwing
|
||||
name = "Witch Wing"
|
||||
icon_state = "witchwing"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/colored
|
||||
name = "Colored (Hair)"
|
||||
icon_state = "snow"
|
||||
color_src = HAIR
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/colored1
|
||||
name = "Colored (Primary)"
|
||||
icon_state = "snow"
|
||||
@@ -314,4 +255,69 @@
|
||||
/datum/sprite_accessory/insect_fluff/colored3
|
||||
name = "Colored (Tertiary)"
|
||||
icon_state = "snow"
|
||||
color_src = MUTCOLORS3
|
||||
color_src = MUTCOLORS3
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/colored
|
||||
name = "Colored (Hair)"
|
||||
icon_state = "snow"
|
||||
color_src = HAIR
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/deathhead
|
||||
name = "Deathshead"
|
||||
icon_state = "deathhead"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/firewatch
|
||||
name = "Firewatch"
|
||||
icon_state = "firewatch"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/gothic
|
||||
name = "Gothic"
|
||||
icon_state = "gothic"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/jungle
|
||||
name = "Jungle"
|
||||
icon_state = "jungle"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/lovers
|
||||
name = "Lovers"
|
||||
icon_state = "lovers"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/moonfly
|
||||
name = "Moon Fly"
|
||||
icon_state = "moonfly"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/oakworm
|
||||
name = "Oak Worm"
|
||||
icon_state = "oakworm"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/plain
|
||||
name = "Plain"
|
||||
icon_state = "plain"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/poison
|
||||
name = "Poison"
|
||||
icon_state = "poison"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/ragged
|
||||
name = "Ragged"
|
||||
icon_state = "ragged"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/reddish
|
||||
name = "Reddish"
|
||||
icon_state = "redish"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/royal
|
||||
name = "Royal"
|
||||
icon_state = "royal"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/snow
|
||||
name = "Snow"
|
||||
icon_state = "snow"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/whitefly
|
||||
name = "White Fly"
|
||||
icon_state = "whitefly"
|
||||
|
||||
/datum/sprite_accessory/insect_fluff/witchwing
|
||||
name = "Witch Wing"
|
||||
icon_state = "witchwing"
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
extra = TRUE
|
||||
extra_color_src = NONE
|
||||
|
||||
/datum/sprite_accessory/ears/human/bigwolfdark
|
||||
/datum/sprite_accessory/ears/human/bigwolfdark //ignore alphabetical sort here for ease-of-use
|
||||
name = "Dark Big Wolf"
|
||||
icon_state = "bigwolfdark"
|
||||
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
|
||||
@@ -55,6 +55,12 @@
|
||||
extra = TRUE
|
||||
extra_color_src = NONE
|
||||
|
||||
/datum/sprite_accessory/ears/bunny
|
||||
name = "Bunny"
|
||||
icon_state = "bunny"
|
||||
color_src = MATRIXED
|
||||
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
|
||||
|
||||
/datum/sprite_accessory/ears/cat
|
||||
name = "Cat"
|
||||
icon_state = "cat"
|
||||
@@ -74,6 +80,12 @@
|
||||
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
|
||||
color_src = MUTCOLORS3
|
||||
|
||||
/datum/sprite_accessory/ears/lab
|
||||
name = "Dog, Floppy"
|
||||
icon_state = "lab"
|
||||
color_src = MATRIXED
|
||||
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
|
||||
|
||||
/datum/sprite_accessory/ears/human/eevee
|
||||
name = "Eevee"
|
||||
icon_state = "eevee"
|
||||
@@ -115,12 +127,6 @@
|
||||
icon_state = "jellyfish"
|
||||
color_src = HAIR
|
||||
|
||||
/datum/sprite_accessory/ears/lab
|
||||
name = "Dog, Floppy"
|
||||
icon_state = "lab"
|
||||
color_src = MATRIXED
|
||||
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
|
||||
|
||||
/datum/sprite_accessory/ears/murid
|
||||
name = "Murid"
|
||||
icon_state = "murid"
|
||||
@@ -133,18 +139,18 @@
|
||||
color_src = MATRIXED
|
||||
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
|
||||
|
||||
/datum/sprite_accessory/ears/human/pede
|
||||
name = "Scolipede"
|
||||
icon_state = "pede"
|
||||
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
|
||||
color_src = MATRIXED
|
||||
|
||||
/datum/sprite_accessory/ears/human/rabbit
|
||||
name = "Rabbit"
|
||||
icon_state = "rabbit"
|
||||
color_src = MATRIXED
|
||||
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
|
||||
|
||||
/datum/sprite_accessory/ears/human/pede
|
||||
name = "Scolipede"
|
||||
icon_state = "pede"
|
||||
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
|
||||
color_src = MATRIXED
|
||||
|
||||
/datum/sprite_accessory/ears/human/sergal
|
||||
name = "Sergal"
|
||||
icon_state = "sergal"
|
||||
@@ -169,12 +175,6 @@
|
||||
color_src = MATRIXED
|
||||
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
|
||||
|
||||
/datum/sprite_accessory/ears/bunny
|
||||
name = "Bunny"
|
||||
icon_state = "bunny"
|
||||
color_src = MATRIXED
|
||||
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
|
||||
|
||||
/******************************************
|
||||
*************** Furry Ears ****************
|
||||
*******************************************/
|
||||
@@ -216,7 +216,7 @@
|
||||
extra = TRUE
|
||||
extra_color_src = NONE
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/bigwolfdark
|
||||
/datum/sprite_accessory/ears/mam_ears/bigwolfdark //alphabetical sort ignored here for ease-of-use
|
||||
name = "Dark Big Wolf"
|
||||
icon_state = "bigwolfdark"
|
||||
|
||||
@@ -226,6 +226,10 @@
|
||||
extra = TRUE
|
||||
extra_color_src = NONE
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/bunny
|
||||
name = "Bunny"
|
||||
icon_state = "bunny"
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/cat
|
||||
name = "Cat"
|
||||
icon_state = "cat"
|
||||
@@ -256,13 +260,11 @@
|
||||
name = "Eevee"
|
||||
icon_state = "eevee"
|
||||
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/elf
|
||||
name = "Elf"
|
||||
icon_state = "elf"
|
||||
color_src = MUTCOLORS3
|
||||
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/elephant
|
||||
name = "Elephant"
|
||||
icon_state = "elephant"
|
||||
@@ -283,15 +285,15 @@
|
||||
name = "Husky"
|
||||
icon_state = "wolf"
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/kangaroo
|
||||
name = "kangaroo"
|
||||
icon_state = "kangaroo"
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/jellyfish
|
||||
name = "Jellyfish"
|
||||
icon_state = "jellyfish"
|
||||
color_src = HAIR
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/kangaroo
|
||||
name = "kangaroo"
|
||||
icon_state = "kangaroo"
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/lab
|
||||
name = "Dog, Long"
|
||||
icon_state = "lab"
|
||||
@@ -304,18 +306,14 @@
|
||||
name = "Otusian"
|
||||
icon_state = "otie"
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/squirrel
|
||||
name = "Squirrel"
|
||||
icon_state = "squirrel"
|
||||
/datum/sprite_accessory/ears/mam_ears/rabbit
|
||||
name = "Rabbit"
|
||||
icon_state = "rabbit"
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/pede
|
||||
name = "Scolipede"
|
||||
icon_state = "pede"
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/rabbit
|
||||
name = "Rabbit"
|
||||
icon_state = "rabbit"
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/sergal
|
||||
name = "Sergal"
|
||||
icon_state = "sergal"
|
||||
@@ -324,10 +322,10 @@
|
||||
name = "skunk"
|
||||
icon_state = "skunk"
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/squirrel
|
||||
name = "Squirrel"
|
||||
icon_state = "squirrel"
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/wolf
|
||||
name = "Wolf"
|
||||
icon_state = "wolf"
|
||||
|
||||
/datum/sprite_accessory/ears/mam_ears/bunny
|
||||
name = "Bunny"
|
||||
icon_state = "bunny"
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
icon_state = "none"
|
||||
relevant_layers = null
|
||||
|
||||
/datum/sprite_accessory/frills/aquatic
|
||||
name = "Aquatic"
|
||||
icon_state = "aqua"
|
||||
|
||||
/datum/sprite_accessory/frills/simple
|
||||
name = "Simple"
|
||||
icon_state = "simple"
|
||||
@@ -18,7 +22,3 @@
|
||||
/datum/sprite_accessory/frills/short
|
||||
name = "Short"
|
||||
icon_state = "short"
|
||||
|
||||
/datum/sprite_accessory/frills/aquatic
|
||||
name = "Aquatic"
|
||||
icon_state = "aqua"
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
gender = MALE // barf (unless you're a dorf, dorfs dig chix w/ beards :P)
|
||||
|
||||
// please make sure they're sorted alphabetically and categorized
|
||||
/datum/sprite_accessory/facial_hair/shaved //this is exempt from the alphabetical sort
|
||||
name = "Shaved"
|
||||
icon_state = null
|
||||
gender = NEUTER
|
||||
|
||||
/datum/sprite_accessory/facial_hair/threeoclock
|
||||
name = "Beard (3 o\'Clock)"
|
||||
@@ -135,11 +139,6 @@
|
||||
name = "Mutton Chops with Moustache"
|
||||
icon_state = "facial_muttonmus"
|
||||
|
||||
/datum/sprite_accessory/facial_hair/shaved
|
||||
name = "Shaved"
|
||||
icon_state = null
|
||||
gender = NEUTER
|
||||
|
||||
/datum/sprite_accessory/facial_hair/sideburn
|
||||
name = "Sideburns"
|
||||
icon_state = "facial_sideburns"
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
// try to spell
|
||||
// you do not need to define _s or _l sub-states, game automatically does this for you
|
||||
|
||||
/datum/sprite_accessory/hair/bald //this is exempt from the alphabetical sort
|
||||
name = "Bald"
|
||||
icon_state = "bald"
|
||||
|
||||
/datum/sprite_accessory/hair/afro
|
||||
name = "Afro"
|
||||
icon_state = "hair_afro"
|
||||
@@ -25,10 +29,6 @@
|
||||
name = "Ahoge"
|
||||
icon_state = "hair_antenna"
|
||||
|
||||
/datum/sprite_accessory/hair/bald
|
||||
name = "Bald"
|
||||
icon_state = "bald"
|
||||
|
||||
/datum/sprite_accessory/hair/balding
|
||||
name = "Balding Hair"
|
||||
icon_state = "hair_e"
|
||||
|
||||
@@ -12,22 +12,10 @@
|
||||
icon_state = "none"
|
||||
relevant_layers = null
|
||||
|
||||
/datum/sprite_accessory/horns/simple
|
||||
name = "Simple"
|
||||
icon_state = "simple"
|
||||
|
||||
/datum/sprite_accessory/horns/short
|
||||
name = "Short"
|
||||
icon_state = "short"
|
||||
|
||||
/datum/sprite_accessory/horns/curled
|
||||
name = "Curled"
|
||||
icon_state = "curled"
|
||||
|
||||
/datum/sprite_accessory/horns/ram
|
||||
name = "Ram"
|
||||
icon_state = "ram"
|
||||
|
||||
/datum/sprite_accessory/horns/angler
|
||||
name = "Angeler"
|
||||
icon_state = "angler"
|
||||
@@ -40,3 +28,15 @@
|
||||
/datum/sprite_accessory/horns/guilmon
|
||||
name = "Guilmon"
|
||||
icon_state = "guilmon"
|
||||
|
||||
/datum/sprite_accessory/horns/ram
|
||||
name = "Ram"
|
||||
icon_state = "ram"
|
||||
|
||||
/datum/sprite_accessory/horns/simple
|
||||
name = "Simple"
|
||||
icon_state = "simple"
|
||||
|
||||
/datum/sprite_accessory/horns/short
|
||||
name = "Short"
|
||||
icon_state = "short"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user