diff --git a/.github/max_required_byond_client.txt b/.github/max_required_byond_client.txt
index faf8058076a2a..bd10125cce940 100644
--- a/.github/max_required_byond_client.txt
+++ b/.github/max_required_byond_client.txt
@@ -5,4 +5,4 @@
# (Requiring clients update to connect to the game server is not something we like to spring on them with no notice,
# especially for beta builds where the pager/updater won't let them update without additional configuration.)
-514
+515
diff --git a/.github/workflows/run_integration_tests.yml b/.github/workflows/run_integration_tests.yml
index 42954b571b6cc..90233292ecb4c 100644
--- a/.github/workflows/run_integration_tests.yml
+++ b/.github/workflows/run_integration_tests.yml
@@ -57,7 +57,7 @@ jobs:
run: |
bash tools/ci/install_byond.sh
source $HOME/BYOND/byond/bin/byondsetup
- tools/build/build --ci dm -DCIBUILDING -DANSICOLORS -WError -NWTG0001
+ tools/build/build --ci dm -DCIBUILDING -DANSICOLORS -Werror -ITG0001 -I"loop_checks"
- name: Run Tests
run: |
source $HOME/BYOND/byond/bin/byondsetup
diff --git a/_maps/map_files/debug/runtimestation.dmm b/_maps/map_files/debug/runtimestation.dmm
index 1c5a88860bea5..584ba1eb7ee9d 100644
--- a/_maps/map_files/debug/runtimestation.dmm
+++ b/_maps/map_files/debug/runtimestation.dmm
@@ -683,6 +683,10 @@
/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/item/disk/data/debug{
+ pixel_y = 9;
+ pixel_x = 7
+ },
/turf/open/floor/iron/white/corner,
/area/station/medical/medbay)
"cL" = (
diff --git a/code/__DEFINES/admin_verb.dm b/code/__DEFINES/admin_verb.dm
index 7e811c121961c..04806e098b2c4 100644
--- a/code/__DEFINES/admin_verb.dm
+++ b/code/__DEFINES/admin_verb.dm
@@ -87,7 +87,7 @@ _ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_categor
#define ADMIN_CATEGORY_OBJECT "Object"
#define ADMIN_CATEGORY_MAPPING "Mapping"
#define ADMIN_CATEGORY_PROFILE "Profile"
-#define ADMIN_CATEGORY_IPINTEL "IPIntel"
+#define ADMIN_CATEGORY_IPINTEL "Admin.IPIntel"
// Visibility flags
#define ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG "Map-Debug"
diff --git a/code/__DEFINES/construction/structures.dm b/code/__DEFINES/construction/structures.dm
index 1b4ea8aa11297..e48dc078ca4bc 100644
--- a/code/__DEFINES/construction/structures.dm
+++ b/code/__DEFINES/construction/structures.dm
@@ -48,9 +48,11 @@
#define AIRLOCK_ASSEMBLY_NEEDS_ELECTRONICS 1
#define AIRLOCK_ASSEMBLY_NEEDS_SCREWDRIVER 2
-//blast door (de)construction states
+///The blast door is missing wires, first step of construction.
#define BLASTDOOR_NEEDS_WIRES 0
+///The blast door needs electronics, second step of construction.
#define BLASTDOOR_NEEDS_ELECTRONICS 1
+///The blast door is fully constructed.
#define BLASTDOOR_FINISHED 2
//floodlights because apparently we use defines now
diff --git a/code/__DEFINES/crafting.dm b/code/__DEFINES/crafting.dm
index 647278aa3ec0b..54dc479aa7306 100644
--- a/code/__DEFINES/crafting.dm
+++ b/code/__DEFINES/crafting.dm
@@ -7,6 +7,28 @@
///If the structure is only "used" i.e. it checks to see if it's nearby and allows crafting, but doesn't delete it
#define CRAFTING_STRUCTURE_USE 0
+//stack recipe placement check types
+/// Checks if there is an object of the result type in any of the cardinal directions
+#define STACK_CHECK_CARDINALS (1<<0)
+/// Checks if there is an object of the result type within one tile
+#define STACK_CHECK_ADJACENT (1<<1)
+
+//---- Defines for var/crafting_flags
+///If this craft must be learned before it becomes available
+#define CRAFT_MUST_BE_LEARNED (1<<0)
+///Should only one object exist on the same turf?
+#define CRAFT_ONE_PER_TURF (1<<1)
+/// Setting this to true will effectively set check_direction to true.
+#define CRAFT_IS_FULLTILE (1<<2)
+/// If this craft should run the direction check, for use when building things like directional windows where you can have more than one per turf
+#define CRAFT_CHECK_DIRECTION (1<<3)
+/// If the craft requires a floor below
+#define CRAFT_ON_SOLID_GROUND (1<<4)
+/// If the craft checks that there are objects with density in the same turf when being built
+#define CRAFT_CHECK_DENSITY (1<<5)
+/// If the created atom will gain custom mat datums
+#define CRAFT_APPLIES_MATS (1<<6)
+
//food/drink crafting defines
//When adding new defines, please make sure to also add them to the encompassing list
#define CAT_FOOD "Foods"
diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm
index cc9e4d2e9666a..5a328a62ef796 100644
--- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm
+++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm
@@ -146,6 +146,8 @@
#define COMPONENT_LIVING_BLOCK_PRE_MOB_BUMP (1<<0)
///From base of mob/living/MobBump() (mob/living)
#define COMSIG_LIVING_MOB_BUMP "living_mob_bump"
+///From base of mob/living/MobBump() (mob/living)
+#define COMSIG_LIVING_MOB_BUMPED "living_mob_bumped"
///From base of mob/living/Bump() (turf/closed)
#define COMSIG_LIVING_WALL_BUMP "living_wall_bump"
///From base of turf/closed/Exited() (turf/closed)
diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm
index 43e3a09a0287d..f628df0e964b4 100644
--- a/code/__DEFINES/dcs/signals/signals_object.dm
+++ b/code/__DEFINES/dcs/signals/signals_object.dm
@@ -448,7 +448,10 @@
/// Prevents click from happening.
#define COMPONENT_CANCEL_EQUIPMENT_CLICK (1<<0)
+///from base of /obj/item/attack(): (mob/living, mob/living, params)
#define COMSIG_ITEM_ATTACK "item_attack"
+///from base of /obj/item/attack(): (mob/living, mob/living, params)
+#define COMSIG_ITEM_POST_ATTACK "item_post_attack" // called only if the attack was executed
///from base of obj/item/attack_self(): (/mob)
#define COMSIG_ITEM_ATTACK_SELF "item_attack_self"
//from base of obj/item/attack_self_secondary(): (/mob)
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index 031244d3d76c1..8d460c3aecb6f 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -346,3 +346,6 @@
#define VOTE_WINNER_METHOD_WEIGHTED_RANDOM "Weighted Random"
/// There is no winner for this vote.
#define VOTE_WINNER_METHOD_NONE "None"
+
+/// Returned by [/datum/vote/proc/can_be_initiated] to denote the vote is valid and can be initiated.
+#define VOTE_AVAILABLE "Vote Available"
diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm
index f2cb9069fb64f..a3218bd5db733 100644
--- a/code/__DEFINES/traits/declarations.dm
+++ b/code/__DEFINES/traits/declarations.dm
@@ -950,6 +950,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define STATION_TRAIT_BIGGER_PODS "station_trait_bigger_pods"
#define STATION_TRAIT_BIRTHDAY "station_trait_birthday"
#define STATION_TRAIT_BOTS_GLITCHED "station_trait_bot_glitch"
+#define STATION_TRAIT_BRIGHT_DAY "station_trait_bright_day"
#define STATION_TRAIT_CARP_INFESTATION "station_trait_carp_infestation"
#define STATION_TRAIT_CYBERNETIC_REVOLUTION "station_trait_cybernetic_revolution"
#define STATION_TRAIT_EMPTY_MAINT "station_trait_empty_maint"
diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm
index 7af30c8d9727c..6811a31284aa4 100644
--- a/code/__HELPERS/_lists.dm
+++ b/code/__HELPERS/_lists.dm
@@ -417,7 +417,7 @@
**/
/proc/list_clear_nulls(list/list_to_clear)
return (list_to_clear.RemoveAll(null) > 0)
-
+
/**
* Removes any empty weakrefs from the list
@@ -473,17 +473,23 @@
* You should only pass integers in.
*/
/proc/pick_weight(list/list_to_pick)
+ if(length(list_to_pick) == 0)
+ return null
+
var/total = 0
- var/item
- for(item in list_to_pick)
+ for(var/item in list_to_pick)
if(!list_to_pick[item])
list_to_pick[item] = 0
total += list_to_pick[item]
total = rand(1, total)
- for(item in list_to_pick)
- total -= list_to_pick[item]
- if(total <= 0 && list_to_pick[item])
+ for(var/item in list_to_pick)
+ var/item_weight = list_to_pick[item]
+ if(item_weight == 0)
+ continue
+
+ total -= item_weight
+ if(total <= 0)
return item
return null
diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index 83294d26180e7..bd991f29d014a 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -2,44 +2,6 @@
/////Initial Building/////
//////////////////////////
-/proc/init_sprite_accessories()
- //hair
- init_sprite_accessory_subtypes(/datum/sprite_accessory/hair, GLOB.hairstyles_list, GLOB.hairstyles_male_list, GLOB.hairstyles_female_list)
- //facial hair
- init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, GLOB.facial_hairstyles_list, GLOB.facial_hairstyles_male_list, GLOB.facial_hairstyles_female_list)
- //underwear
- init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear, GLOB.underwear_list, GLOB.underwear_m, GLOB.underwear_f)
- //undershirt
- init_sprite_accessory_subtypes(/datum/sprite_accessory/undershirt, GLOB.undershirt_list, GLOB.undershirt_m, GLOB.undershirt_f)
- //socks
- init_sprite_accessory_subtypes(/datum/sprite_accessory/socks, GLOB.socks_list)
- //bodypart accessories (blizzard intensifies)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings, GLOB.body_markings_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, GLOB.tails_list_human, add_blank = TRUE)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard, GLOB.tails_list_lizard, add_blank = TRUE)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/monkey, GLOB.tails_list_monkey, add_blank = FALSE)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts, GLOB.snouts_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/horns,GLOB.horns_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.ears_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.wings_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/wings_open, GLOB.wings_open_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/frills, GLOB.frills_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/spines, GLOB.spines_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/tail_spines, GLOB.tail_spines_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/legs, GLOB.legs_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/caps, GLOB.caps_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings, GLOB.moth_wings_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_antennae, GLOB.moth_antennae_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_markings, GLOB.moth_markings_list)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/pod_hair, GLOB.pod_hair_list)
-
-/// Inits GLOB.species_list. Not using GLOBAL_LIST_INIT b/c it depends on GLOB.string_lists
-/proc/init_species_list()
- for(var/species_path in subtypesof(/datum/species))
- var/datum/species/species = new species_path()
- GLOB.species_list[species.id] = species_path
- sort_list(GLOB.species_list, GLOBAL_PROC_REF(cmp_typepaths_asc))
-
/// Inits GLOB.surgeries
/proc/init_surgeries()
var/surgeries = list()
@@ -48,21 +10,9 @@
sort_list(surgeries, GLOBAL_PROC_REF(cmp_typepaths_asc))
return surgeries
-/// Hair Gradients - Initialise all /datum/sprite_accessory/hair_gradient into an list indexed by gradient-style name
-/proc/init_hair_gradients()
- for(var/path in subtypesof(/datum/sprite_accessory/gradient))
- var/datum/sprite_accessory/gradient/gradient = new path()
- if(gradient.gradient_category & GRADIENT_APPLIES_TO_HAIR)
- GLOB.hair_gradients_list[gradient.name] = gradient
- if(gradient.gradient_category & GRADIENT_APPLIES_TO_FACIAL_HAIR)
- GLOB.facial_hair_gradients_list[gradient.name] = gradient
-
/// Legacy procs that really should be replaced with proper _INIT macros
/proc/make_datum_reference_lists()
// I tried to eliminate this proc but I couldn't untangle their init-order interdependencies -Dominion/Cyberboss
- init_sprite_accessories()
- init_species_list()
- init_hair_gradients()
init_keybindings()
GLOB.emote_list = init_emote_list() // WHY DOES THIS NEED TO GO HERE? IT JUST INITS DATUMS
init_crafting_recipes()
diff --git a/code/__HELPERS/hallucinations.dm b/code/__HELPERS/hallucinations.dm
index 1eeab08d87691..edd65ee926abf 100644
--- a/code/__HELPERS/hallucinations.dm
+++ b/code/__HELPERS/hallucinations.dm
@@ -145,7 +145,7 @@ ADMIN_VERB(debug_hallucination_weighted_list_per_type, R_DEBUG, "Show Hallucinat
last_type_weight = this_weight
// Sort by weight descending, where weight is the values (not the keys). We assoc_to_keys later to get JUST the text
- all_weights = sortTim(all_weights, GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE)
+ sortTim(all_weights, GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE)
var/page_style = ""
var/page_contents = "[page_style]
[header][jointext(assoc_to_keys(all_weights), "")]
"
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index 68965248115cd..084e51167eaa6 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -29,31 +29,31 @@
return COLOR_BLACK
/proc/random_underwear(gender)
- if(!GLOB.underwear_list.len)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear, GLOB.underwear_list, GLOB.underwear_m, GLOB.underwear_f)
+ if(length(SSaccessories.underwear_list) == 0)
+ CRASH("No underwear to choose from!")
switch(gender)
if(MALE)
- return pick(GLOB.underwear_m)
+ return pick(SSaccessories.underwear_m)
if(FEMALE)
- return pick(GLOB.underwear_f)
+ return pick(SSaccessories.underwear_f)
else
- return pick(GLOB.underwear_list)
+ return pick(SSaccessories.underwear_list)
/proc/random_undershirt(gender)
- if(!GLOB.undershirt_list.len)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/undershirt, GLOB.undershirt_list, GLOB.undershirt_m, GLOB.undershirt_f)
+ if(length(SSaccessories.undershirt_list) == 0)
+ CRASH("No undershirts to choose from!")
switch(gender)
if(MALE)
- return pick(GLOB.undershirt_m)
+ return pick(SSaccessories.undershirt_m)
if(FEMALE)
- return pick(GLOB.undershirt_f)
+ return pick(SSaccessories.undershirt_f)
else
- return pick(GLOB.undershirt_list)
+ return pick(SSaccessories.undershirt_list)
/proc/random_socks()
- if(!GLOB.socks_list.len)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/socks, GLOB.socks_list)
- return pick(GLOB.socks_list)
+ if(length(SSaccessories.socks_list) == 0)
+ CRASH("No socks to choose from!")
+ return pick(SSaccessories.socks_list)
/proc/random_backpack()
return pick(GLOB.backpacklist)
@@ -61,61 +61,20 @@
/proc/random_hairstyle(gender)
switch(gender)
if(MALE)
- return pick(GLOB.hairstyles_male_list)
+ return pick(SSaccessories.hairstyles_male_list)
if(FEMALE)
- return pick(GLOB.hairstyles_female_list)
+ return pick(SSaccessories.hairstyles_female_list)
else
- return pick(GLOB.hairstyles_list)
+ return pick(SSaccessories.hairstyles_list)
/proc/random_facial_hairstyle(gender)
switch(gender)
if(MALE)
- return pick(GLOB.facial_hairstyles_male_list)
+ return pick(SSaccessories.facial_hairstyles_male_list)
if(FEMALE)
- return pick(GLOB.facial_hairstyles_female_list)
+ return pick(SSaccessories.facial_hairstyles_female_list)
else
- return pick(GLOB.facial_hairstyles_list)
-
-/proc/random_unique_name(gender, attempts_to_find_unique_name=10)
- for(var/i in 1 to attempts_to_find_unique_name)
- if(gender == FEMALE)
- . = capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names))
- else
- . = capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names))
-
- if(!findname(.))
- break
-
-/proc/random_unique_lizard_name(gender, attempts_to_find_unique_name=10)
- for(var/i in 1 to attempts_to_find_unique_name)
- . = capitalize(lizard_name(gender))
-
- if(!findname(.))
- break
-
-/proc/random_unique_plasmaman_name(attempts_to_find_unique_name=10)
- for(var/i in 1 to attempts_to_find_unique_name)
- . = capitalize(plasmaman_name())
-
- if(!findname(.))
- break
-
-/proc/random_unique_ethereal_name(attempts_to_find_unique_name=10)
- for(var/i in 1 to attempts_to_find_unique_name)
- . = capitalize(ethereal_name())
-
- if(!findname(.))
- break
-
-/proc/random_unique_moth_name(attempts_to_find_unique_name=10)
- for(var/i in 1 to attempts_to_find_unique_name)
- . = capitalize(pick(GLOB.moth_first)) + " " + capitalize(pick(GLOB.moth_last))
-
- if(!findname(.))
- break
-
-/proc/random_skin_tone()
- return pick(GLOB.skin_tones)
+ return pick(SSaccessories.facial_hairstyles_list)
GLOBAL_LIST_INIT(skin_tones, sort_list(list(
"albino",
@@ -155,9 +114,6 @@ GLOBAL_LIST_INIT(skin_tone_names, list(
"mixed4" = "Macadamia",
))
-/// An assoc list of species IDs to type paths
-GLOBAL_LIST_EMPTY(species_list)
-
/proc/age2agedescription(age)
switch(age)
if(0 to 1)
diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm
index 12c34d3a705ca..3a82c8dc1a66c 100644
--- a/code/__HELPERS/names.dm
+++ b/code/__HELPERS/names.dm
@@ -1,20 +1,75 @@
-/proc/lizard_name(gender)
- if(gender == MALE)
- return "[pick(GLOB.lizard_names_male)]-[pick(GLOB.lizard_names_male)]"
- else
- return "[pick(GLOB.lizard_names_female)]-[pick(GLOB.lizard_names_female)]"
+/**
+ * Generate a random name based off of one of the roundstart languages
+ *
+ * * gender - What gender to pick from. Picks between male, female if not provided.
+ * * unique - If the name should be unique, IE, avoid picking names that mobs already have.
+ * * list/language_weights - A list of language weights to pick from.
+ * If not provided, it will default to a list of roundstart languages, with common being the most likely.
+ */
+/proc/generate_random_name(gender, unique, list/language_weights)
+ if(isnull(language_weights))
+ language_weights = list()
+ for(var/lang_type in GLOB.uncommon_roundstart_languages)
+ language_weights[lang_type] = 1
+ language_weights[/datum/language/common] = 20
+
+ var/datum/language/picked = GLOB.language_datum_instances[pick_weight(language_weights)]
+ if(unique)
+ return picked.get_random_unique_name(gender)
+ return picked.get_random_name(gender)
+
+/**
+ * Generate a random name based off of a species
+ * This will pick a name from the species language, and avoid picking common if there are alternatives
+ *
+ * * gender - What gender to pick from. Picks between male, female if not provided.
+ * * unique - If the name should be unique, IE, avoid picking names that mobs already have.
+ * * datum/species/species_type - The species to pick from
+ * * include_all - Makes the generated name a mix of all the languages the species can speak rather than just one of them
+ * Does this on a per-name basis, IE "Lizard first name, uncommon last name".
+ */
+/proc/generate_random_name_species_based(gender, unique, datum/species/species_type, include_all = FALSE)
+ ASSERT(ispath(species_type, /datum/species))
+ var/datum/language_holder/holder = GLOB.prototype_language_holders[species_type::species_language_holder]
-/proc/ethereal_name()
- var/tempname = "[pick(GLOB.ethereal_names)] [random_capital_letter()]"
- if(prob(65))
- tempname += random_capital_letter()
- return tempname
+ var/list/languages_to_pick_from = list()
+ for(var/language in holder.spoken_languages)
+ languages_to_pick_from[language] = 1
-/proc/plasmaman_name()
- return "[pick(GLOB.plasmaman_names)] \Roman[rand(1,99)]"
+ if(length(languages_to_pick_from) >= 2)
+ // Basically, if we have alternatives, don't pick common it's boring
+ languages_to_pick_from -= /datum/language/common
-/proc/moth_name()
- return "[pick(GLOB.moth_first)] [pick(GLOB.moth_last)]"
+ if(!include_all || length(languages_to_pick_from) <= 1)
+ return generate_random_name(gender, unique, languages_to_pick_from)
+
+ var/list/name_parts = list()
+ for(var/lang_type in shuffle(languages_to_pick_from))
+ name_parts += GLOB.language_datum_instances[lang_type].get_random_name(gender, name_count = 1, force_use_syllables = TRUE)
+ return jointext(name_parts, " ")
+
+/**
+ * Generates a random name for the mob based on their gender or species (for humans)
+ *
+ * * unique - If the name should be unique, IE, avoid picking names that mobs already have.
+ */
+/mob/proc/generate_random_mob_name(unique)
+ return generate_random_name_species_based(gender, unique, /datum/species/human)
+
+/mob/living/carbon/generate_random_mob_name(unique)
+ return generate_random_name_species_based(gender, unique, dna?.species?.type || /datum/species/human)
+
+/mob/living/silicon/generate_random_mob_name(unique)
+ return generate_random_name(gender, unique, list(/datum/language/machine = 1))
+
+/mob/living/basic/drone/generate_random_mob_name(unique)
+ return generate_random_name(gender, unique, list(/datum/language/machine = 1))
+
+/mob/living/basic/bot/generate_random_mob_name(unique)
+ return generate_random_name(gender, unique, list(/datum/language/machine = 1))
+
+/mob/living/simple_animal/bot/generate_random_mob_name(unique)
+ return generate_random_name(gender, unique, list(/datum/language/machine = 1))
GLOBAL_VAR(command_name)
/proc/command_name()
@@ -194,16 +249,11 @@ GLOBAL_DATUM(syndicate_code_response_regex, /regex)
if(1)//1 and 2 can only be selected once each to prevent more than two specific names/places/etc.
switch(rand(1,2))//Mainly to add more options later.
if(1)
- if(names.len && prob(70))
+ if(length(names) && prob(70))
. += pick(names)
else
- if(prob(10))
- . += pick(lizard_name(MALE),lizard_name(FEMALE))
- else
- var/new_name = pick(pick(GLOB.first_names_male,GLOB.first_names_female))
- new_name += " "
- new_name += pick(GLOB.last_names)
- . += new_name
+ . += generate_random_name()
+
if(2)
var/datum/job/job = pick(SSjob.joinable_occupations)
if(job)
diff --git a/code/__HELPERS/sorts/InsertSort.dm b/code/__HELPERS/sorts/InsertSort.dm
deleted file mode 100644
index 2d5ca408ce3b3..0000000000000
--- a/code/__HELPERS/sorts/InsertSort.dm
+++ /dev/null
@@ -1,19 +0,0 @@
-//simple insertion sort - generally faster than merge for runs of 7 or smaller
-/proc/sortInsert(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex=0)
- if(L && L.len >= 2)
- fromIndex = fromIndex % L.len
- toIndex = toIndex % (L.len+1)
- if(fromIndex <= 0)
- fromIndex += L.len
- if(toIndex <= 0)
- toIndex += L.len + 1
-
- var/datum/sort_instance/SI = GLOB.sortInstance
- if(!SI)
- SI = new
- SI.L = L
- SI.cmp = cmp
- SI.associative = associative
-
- SI.binarySort(fromIndex, toIndex, fromIndex)
- return L
diff --git a/code/__HELPERS/sorts/MergeSort.dm b/code/__HELPERS/sorts/MergeSort.dm
deleted file mode 100644
index 4692534edffd7..0000000000000
--- a/code/__HELPERS/sorts/MergeSort.dm
+++ /dev/null
@@ -1,19 +0,0 @@
-//merge-sort - gernerally faster than insert sort, for runs of 7 or larger
-/proc/sortMerge(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex)
- if(L && L.len >= 2)
- fromIndex = fromIndex % L.len
- toIndex = toIndex % (L.len+1)
- if(fromIndex <= 0)
- fromIndex += L.len
- if(toIndex <= 0)
- toIndex += L.len + 1
-
- var/datum/sort_instance/SI = GLOB.sortInstance
- if(!SI)
- SI = new
- SI.L = L
- SI.cmp = cmp
- SI.associative = associative
-
- SI.mergeSort(fromIndex, toIndex)
- return L
diff --git a/code/__HELPERS/sorts/TimSort.dm b/code/__HELPERS/sorts/TimSort.dm
deleted file mode 100644
index 44f6d170df402..0000000000000
--- a/code/__HELPERS/sorts/TimSort.dm
+++ /dev/null
@@ -1,20 +0,0 @@
-//TimSort interface
-/proc/sortTim(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex=0)
- if(L && L.len >= 2)
- fromIndex = fromIndex % L.len
- toIndex = toIndex % (L.len+1)
- if(fromIndex <= 0)
- fromIndex += L.len
- if(toIndex <= 0)
- toIndex += L.len + 1
-
- var/datum/sort_instance/SI = GLOB.sortInstance
- if(!SI)
- SI = new
-
- SI.L = L
- SI.cmp = cmp
- SI.associative = associative
-
- SI.timSort(fromIndex, toIndex)
- return L
diff --git a/code/__HELPERS/sorts/helpers.dm b/code/__HELPERS/sorts/helpers.dm
new file mode 100644
index 0000000000000..7198286f29fe2
--- /dev/null
+++ b/code/__HELPERS/sorts/helpers.dm
@@ -0,0 +1,95 @@
+/// Sorts the list in place with timSort, default settings.
+#define SORT_TIM(to_sort, associative) if(length(to_sort) >= 2) { \
+ var/datum/sort_instance/sorter = GLOB.sortInstance; \
+ if (isnull(sorter)) { \
+ sorter = new; \
+ } \
+ sorter.L = to_sort; \
+ sorter.cmp = GLOBAL_PROC_REF(cmp_numeric_asc); \
+ sorter.associative = associative; \
+ sorter.timSort(1, 0); \
+}
+
+
+/// Helper for the sorting procs. Prevents some code duplication. Creates /datum/sort_instance/sorter
+#define CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex) \
+ if(length(to_sort) < 2) { \
+ return to_sort; \
+ } \
+ fromIndex = fromIndex % length(to_sort); \
+ toIndex = toIndex % (length(to_sort) + 1); \
+ if (fromIndex <= 0) { \
+ fromIndex += length(to_sort); \
+ } \
+ if (toIndex <= 0) { \
+ toIndex += length(to_sort) + 1; \
+ } \
+ var/datum/sort_instance/sorter = GLOB.sortInstance; \
+ if (isnull(sorter)) { \
+ sorter = new; \
+ } \
+ sorter.L = to_sort; \
+ sorter.cmp = cmp; \
+ sorter.associative = associative;
+
+
+/**
+ * ## Tim Sort
+ * Hybrid sorting algorithm derived from merge sort and insertion sort.
+ *
+ * **Sorts in place**.
+ * You might not need to get the return value.
+ *
+ * @see
+ * https://en.wikipedia.org/wiki/Timsort
+ *
+ * @param {list} to_sort - The list to sort.
+ *
+ * @param {proc} cmp - The comparison proc to use. Default: Numeric ascending.
+ *
+ * @param {boolean} associative - Whether the list is associative. Default: FALSE.
+ *
+ * @param {int} fromIndex - The index to start sorting from. Default: 1.
+ *
+ * @param {int} toIndex - The index to stop sorting at. Default: 0.
+ */
+/proc/sortTim(list/to_sort, cmp = GLOBAL_PROC_REF(cmp_numeric_asc), associative = FALSE, fromIndex = 1, toIndex = 0) as /list
+ CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex)
+
+ sorter.timSort(fromIndex, toIndex)
+
+ return to_sort
+
+
+/**
+ * ## Merge Sort
+ * Divide and conquer sorting algorithm.
+ *
+ * @see
+ * - https://en.wikipedia.org/wiki/Merge_sort
+ */
+/proc/sortMerge(list/to_sort, cmp = GLOBAL_PROC_REF(cmp_numeric_asc), associative = FALSE, fromIndex = 1, toIndex = 0) as /list
+ CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex)
+
+ sorter.mergeSort(fromIndex, toIndex)
+
+ return to_sort
+
+
+/**
+ * ## Insertion Sort
+ * Simple sorting algorithm that builds the final sorted list one item at a time.
+ *
+
+ * @see
+ * - https://en.wikipedia.org/wiki/Insertion_sort
+ */
+/proc/sortInsert(list/to_sort, cmp = GLOBAL_PROC_REF(cmp_numeric_asc), associative = FALSE, fromIndex = 1, toIndex = 0) as /list
+ CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex)
+
+ sorter.binarySort(fromIndex, toIndex)
+
+ return to_sort
+
+
+#undef CREATE_SORT_INSTANCE
diff --git a/code/__HELPERS/sorts/__main.dm b/code/__HELPERS/sorts/sort_instance.dm
similarity index 100%
rename from code/__HELPERS/sorts/__main.dm
rename to code/__HELPERS/sorts/sort_instance.dm
diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm
index ce4d847928988..e7c6368d4d5fd 100644
--- a/code/_globalvars/lists/flavor_misc.dm
+++ b/code/_globalvars/lists/flavor_misc.dm
@@ -1,45 +1,3 @@
-//Preferences stuff
- //Hairstyles
-GLOBAL_LIST_EMPTY(hairstyles_list) //stores /datum/sprite_accessory/hair indexed by name
-GLOBAL_LIST_EMPTY(hairstyles_male_list) //stores only hair names
-GLOBAL_LIST_EMPTY(hairstyles_female_list) //stores only hair names
-GLOBAL_LIST_EMPTY(facial_hairstyles_list) //stores /datum/sprite_accessory/facial_hair indexed by name
-GLOBAL_LIST_EMPTY(facial_hairstyles_male_list) //stores only hair names
-GLOBAL_LIST_EMPTY(facial_hairstyles_female_list) //stores only hair names
-GLOBAL_LIST_EMPTY(hair_gradients_list) //stores /datum/sprite_accessory/hair_gradient indexed by name
-GLOBAL_LIST_EMPTY(facial_hair_gradients_list) //stores /datum/sprite_accessory/facial_hair_gradient indexed by name
- //Underwear
-GLOBAL_LIST_EMPTY(underwear_list) //stores /datum/sprite_accessory/underwear indexed by name
-GLOBAL_LIST_EMPTY(underwear_m) //stores only underwear name
-GLOBAL_LIST_EMPTY(underwear_f) //stores only underwear name
- //Undershirts
-GLOBAL_LIST_EMPTY(undershirt_list) //stores /datum/sprite_accessory/undershirt indexed by name
-GLOBAL_LIST_EMPTY(undershirt_m) //stores only undershirt name
-GLOBAL_LIST_EMPTY(undershirt_f) //stores only undershirt name
- //Socks
-GLOBAL_LIST_EMPTY(socks_list) //stores /datum/sprite_accessory/socks indexed by name
- //Lizard Bits (all datum lists indexed by name)
-GLOBAL_LIST_EMPTY(body_markings_list)
-GLOBAL_LIST_EMPTY(snouts_list)
-GLOBAL_LIST_EMPTY(horns_list)
-GLOBAL_LIST_EMPTY(frills_list)
-GLOBAL_LIST_EMPTY(spines_list)
-GLOBAL_LIST_EMPTY(tail_spines_list)
-GLOBAL_LIST_EMPTY(legs_list)
-
- //Mutant Human bits
-GLOBAL_LIST_EMPTY(tails_list_human)
-GLOBAL_LIST_EMPTY(tails_list_lizard)
-GLOBAL_LIST_EMPTY(tails_list_monkey)
-GLOBAL_LIST_EMPTY(ears_list)
-GLOBAL_LIST_EMPTY(wings_list)
-GLOBAL_LIST_EMPTY(wings_open_list)
-GLOBAL_LIST_EMPTY(moth_wings_list)
-GLOBAL_LIST_EMPTY(moth_antennae_list)
-GLOBAL_LIST_EMPTY(moth_markings_list)
-GLOBAL_LIST_EMPTY(caps_list)
-GLOBAL_LIST_EMPTY(pod_hair_list)
-
GLOBAL_LIST_INIT(color_list_ethereal, list(
"Blue" = "#3399ff",
"Bright Yellow" = "#ffff99",
diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm
index 4e33aa43708a2..692704be0fffd 100644
--- a/code/_globalvars/lists/mobs.dm
+++ b/code/_globalvars/lists/mobs.dm
@@ -85,11 +85,54 @@ GLOBAL_LIST_EMPTY(revenant_relay_mobs)
///underages who have been reported to security for trying to buy things they shouldn't, so they can't spam
GLOBAL_LIST_EMPTY(narcd_underages)
+/// List of language prototypes to reference, assoc [type] = prototype
+GLOBAL_LIST_INIT_TYPED(language_datum_instances, /datum/language, init_language_prototypes())
+/// List if all language typepaths learnable, IE, those with keys
+GLOBAL_LIST_INIT(all_languages, init_all_languages())
+// /List of language prototypes to reference, assoc "name" = typepath
+GLOBAL_LIST_INIT(language_types_by_name, init_language_types_by_name())
+
+/proc/init_language_prototypes()
+ var/list/lang_list = list()
+ for(var/datum/language/lang_type as anything in typesof(/datum/language))
+ if(!initial(lang_type.key))
+ continue
+
+ lang_list[lang_type] = new lang_type()
+ return lang_list
-GLOBAL_LIST_EMPTY(language_datum_instances)
-GLOBAL_LIST_EMPTY(all_languages)
-///List of all languages ("name" = type)
-GLOBAL_LIST_EMPTY(language_types_by_name)
+/proc/init_all_languages()
+ var/list/lang_list = list()
+ for(var/datum/language/lang_type as anything in typesof(/datum/language))
+ if(!initial(lang_type.key))
+ continue
+ lang_list += lang_type
+ return lang_list
+
+/proc/init_language_types_by_name()
+ var/list/lang_list = list()
+ for(var/datum/language/lang_type as anything in typesof(/datum/language))
+ if(!initial(lang_type.key))
+ continue
+ lang_list[initial(lang_type.name)] = lang_type
+ return lang_list
+
+/// An assoc list of species IDs to type paths
+GLOBAL_LIST_INIT(species_list, init_species_list())
+/// List of all species prototypes to reference, assoc [type] = prototype
+GLOBAL_LIST_INIT_TYPED(species_prototypes, /datum/species, init_species_prototypes())
+
+/proc/init_species_list()
+ var/list/species_list = list()
+ for(var/datum/species/species_path as anything in subtypesof(/datum/species))
+ species_list[initial(species_path.id)] = species_path
+ return species_list
+
+/proc/init_species_prototypes()
+ var/list/species_list = list()
+ for(var/species_type in subtypesof(/datum/species))
+ species_list[species_type] = new species_type()
+ return species_list
GLOBAL_LIST_EMPTY(sentient_disease_instances)
diff --git a/code/_globalvars/lists/names.dm b/code/_globalvars/lists/names.dm
index c51fbaa9eb7a0..81fe08373b31a 100644
--- a/code/_globalvars/lists/names.dm
+++ b/code/_globalvars/lists/names.dm
@@ -8,12 +8,12 @@ GLOBAL_LIST_INIT(first_names, world.file2list("strings/names/first.txt"))
GLOBAL_LIST_INIT(first_names_male, world.file2list("strings/names/first_male.txt"))
GLOBAL_LIST_INIT(first_names_female, world.file2list("strings/names/first_female.txt"))
GLOBAL_LIST_INIT(last_names, world.file2list("strings/names/last.txt"))
-GLOBAL_LIST_INIT(lizard_names_male, world.file2list("strings/names/lizard_male.txt"))
-GLOBAL_LIST_INIT(lizard_names_female, world.file2list("strings/names/lizard_female.txt"))
GLOBAL_LIST_INIT(clown_names, world.file2list("strings/names/clown.txt"))
GLOBAL_LIST_INIT(mime_names, world.file2list("strings/names/mime.txt"))
GLOBAL_LIST_INIT(religion_names, world.file2list("strings/names/religion.txt"))
GLOBAL_LIST_INIT(carp_names, world.file2list("strings/names/carp.txt"))
+GLOBAL_LIST_INIT(lizard_names_male, world.file2list("strings/names/lizard_male.txt"))
+GLOBAL_LIST_INIT(lizard_names_female, world.file2list("strings/names/lizard_female.txt"))
GLOBAL_LIST_INIT(golem_names, world.file2list("strings/names/golem.txt"))
GLOBAL_LIST_INIT(moth_first, world.file2list("strings/names/moth_first.txt"))
GLOBAL_LIST_INIT(moth_last, world.file2list("strings/names/moth_last.txt"))
diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm
index dd0c89c2211c8..91ea4d2be0033 100644
--- a/code/_globalvars/traits/_traits.dm
+++ b/code/_globalvars/traits/_traits.dm
@@ -79,6 +79,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"STATION_TRAIT_BIGGER_PODS" = STATION_TRAIT_BIGGER_PODS,
"STATION_TRAIT_BIRTHDAY" = STATION_TRAIT_BIRTHDAY,
"STATION_TRAIT_BOTS_GLITCHED" = STATION_TRAIT_BOTS_GLITCHED,
+ "STATION_TRAIT_BRIGHT_DAY" = STATION_TRAIT_BRIGHT_DAY,
"STATION_TRAIT_CARP_INFESTATION" = STATION_TRAIT_CARP_INFESTATION,
"STATION_TRAIT_CYBERNETIC_REVOLUTION" = STATION_TRAIT_CYBERNETIC_REVOLUTION,
"STATION_TRAIT_EMPTY_MAINT" = STATION_TRAIT_EMPTY_MAINT,
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index be4a481e6773c..9fa8fbf7ff1a2 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -236,6 +236,8 @@
user.do_attack_animation(target_mob)
target_mob.attacked_by(src, user)
+ SEND_SIGNAL(src, COMSIG_ITEM_POST_ATTACK, target_mob, user, params)
+
log_combat(user, target_mob, "attacked", src.name, "(COMBAT MODE: [uppertext(user.combat_mode)]) (DAMTYPE: [uppertext(damtype)])")
add_fingerprint(user)
diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index 368ae3a384035..068f857c8cb31 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -347,6 +347,16 @@
min_val = 0
integer = FALSE
+/datum/config_entry/number/events_frequency_lower
+ default = 2.5 MINUTES
+ min_val = 0
+ protection = CONFIG_ENTRY_LOCKED
+
+/datum/config_entry/number/events_frequency_upper
+ default = 7 MINUTES
+ min_val = 0
+ protection = CONFIG_ENTRY_LOCKED
+
/datum/config_entry/number/mice_roundstart
default = 10
min_val = 0
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
index 5292e47ecd654..69b3bbcad64f6 100644
--- a/code/controllers/configuration/entries/general.dm
+++ b/code/controllers/configuration/entries/general.dm
@@ -184,13 +184,13 @@
/// minimum time between voting sessions (deciseconds, 10 minute default)
/datum/config_entry/number/vote_delay
- default = 6000
+ default = 10 MINUTES
integer = FALSE
min_val = 0
/// length of voting period (deciseconds, default 1 minute)
/datum/config_entry/number/vote_period
- default = 600
+ default = 1 MINUTES
integer = FALSE
min_val = 0
@@ -453,7 +453,7 @@
/datum/config_entry/string/ipintel_email
/datum/config_entry/string/ipintel_email/ValidateAndSet(str_val)
- return str_val != "ch@nge.me" && ..()
+ return str_val != "ch@nge.me" && (!length(str_val) || findtext(str_val, "@")) && ..()
/datum/config_entry/number/ipintel_rating_bad
default = 1
@@ -462,25 +462,25 @@
max_val = 1
/datum/config_entry/flag/ipintel_reject_rate_limited
- default = TRUE
+ default = FALSE
/datum/config_entry/flag/ipintel_reject_bad
- default = TRUE
+ default = FALSE
/datum/config_entry/flag/ipintel_reject_unknown
default = FALSE
/datum/config_entry/number/ipintel_rate_minute
default = 15
-
-/datum/config_entry/number/ipintel_rate_day
- default = 500
+ min_val = 0
/datum/config_entry/number/ipintel_cache_length
default = 7
+ min_val = 0
/datum/config_entry/number/ipintel_exempt_playtime_living
- default = 0
+ default = 5
+ min_val = 0
/datum/config_entry/flag/aggressive_changelog
diff --git a/code/controllers/subsystem/dcs.dm b/code/controllers/subsystem/dcs.dm
index eefbede308739..a3dcc26af54fb 100644
--- a/code/controllers/subsystem/dcs.dm
+++ b/code/controllers/subsystem/dcs.dm
@@ -84,7 +84,7 @@ PROCESSING_SUBSYSTEM_DEF(dcs)
fullid += REF(key)
if(named_arguments)
- named_arguments = sortTim(named_arguments, GLOBAL_PROC_REF(cmp_text_asc))
+ sortTim(named_arguments, GLOBAL_PROC_REF(cmp_text_asc))
fullid += named_arguments
return list2params(fullid)
diff --git a/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm b/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm
index 51ecd59925a4d..1f315391a8f2c 100644
--- a/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm
+++ b/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm
@@ -135,10 +135,7 @@ GLOBAL_VAR_INIT(revolutionary_win, FALSE)
/datum/dynamic_ruleset/roundstart/traitorbro/execute()
for (var/datum/mind/mind in assigned)
- var/datum/team/brother_team/team = new
- team.add_member(mind)
- team.forge_brother_objectives()
- mind.add_antag_datum(/datum/antagonist/brother, team)
+ new /datum/team/brother_team(mind)
GLOB.pre_setup_antags -= mind
return TRUE
diff --git a/code/controllers/subsystem/events.dm b/code/controllers/subsystem/events.dm
index 362129f130570..50e437195a74a 100644
--- a/code/controllers/subsystem/events.dm
+++ b/code/controllers/subsystem/events.dm
@@ -23,6 +23,10 @@ SUBSYSTEM_DEF(events)
if(!event.typepath || !event.valid_for_map())
continue //don't want this one! leave it for the garbage collector
control += event //add it to the list of all events (controls)
+
+ frequency_lower = CONFIG_GET(number/events_frequency_lower)
+ frequency_upper = CONFIG_GET(number/events_frequency_upper)
+
reschedule()
// Instantiate our holidays list if it hasn't been already
if(isnull(GLOB.holidays))
@@ -85,7 +89,8 @@ SUBSYSTEM_DEF(events)
event_roster[event_to_check] = event_to_check.weight
var/datum/round_event_control/event_to_run = pick_weight(event_roster)
- TriggerEvent(event_to_run)
+ if(event_to_run)
+ TriggerEvent(event_to_run)
///Does the last pre-flight checks for the passed event, and runs it if the event is ready.
/datum/controller/subsystem/events/proc/TriggerEvent(datum/round_event_control/event_to_trigger)
@@ -103,8 +108,8 @@ SUBSYSTEM_DEF(events)
///Sets the event frequency bounds back to their initial value.
/datum/controller/subsystem/events/proc/resetFrequency()
- frequency_lower = initial(frequency_lower)
- frequency_upper = initial(frequency_upper)
+ frequency_lower = CONFIG_GET(number/events_frequency_lower)
+ frequency_upper = CONFIG_GET(number/events_frequency_upper)
/**
* HOLIDAYS
diff --git a/code/controllers/subsystem/ipintel.dm b/code/controllers/subsystem/ipintel.dm
index 3f1c738b09c0e..0f162e2a8616f 100644
--- a/code/controllers/subsystem/ipintel.dm
+++ b/code/controllers/subsystem/ipintel.dm
@@ -1,26 +1,14 @@
SUBSYSTEM_DEF(ipintel)
name = "XKeyScore"
init_order = INIT_ORDER_XKEYSCORE
- flags = SS_INIT_NO_NEED|SS_NO_FIRE
+ flags = SS_NO_INIT|SS_NO_FIRE
/// The threshold for probability to be considered a VPN and/or bad IP
var/probability_threshold
- /// The email used in conjuction with https://check.getipintel.net/check.php
- var/contact_email
- /// Maximum number of queries per minute
- var/max_queries_per_minute
- /// Maximum number of queries per day
- var/max_queries_per_day
- /// Query base
- var/query_base
- /// The length of time (days) to cache IP intel
- var/ipintel_cache_length
- /// The living playtime (minutes) for players to be exempt from IPIntel checks
- var/exempt_living_playtime
/// Cache for previously queried IP addresses and those stored in the database
var/list/datum/ip_intel/cached_queries = list()
/// The store for rate limiting
- var/list/rate_limits
+ var/list/rate_limit_minute
/// The ip intel for a given address
/datum/ip_intel
@@ -30,47 +18,39 @@ SUBSYSTEM_DEF(ipintel)
var/address
var/date
-/datum/controller/subsystem/ipintel/Initialize()
+/datum/controller/subsystem/ipintel/OnConfigLoad()
var/list/fail_messages = list()
- probability_threshold = CONFIG_GET(number/ipintel_rating_bad)
- if(probability_threshold < 0 || probability_threshold > 1)
- fail_messages += list("invalid probability threshold")
+ var/contact_email = CONFIG_GET(string/ipintel_email)
- contact_email = CONFIG_GET(string/ipintel_email)
- if(isnull(contact_email) || !findtext(contact_email, "@"))
- fail_messages += list("invalid contact email")
+ if(!length(contact_email))
+ fail_messages += "No contact email"
- var/max_queries_per_minute = CONFIG_GET(number/ipintel_rate_minute)
- var/max_queries_per_day = CONFIG_GET(number/ipintel_rate_day)
- if(max_queries_per_minute < 0 || max_queries_per_day < 0)
- fail_messages += list("invalid rate limits")
+ if(!findtext(contact_email, "@"))
+ fail_messages += "Invalid contact email"
- var/query_base = CONFIG_GET(string/ipintel_base)
- if(isnull(query_base))
- fail_messages += list("invalid query base")
+ if(!length(CONFIG_GET(string/ipintel_base)))
+ fail_messages += "Invalid query base"
- var/ipintel_cache_length = CONFIG_GET(number/ipintel_cache_length)
- if(ipintel_cache_length < 0)
- fail_messages += list("invalid cache length")
-
- var/exempt_living_playtime = CONFIG_GET(number/ipintel_exempt_playtime_living)
- if(exempt_living_playtime < 0)
- fail_messages += list("invalid exempt living playtime")
+ if (!CONFIG_GET(flag/sql_enabled))
+ fail_messages += "The database is not enabled"
if(length(fail_messages))
message_admins("IPIntel: Initialization failed check logs!")
- logger.Log(LOG_CATEGORY_GAME_ACCESS, "IPIntel failed to initialize.", list(
+ logger.Log(LOG_CATEGORY_GAME_ACCESS, "IPIntel is not enabled because the configs are not valid.", list(
"fail_messages" = fail_messages,
))
- return SS_INIT_FAILURE
-
- return SS_INIT_SUCCESS
/datum/controller/subsystem/ipintel/stat_entry(msg)
- return "[..()] | D: [max_queries_per_day - rate_limits[IPINTEL_RATE_LIMIT_DAY]] | M: [max_queries_per_minute - rate_limits[IPINTEL_RATE_LIMIT_MINUTE]]"
+ return "[..()] | M: [CONFIG_GET(number/ipintel_rate_minute) - rate_limit_minute]"
+
+
+/datum/controller/subsystem/ipintel/proc/is_enabled()
+ return length(CONFIG_GET(string/ipintel_email)) && length(CONFIG_GET(string/ipintel_base)) && CONFIG_GET(flag/sql_enabled)
/datum/controller/subsystem/ipintel/proc/get_address_intel_state(address, probability_override)
+ if (!is_enabled())
+ return IPINTEL_GOOD_IP
var/datum/ip_intel/intel = query_address(address)
if(isnull(intel))
stack_trace("query_address did not return an ip intel response")
@@ -81,7 +61,7 @@ SUBSYSTEM_DEF(ipintel)
if(!(intel.query_status in list("success", "cached")))
return IPINTEL_UNKNOWN_QUERY_ERROR
- var/check_probability = probability_override || probability_threshold
+ var/check_probability = probability_override || CONFIG_GET(number/ipintel_rating_bad)
if(intel.result >= check_probability)
return IPINTEL_BAD_IP
return IPINTEL_GOOD_IP
@@ -92,40 +72,40 @@ SUBSYSTEM_DEF(ipintel)
if(minute_key != expected_minute_key)
minute_key = expected_minute_key
- rate_limits[IPINTEL_RATE_LIMIT_MINUTE] = 0
+ rate_limit_minute = 0
- if(rate_limits[IPINTEL_RATE_LIMIT_MINUTE] >= max_queries_per_minute)
+ if(rate_limit_minute >= CONFIG_GET(number/ipintel_rate_minute))
return IPINTEL_RATE_LIMITED_MINUTE
- if(rate_limits[IPINTEL_RATE_LIMIT_DAY] >= max_queries_per_day)
- return IPINTEL_RATE_LIMITED_DAY
return FALSE
/datum/controller/subsystem/ipintel/proc/query_address(address, allow_cached = TRUE)
+ if (!is_enabled())
+ return
if(allow_cached && fetch_cached_ip_intel(address))
return cached_queries[address]
var/is_rate_limited = is_rate_limited()
if(is_rate_limited)
return is_rate_limited
- if(!initialized)
- return IPINTEL_UNKNOWN_INTERNAL_ERROR
-
- rate_limits[IPINTEL_RATE_LIMIT_MINUTE] += 1
- rate_limits[IPINTEL_RATE_LIMIT_DAY] += 1
+ rate_limit_minute += 1
- var/query_base = "https://[src.query_base]/check.php?ip="
- var/query = "[query_base][address]&contact=[contact_email]&flags=b&format=json"
+ var/query_base = "https://[CONFIG_GET(string/ipintel_base)]/check.php?ip="
+ var/query = "[query_base][address]&contact=[CONFIG_GET(string/ipintel_email)]&flags=b&format=json"
var/datum/http_request/request = new
request.prepare(RUSTG_HTTP_METHOD_GET, query)
request.execute_blocking()
var/datum/http_response/response = request.into_response()
- var/list/data = response.body
+ var/list/data = json_decode(response.body)
+ // Log the response
+ logger.Log(LOG_CATEGORY_DEBUG, "ip check response body", data)
var/datum/ip_intel/intel = new
intel.query_status = data["status"]
if(intel.query_status != "success")
return intel
intel.result = data["result"]
+ if(istext(intel.result))
+ intel.result = text2num(intel.result)
intel.date = SQLtime()
intel.address = address
cached_queries[address] = intel
@@ -133,6 +113,9 @@ SUBSYSTEM_DEF(ipintel)
return intel
/datum/controller/subsystem/ipintel/proc/add_intel_to_database(datum/ip_intel/intel)
+ set waitfor = FALSE //no need to make the client connection wait for this step.
+ if (!SSdbcore.Connect())
+ return
var/datum/db_query/query = SSdbcore.NewQuery(
"INSERT INTO [format_table_name("ipintel")] ( \
ip, \
@@ -150,13 +133,17 @@ SUBSYSTEM_DEF(ipintel)
qdel(query)
/datum/controller/subsystem/ipintel/proc/fetch_cached_ip_intel(address)
- var/date_restrictor
- if(ipintel_cache_length > 0)
- date_restrictor = " AND date > DATE_SUB(NOW(), INTERVAL [ipintel_cache_length] DAY)"
+ if (!SSdbcore.Connect())
+ return
+ var/ipintel_cache_length = CONFIG_GET(number/ipintel_cache_length)
+ var/date_restrictor = ""
+ var/sql_args = list("address" = address)
+ if(ipintel_cache_length > 1)
+ date_restrictor = " AND date > DATE_SUB(NOW(), INTERVAL :ipintel_cache_length DAY)"
+ sql_args["ipintel_cache_length"] = ipintel_cache_length
var/datum/db_query/query = SSdbcore.NewQuery(
- "SELECT * FROM [format_table_name("ipintel")] WHERE ip = INET_ATON(:address)[date_restrictor]", list(
- "address" = address
- )
+ "SELECT * FROM [format_table_name("ipintel")] WHERE ip = INET_ATON(:address)[date_restrictor]",
+ sql_args
)
query.warn_execute()
query.sync()
@@ -173,11 +160,16 @@ SUBSYSTEM_DEF(ipintel)
var/datum/ip_intel/intel = new
intel.query_status = "cached"
intel.result = data["intel"]
+ if(istext(intel.result))
+ intel.result = text2num(intel.result)
intel.date = data["date"]
intel.address = address
return TRUE
/datum/controller/subsystem/ipintel/proc/is_exempt(client/player)
+ if(player.holder || GLOB.deadmins[player.ckey])
+ return TRUE
+ var/exempt_living_playtime = CONFIG_GET(number/ipintel_exempt_playtime_living)
if(exempt_living_playtime > 0)
var/list/play_records = player.prefs.exp
if (!play_records.len)
@@ -199,9 +191,13 @@ SUBSYSTEM_DEF(ipintel)
qdel(query)
return FALSE
query.NextRow()
- return !!query.item // if they have a row, they are whitelisted
+ . = !!query.item // if they have a row, they are whitelisted
+ qdel(query)
+
ADMIN_VERB(ipintel_allow, R_BAN, "Whitelist Player VPN", "Allow a player to connect even if they are using a VPN.", ADMIN_CATEGORY_IPINTEL, ckey as text)
+ if (!SSipintel.is_enabled())
+ to_chat(user, "The ipintel system is not currently enabled but you can still edit the whitelists")
if(SSipintel.is_whitelisted(ckey))
to_chat(user, "Player is already whitelisted.")
return
@@ -224,6 +220,8 @@ ADMIN_VERB(ipintel_allow, R_BAN, "Whitelist Player VPN", "Allow a player to conn
message_admins("IPINTEL: [key_name_admin(user)] has whitelisted '[ckey]'")
ADMIN_VERB(ipintel_revoke, R_BAN, "Revoke Player VPN Whitelist", "Revoke a player's VPN whitelist.", ADMIN_CATEGORY_IPINTEL, ckey as text)
+ if (!SSipintel.is_enabled())
+ to_chat(user, "The ipintel system is not currently enabled but you can still edit the whitelists")
if(!SSipintel.is_whitelisted(ckey))
to_chat(user, "Player is not whitelisted.")
return
@@ -238,6 +236,8 @@ ADMIN_VERB(ipintel_revoke, R_BAN, "Revoke Player VPN Whitelist", "Revoke a playe
message_admins("IPINTEL: [key_name_admin(user)] has revoked the VPN whitelist for '[ckey]'")
/client/proc/check_ip_intel()
+ if (!SSipintel.is_enabled())
+ return
if(SSipintel.is_exempt(src) || SSipintel.is_whitelisted(ckey))
return
diff --git a/code/controllers/subsystem/language.dm b/code/controllers/subsystem/language.dm
deleted file mode 100644
index 88e92e2f93c5f..0000000000000
--- a/code/controllers/subsystem/language.dm
+++ /dev/null
@@ -1,17 +0,0 @@
-SUBSYSTEM_DEF(language)
- name = "Language"
- init_order = INIT_ORDER_LANGUAGE
- flags = SS_NO_FIRE
-
-/datum/controller/subsystem/language/Initialize()
- for(var/datum/language/language as anything in subtypesof(/datum/language))
- if(!initial(language.key))
- continue
-
- GLOB.all_languages += language
- GLOB.language_types_by_name[initial(language.name)] = language
-
- var/datum/language/instance = new language
- GLOB.language_datum_instances[language] = instance
-
- return SS_INIT_SUCCESS
diff --git a/code/controllers/subsystem/materials.dm b/code/controllers/subsystem/materials.dm
index b4664323eebfa..3a704d01a82fd 100644
--- a/code/controllers/subsystem/materials.dm
+++ b/code/controllers/subsystem/materials.dm
@@ -21,15 +21,15 @@ SUBSYSTEM_DEF(materials)
var/list/list/material_combos
///List of stackcrafting recipes for materials using base recipes
var/list/base_stack_recipes = list(
- new /datum/stack_recipe("Chair", /obj/structure/chair/greyscale, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("Toilet", /obj/structure/toilet/greyscale, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("Sink Frame", /obj/structure/sinkframe, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("Material floor tile", /obj/item/stack/tile/material, 1, 4, 20, applies_mats = TRUE, check_density = FALSE, category = CAT_TILES),
- new /datum/stack_recipe("Material airlock assembly", /obj/structure/door_assembly/door_assembly_material, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS),
+ new /datum/stack_recipe("Chair", /obj/structure/chair/greyscale, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_FURNITURE),
+ new /datum/stack_recipe("Toilet", /obj/structure/toilet/greyscale, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_FURNITURE),
+ new /datum/stack_recipe("Sink Frame", /obj/structure/sinkframe, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_FURNITURE),
+ new /datum/stack_recipe("Material floor tile", /obj/item/stack/tile/material, 1, 4, 20, crafting_flags = CRAFT_APPLIES_MATS, category = CAT_TILES),
+ new /datum/stack_recipe("Material airlock assembly", /obj/structure/door_assembly/door_assembly_material, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS),
)
///List of stackcrafting recipes for materials using rigid recipes
var/list/rigid_stack_recipes = list(
- new /datum/stack_recipe("Carving block", /obj/structure/carving_block, 5, time = 3 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_STRUCTURE),
+ new /datum/stack_recipe("Carving block", /obj/structure/carving_block, 5, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_STRUCTURE),
)
///A list of dimensional themes used by the dimensional anomaly and other things, most of which require materials to function.
diff --git a/code/controllers/subsystem/sprite_accessories.dm b/code/controllers/subsystem/sprite_accessories.dm
new file mode 100644
index 0000000000000..ec5934ac8e8d4
--- /dev/null
+++ b/code/controllers/subsystem/sprite_accessories.dm
@@ -0,0 +1,154 @@
+/// The non gender specific list that we get from init_sprite_accessory_subtypes()
+#define DEFAULT_SPRITE_LIST "default_sprites"
+/// The male specific list that we get from init_sprite_accessory_subtypes()
+#define MALE_SPRITE_LIST "male_sprites"
+/// The female specific list that we get from init_sprite_accessory_subtypes()
+#define FEMALE_SPRITE_LIST "female_sprites"
+
+/// subsystem that just holds lists of sprite accessories for accession in generating said sprites.
+/// A sprite accessory is something that we add to a human sprite to make them look different. This is hair, facial hair, underwear, mutant bits, etc.
+SUBSYSTEM_DEF(accessories) // just 'accessories' for brevity
+ name = "Sprite Accessories"
+ flags = SS_NO_FIRE | SS_NO_INIT
+
+ //Hairstyles
+ var/list/hairstyles_list //! stores /datum/sprite_accessory/hair indexed by name
+ var/list/hairstyles_male_list //! stores only hair names
+ var/list/hairstyles_female_list //! stores only hair names
+ var/list/facial_hairstyles_list //! stores /datum/sprite_accessory/facial_hair indexed by name
+ var/list/facial_hairstyles_male_list //! stores only hair names
+ var/list/facial_hairstyles_female_list //! stores only hair names
+ var/list/hair_gradients_list //! stores /datum/sprite_accessory/hair_gradient indexed by name
+ var/list/facial_hair_gradients_list //! stores /datum/sprite_accessory/facial_hair_gradient indexed by name
+
+ //Underwear
+ var/list/underwear_list //! stores /datum/sprite_accessory/underwear indexed by name
+ var/list/underwear_m //! stores only underwear name
+ var/list/underwear_f //! stores only underwear name
+
+ //Undershirts
+ var/list/undershirt_list //! stores /datum/sprite_accessory/undershirt indexed by name
+ var/list/undershirt_m //! stores only undershirt name
+ var/list/undershirt_f //! stores only undershirt name
+
+ //Socks
+ var/list/socks_list //! stores /datum/sprite_accessory/socks indexed by name
+
+ //Lizard Bits (all datum lists indexed by name)
+ var/list/body_markings_list
+ var/list/snouts_list
+ var/list/horns_list
+ var/list/frills_list
+ var/list/spines_list
+ var/list/legs_list
+ var/list/tail_spines_list
+
+ //Mutant Human bits
+ var/list/tails_list_human
+ var/list/tails_list_lizard
+ var/list/tails_list_monkey
+ var/list/ears_list
+ var/list/wings_list
+ var/list/wings_open_list
+ var/list/moth_wings_list
+ var/list/moth_antennae_list
+ var/list/moth_markings_list
+ var/list/caps_list
+ var/list/pod_hair_list
+
+/datum/controller/subsystem/accessories/PreInit() // this stuff NEEDS to be set up before GLOB for preferences and stuff to work so this must go here. sorry
+ setup_lists()
+ init_hair_gradients()
+
+/// Sets up all of the lists for later utilization in the round and building sprites.
+/// In an ideal world we could tack everything that just needed `DEFAULT_SPRITE_LIST` into static variables on the top, but due to the initialization order
+/// where this subsystem will initialize BEFORE statics, it's just not feasible since this all needs to be ready for actual subsystems to use.
+/// Sorry.
+/datum/controller/subsystem/accessories/proc/setup_lists()
+ var/hair_lists = init_sprite_accessory_subtypes(/datum/sprite_accessory/hair)
+ hairstyles_list = hair_lists[DEFAULT_SPRITE_LIST]
+ hairstyles_male_list = hair_lists[MALE_SPRITE_LIST]
+ hairstyles_female_list = hair_lists[FEMALE_SPRITE_LIST]
+
+ var/facial_hair_lists = init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair)
+ facial_hairstyles_list = facial_hair_lists[DEFAULT_SPRITE_LIST]
+ facial_hairstyles_male_list = facial_hair_lists[MALE_SPRITE_LIST]
+ facial_hairstyles_female_list = facial_hair_lists[FEMALE_SPRITE_LIST]
+
+ var/underwear_lists = init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear)
+ underwear_list = underwear_lists[DEFAULT_SPRITE_LIST]
+ underwear_m = underwear_lists[MALE_SPRITE_LIST]
+ underwear_f = underwear_lists[FEMALE_SPRITE_LIST]
+
+ var/undershirt_lists = init_sprite_accessory_subtypes(/datum/sprite_accessory/undershirt)
+ undershirt_list = undershirt_lists[DEFAULT_SPRITE_LIST]
+ undershirt_m = undershirt_lists[MALE_SPRITE_LIST]
+ undershirt_f = undershirt_lists[FEMALE_SPRITE_LIST]
+
+ socks_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/socks)[DEFAULT_SPRITE_LIST]
+
+ body_markings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings)[DEFAULT_SPRITE_LIST]
+ tails_list_human = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
+ tails_list_lizard = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
+ tails_list_monkey = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/monkey, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
+ snouts_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts)[DEFAULT_SPRITE_LIST]
+ horns_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/horns)[DEFAULT_SPRITE_LIST]
+ ears_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/ears)[DEFAULT_SPRITE_LIST]
+ wings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/wings)[DEFAULT_SPRITE_LIST]
+ wings_open_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/wings_open)[DEFAULT_SPRITE_LIST]
+ frills_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/frills)[DEFAULT_SPRITE_LIST]
+ spines_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/spines)[DEFAULT_SPRITE_LIST]
+ tail_spines_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/tail_spines)[DEFAULT_SPRITE_LIST]
+ legs_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/legs)[DEFAULT_SPRITE_LIST]
+ caps_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/caps)[DEFAULT_SPRITE_LIST]
+ moth_wings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings)[DEFAULT_SPRITE_LIST]
+ moth_antennae_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_antennae)[DEFAULT_SPRITE_LIST]
+ moth_markings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_markings)[DEFAULT_SPRITE_LIST]
+ pod_hair_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/pod_hair)[DEFAULT_SPRITE_LIST]
+
+/// This proc just intializes all /datum/sprite_accessory/hair_gradient into an list indexed by gradient-style name
+/datum/controller/subsystem/accessories/proc/init_hair_gradients()
+ hair_gradients_list = list()
+ facial_hair_gradients_list = list()
+ for(var/path in subtypesof(/datum/sprite_accessory/gradient))
+ var/datum/sprite_accessory/gradient/gradient = new path
+ if(gradient.gradient_category & GRADIENT_APPLIES_TO_HAIR)
+ hair_gradients_list[gradient.name] = gradient
+ if(gradient.gradient_category & GRADIENT_APPLIES_TO_FACIAL_HAIR)
+ facial_hair_gradients_list[gradient.name] = gradient
+
+/// This reads the applicable sprite accessory datum's subtypes and adds it to the subsystem's list of sprite accessories.
+/// The boolean `add_blank` argument just adds a "None" option to the list of sprite accessories, like if a felinid doesn't want a tail or something, typically good for gated-off things.
+/datum/controller/subsystem/accessories/proc/init_sprite_accessory_subtypes(prototype, add_blank = FALSE)
+ RETURN_TYPE(/list)
+ var/returnable_list = list(
+ DEFAULT_SPRITE_LIST = list(),
+ MALE_SPRITE_LIST = list(),
+ FEMALE_SPRITE_LIST = list(),
+ )
+
+ for(var/path in subtypesof(prototype))
+ var/datum/sprite_accessory/accessory = new path
+
+ if(accessory.icon_state)
+ returnable_list[DEFAULT_SPRITE_LIST][accessory.name] = accessory
+ else
+ returnable_list[DEFAULT_SPRITE_LIST] += accessory.name
+
+ switch(accessory.gender)
+ if(MALE)
+ returnable_list[MALE_SPRITE_LIST] += accessory.name
+ if(FEMALE)
+ returnable_list[FEMALE_SPRITE_LIST] += accessory.name
+ else
+ returnable_list[MALE_SPRITE_LIST] += accessory.name
+ returnable_list[FEMALE_SPRITE_LIST] += accessory.name
+
+ if(add_blank)
+ returnable_list[DEFAULT_SPRITE_LIST][SPRITE_ACCESSORY_NONE] = new /datum/sprite_accessory/blank
+
+ return returnable_list
+
+#undef DEFAULT_SPRITE_LIST
+#undef MALE_SPRITE_LIST
+#undef FEMALE_SPRITE_LIST
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index 410db36988dd8..b7c26acf375ee 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -18,6 +18,8 @@ SUBSYSTEM_DEF(vote)
var/list/voted = list()
/// A list of all ckeys currently voting for the current vote.
var/list/voting = list()
+ /// World.time we started our last vote
+ var/last_vote_time = -INFINITY
/datum/controller/subsystem/vote/Initialize()
for(var/vote_type in subtypesof(/datum/vote))
@@ -30,16 +32,20 @@ SUBSYSTEM_DEF(vote)
return SS_INIT_SUCCESS
-
// Called by master_controller
/datum/controller/subsystem/vote/fire()
if(!current_vote)
return
current_vote.time_remaining = round((current_vote.started_time + CONFIG_GET(number/vote_period) - world.time) / 10)
if(current_vote.time_remaining < 0)
- process_vote_result()
- SStgui.close_uis(src)
- reset()
+ end_vote()
+
+/// Ends the current vote.
+/datum/controller/subsystem/vote/proc/end_vote()
+ ASSERT(current_vote)
+ process_vote_result()
+ SStgui.close_uis(src)
+ reset()
/// Resets all of our vars after votes conclude / are cancelled.
/datum/controller/subsystem/vote/proc/reset()
@@ -168,24 +174,10 @@ SUBSYSTEM_DEF(vote)
* * vote_type - The type of vote to initiate. Can be a [/datum/vote] typepath, a [/datum/vote] instance, or the name of a vote datum.
* * vote_initiator_name - The ckey (if player initiated) or name that initiated a vote. Ex: "UristMcAdmin", "the server"
* * vote_initiator - If a person / mob initiated the vote, this is the mob that did it
- * * forced - Whether we're forcing the vote to go through regardless of existing votes or other circumstances. Note: If the vote is admin created, forced becomes true regardless.
+ * * forced - Whether we're forcing the vote to go through regardless of existing votes or other circumstances.
*/
/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, vote_initiator_name, mob/vote_initiator, forced = FALSE)
-
- // Even if it's forced we can't vote before we're set up
- if(!MC_RUNNING(init_stage))
- if(vote_initiator)
- to_chat(vote_initiator, span_warning("You cannot start vote now, the server is not done initializing."))
- return FALSE
-
- // Check if we have unlimited voting power.
- // Admin started (or forced) voted will go through even if there's an ongoing vote,
- // if voting is on cooldown, or regardless if a vote is config disabled (in some cases)
- var/unlimited_vote_power = forced || !!GLOB.admin_datums[vote_initiator?.ckey]
-
- if(current_vote && !unlimited_vote_power)
- if(vote_initiator)
- to_chat(vote_initiator, span_warning("There is already a vote in progress! Please wait for it to finish."))
+ if(!can_vote_start(vote_initiator, forced))
return FALSE
// Get our actual datum
@@ -212,7 +204,7 @@ SUBSYSTEM_DEF(vote)
return FALSE
// Vote can't be initiated in our circumstances? No vote
- if(!to_vote.can_be_initiated(vote_initiator, unlimited_vote_power))
+ if(to_vote.can_be_initiated(forced) != VOTE_AVAILABLE)
return FALSE
// Okay, we're ready to actually create a vote -
@@ -223,8 +215,12 @@ SUBSYSTEM_DEF(vote)
if(!to_vote.create_vote(vote_initiator))
return FALSE
+ if(!vote_initiator_name && vote_initiator)
+ vote_initiator_name = vote_initiator.key
+
// Okay, the vote's happening now, for real. Set it up.
current_vote = to_vote
+ last_vote_time = world.time
var/duration = CONFIG_GET(number/vote_period)
var/to_display = current_vote.initiate_vote(vote_initiator_name, duration)
@@ -248,6 +244,36 @@ SUBSYSTEM_DEF(vote)
return TRUE
+/**
+ * Checks if we can start a vote.
+ *
+ * * vote_initiator - The mob that initiated the vote.
+ * * forced - Whether we're forcing the vote to go through regardless of existing votes or other circumstances.
+ *
+ * Returns TRUE if we can start a vote, FALSE if we can't.
+ */
+/datum/controller/subsystem/vote/proc/can_vote_start(mob/vote_initiator, forced)
+ // Even if it's forced we can't vote before we're set up
+ if(!MC_RUNNING(init_stage))
+ if(vote_initiator)
+ to_chat(vote_initiator, span_warning("You cannot start a vote now, the server is not done initializing."))
+ return FALSE
+
+ if(forced)
+ return TRUE
+
+ var/next_allowed_time = last_vote_time + CONFIG_GET(number/vote_delay)
+ if(next_allowed_time > world.time)
+ if(vote_initiator)
+ to_chat(vote_initiator, span_warning("A vote was initiated recently. You must wait [DisplayTimeText(next_allowed_time - world.time)] before a new vote can be started!"))
+ return FALSE
+
+ if(current_vote)
+ if(vote_initiator)
+ to_chat(vote_initiator, span_warning("There is already a vote in progress! Please wait for it to finish."))
+ return FALSE
+
+ return TRUE
/datum/controller/subsystem/vote/ui_state()
return GLOB.always_state
@@ -282,11 +308,12 @@ SUBSYSTEM_DEF(vote)
if(!istype(vote))
continue
+ var/can_vote = vote.can_be_initiated(is_lower_admin)
var/list/vote_data = list(
"name" = vote_name,
- "canBeInitiated" = vote.can_be_initiated(forced = is_lower_admin),
+ "canBeInitiated" = can_vote == VOTE_AVAILABLE,
"config" = vote.is_config_enabled(),
- "message" = vote.message,
+ "message" = can_vote == VOTE_AVAILABLE ? vote.default_message : can_vote,
)
if(vote == current_vote)
@@ -310,7 +337,13 @@ SUBSYSTEM_DEF(vote)
all_vote_data += list(vote_data)
data["possibleVotes"] = all_vote_data
+ data["LastVoteTime"] = last_vote_time - world.time
+
+ return data
+/datum/controller/subsystem/vote/ui_static_data(mob/user)
+ var/list/data = list()
+ data["VoteCD"] = CONFIG_GET(number/vote_delay)
return data
/datum/controller/subsystem/vote/ui_act(action, params)
@@ -323,19 +356,37 @@ SUBSYSTEM_DEF(vote)
switch(action)
if("cancel")
if(!voter.client?.holder)
+ message_admins("[key_name(voter)] tried to cancel the current vote while having no admin holder, \
+ this is potentially a malicious exploit and worth noting.")
return
voter.log_message("cancelled a vote.", LOG_ADMIN)
message_admins("[key_name_admin(voter)] has cancelled the current vote.")
+ SStgui.close_uis(src)
reset()
return TRUE
+ if("endNow")
+ if(!voter.client?.holder)
+ message_admins("[key_name(voter)] tried to end the current vote while having no admin holder, \
+ this is potentially a malicious exploit and worth noting.")
+ return
+
+ voter.log_message("ended the current vote early", LOG_ADMIN)
+ message_admins("[key_name_admin(voter)] has ended the current vote.")
+ end_vote()
+ return TRUE
+
if("toggleVote")
var/datum/vote/selected = possible_votes[params["voteName"]]
if(!istype(selected))
return
+ if(!check_rights_for(voter.client, R_ADMIN))
+ message_admins("[key_name(voter)] tried to toggle vote availability while having improper rights, \
+ this is potentially a malicious exploit and worth noting.")
+ return
- return selected.toggle_votable(voter)
+ return selected.toggle_votable()
if("callVote")
var/datum/vote/selected = possible_votes[params["voteName"]]
@@ -344,7 +395,12 @@ SUBSYSTEM_DEF(vote)
// Whether the user actually can initiate this vote is checked in initiate_vote,
// meaning you can't spoof initiate a vote you're not supposed to be able to
- return initiate_vote(selected, voter.key, voter)
+ return initiate_vote(
+ vote_type = selected,
+ vote_initiator_name = voter.key,
+ vote_initiator = voter,
+ forced = !!GLOB.admin_datums[voter.ckey],
+ )
if("voteSingle")
return submit_single_vote(voter, params["voteOption"])
@@ -352,6 +408,15 @@ SUBSYSTEM_DEF(vote)
if("voteMulti")
return submit_multi_vote(voter, params["voteOption"])
+ if("resetCooldown")
+ if(!voter.client.holder)
+ message_admins("[key_name(voter)] tried to reset the vote cooldown while having no admin holder, \
+ this is potentially a malicious exploit and worth noting.")
+ return
+
+ last_vote_time = -INFINITY
+ return TRUE
+
/datum/controller/subsystem/vote/ui_close(mob/user)
voting -= user.client?.ckey
@@ -360,6 +425,10 @@ SUBSYSTEM_DEF(vote)
set category = "OOC"
set name = "Vote"
+ if(!SSvote.initialized)
+ to_chat(usr, span_notice("Voting is not set up yet! "))
+ return
+
SSvote.ui_interact(usr)
/// Datum action given to mobs that allows players to vote on the current vote.
diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm
index 309be50878341..35615c6704c42 100644
--- a/code/datums/ai/_ai_controller.dm
+++ b/code/datums/ai/_ai_controller.dm
@@ -172,9 +172,13 @@ multiple modular subtrees with behaviors
return FALSE
return TRUE
-/datum/ai_controller/proc/recalculate_idle()
+/datum/ai_controller/proc/recalculate_idle(datum/exited)
if(ai_status == AI_STATUS_OFF)
return
+
+ if(exited && (get_dist(pawn, (islist(exited) ? exited[1] : exited)) <= interesting_dist)) //is our target in between interesting cells?
+ return
+
if(should_idle())
set_ai_status(AI_STATUS_IDLE)
@@ -187,7 +191,7 @@ multiple modular subtrees with behaviors
/datum/ai_controller/proc/on_client_exit(datum/source, datum/exited)
SIGNAL_HANDLER
- recalculate_idle()
+ recalculate_idle(exited)
/// Sets the AI on or off based on current conditions, call to reset after you've manually disabled it somewhere
/datum/ai_controller/proc/reset_ai_status()
diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm
index f0ee4bb9bba37..4cf04039e8535 100644
--- a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm
+++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm
@@ -7,6 +7,7 @@ GLOBAL_LIST_INIT(target_interested_atoms, typecacheof(list(/mob, /obj/machinery/
/datum/ai_behavior/find_potential_targets
action_cooldown = 2 SECONDS
+ behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
/// How far can we see stuff?
var/vision_range = 9
/// Blackboard key for aggro range, uses vision range if not specified
@@ -34,7 +35,7 @@ GLOBAL_LIST_INIT(target_interested_atoms, typecacheof(list(/mob, /obj/machinery/
// If we're using a field rn, just don't do anything yeah?
if(controller.blackboard[BB_FIND_TARGETS_FIELD(type)])
- return
+ return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
var/list/potential_targets = hearers(aggro_range, get_turf(controller.pawn)) - living_mob //Remove self, so we don't suicide
diff --git a/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm b/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm
index a4fc49facc000..52b19036b9a47 100644
--- a/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm
+++ b/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm
@@ -21,6 +21,7 @@
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
pawn.visible_message(span_notice("[pawn] calms down.")) // We can blackboard key this if anyone else actually wants to customise it
controller.clear_blackboard_key(BB_BASIC_MOB_RETALIATE_LIST)
+ controller.clear_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET)
controller.CancelActions() // Otherwise they will try and get one last kick in
return AI_BEHAVIOR_DELAY
diff --git a/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm
index d327b1047cf57..042ccb2310c1a 100644
--- a/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm
+++ b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm
@@ -11,7 +11,6 @@
var/check_faction = FALSE
/datum/ai_planning_subtree/target_retaliate/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
- . = ..()
controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list, BB_BASIC_MOB_RETALIATE_LIST, target_key, targeting_strategy_key, hiding_place_key, check_faction)
/datum/ai_planning_subtree/target_retaliate/check_faction
@@ -35,7 +34,6 @@
var/vision_range = 9
/datum/ai_behavior/target_from_retaliate_list/perform(seconds_per_tick, datum/ai_controller/controller, shitlist_key, target_key, targeting_strategy_key, hiding_location_key, check_faction)
- . = ..()
var/mob/living/living_mob = controller.pawn
var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key])
if(!targeting_strategy)
@@ -58,7 +56,6 @@
enemies_list += potential_target
if(!length(enemies_list))
- controller.clear_blackboard_key(target_key)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
var/atom/new_target = pick_final_target(controller, enemies_list)
@@ -75,7 +72,7 @@
/datum/ai_behavior/target_from_retaliate_list/proc/pick_final_target(datum/ai_controller/controller, list/enemies_list)
return pick(enemies_list)
-/datum/ai_behavior/target_from_retaliate_list/finish_action(datum/ai_controller/controller, succeeded, check_faction)
+/datum/ai_behavior/target_from_retaliate_list/finish_action(datum/ai_controller/controller, succeeded, shitlist_key, target_key, targeting_strategy_key, hiding_location_key, check_faction)
. = ..()
if (succeeded || check_faction)
return
diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm
index e3891392d1a76..251414241c92d 100644
--- a/code/datums/brain_damage/imaginary_friend.dm
+++ b/code/datums/brain_damage/imaginary_friend.dm
@@ -129,8 +129,8 @@
/// Randomise friend name and appearance
/mob/camera/imaginary_friend/proc/setup_friend()
- var/gender = pick(MALE, FEMALE)
- real_name = random_unique_name(gender)
+ gender = pick(MALE, FEMALE)
+ real_name = generate_random_name_species_based(gender, FALSE, /datum/species/human)
name = real_name
human_image = get_flat_human_icon(null, pick(SSjob.joinable_occupations))
Show()
diff --git a/code/datums/components/crafting/_recipes.dm b/code/datums/components/crafting/_recipes.dm
index 09121339d3058..31825ac66118a 100644
--- a/code/datums/components/crafting/_recipes.dm
+++ b/code/datums/components/crafting/_recipes.dm
@@ -23,14 +23,12 @@
var/list/chem_catalysts = list()
///where it shows up in the crafting UI
var/category
- ///Set to FALSE if it needs to be learned first.
- var/always_available = TRUE
///Required machines for the craft, set the assigned value of the typepath to CRAFTING_MACHINERY_CONSUME or CRAFTING_MACHINERY_USE. Lazy associative list: type_path key -> flag value.
var/list/machinery
///Required structures for the craft, set the assigned value of the typepath to CRAFTING_STRUCTURE_CONSUME or CRAFTING_STRUCTURE_USE. Lazy associative list: type_path key -> flag value.
var/list/structures
- ///Should only one object exist on the same turf?
- var/one_per_turf = FALSE
+ /// Bitflag of additional placement checks required to place. (STACK_CHECK_CARDINALS|STACK_CHECK_ADJACENT|STACK_CHECK_TRAM_FORBIDDEN|STACK_CHECK_TRAM_EXCLUSIVE)
+ var/placement_checks = NONE
/// Steps needed to achieve the result
var/list/steps
/// Whether the result can be crafted with a crafting menu button
@@ -44,6 +42,9 @@
/// Allows you to craft so that you don't have to click the craft button many times.
var/mass_craftable = FALSE
+ ///crafting_flags var to hold bool values
+ var/crafting_flags = CRAFT_CHECK_DENSITY
+
/datum/crafting_recipe/New()
if(!name && result)
var/atom/atom_result = result
@@ -83,6 +84,7 @@
src.result_amount = stack_recipe.res_amount
src.reqs[material] = stack_recipe.req_amount
src.category = stack_recipe.category || CAT_MISC
+ src.placement_checks = stack_recipe.placement_checks
/**
* Run custom pre-craft checks for this recipe, don't add feedback messages in this because it will spam the client
diff --git a/code/datums/components/crafting/atmospheric.dm b/code/datums/components/crafting/atmospheric.dm
index cb5bba9ab52b2..b2993012e82b0 100644
--- a/code/datums/components/crafting/atmospheric.dm
+++ b/code/datums/components/crafting/atmospheric.dm
@@ -25,7 +25,7 @@
/obj/item/assembly/igniter = 1,
)
blacklist = list(/obj/item/assembly/igniter/condenser)
- one_per_turf = TRUE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF
time = 2 SECONDS
category = CAT_ATMOSPHERIC
diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm
index 6fc560a293f21..7a56f89c8e924 100644
--- a/code/datums/components/crafting/crafting.dm
+++ b/code/datums/components/crafting/crafting.dm
@@ -191,42 +191,86 @@
var/list/contents = get_surroundings(crafter, recipe.blacklist)
var/send_feedback = 1
- if(check_contents(crafter, recipe, contents))
- if(check_tools(crafter, recipe, contents))
- if(recipe.one_per_turf)
- for(var/content in get_turf(crafter))
- if(istype(content, recipe.result))
- return ", object already present."
- //If we're a mob we'll try a do_after; non mobs will instead instantly construct the item
- if(ismob(crafter) && !do_after(crafter, recipe.time, target = crafter))
- return "."
- contents = get_surroundings(crafter, recipe.blacklist)
- if(!check_contents(crafter, recipe, contents))
- return ", missing component."
- if(!check_tools(crafter, recipe, contents))
- return ", missing tool."
- var/list/parts = del_reqs(recipe, crafter)
- var/atom/movable/result
- if(ispath(recipe.result, /obj/item/stack))
- result = new recipe.result(get_turf(crafter.loc), recipe.result_amount || 1)
- else
- result = new recipe.result(get_turf(crafter.loc))
- if(result.atom_storage && recipe.delete_contents)
- for(var/obj/item/thing in result)
- qdel(thing)
- var/datum/reagents/holder = locate() in parts
- if(holder) //transfer reagents from ingredients to result
- if(!ispath(recipe.result, /obj/item/reagent_containers) && result.reagents)
- result.reagents.clear_reagents()
- holder.trans_to(result.reagents, holder.total_volume, no_react = TRUE)
- parts -= holder
- qdel(holder)
- result.CheckParts(parts, recipe)
- if(send_feedback)
- SSblackbox.record_feedback("tally", "object_crafted", 1, result.type)
- return result //Send the item back to whatever called this proc so it can handle whatever it wants to do with the new item
+ var/turf/dest_turf = get_turf(crafter)
+
+ if(!check_contents(crafter, recipe, contents))
+ return ", missing component."
+
+ if(!check_tools(crafter, recipe, contents))
return ", missing tool."
- return ", missing component."
+
+
+
+ if((recipe.crafting_flags & CRAFT_ONE_PER_TURF) && (locate(recipe.result) in dest_turf))
+ return ", already one here!"
+
+ if(recipe.crafting_flags & CRAFT_CHECK_DIRECTION)
+ if(!valid_build_direction(dest_turf, crafter.dir, is_fulltile = (recipe.crafting_flags & CRAFT_IS_FULLTILE)))
+ return ", won't fit here!"
+
+ if(recipe.crafting_flags & CRAFT_ON_SOLID_GROUND)
+ if(isclosedturf(dest_turf))
+ return ", cannot be made on a wall!"
+
+ if(is_type_in_typecache(dest_turf, GLOB.turfs_without_ground))
+ if(!locate(/obj/structure/thermoplastic) in dest_turf) // for tram construction
+ return ", must be made on solid ground!"
+
+ if(recipe.crafting_flags & CRAFT_CHECK_DENSITY)
+ for(var/obj/object in dest_turf)
+ if(object.density && !(object.obj_flags & IGNORE_DENSITY) || object.obj_flags & BLOCKS_CONSTRUCTION)
+ return ", something is in the way!"
+
+ if(recipe.placement_checks & STACK_CHECK_CARDINALS)
+ var/turf/nearby_turf
+ for(var/direction in GLOB.cardinals)
+ nearby_turf = get_step(dest_turf, direction)
+ if(locate(recipe.result) in nearby_turf)
+ to_chat(crafter, span_warning("\The [recipe.name] must not be built directly adjacent to another!"))
+ return ", can't be adjacent to another!"
+
+ if(recipe.placement_checks & STACK_CHECK_ADJACENT)
+ if(locate(recipe.result) in range(1, dest_turf))
+ return ", can't be near another!"
+
+ if(recipe.placement_checks & STACK_CHECK_TRAM_FORBIDDEN)
+ if(locate(/obj/structure/transport/linear/tram) in dest_turf || locate(/obj/structure/thermoplastic) in dest_turf)
+ return ", can't be on tram!"
+
+ if(recipe.placement_checks & STACK_CHECK_TRAM_EXCLUSIVE)
+ if(!locate(/obj/structure/transport/linear/tram) in dest_turf)
+ return ", must be made on a tram!"
+
+ //If we're a mob we'll try a do_after; non mobs will instead instantly construct the item
+ if(ismob(crafter) && !do_after(crafter, recipe.time, target = crafter))
+ return "."
+ contents = get_surroundings(crafter, recipe.blacklist)
+ if(!check_contents(crafter, recipe, contents))
+ return ", missing component."
+ if(!check_tools(crafter, recipe, contents))
+ return ", missing tool."
+ var/list/parts = del_reqs(recipe, crafter)
+ var/atom/movable/result
+ if(ispath(recipe.result, /obj/item/stack))
+ result = new recipe.result(get_turf(crafter.loc), recipe.result_amount || 1)
+ result.dir = crafter.dir
+ else
+ result = new recipe.result(get_turf(crafter.loc))
+ result.dir = crafter.dir
+ if(result.atom_storage && recipe.delete_contents)
+ for(var/obj/item/thing in result)
+ qdel(thing)
+ var/datum/reagents/holder = locate() in parts
+ if(holder) //transfer reagents from ingredients to result
+ if(!ispath(recipe.result, /obj/item/reagent_containers) && result.reagents)
+ result.reagents.clear_reagents()
+ holder.trans_to(result.reagents, holder.total_volume, no_react = TRUE)
+ parts -= holder
+ qdel(holder)
+ result.CheckParts(parts, recipe)
+ if(send_feedback)
+ SSblackbox.record_feedback("tally", "object_crafted", 1, result.type)
+ return result //Send the item back to whatever called this proc so it can handle whatever it wants to do with the new item
/*Del reqs works like this:
@@ -369,7 +413,7 @@
qdel(DL)
/datum/component/personal_crafting/proc/is_recipe_available(datum/crafting_recipe/recipe, mob/user)
- if(!recipe.always_available && !(recipe.type in user?.mind?.learned_recipes)) //User doesn't actually know how to make this.
+ if((recipe.crafting_flags & CRAFT_MUST_BE_LEARNED) && !(recipe.type in user?.mind?.learned_recipes)) //User doesn't actually know how to make this.
return FALSE
if (recipe.category == CAT_CULT && !IS_CULTIST(user)) // Skip blood cult recipes if not cultist
return FALSE
diff --git a/code/datums/components/crafting/doors.dm b/code/datums/components/crafting/doors.dm
index e8fcb3fdfd915..d9ed708904e51 100644
--- a/code/datums/components/crafting/doors.dm
+++ b/code/datums/components/crafting/doors.dm
@@ -9,7 +9,7 @@
tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL, TOOL_WIRECUTTER, TOOL_WELDER)
time = 10 SECONDS
category = CAT_DOORS
- one_per_turf = TRUE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF
/datum/crafting_recipe/blast_doors
name = "Blast Door"
@@ -22,4 +22,4 @@
tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL, TOOL_WIRECUTTER, TOOL_WELDER)
time = 30 SECONDS
category = CAT_DOORS
- one_per_turf = TRUE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF
diff --git a/code/datums/components/crafting/melee_weapon.dm b/code/datums/components/crafting/melee_weapon.dm
index 869d223a758c9..1c4150585fccc 100644
--- a/code/datums/components/crafting/melee_weapon.dm
+++ b/code/datums/components/crafting/melee_weapon.dm
@@ -144,7 +144,6 @@
/datum/crafting_recipe/house_edge
name = "House Edge"
result = /obj/item/house_edge
- always_available = FALSE
tool_behaviors = list(TOOL_WRENCH, TOOL_SCREWDRIVER, TOOL_WELDER)
reqs = list(
/obj/item/v8_engine = 1,
@@ -157,6 +156,7 @@
)
time = 10 SECONDS
category = CAT_WEAPON_MELEE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/giant_wrench
name = "Big Slappy"
diff --git a/code/datums/components/crafting/misc.dm b/code/datums/components/crafting/misc.dm
index 264ff98156533..606cf1fc29262 100644
--- a/code/datums/components/crafting/misc.dm
+++ b/code/datums/components/crafting/misc.dm
@@ -11,8 +11,8 @@
time = 3 SECONDS
reqs = list(/obj/item/stack/sheet/bone = 5)
result = /obj/item/skeleton_key
- always_available = FALSE
category = CAT_MISC
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/coffee_cartridge
name = "Bootleg Coffee Cartridge"
diff --git a/code/datums/components/crafting/ranged_weapon.dm b/code/datums/components/crafting/ranged_weapon.dm
index ace9f2c7c8b0d..0cf681ac2b107 100644
--- a/code/datums/components/crafting/ranged_weapon.dm
+++ b/code/datums/components/crafting/ranged_weapon.dm
@@ -222,7 +222,6 @@
/datum/crafting_recipe/pipegun_prime
name = "Regal Pipegun"
- always_available = FALSE
result = /obj/item/gun/ballistic/rifle/boltaction/pipegun/prime
reqs = list(
/obj/item/gun/ballistic/rifle/boltaction/pipegun = 1,
@@ -235,10 +234,10 @@
tool_paths = list(/obj/item/clothing/gloves/color/yellow, /obj/item/clothing/mask/gas, /obj/item/melee/baton/security/cattleprod)
time = 30 SECONDS //contemplate for a bit
category = CAT_WEAPON_RANGED
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/deagle_prime //When you factor in the makarov (7 tc), the toolbox (1 tc), and the emag (3 tc), this comes to a total of 18 TC or thereabouts. Igorning the 20k pricetag, obviously.
name = "Regal Condor"
- always_available = FALSE
result = /obj/item/gun/ballistic/automatic/pistol/deagle/regal
reqs = list(
/obj/item/gun/ballistic/automatic/pistol = 1,
@@ -258,6 +257,7 @@
)
time = 30 SECONDS
category = CAT_WEAPON_RANGED
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/deagle_prime/New()
..()
@@ -265,7 +265,6 @@
/datum/crafting_recipe/deagle_prime_mag
name = "Regal Condor Magazine (10mm Reaper)"
- always_available = FALSE
result = /obj/item/ammo_box/magazine/r10mm
reqs = list(
/obj/item/stack/sheet/iron = 10,
@@ -283,10 +282,10 @@
)
time = 5 SECONDS
category = CAT_WEAPON_RANGED
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/trash_cannon
name = "Trash Cannon"
- always_available = FALSE
tool_behaviors = list(TOOL_WELDER, TOOL_SCREWDRIVER)
result = /obj/structure/cannon/trash
reqs = list(
@@ -297,6 +296,7 @@
/obj/item/storage/toolbox = 1,
)
category = CAT_WEAPON_RANGED
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/laser_musket
name = "Laser Musket"
@@ -316,7 +316,6 @@
/datum/crafting_recipe/laser_musket_prime
name = "Heroic Laser Musket"
- always_available = FALSE
result = /obj/item/gun/energy/laser/musket/prime
reqs = list(
/obj/item/gun/energy/laser/musket = 1,
@@ -329,6 +328,7 @@
tool_paths = list(/obj/item/clothing/head/cowboy, /obj/item/clothing/shoes/cowboy)
time = 30 SECONDS //contemplate for a bit
category = CAT_WEAPON_RANGED
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/smoothbore_disabler
name = "Smoothbore Disabler"
@@ -347,7 +347,6 @@
/datum/crafting_recipe/smoothbore_disabler_prime
name = "Elite Smoothbore Disabler"
- always_available = FALSE
result = /obj/item/gun/energy/disabler/smoothbore/prime
reqs = list(
/obj/item/gun/energy/disabler/smoothbore = 1,
@@ -358,3 +357,4 @@
tool_behaviors = list(TOOL_SCREWDRIVER)
time = 20 SECONDS
category = CAT_WEAPON_RANGED
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
diff --git a/code/datums/components/crafting/structures.dm b/code/datums/components/crafting/structures.dm
index 2cbe2c353020b..c4a9b48ec36b6 100644
--- a/code/datums/components/crafting/structures.dm
+++ b/code/datums/components/crafting/structures.dm
@@ -11,33 +11,33 @@
/datum/crafting_recipe/rib
name = "Colossal Rib"
- always_available = FALSE
reqs = list(
/obj/item/stack/sheet/bone = 10,
/datum/reagent/fuel/oil = 5,
)
result = /obj/structure/statue/bone/rib
category = CAT_STRUCTURE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/skull
name = "Skull Carving"
- always_available = FALSE
reqs = list(
/obj/item/stack/sheet/bone = 6,
/datum/reagent/fuel/oil = 5,
)
result = /obj/structure/statue/bone/skull
category = CAT_STRUCTURE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/halfskull
name = "Cracked Skull Carving"
- always_available = FALSE
reqs = list(
/obj/item/stack/sheet/bone = 3,
/datum/reagent/fuel/oil = 5,
)
result = /obj/structure/statue/bone/skull/half
category = CAT_STRUCTURE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/firecabinet
name = "Fire Axe Cabinet"
@@ -65,7 +65,6 @@
name = "Syndicate Uplink Beacon"
result = /obj/structure/syndicate_uplink_beacon
tool_behaviors = list(TOOL_SCREWDRIVER)
- always_available = FALSE
time = 6 SECONDS
reqs = list(
/obj/item/stack/sheet/iron = 5,
@@ -74,3 +73,4 @@
/obj/item/stack/ore/bluespace_crystal = 1,
)
category = CAT_STRUCTURE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
diff --git a/code/datums/components/crafting/tools.dm b/code/datums/components/crafting/tools.dm
index 8b4b00d006026..d1d303daf8040 100644
--- a/code/datums/components/crafting/tools.dm
+++ b/code/datums/components/crafting/tools.dm
@@ -19,7 +19,6 @@
/datum/crafting_recipe/boneshovel
name = "Serrated Bone Shovel"
- always_available = FALSE
reqs = list(
/obj/item/stack/sheet/bone = 4,
/datum/reagent/fuel/oil = 5,
@@ -27,6 +26,7 @@
)
result = /obj/item/shovel/serrated
category = CAT_TOOLS
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/lasso
name = "Bone Lasso"
diff --git a/code/datums/components/crafting/weapon_ammo.dm b/code/datums/components/crafting/weapon_ammo.dm
index 44b8055b3ff94..55701dbde5349 100644
--- a/code/datums/components/crafting/weapon_ammo.dm
+++ b/code/datums/components/crafting/weapon_ammo.dm
@@ -20,8 +20,8 @@
)
tool_behaviors = list(TOOL_WIRECUTTER)
time = 0.5 SECONDS
- always_available = FALSE
category = CAT_WEAPON_AMMO
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/pulseslug
name = "Pulse Slug Shell"
@@ -85,10 +85,10 @@
/datum/crafting_recipe/trashball
name = "Trashball"
- always_available = FALSE
result = /obj/item/stack/cannonball/trashball
reqs = list(
/obj/item/stack/sheet = 5,
/datum/reagent/consumable/space_cola = 10,
)
category = CAT_WEAPON_AMMO
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
diff --git a/code/datums/components/jousting.dm b/code/datums/components/jousting.dm
index 56b65c6f758b5..9c3dab3c8fbdd 100644
--- a/code/datums/components/jousting.dm
+++ b/code/datums/components/jousting.dm
@@ -44,7 +44,7 @@
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip))
RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
- RegisterSignal(parent, COMSIG_ITEM_ATTACK, PROC_REF(on_attack))
+ RegisterSignal(parent, COMSIG_ITEM_POST_ATTACK, PROC_REF(on_successful_attack))
RegisterSignal(parent, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
/datum/component/jousting/UnregisterFromParent()
@@ -53,7 +53,7 @@
COMSIG_ATOM_EXAMINE,
COMSIG_ITEM_EQUIPPED,
COMSIG_ITEM_DROPPED,
- COMSIG_ITEM_ATTACK,
+ COMSIG_ITEM_POST_ATTACK,
COMSIG_TRANSFORMING_ON_TRANSFORM,
))
@@ -94,7 +94,7 @@
* We deduct the minimum tile charge from the current tile charge to get what will actually be buffed
* So your charge will only get benefits from each extra tile after the minimum (and before the maximum).
*/
-/datum/component/jousting/proc/on_attack(datum/source, mob/living/target, mob/user)
+/datum/component/jousting/proc/on_successful_attack(datum/source, mob/living/target, mob/user)
SIGNAL_HANDLER
if(user != current_holder || !user.buckled)
return
diff --git a/code/datums/components/singularity.dm b/code/datums/components/singularity.dm
index 56a6723f21f41..14aaedff7172a 100644
--- a/code/datums/components/singularity.dm
+++ b/code/datums/components/singularity.dm
@@ -286,7 +286,7 @@
if (STAGE_ONE)
steps = 1
if (STAGE_TWO)
- steps = 3//Yes this is right
+ steps = 2
if (STAGE_THREE)
steps = 3
if (STAGE_FOUR)
diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm
index 163de4867d575..d62414a862b24 100644
--- a/code/datums/components/uplink.dm
+++ b/code/datums/components/uplink.dm
@@ -266,7 +266,7 @@
/datum/component/uplink/ui_assets(mob/user)
return list(
- get_asset_datum(/datum/asset/json/uplink)
+ get_asset_datum(/datum/asset/json/uplink),
)
/datum/component/uplink/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
diff --git a/code/datums/datum.dm b/code/datums/datum.dm
index 77d787eb85ba0..6288244667e85 100644
--- a/code/datums/datum.dm
+++ b/code/datums/datum.dm
@@ -328,7 +328,7 @@
ASSERT(isatom(src) || isimage(src))
var/atom/atom_cast = src // filters only work with images or atoms.
atom_cast.filters = null
- filter_data = sortTim(filter_data, GLOBAL_PROC_REF(cmp_filter_data_priority), TRUE)
+ sortTim(filter_data, GLOBAL_PROC_REF(cmp_filter_data_priority), TRUE)
for(var/filter_raw in filter_data)
var/list/data = filter_data[filter_raw]
var/list/arguments = data.Copy()
diff --git a/code/datums/diseases/advance/symptoms/voice_change.dm b/code/datums/diseases/advance/symptoms/voice_change.dm
index 255c2a3f3a7f5..9654365c49d34 100644
--- a/code/datums/diseases/advance/symptoms/voice_change.dm
+++ b/code/datums/diseases/advance/symptoms/voice_change.dm
@@ -54,7 +54,7 @@
else
if(ishuman(M))
var/mob/living/carbon/human/H = M
- H.SetSpecialVoice(H.dna.species.random_name(H.gender))
+ H.SetSpecialVoice(H.generate_random_mob_name())
if(scramble_language && !current_language) // Last part prevents rerolling language with small amounts of cure.
current_language = pick(subtypesof(/datum/language) - /datum/language/common)
H.add_blocked_language(subtypesof(/datum/language) - current_language, LANGUAGE_VOICECHANGE)
diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index 7d69353e02ffc..8f5844aa48093 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -179,13 +179,12 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
L[DNA_GENDER_BLOCK] = construct_block(G_PLURAL, GENDERS)
if(ishuman(holder))
var/mob/living/carbon/human/H = holder
- if(!GLOB.hairstyles_list.len)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/hair,GLOB.hairstyles_list, GLOB.hairstyles_male_list, GLOB.hairstyles_female_list)
- L[DNA_HAIRSTYLE_BLOCK] = construct_block(GLOB.hairstyles_list.Find(H.hairstyle), GLOB.hairstyles_list.len)
+ if(length(SSaccessories.hairstyles_list) == 0 || length(SSaccessories.facial_hairstyles_list) == 0)
+ CRASH("SSaccessories lists are empty, this is bad!")
+
+ L[DNA_HAIRSTYLE_BLOCK] = construct_block(SSaccessories.hairstyles_list.Find(H.hairstyle), length(SSaccessories.hairstyles_list))
L[DNA_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.hair_color, include_crunch = FALSE)
- if(!GLOB.facial_hairstyles_list.len)
- init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, GLOB.facial_hairstyles_list, GLOB.facial_hairstyles_male_list, GLOB.facial_hairstyles_female_list)
- L[DNA_FACIAL_HAIRSTYLE_BLOCK] = construct_block(GLOB.facial_hairstyles_list.Find(H.facial_hairstyle), GLOB.facial_hairstyles_list.len)
+ L[DNA_FACIAL_HAIRSTYLE_BLOCK] = construct_block(SSaccessories.facial_hairstyles_list.Find(H.facial_hairstyle), length(SSaccessories.facial_hairstyles_list))
L[DNA_FACIAL_HAIR_COLOR_BLOCK] = sanitize_hexcolor(H.facial_hair_color, include_crunch = FALSE)
L[DNA_SKIN_TONE_BLOCK] = construct_block(GLOB.skin_tones.Find(H.skin_tone), GLOB.skin_tones.len)
L[DNA_EYE_COLOR_LEFT_BLOCK] = sanitize_hexcolor(H.eye_color_left, include_crunch = FALSE)
@@ -203,33 +202,33 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
if(features["ethcolor"])
L[DNA_ETHEREAL_COLOR_BLOCK] = sanitize_hexcolor(features["ethcolor"], include_crunch = FALSE)
if(features["body_markings"])
- L[DNA_LIZARD_MARKINGS_BLOCK] = construct_block(GLOB.body_markings_list.Find(features["body_markings"]), GLOB.body_markings_list.len)
+ L[DNA_LIZARD_MARKINGS_BLOCK] = construct_block(SSaccessories.body_markings_list.Find(features["body_markings"]), length(SSaccessories.body_markings_list))
if(features["tail_cat"])
- L[DNA_TAIL_BLOCK] = construct_block(GLOB.tails_list_human.Find(features["tail_cat"]), GLOB.tails_list_human.len)
+ L[DNA_TAIL_BLOCK] = construct_block(SSaccessories.tails_list_human.Find(features["tail_cat"]), length(SSaccessories.tails_list_human))
if(features["tail_lizard"])
- L[DNA_LIZARD_TAIL_BLOCK] = construct_block(GLOB.tails_list_lizard.Find(features["tail_lizard"]), GLOB.tails_list_lizard.len)
+ L[DNA_LIZARD_TAIL_BLOCK] = construct_block(SSaccessories.tails_list_lizard.Find(features["tail_lizard"]), length(SSaccessories.tails_list_lizard))
if(features["tail_monkey"])
- L[DNA_MONKEY_TAIL_BLOCK] = construct_block(GLOB.tails_list_monkey.Find(features["tail_monkey"]), GLOB.tails_list_monkey.len)
+ L[DNA_MONKEY_TAIL_BLOCK] = construct_block(SSaccessories.tails_list_monkey.Find(features["tail_monkey"]), length(SSaccessories.tails_list_monkey))
if(features["snout"])
- L[DNA_SNOUT_BLOCK] = construct_block(GLOB.snouts_list.Find(features["snout"]), GLOB.snouts_list.len)
+ L[DNA_SNOUT_BLOCK] = construct_block(SSaccessories.snouts_list.Find(features["snout"]), length(SSaccessories.snouts_list))
if(features["horns"])
- L[DNA_HORNS_BLOCK] = construct_block(GLOB.horns_list.Find(features["horns"]), GLOB.horns_list.len)
+ L[DNA_HORNS_BLOCK] = construct_block(SSaccessories.horns_list.Find(features["horns"]), length(SSaccessories.horns_list))
if(features["frills"])
- L[DNA_FRILLS_BLOCK] = construct_block(GLOB.frills_list.Find(features["frills"]), GLOB.frills_list.len)
+ L[DNA_FRILLS_BLOCK] = construct_block(SSaccessories.frills_list.Find(features["frills"]), length(SSaccessories.frills_list))
if(features["spines"])
- L[DNA_SPINES_BLOCK] = construct_block(GLOB.spines_list.Find(features["spines"]), GLOB.spines_list.len)
+ L[DNA_SPINES_BLOCK] = construct_block(SSaccessories.spines_list.Find(features["spines"]), length(SSaccessories.spines_list))
if(features["ears"])
- L[DNA_EARS_BLOCK] = construct_block(GLOB.ears_list.Find(features["ears"]), GLOB.ears_list.len)
+ L[DNA_EARS_BLOCK] = construct_block(SSaccessories.ears_list.Find(features["ears"]), length(SSaccessories.ears_list))
if(features["moth_wings"] != "Burnt Off")
- L[DNA_MOTH_WINGS_BLOCK] = construct_block(GLOB.moth_wings_list.Find(features["moth_wings"]), GLOB.moth_wings_list.len)
+ L[DNA_MOTH_WINGS_BLOCK] = construct_block(SSaccessories.moth_wings_list.Find(features["moth_wings"]), length(SSaccessories.moth_wings_list))
if(features["moth_antennae"] != "Burnt Off")
- L[DNA_MOTH_ANTENNAE_BLOCK] = construct_block(GLOB.moth_antennae_list.Find(features["moth_antennae"]), GLOB.moth_antennae_list.len)
+ L[DNA_MOTH_ANTENNAE_BLOCK] = construct_block(SSaccessories.moth_antennae_list.Find(features["moth_antennae"]), length(SSaccessories.moth_antennae_list))
if(features["moth_markings"])
- L[DNA_MOTH_MARKINGS_BLOCK] = construct_block(GLOB.moth_markings_list.Find(features["moth_markings"]), GLOB.moth_markings_list.len)
+ L[DNA_MOTH_MARKINGS_BLOCK] = construct_block(SSaccessories.moth_markings_list.Find(features["moth_markings"]), length(SSaccessories.moth_markings_list))
if(features["caps"])
- L[DNA_MUSHROOM_CAPS_BLOCK] = construct_block(GLOB.caps_list.Find(features["caps"]), GLOB.caps_list.len)
+ L[DNA_MUSHROOM_CAPS_BLOCK] = construct_block(SSaccessories.caps_list.Find(features["caps"]), length(SSaccessories.caps_list))
if(features["pod_hair"])
- L[DNA_POD_HAIR_BLOCK] = construct_block(GLOB.pod_hair_list.Find(features["pod_hair"]), GLOB.pod_hair_list.len)
+ L[DNA_POD_HAIR_BLOCK] = construct_block(SSaccessories.pod_hair_list.Find(features["pod_hair"]), length(SSaccessories.pod_hair_list))
for(var/blocknum in 1 to DNA_FEATURE_BLOCKS)
. += L[blocknum] || random_string(GET_UI_BLOCK_LEN(blocknum), GLOB.hex_characters)
@@ -326,9 +325,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
else
set_uni_identity_block(blocknumber, construct_block(G_PLURAL, GENDERS))
if(DNA_FACIAL_HAIRSTYLE_BLOCK)
- set_uni_identity_block(blocknumber, construct_block(GLOB.facial_hairstyles_list.Find(H.facial_hairstyle), GLOB.facial_hairstyles_list.len))
+ set_uni_identity_block(blocknumber, construct_block(SSaccessories.facial_hairstyles_list.Find(H.facial_hairstyle), length(SSaccessories.facial_hairstyles_list)))
if(DNA_HAIRSTYLE_BLOCK)
- set_uni_identity_block(blocknumber, construct_block(GLOB.hairstyles_list.Find(H.hairstyle), GLOB.hairstyles_list.len))
+ set_uni_identity_block(blocknumber, construct_block(SSaccessories.hairstyles_list.Find(H.hairstyle), length(SSaccessories.hairstyles_list)))
/datum/dna/proc/update_uf_block(blocknumber)
if(!blocknumber)
@@ -341,33 +340,33 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
if(DNA_ETHEREAL_COLOR_BLOCK)
set_uni_feature_block(blocknumber, sanitize_hexcolor(features["ethcolor"], include_crunch = FALSE))
if(DNA_LIZARD_MARKINGS_BLOCK)
- set_uni_feature_block(blocknumber, construct_block(GLOB.body_markings_list.Find(features["body_markings"]), GLOB.body_markings_list.len))
+ set_uni_feature_block(blocknumber, construct_block(SSaccessories.body_markings_list.Find(features["body_markings"]), length(SSaccessories.body_markings_list)))
if(DNA_TAIL_BLOCK)
- set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_human.Find(features["tail_cat"]), GLOB.tails_list_human.len))
+ set_uni_feature_block(blocknumber, construct_block(SSaccessories.tails_list_human.Find(features["tail_cat"]), length(SSaccessories.tails_list_human)))
if(DNA_LIZARD_TAIL_BLOCK)
- set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_lizard.Find(features["tail_lizard"]), GLOB.tails_list_lizard.len))
+ set_uni_feature_block(blocknumber, construct_block(SSaccessories.tails_list_lizard.Find(features["tail_lizard"]), length(SSaccessories.tails_list_lizard)))
if(DNA_MONKEY_TAIL_BLOCK)
- set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_monkey.Find(features["tail_monkey"]), GLOB.tails_list_monkey.len))
+ set_uni_feature_block(blocknumber, construct_block(SSaccessories.tails_list_monkey.Find(features["tail_monkey"]), length(SSaccessories.tails_list_monkey)))
if(DNA_SNOUT_BLOCK)
- set_uni_feature_block(blocknumber, construct_block(GLOB.snouts_list.Find(features["snout"]), GLOB.snouts_list.len))
+ set_uni_feature_block(blocknumber, construct_block(SSaccessories.snouts_list.Find(features["snout"]), length(SSaccessories.snouts_list)))
if(DNA_HORNS_BLOCK)
- set_uni_feature_block(blocknumber, construct_block(GLOB.horns_list.Find(features["horns"]), GLOB.horns_list.len))
+ set_uni_feature_block(blocknumber, construct_block(SSaccessories.horns_list.Find(features["horns"]), length(SSaccessories.horns_list)))
if(DNA_FRILLS_BLOCK)
- set_uni_feature_block(blocknumber, construct_block(GLOB.frills_list.Find(features["frills"]), GLOB.frills_list.len))
+ set_uni_feature_block(blocknumber, construct_block(SSaccessories.frills_list.Find(features["frills"]), length(SSaccessories.frills_list)))
if(DNA_SPINES_BLOCK)
- set_uni_feature_block(blocknumber, construct_block(GLOB.spines_list.Find(features["spines"]), GLOB.spines_list.len))
+ set_uni_feature_block(blocknumber, construct_block(SSaccessories.spines_list.Find(features["spines"]), length(SSaccessories.spines_list)))
if(DNA_EARS_BLOCK)
- set_uni_feature_block(blocknumber, construct_block(GLOB.ears_list.Find(features["ears"]), GLOB.ears_list.len))
+ set_uni_feature_block(blocknumber, construct_block(SSaccessories.ears_list.Find(features["ears"]), length(SSaccessories.ears_list)))
if(DNA_MOTH_WINGS_BLOCK)
- set_uni_feature_block(blocknumber, construct_block(GLOB.moth_wings_list.Find(features["moth_wings"]), GLOB.moth_wings_list.len))
+ set_uni_feature_block(blocknumber, construct_block(SSaccessories.moth_wings_list.Find(features["moth_wings"]), length(SSaccessories.moth_wings_list)))
if(DNA_MOTH_ANTENNAE_BLOCK)
- set_uni_feature_block(blocknumber, construct_block(GLOB.moth_antennae_list.Find(features["moth_antennae"]), GLOB.moth_antennae_list.len))
+ set_uni_feature_block(blocknumber, construct_block(SSaccessories.moth_antennae_list.Find(features["moth_antennae"]), length(SSaccessories.moth_antennae_list)))
if(DNA_MOTH_MARKINGS_BLOCK)
- set_uni_feature_block(blocknumber, construct_block(GLOB.moth_markings_list.Find(features["moth_markings"]), GLOB.moth_markings_list.len))
+ set_uni_feature_block(blocknumber, construct_block(SSaccessories.moth_markings_list.Find(features["moth_markings"]), length(SSaccessories.moth_markings_list)))
if(DNA_MUSHROOM_CAPS_BLOCK)
- set_uni_feature_block(blocknumber, construct_block(GLOB.caps_list.Find(features["caps"]), GLOB.caps_list.len))
+ set_uni_feature_block(blocknumber, construct_block(SSaccessories.caps_list.Find(features["caps"]), length(SSaccessories.caps_list)))
if(DNA_POD_HAIR_BLOCK)
- set_uni_feature_block(blocknumber, construct_block(GLOB.pod_hair_list.Find(features["pod_hair"]), GLOB.pod_hair_list.len))
+ set_uni_feature_block(blocknumber, construct_block(SSaccessories.pod_hair_list.Find(features["pod_hair"]), length(SSaccessories.pod_hair_list)))
//Please use add_mutation or activate_mutation instead
/datum/dna/proc/force_give(datum/mutation/human/human_mutation)
@@ -452,14 +451,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
if(create_mutation_blocks) //I hate this
generate_dna_blocks()
if(randomize_features)
- var/static/list/all_species_protoypes
- if(isnull(all_species_protoypes))
- all_species_protoypes = list()
- for(var/species_path in subtypesof(/datum/species))
- all_species_protoypes += new species_path()
-
- for(var/datum/species/random_species as anything in all_species_protoypes)
- features |= random_species.randomize_features()
+ for(var/species_type in GLOB.species_prototypes)
+ features |= GLOB.species_prototypes[species_type].randomize_features()
features["mcolor"] = "#[random_color()]"
@@ -624,12 +617,12 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
if(HAS_TRAIT(src, TRAIT_SHAVED))
set_facial_hairstyle("Shaved", update = FALSE)
else
- var/style = GLOB.facial_hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_FACIAL_HAIRSTYLE_BLOCK), GLOB.facial_hairstyles_list.len)]
+ var/style = SSaccessories.facial_hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_FACIAL_HAIRSTYLE_BLOCK), length(SSaccessories.facial_hairstyles_list))]
set_facial_hairstyle(style, update = FALSE)
if(HAS_TRAIT(src, TRAIT_BALD))
set_hairstyle("Bald", update = FALSE)
else
- var/style = GLOB.hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_HAIRSTYLE_BLOCK), GLOB.hairstyles_list.len)]
+ var/style = SSaccessories.hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_HAIRSTYLE_BLOCK), length(SSaccessories.hairstyles_list))]
set_hairstyle(style, update = FALSE)
var/features = dna.unique_features
if(dna.features["mcolor"])
@@ -637,37 +630,37 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
if(dna.features["ethcolor"])
dna.features["ethcolor"] = sanitize_hexcolor(get_uni_feature_block(features, DNA_ETHEREAL_COLOR_BLOCK))
if(dna.features["body_markings"])
- dna.features["body_markings"] = GLOB.body_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_MARKINGS_BLOCK), GLOB.body_markings_list.len)]
+ dna.features["body_markings"] = SSaccessories.body_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_MARKINGS_BLOCK), length(SSaccessories.body_markings_list))]
if(dna.features["snout"])
- dna.features["snout"] = GLOB.snouts_list[deconstruct_block(get_uni_feature_block(features, DNA_SNOUT_BLOCK), GLOB.snouts_list.len)]
+ dna.features["snout"] = SSaccessories.snouts_list[deconstruct_block(get_uni_feature_block(features, DNA_SNOUT_BLOCK), length(SSaccessories.snouts_list))]
if(dna.features["horns"])
- dna.features["horns"] = GLOB.horns_list[deconstruct_block(get_uni_feature_block(features, DNA_HORNS_BLOCK), GLOB.horns_list.len)]
+ dna.features["horns"] = SSaccessories.horns_list[deconstruct_block(get_uni_feature_block(features, DNA_HORNS_BLOCK), length(SSaccessories.horns_list))]
if(dna.features["frills"])
- dna.features["frills"] = GLOB.frills_list[deconstruct_block(get_uni_feature_block(features, DNA_FRILLS_BLOCK), GLOB.frills_list.len)]
+ dna.features["frills"] = SSaccessories.frills_list[deconstruct_block(get_uni_feature_block(features, DNA_FRILLS_BLOCK), length(SSaccessories.frills_list))]
if(dna.features["spines"])
- dna.features["spines"] = GLOB.spines_list[deconstruct_block(get_uni_feature_block(features, DNA_SPINES_BLOCK), GLOB.spines_list.len)]
+ dna.features["spines"] = SSaccessories.spines_list[deconstruct_block(get_uni_feature_block(features, DNA_SPINES_BLOCK), length(SSaccessories.spines_list))]
if(dna.features["tail_cat"])
- dna.features["tail_cat"] = GLOB.tails_list_human[deconstruct_block(get_uni_feature_block(features, DNA_TAIL_BLOCK), GLOB.tails_list_human.len)]
+ dna.features["tail_cat"] = SSaccessories.tails_list_human[deconstruct_block(get_uni_feature_block(features, DNA_TAIL_BLOCK), length(SSaccessories.tails_list_human))]
if(dna.features["tail_lizard"])
- dna.features["tail_lizard"] = GLOB.tails_list_lizard[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_TAIL_BLOCK), GLOB.tails_list_lizard.len)]
+ dna.features["tail_lizard"] = SSaccessories.tails_list_lizard[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_TAIL_BLOCK), length(SSaccessories.tails_list_lizard))]
if(dna.features["tail_monkey"])
- dna.features["tail_monkey"] = GLOB.tails_list_monkey[deconstruct_block(get_uni_feature_block(features, DNA_MONKEY_TAIL_BLOCK), GLOB.tails_list_monkey.len)]
+ dna.features["tail_monkey"] = SSaccessories.tails_list_monkey[deconstruct_block(get_uni_feature_block(features, DNA_MONKEY_TAIL_BLOCK), length(SSaccessories.tails_list_monkey))]
if(dna.features["ears"])
- dna.features["ears"] = GLOB.ears_list[deconstruct_block(get_uni_feature_block(features, DNA_EARS_BLOCK), GLOB.ears_list.len)]
+ dna.features["ears"] = SSaccessories.ears_list[deconstruct_block(get_uni_feature_block(features, DNA_EARS_BLOCK), length(SSaccessories.ears_list))]
if(dna.features["moth_wings"])
- var/genetic_value = GLOB.moth_wings_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_WINGS_BLOCK), GLOB.moth_wings_list.len)]
+ var/genetic_value = SSaccessories.moth_wings_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_WINGS_BLOCK), length(SSaccessories.moth_wings_list))]
dna.features["original_moth_wings"] = genetic_value
dna.features["moth_wings"] = genetic_value
if(dna.features["moth_antennae"])
- var/genetic_value = GLOB.moth_antennae_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_ANTENNAE_BLOCK), GLOB.moth_antennae_list.len)]
+ var/genetic_value = SSaccessories.moth_antennae_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_ANTENNAE_BLOCK), length(SSaccessories.moth_antennae_list))]
dna.features["original_moth_antennae"] = genetic_value
dna.features["moth_antennae"] = genetic_value
if(dna.features["moth_markings"])
- dna.features["moth_markings"] = GLOB.moth_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_MARKINGS_BLOCK), GLOB.moth_markings_list.len)]
+ dna.features["moth_markings"] = SSaccessories.moth_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_MOTH_MARKINGS_BLOCK), length(SSaccessories.moth_markings_list))]
if(dna.features["caps"])
- dna.features["caps"] = GLOB.caps_list[deconstruct_block(get_uni_feature_block(features, DNA_MUSHROOM_CAPS_BLOCK), GLOB.caps_list.len)]
+ dna.features["caps"] = SSaccessories.caps_list[deconstruct_block(get_uni_feature_block(features, DNA_MUSHROOM_CAPS_BLOCK), length(SSaccessories.caps_list))]
if(dna.features["pod_hair"])
- dna.features["pod_hair"] = GLOB.pod_hair_list[deconstruct_block(get_uni_feature_block(features, DNA_POD_HAIR_BLOCK), GLOB.pod_hair_list.len)]
+ dna.features["pod_hair"] = SSaccessories.pod_hair_list[deconstruct_block(get_uni_feature_block(features, DNA_POD_HAIR_BLOCK), length(SSaccessories.pod_hair_list))]
for(var/obj/item/organ/external/external_organ in organs)
external_organ.mutate_feature(features, src)
diff --git a/code/datums/elements/backblast.dm b/code/datums/elements/backblast.dm
index 8952afbfeaa21..f5e73977159cd 100644
--- a/code/datums/elements/backblast.dm
+++ b/code/datums/elements/backblast.dm
@@ -38,6 +38,9 @@
/// For firing an actual backblast pellet
/datum/element/backblast/proc/pew(obj/item/gun/weapon, mob/living/user, atom/target)
+ if(HAS_TRAIT(user, TRAIT_PACIFISM))
+ return
+
var/turf/origin = get_turf(weapon)
var/backblast_angle = get_angle(target, origin)
explosion(weapon, devastation_range = dev_range, heavy_impact_range = heavy_range, light_impact_range = light_range, flame_range = flame_range, adminlog = FALSE, protect_epicenter = TRUE, explosion_direction = backblast_angle, explosion_arc = blast_angle)
diff --git a/code/datums/quirks/neutral_quirks/bald.dm b/code/datums/quirks/neutral_quirks/bald.dm
index 8a760f6ceefdb..2844b790ddfd3 100644
--- a/code/datums/quirks/neutral_quirks/bald.dm
+++ b/code/datums/quirks/neutral_quirks/bald.dm
@@ -21,7 +21,7 @@
/datum/quirk/item_quirk/bald/add_unique(client/client_source)
var/obj/item/clothing/head/wig/natural/baldie_wig = new(get_turf(quirk_holder))
if(old_hair == "Bald")
- baldie_wig.hairstyle = pick(GLOB.hairstyles_list - "Bald")
+ baldie_wig.hairstyle = pick(SSaccessories.hairstyles_list - "Bald")
else
baldie_wig.hairstyle = old_hair
diff --git a/code/datums/sprite_accessories.dm b/code/datums/sprite_accessories.dm
index 40c17b774b1c2..e6e8b956e6568 100644
--- a/code/datums/sprite_accessories.dm
+++ b/code/datums/sprite_accessories.dm
@@ -16,35 +16,6 @@
* conversion in savefile.dm
*/
-/proc/init_sprite_accessory_subtypes(prototype, list/L, list/male, list/female, add_blank)//Roundstart argument builds a specific list for roundstart parts where some parts may be locked
- if(!istype(L))
- L = list()
- if(!istype(male))
- male = list()
- if(!istype(female))
- female = list()
-
- for(var/path in subtypesof(prototype))
- var/datum/sprite_accessory/D = new path()
-
- if(D.icon_state)
- L[D.name] = D
- else
- L += D.name
-
- switch(D.gender)
- if(MALE)
- male += D.name
- if(FEMALE)
- female += D.name
- else
- male += D.name
- female += D.name
- if(add_blank)
- L[SPRITE_ACCESSORY_NONE] = new /datum/sprite_accessory/blank
-
- return L
-
/datum/sprite_accessory
/// The icon file the accessory is located in.
var/icon
diff --git a/code/datums/station_traits/positive_traits.dm b/code/datums/station_traits/positive_traits.dm
index bff2d532570f9..8398e02139d74 100644
--- a/code/datums/station_traits/positive_traits.dm
+++ b/code/datums/station_traits/positive_traits.dm
@@ -292,6 +292,15 @@
weight_multiplier = 3
max_occurrences_modifier = 10 //lotta cows
+/datum/station_trait/bright_day
+ name = "Bright Day"
+ report_message = "The stars shine bright and the clouds are scarcer than usual. It's a bright day here on the Ice Moon's surface."
+ trait_type = STATION_TRAIT_POSITIVE
+ weight = 5
+ show_in_report = TRUE
+ trait_flags = STATION_TRAIT_PLANETARY
+ trait_to_give = STATION_TRAIT_BRIGHT_DAY
+
/datum/station_trait/shuttle_sale
name = "Shuttle Firesale"
report_message = "The Nanotrasen Emergency Dispatch team is celebrating a record number of shuttle calls in the recent quarter. Some of your emergency shuttle options have been discounted!"
diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm
index b1bacfbceab44..9b661688258f1 100644
--- a/code/datums/storage/storage.dm
+++ b/code/datums/storage/storage.dm
@@ -113,6 +113,10 @@
/// If TRUE, shows the contents of the storage in open_storage
var/display_contents = TRUE
+ /// Switch this off if you want to handle click_alt in the parent atom
+ var/click_alt_open = TRUE
+
+
/datum/storage/New(
atom/parent,
max_slots = src.max_slots,
@@ -198,7 +202,7 @@
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby))
RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, PROC_REF(on_preattack))
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(mass_empty))
- RegisterSignals(parent, list(COMSIG_CLICK_ALT, COMSIG_ATOM_ATTACK_GHOST, COMSIG_ATOM_ATTACK_HAND_SECONDARY), PROC_REF(open_storage_on_signal))
+ RegisterSignals(parent, list(COMSIG_ATOM_ATTACK_GHOST, COMSIG_ATOM_ATTACK_HAND_SECONDARY), PROC_REF(open_storage_on_signal))
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY_SECONDARY, PROC_REF(open_storage_attackby_secondary))
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(close_distance))
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(update_actions))
@@ -208,6 +212,7 @@
RegisterSignal(parent, COMSIG_OBJ_DECONSTRUCT, PROC_REF(on_deconstruct))
RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp_act))
RegisterSignal(parent, COMSIG_ATOM_CONTENTS_WEIGHT_CLASS_CHANGED, PROC_REF(contents_changed_w_class))
+ RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(on_click_alt))
/**
* Sets where items are physically being stored in the case it shouldn't be on the parent.
@@ -919,6 +924,17 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
if(display_contents)
return COMPONENT_NO_AFTERATTACK
+
+/// Alt click on the storage item. Default: Open the storage.
+/datum/storage/proc/on_click_alt(datum/source, mob/user)
+ SIGNAL_HANDLER
+
+ if(!click_alt_open)
+ return
+
+ return open_storage_on_signal(source, user)
+
+
/// Opens the storage to the mob, showing them the contents to their UI.
/datum/storage/proc/open_storage(mob/to_show)
if(isobserver(to_show))
diff --git a/code/datums/storage/subtypes/pockets.dm b/code/datums/storage/subtypes/pockets.dm
index 67a8b2dda7804..2b100d5d3232b 100644
--- a/code/datums/storage/subtypes/pockets.dm
+++ b/code/datums/storage/subtypes/pockets.dm
@@ -45,6 +45,7 @@
/datum/storage/pockets/small/fedora/detective
attack_hand_interact = TRUE // so the detectives would discover pockets in their hats
+ click_alt_open = FALSE
/datum/storage/pockets/chefhat
attack_hand_interact = TRUE
diff --git a/code/datums/votes/_vote_datum.dm b/code/datums/votes/_vote_datum.dm
index 3f821a7129ada..76833f73ff5b0 100644
--- a/code/datums/votes/_vote_datum.dm
+++ b/code/datums/votes/_vote_datum.dm
@@ -15,25 +15,25 @@
var/list/default_choices
/// Does the name of this vote contain the word "vote"?
var/contains_vote_in_name = FALSE
- /// What message do we want to pass to the player-side vote panel as a tooltip?
- var/message = "Click to initiate a vote."
+ /// What message do we show as the tooltip of this vote if the vote can be initiated?
+ var/default_message = "Click to initiate a vote."
+ /// The counting method we use for votes.
+ var/count_method = VOTE_COUNT_METHOD_SINGLE
+ /// The method for selecting a winner.
+ var/winner_method = VOTE_WINNER_METHOD_SIMPLE
+ /// Should we show details about the number of votes submitted for each option?
+ var/display_statistics = TRUE
// Internal values used when tracking ongoing votes.
// Don't mess with these, change the above values / override procs for subtypes.
/// An assoc list of [all choices] to [number of votes in the current running vote].
- var/list/choices = list()
+ VAR_FINAL/list/choices = list()
/// A assoc list of [ckey] to [what they voted for in the current running vote].
- var/list/choices_by_ckey = list()
+ VAR_FINAL/list/choices_by_ckey = list()
/// The world time this vote was started.
- var/started_time
+ VAR_FINAL/started_time = -1
/// The time remaining in this vote's run.
- var/time_remaining
- /// The counting method we use for votes.
- var/count_method = VOTE_COUNT_METHOD_SINGLE
- /// The method for selecting a winner.
- var/winner_method = VOTE_WINNER_METHOD_SIMPLE
- /// Should we show details about the number of votes submitted for each option?
- var/display_statistics = TRUE
+ VAR_FINAL/time_remaining = -1
/**
* Used to determine if this vote is a possible
@@ -55,14 +55,13 @@
choices.Cut()
choices_by_ckey.Cut()
started_time = null
- time_remaining = null
+ time_remaining = -1
/**
* If this vote has a config associated, toggles it between enabled and disabled.
- * Returns TRUE on a successful toggle, FALSE otherwise
*/
-/datum/vote/proc/toggle_votable(mob/toggler)
- return FALSE
+/datum/vote/proc/toggle_votable()
+ return
/**
* If this vote has a config associated, returns its value (True or False, usually).
@@ -74,20 +73,18 @@
/**
* Checks if the passed mob can initiate this vote.
*
- * Return TRUE if the mob can begin the vote, allowing anyone to actually vote on it.
- * Return FALSE if the mob cannot initiate the vote.
+ * * forced - if being invoked by someone who is an admin
+ *
+ * Return VOTE_AVAILABLE if the mob can initiate the vote.
+ * Return a string with the reason why the mob can't initiate the vote.
*/
-/datum/vote/proc/can_be_initiated(mob/by_who, forced = FALSE)
+/datum/vote/proc/can_be_initiated(forced = FALSE)
SHOULD_CALL_PARENT(TRUE)
- if(started_time)
- var/next_allowed_time = (started_time + CONFIG_GET(number/vote_delay))
- if(next_allowed_time > world.time && !forced)
- message = "A vote was initiated recently. You must wait [DisplayTimeText(next_allowed_time - world.time)] before a new vote can be started!"
- return FALSE
+ if(!forced && !is_config_enabled())
+ return "This vote is currently disabled by the server configuration."
- message = initial(message)
- return TRUE
+ return VOTE_AVAILABLE
/**
* Called prior to the vote being initiated.
diff --git a/code/datums/votes/custom_vote.dm b/code/datums/votes/custom_vote.dm
index d67eb0281c6c6..78eb6d3b876d8 100644
--- a/code/datums/votes/custom_vote.dm
+++ b/code/datums/votes/custom_vote.dm
@@ -1,14 +1,9 @@
/// The max amount of options someone can have in a custom vote.
#define MAX_CUSTOM_VOTE_OPTIONS 10
-/datum/vote/custom_vote/single
- name = "Custom Standard"
- message = "Click here to start a custom vote (one selection per voter)"
-
-/datum/vote/custom_vote/multi
- name = "Custom Multi"
- message = "Click here to start a custom multi vote (multiple selections per voter)"
- count_method = VOTE_COUNT_METHOD_MULTI
+/datum/vote/custom_vote
+ name = "Custom"
+ default_message = "Click here to start a custom vote."
// Custom votes ares always accessible.
/datum/vote/custom_vote/is_accessible_vote()
@@ -17,23 +12,45 @@
/datum/vote/custom_vote/reset()
default_choices = null
override_question = null
+ count_method = VOTE_COUNT_METHOD_SINGLE
return ..()
-/datum/vote/custom_vote/can_be_initiated(mob/by_who, forced = FALSE)
+/datum/vote/custom_vote/can_be_initiated(forced)
. = ..()
- if(!.)
- return FALSE
+ if(. != VOTE_AVAILABLE)
+ return .
+ if(forced)
+ return .
// Custom votes can only be created if they're forced to be made.
// (Either an admin makes it, or otherwise.)
- return forced
+ return "Only admins can create custom votes."
/datum/vote/custom_vote/create_vote(mob/vote_creator)
+ var/custom_count_method = tgui_input_list(
+ user = vote_creator,
+ message = "Single or multiple choice?",
+ title = "Choice Method",
+ items = list("Single", "Multiple"),
+ default = "Single",
+ )
+ switch(custom_count_method)
+ if("Single")
+ count_method = VOTE_COUNT_METHOD_SINGLE
+ if("Multiple")
+ count_method = VOTE_COUNT_METHOD_MULTI
+ if(null)
+ return FALSE
+ else
+ stack_trace("Got '[custom_count_method]' in create_vote() for custom voting.")
+ to_chat(vote_creator, span_boldwarning("Unknown choice method. Contact a coder."))
+ return FALSE
+
var/custom_win_method = tgui_input_list(
- vote_creator,
- "How should the vote winner be determined?",
- "Winner Method",
- list("Simple", "Weighted Random", "No Winner"),
+ user = vote_creator,
+ message = "How should the vote winner be determined?",
+ title = "Winner Method",
+ items = list("Simple", "Weighted Random", "No Winner"),
default = "Simple",
)
switch(custom_win_method)
@@ -43,7 +60,10 @@
winner_method = VOTE_WINNER_METHOD_WEIGHTED_RANDOM
if("No Winner")
winner_method = VOTE_WINNER_METHOD_NONE
+ if(null)
+ return FALSE
else
+ stack_trace("Got '[custom_win_method]' in create_vote() for custom voting.")
to_chat(vote_creator, span_boldwarning("Unknown winner method. Contact a coder."))
return FALSE
@@ -54,7 +74,7 @@
list("Yes", "No"),
)
- if(display_stats == null)
+ if(isnull(display_stats))
return FALSE
display_statistics = display_stats == "Yes"
@@ -74,6 +94,9 @@
if(!length(default_choices))
return FALSE
+ // Sanity for all the tgui input stalling we are doing
+ if(isnull(vote_creator.client?.holder))
+ return FALSE
return ..()
diff --git a/code/datums/votes/map_vote.dm b/code/datums/votes/map_vote.dm
index a07d87846f050..abe452ce4fedf 100644
--- a/code/datums/votes/map_vote.dm
+++ b/code/datums/votes/map_vote.dm
@@ -1,6 +1,6 @@
/datum/vote/map_vote
name = "Map"
- message = "Vote for next round's map!"
+ default_message = "Vote for next round's map!"
count_method = VOTE_COUNT_METHOD_SINGLE
winner_method = VOTE_WINNER_METHOD_WEIGHTED_RANDOM
display_statistics = FALSE
@@ -21,77 +21,62 @@
/datum/vote/map_vote/create_vote()
. = ..()
- check_population(should_key_choices = FALSE)
- if(length(choices) == 1) // Only one choice, no need to vote. Let's just auto-rotate it to the only remaining map because it would just happen anyways.
- var/de_facto_winner = choices[1]
- var/datum/map_config/change_me_out = global.config.maplist[de_facto_winner]
- SSmapping.changemap(change_me_out)
- to_chat(world, span_boldannounce("The map vote has been skipped because there is only one map left to vote for. The map has been changed to [change_me_out.map_name]."))
- SSmapping.map_voted = TRUE // voted by not voting, very sad.
+ if(!.)
return FALSE
-/datum/vote/map_vote/toggle_votable(mob/toggler)
- if(!toggler)
- CRASH("[type] wasn't passed a \"toggler\" mob to toggle_votable.")
- if(!check_rights_for(toggler.client, R_ADMIN))
+ choices -= get_choices_invalid_for_population()
+ if(length(choices) == 1) // Only one choice, no need to vote. Let's just auto-rotate it to the only remaining map because it would just happen anyways.
+ var/datum/map_config/change_me_out = global.config.maplist[choices[1]]
+ finalize_vote(choices[1])// voted by not voting, very sad.
+ to_chat(world, span_boldannounce("The map vote has been skipped because there is only one map left to vote for. \
+ The map has been changed to [change_me_out.map_name]."))
+ return FALSE
+ if(length(choices) == 0)
+ to_chat(world, span_boldannounce("A map vote was called, but there are no maps to vote for! \
+ Players, complain to the admins. Admins, complain to the coders."))
return FALSE
- CONFIG_SET(flag/allow_vote_map, !CONFIG_GET(flag/allow_vote_map))
return TRUE
+/datum/vote/map_vote/toggle_votable()
+ CONFIG_SET(flag/allow_vote_map, !CONFIG_GET(flag/allow_vote_map))
+
/datum/vote/map_vote/is_config_enabled()
return CONFIG_GET(flag/allow_vote_map)
-/datum/vote/map_vote/can_be_initiated(mob/by_who, forced = FALSE)
+/datum/vote/map_vote/can_be_initiated(forced)
. = ..()
- if(!.)
- return FALSE
-
+ if(. != VOTE_AVAILABLE)
+ return .
if(forced)
- return TRUE
-
- var/number_of_choices = length(check_population())
- if(number_of_choices < 2)
- message = "There [number_of_choices == 1 ? "is only one map" : "are no maps"] to choose from."
- return FALSE
-
+ return VOTE_AVAILABLE
+ var/num_choices = length(default_choices - get_choices_invalid_for_population())
+ if(num_choices <= 1)
+ return "There [num_choices == 1 ? "is only one map" : "are no maps"] to choose from."
if(SSmapping.map_vote_rocked)
- return TRUE
-
- if(!CONFIG_GET(flag/allow_vote_map))
- message = "Map voting is disabled by server configuration settings."
- return FALSE
-
+ return VOTE_AVAILABLE
if(SSmapping.map_voted)
- message = "The next map has already been selected."
- return FALSE
-
- message = initial(message)
- return TRUE
-
-/// Before we create a vote, remove all maps from our choices that are outside of our population range.
-/// Note that this can result in zero remaining choices for our vote, which is not ideal (but ultimately okay).
-/// Argument should_key_choices is TRUE, pass as FALSE in a context where choices are already keyed in a list.
-/datum/vote/map_vote/proc/check_population(should_key_choices = TRUE)
- if(should_key_choices)
- for(var/key in default_choices)
- choices[key] = 0
+ return "The next map has already been selected."
+ return VOTE_AVAILABLE
+/// Returns a list of all map options that are invalid for the current population.
+/datum/vote/map_vote/proc/get_choices_invalid_for_population()
var/filter_threshold = 0
if(SSticker.HasRoundStarted())
filter_threshold = get_active_player_count(alive_check = FALSE, afk_check = TRUE, human_check = FALSE)
else
filter_threshold = GLOB.clients.len
- for(var/map in choices)
+ var/list/invalid_choices = list()
+ for(var/map in default_choices)
var/datum/map_config/possible_config = config.maplist[map]
if(possible_config.config_min_users > 0 && filter_threshold < possible_config.config_min_users)
- choices -= map
+ invalid_choices += map
else if(possible_config.config_max_users > 0 && filter_threshold > possible_config.config_max_users)
- choices -= map
+ invalid_choices += map
- return choices
+ return invalid_choices
/datum/vote/map_vote/get_vote_result(list/non_voters)
// Even if we have default no vote off,
diff --git a/code/datums/votes/restart_vote.dm b/code/datums/votes/restart_vote.dm
index 987d5b87eb363..3c74d7e518e28 100644
--- a/code/datums/votes/restart_vote.dm
+++ b/code/datums/votes/restart_vote.dm
@@ -7,7 +7,8 @@
CHOICE_RESTART,
CHOICE_CONTINUE,
)
- message = "Vote to restart the ongoing round."
+ default_message = "Vote to restart the ongoing round. \
+ Only works if there are no non-AFK admins online."
/// This proc checks to see if any admins are online for the purposes of this vote to see if it can pass. Returns TRUE if there are valid admins online (Has +SERVER and is not AFK), FALSE otherwise.
/datum/vote/restart_vote/proc/admins_present()
@@ -19,36 +20,24 @@
return FALSE
-/datum/vote/restart_vote/toggle_votable(mob/toggler)
- if(!toggler)
- CRASH("[type] wasn't passed a \"toggler\" mob to toggle_votable.")
-
- if(!check_rights_for(toggler.client, R_ADMIN))
- return FALSE
-
+/datum/vote/restart_vote/toggle_votable()
CONFIG_SET(flag/allow_vote_restart, !CONFIG_GET(flag/allow_vote_restart))
- return TRUE
/datum/vote/restart_vote/is_config_enabled()
return CONFIG_GET(flag/allow_vote_restart)
-/datum/vote/restart_vote/can_be_initiated(mob/by_who, forced)
+/datum/vote/restart_vote/create_vote(mob/vote_creator)
. = ..()
if(!.)
- return FALSE
-
- if(!forced && !CONFIG_GET(flag/allow_vote_restart))
- message = "Restart voting is disabled by server configuration settings."
- return FALSE
-
- // We still want players to be able to vote to restart even if valid admins are online. Let's update the message just so that the player is aware of this fact.
- // We don't want to lock-out the vote though, so we'll return TRUE.
- if(admins_present())
- message = "Regardless of the results of this vote, the round will not automatically restart because an admin is online."
- return TRUE
+ return
+ if(!admins_present())
+ return
+ async_alert_about_admins(vote_creator)
- message = initial(message)
- return TRUE
+/datum/vote/restart_vote/proc/async_alert_about_admins(mob/vote_creator)
+ set waitfor = FALSE
+ tgui_alert(vote_creator, "Note: Regardless of the results of this vote, \
+ the round will not automatically restart because an active admin is online.")
/datum/vote/restart_vote/get_vote_result(list/non_voters)
if(!CONFIG_GET(flag/default_no_vote))
diff --git a/code/datums/votes/rock_the_vote.dm b/code/datums/votes/rock_the_vote.dm
index 6cffeb5ad6702..6c7ac4ff2572e 100644
--- a/code/datums/votes/rock_the_vote.dm
+++ b/code/datums/votes/rock_the_vote.dm
@@ -10,58 +10,40 @@
CHOICE_TO_ROCK,
CHOICE_NOT_TO_ROCK,
)
- message = "Override the current map vote."
+ default_message = "Override the current map vote."
/// The number of times we have rocked the vote thus far.
var/rocking_votes = 0
-/datum/vote/rock_the_vote/toggle_votable(mob/toggler)
- if(!toggler)
- CRASH("[type] wasn't passed a \"toggler\" mob to toggle_votable.")
- if(!check_rights_for(toggler.client, R_ADMIN))
- return FALSE
-
+/datum/vote/rock_the_vote/toggle_votable()
CONFIG_SET(flag/allow_rock_the_vote, !CONFIG_GET(flag/allow_rock_the_vote))
- return TRUE
/datum/vote/rock_the_vote/is_config_enabled()
return CONFIG_GET(flag/allow_rock_the_vote)
-/datum/vote/rock_the_vote/can_be_initiated(mob/by_who, forced)
+/datum/vote/rock_the_vote/can_be_initiated(forced)
. = ..()
-
- if(!.)
- return FALSE
-
- if(!forced && !CONFIG_GET(flag/allow_rock_the_vote))
- message = "Rocking the vote is disabled by this server's configuration settings."
- return FALSE
+ if(. != VOTE_AVAILABLE)
+ return .
if(SSticker.current_state == GAME_STATE_FINISHED)
- message = "The game is finished, no map votes can be initiated."
- return FALSE
+ return "The game is finished, no map votes can be initiated."
if(rocking_votes >= CONFIG_GET(number/max_rocking_votes))
- message = "The maximum number of times to rock the vote has been reached."
- return FALSE
+ return "The maximum number of times to rock the vote has been reached."
if(SSmapping.map_vote_rocked)
- message = "The vote has already been rocked! Initiate a map vote!"
- return FALSE
+ return "The vote has already been rocked! Initiate a map vote!"
if(!SSmapping.map_voted)
- message = "Rocking the vote is disabled because no map has been voted on yet!"
- return FALSE
+ return "Rocking the vote is disabled because no map has been voted on yet!"
if(SSmapping.map_force_chosen)
- message = "Rocking the vote is disabled because an admin has forcibly set the map!"
- return FALSE
+ return "Rocking the vote is disabled because an admin has forcibly set the map!"
if(EMERGENCY_ESCAPED_OR_ENDGAMED && SSmapping.map_voted)
- message = "The emergency shuttle has already left the station and the next map has already been chosen!"
- return FALSE
+ return "The emergency shuttle has already left the station and the next map has already been chosen!"
- message = initial(message)
- return TRUE
+ return VOTE_AVAILABLE
/datum/vote/rock_the_vote/finalize_vote(winning_option)
rocking_votes++
diff --git a/code/game/area/areas/mining.dm b/code/game/area/areas/mining.dm
index 1582f7390cf04..38855de366f9f 100644
--- a/code/game/area/areas/mining.dm
+++ b/code/game/area/areas/mining.dm
@@ -209,6 +209,11 @@
name = "Icemoon Wastes"
outdoors = TRUE
+/area/icemoon/surface/outdoors/Initialize(mapload)
+ if(HAS_TRAIT(SSstation, STATION_TRAIT_BRIGHT_DAY))
+ base_lighting_alpha = 145
+ return ..()
+
/area/icemoon/surface/outdoors/nospawn // this is the area you use for stuff to not spawn, but if you still want weather.
/area/icemoon/surface/outdoors/nospawn/New() // unless you roll forested trait lol
diff --git a/code/game/machinery/civilian_bounties.dm b/code/game/machinery/civilian_bounties.dm
index 1cb7ee1477ef2..792c1ba22eb31 100644
--- a/code/game/machinery/civilian_bounties.dm
+++ b/code/game/machinery/civilian_bounties.dm
@@ -184,6 +184,9 @@
data["id_bounty_names"] = list(inserted_scan_id.registered_account.bounties[1].name,
inserted_scan_id.registered_account.bounties[2].name,
inserted_scan_id.registered_account.bounties[3].name)
+ data["id_bounty_infos"] = list(inserted_scan_id.registered_account.bounties[1].description,
+ inserted_scan_id.registered_account.bounties[2].description,
+ inserted_scan_id.registered_account.bounties[3].description)
data["id_bounty_values"] = list(inserted_scan_id.registered_account.bounties[1].reward * (CIV_BOUNTY_SPLIT/100),
inserted_scan_id.registered_account.bounties[2].reward * (CIV_BOUNTY_SPLIT/100),
inserted_scan_id.registered_account.bounties[3].reward * (CIV_BOUNTY_SPLIT/100))
diff --git a/code/game/machinery/computer/arcade/battle.dm b/code/game/machinery/computer/arcade/battle.dm
index 63d2808c773e0..b97dac9e15dad 100644
--- a/code/game/machinery/computer/arcade/battle.dm
+++ b/code/game/machinery/computer/arcade/battle.dm
@@ -531,7 +531,8 @@
return
player_turn = TRUE
ui_panel = UI_PANEL_WORLD_MAP
- player_gold /= 2
+ if(player_gold)
+ player_gold = max(round(player_gold /= 2, 1), 0)
return TRUE
//they pressed something but it wasn't in the menu, we'll be nice and give them back their turn anyway.
player_turn = TRUE
diff --git a/code/game/machinery/computer/records/security.dm b/code/game/machinery/computer/records/security.dm
index 0797b4d1890a1..c41779e7384ec 100644
--- a/code/game/machinery/computer/records/security.dm
+++ b/code/game/machinery/computer/records/security.dm
@@ -49,10 +49,8 @@
if(prob(10/severity))
switch(rand(1,5))
if(1)
- if(prob(10))
- target.name = "[pick(lizard_name(MALE),lizard_name(FEMALE))]"
- else
- target.name = "[pick(pick(GLOB.first_names_male), pick(GLOB.first_names_female))] [pick(GLOB.last_names)]"
+ target.name = generate_random_name()
+
if(2)
target.gender = pick("Male", "Female", "Other")
if(3)
diff --git a/code/game/machinery/doors/poddoor.dm b/code/game/machinery/doors/poddoor.dm
index ea8d758666e7d..48e0cb195d7f3 100644
--- a/code/game/machinery/doors/poddoor.dm
+++ b/code/game/machinery/doors/poddoor.dm
@@ -35,6 +35,72 @@
/obj/machinery/door/poddoor/get_save_vars()
return ..() + NAMEOF(src, id)
+/obj/machinery/door/poddoor/examine(mob/user)
+ . = ..()
+ if(panel_open)
+ if(deconstruction == BLASTDOOR_FINISHED)
+ . += span_notice("The maintenance panel is opened and the electronics could be pried out.")
+ . += span_notice("\The [src] could be calibrated to a blast door controller ID with a multitool .")
+ else if(deconstruction == BLASTDOOR_NEEDS_ELECTRONICS)
+ . += span_notice("The electronics are missing and there are some wires sticking out.")
+ else if(deconstruction == BLASTDOOR_NEEDS_WIRES)
+ . += span_notice("The wires have been removed and it's ready to be sliced apart .")
+
+/obj/machinery/door/poddoor/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+ . = ..()
+ if(isnull(held_item))
+ return NONE
+ if(deconstruction == BLASTDOOR_NEEDS_WIRES && istype(held_item, /obj/item/stack/cable_coil))
+ context[SCREENTIP_CONTEXT_LMB] = "Wire assembly"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(deconstruction == BLASTDOOR_NEEDS_ELECTRONICS && istype(held_item, /obj/item/electronics/airlock))
+ context[SCREENTIP_CONTEXT_LMB] = "Add electronics"
+ return CONTEXTUAL_SCREENTIP_SET
+ //we do not check for special effects like if they can actually perform the action because they will be told they can't do it when they try,
+ //with feedback on what they have to do in order to do so.
+ switch(held_item.tool_behaviour)
+ if(TOOL_SCREWDRIVER)
+ context[SCREENTIP_CONTEXT_LMB] = "Open panel"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(TOOL_MULTITOOL)
+ context[SCREENTIP_CONTEXT_LMB] = "Calibrate ID"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(TOOL_CROWBAR)
+ context[SCREENTIP_CONTEXT_LMB] = "Remove electronics"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(TOOL_WIRECUTTER)
+ context[SCREENTIP_CONTEXT_LMB] = "Remove wires"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(TOOL_WELDER)
+ context[SCREENTIP_CONTEXT_LMB] = "Disassemble"
+ return CONTEXTUAL_SCREENTIP_SET
+
+/obj/machinery/door/poddoor/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
+ if(deconstruction == BLASTDOOR_NEEDS_WIRES && istype(tool, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/coil = tool
+ var/datum/crafting_recipe/recipe = locate(recipe_type) in GLOB.crafting_recipes
+ var/amount_needed = recipe.reqs[/obj/item/stack/cable_coil]
+ if(coil.get_amount() < amount_needed)
+ balloon_alert(user, "not enough cable!")
+ return ITEM_INTERACT_SUCCESS
+ balloon_alert(user, "adding cables...")
+ if(!do_after(user, 5 SECONDS, src))
+ return ITEM_INTERACT_SUCCESS
+ coil.use(amount_needed)
+ deconstruction = BLASTDOOR_NEEDS_ELECTRONICS
+ balloon_alert(user, "cables added")
+ return ITEM_INTERACT_SUCCESS
+
+ if(deconstruction == BLASTDOOR_NEEDS_ELECTRONICS && istype(tool, /obj/item/electronics/airlock))
+ balloon_alert(user, "adding electronics...")
+ if(!do_after(user, 10 SECONDS, src))
+ return ITEM_INTERACT_SUCCESS
+ qdel(tool)
+ balloon_alert(user, "electronics added")
+ deconstruction = BLASTDOOR_FINISHED
+ return ITEM_INTERACT_SUCCESS
+ return NONE
+
/obj/machinery/door/poddoor/screwdriver_act(mob/living/user, obj/item/tool)
. = ..()
if (density)
@@ -49,7 +115,8 @@
balloon_alert(user, "open the door first!")
return ITEM_INTERACT_SUCCESS
if (!panel_open)
- return
+ balloon_alert(user, "open the panel first!")
+ return ITEM_INTERACT_SUCCESS
if (deconstruction != BLASTDOOR_FINISHED)
return
var/change_id = tgui_input_number(user, "Set the door controllers ID (Current: [id])", "Door Controller ID", isnum(id) ? id : null, 100)
@@ -69,7 +136,8 @@
balloon_alert(user, "open the door first!")
return ITEM_INTERACT_SUCCESS
if (!panel_open)
- return
+ balloon_alert(user, "open the panel first!")
+ return ITEM_INTERACT_SUCCESS
if (deconstruction != BLASTDOOR_FINISHED)
return
balloon_alert(user, "removing airlock electronics...")
@@ -86,7 +154,8 @@
balloon_alert(user, "open the door first!")
return ITEM_INTERACT_SUCCESS
if (!panel_open)
- return
+ balloon_alert(user, "open the panel first!")
+ return ITEM_INTERACT_SUCCESS
if (deconstruction != BLASTDOOR_NEEDS_ELECTRONICS)
return
balloon_alert(user, "removing internal cables...")
@@ -104,7 +173,8 @@
balloon_alert(user, "open the door first!")
return ITEM_INTERACT_SUCCESS
if (!panel_open)
- return
+ balloon_alert(user, "open the panel first!")
+ return ITEM_INTERACT_SUCCESS
if (deconstruction != BLASTDOOR_NEEDS_WIRES)
return
balloon_alert(user, "tearing apart...") //You're tearing me apart, Lisa!
@@ -116,17 +186,6 @@
qdel(src)
return ITEM_INTERACT_SUCCESS
-/obj/machinery/door/poddoor/examine(mob/user)
- . = ..()
- if(panel_open)
- if(deconstruction == BLASTDOOR_FINISHED)
- . += span_notice("The maintenance panel is opened and the electronics could be pried out.")
- . += span_notice("\The [src] could be calibrated to a blast door controller ID with a multitool .")
- else if(deconstruction == BLASTDOOR_NEEDS_ELECTRONICS)
- . += span_notice("The electronics are missing and there are some wires sticking out.")
- else if(deconstruction == BLASTDOOR_NEEDS_WIRES)
- . += span_notice("The wires have been removed and it's ready to be sliced apart .")
-
/obj/machinery/door/poddoor/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock)
id = "[port.shuttle_id]_[id]"
diff --git a/code/game/machinery/doors/shutters.dm b/code/game/machinery/doors/shutters.dm
index eca8d88da4baf..0df6024ca827a 100644
--- a/code/game/machinery/doors/shutters.dm
+++ b/code/game/machinery/doors/shutters.dm
@@ -16,6 +16,9 @@
density = FALSE
opacity = FALSE
+/obj/machinery/door/poddoor/shutters/preopen/deconstructed
+ deconstruction = BLASTDOOR_NEEDS_WIRES
+
/obj/machinery/door/poddoor/shutters/indestructible
name = "hardened shutters"
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm
index f21bfc4788426..0af1e402ee1dd 100644
--- a/code/game/objects/effects/decals/cleanable/misc.dm
+++ b/code/game/objects/effects/decals/cleanable/misc.dm
@@ -412,9 +412,7 @@
. += emissive_appearance(icon, "[icon_state]_light", src, alpha = src.alpha)
/obj/effect/decal/cleanable/ants/fire_act(exposed_temperature, exposed_volume)
- var/obj/effect/decal/cleanable/ants/fire/fire_ants = new(loc)
- fire_ants.reagents.clear_reagents()
- reagents.trans_to(fire_ants, fire_ants.reagents.maximum_volume)
+ new /obj/effect/decal/cleanable/ants/fire(loc)
qdel(src)
/obj/effect/decal/cleanable/ants/fire
diff --git a/code/game/objects/items/bodybag.dm b/code/game/objects/items/bodybag.dm
index 7e67b23c3b716..19d3d273337c4 100644
--- a/code/game/objects/items/bodybag.dm
+++ b/code/game/objects/items/bodybag.dm
@@ -14,12 +14,11 @@
else
deploy_bodybag(user, get_turf(src))
-/obj/item/bodybag/afterattack(atom/target, mob/user, proximity)
- . = ..()
- if(proximity)
- if(isopenturf(target))
- deploy_bodybag(user, target)
-
+/obj/item/bodybag/interact_with_atom(atom/interacting_with, mob/living/user, flags)
+ if(isopenturf(interacting_with))
+ deploy_bodybag(user, interacting_with)
+ return ITEM_INTERACT_SUCCESS
+ return NONE
/obj/item/bodybag/attempt_pickup(mob/user)
// can't pick ourselves up if we are inside of the bodybag, else very weird things may happen
if(contains(user))
diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm
index 71f3a244a3081..1e6c2b35ede2c 100644
--- a/code/game/objects/items/cardboard_cutouts.dm
+++ b/code/game/objects/items/cardboard_cutouts.dm
@@ -317,7 +317,7 @@
outfit = /datum/outfit/ashwalker/spear
/datum/cardboard_cutout/ash_walker/get_name()
- return lizard_name(pick(MALE, FEMALE))
+ return generate_random_name_species_based(species_type = /datum/species/lizard)
/datum/cardboard_cutout/death_squad
name = "Deathsquad Officer"
diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm
index a78d9d4fbf0b9..b16cf3a6ef61a 100644
--- a/code/game/objects/items/cosmetics.dm
+++ b/code/game/objects/items/cosmetics.dm
@@ -217,7 +217,7 @@
return
if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
- var/new_style = tgui_input_list(user, "Select a facial hairstyle", "Grooming", GLOB.facial_hairstyles_list)
+ var/new_style = tgui_input_list(user, "Select a facial hairstyle", "Grooming", SSaccessories.facial_hairstyles_list)
if(isnull(new_style))
return
if(!get_location_accessible(human_target, location))
@@ -270,7 +270,7 @@
return
if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
- var/new_style = tgui_input_list(user, "Select a hairstyle", "Grooming", GLOB.hairstyles_list)
+ var/new_style = tgui_input_list(user, "Select a hairstyle", "Grooming", SSaccessories.hairstyles_list)
if(isnull(new_style))
return
if(!get_location_accessible(human_target, location))
diff --git a/code/game/objects/items/debug_items.dm b/code/game/objects/items/debug_items.dm
index 4f6239acbe817..44f53df2c2b2d 100644
--- a/code/game/objects/items/debug_items.dm
+++ b/code/game/objects/items/debug_items.dm
@@ -21,7 +21,7 @@
/obj/item/debug/human_spawner/attack_self(mob/user)
..()
- var/choice = input("Select a species", "Human Spawner", null) in GLOB.species_list
+ var/choice = input("Select a species", "Human Spawner", null) in sortTim(GLOB.species_list, GLOBAL_PROC_REF(cmp_text_asc))
selected_species = GLOB.species_list[choice]
/obj/item/debug/omnitool
@@ -168,4 +168,3 @@
var/turf/loc_turf = get_turf(src)
for(var/spawn_atom in (choice == "No" ? typesof(path) : subtypesof(path)))
new spawn_atom(loc_turf)
-
diff --git a/code/game/objects/items/dyespray.dm b/code/game/objects/items/dyespray.dm
index fd198ec1c40e3..b64f15fe69073 100644
--- a/code/game/objects/items/dyespray.dm
+++ b/code/game/objects/items/dyespray.dm
@@ -27,7 +27,7 @@
if(!beard_or_hair || !user.can_perform_action(src, NEED_DEXTERITY))
return
- var/list/choices = beard_or_hair == "Hair" ? GLOB.hair_gradients_list : GLOB.facial_hair_gradients_list
+ var/list/choices = beard_or_hair == "Hair" ? SSaccessories.hair_gradients_list : SSaccessories.facial_hair_gradients_list
var/new_grad_style = tgui_input_list(user, "Choose a color pattern", "Character Preference", choices)
if(isnull(new_grad_style))
return
diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm
index 064f933573ca3..63625536b74b5 100644
--- a/code/game/objects/items/stacks/rods.dm
+++ b/code/game/objects/items/stacks/rods.dm
@@ -1,19 +1,20 @@
GLOBAL_LIST_INIT(rod_recipes, list ( \
- new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = FALSE, check_density = FALSE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("table frame", /obj/structure/table_frame, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("scooter frame", /obj/item/scooter_frame, 10, time = 2.5 SECONDS, one_per_turf = FALSE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("linen bin", /obj/structure/bedsheetbin/empty, 2, time = 0.5 SECONDS, one_per_turf = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("railing", /obj/structure/railing, 2, time = 1 SECONDS, check_direction = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("railing corner", /obj/structure/railing/corner, 1, time = 1 SECONDS, check_direction = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("railing end", /obj/structure/railing/corner/end, 1, time = 1 SECONDS, check_direction = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("railing end (flipped)", /obj/structure/railing/corner/end/flip, 1, time = 1 SECONDS, check_direction = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("tank holder", /obj/structure/tank_holder, 2, time = 0.5 SECONDS, one_per_turf = TRUE, on_solid_ground = FALSE, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("ladder", /obj/structure/ladder/crafted, 15, time = 15 SECONDS, one_per_turf = TRUE, on_solid_ground = FALSE, check_density = FALSE, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 1 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("table frame", /obj/structure/table_frame, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("scooter frame", /obj/item/scooter_frame, 10, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("linen bin", /obj/structure/bedsheetbin/empty, 2, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("railing", /obj/structure/railing, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_CHECK_DIRECTION, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("railing corner", /obj/structure/railing/corner, 1, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_CHECK_DIRECTION, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("railing end", /obj/structure/railing/corner/end, 1, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_CHECK_DIRECTION, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("railing end (flipped)", /obj/structure/railing/corner/end/flip, 1, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_CHECK_DIRECTION, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("tank holder", /obj/structure/tank_holder, 2, time = 0.5 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("ladder", /obj/structure/ladder/crafted, 15, time = 15 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
new/datum/stack_recipe("catwalk floor tile", /obj/item/stack/tile/catwalk_tile, 1, 4, 20, category = CAT_TILES), \
- new/datum/stack_recipe("stairs frame", /obj/structure/stairs_frame, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("white cane", /obj/item/cane/white, 3, time = 1 SECONDS, one_per_turf = FALSE, category = CAT_TOOLS), \
- new/datum/stack_recipe("sharpened iron rod", /obj/item/ammo_casing/rebar, 1, time = 0.2 SECONDS, one_per_turf = FALSE, category = CAT_WEAPON_AMMO), \
+ new/datum/stack_recipe("stairs frame", /obj/structure/stairs_frame, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("white cane", /obj/item/cane/white, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY, category = CAT_TOOLS), \
+ new/datum/stack_recipe("sharpened iron rod", /obj/item/ammo_casing/rebar, 1, time = 0.2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY, category = CAT_WEAPON_AMMO), \
))
+
/obj/item/stack/rods
name = "iron rod"
desc = "Some rods. Can be used for building or something."
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index 1f66b80cf55b7..e93b8c4cea59d 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -9,9 +9,9 @@
* Glass sheets
*/
GLOBAL_LIST_INIT(glass_recipes, list ( \
- new/datum/stack_recipe("directional window", /obj/structure/window/unanchored, time = 0.5 SECONDS, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("fulltile window", /obj/structure/window/fulltile/unanchored, 2, time = 1 SECONDS, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("glass shard", /obj/item/shard, time = 0, on_solid_ground = TRUE, category = CAT_MISC), \
+ new/datum/stack_recipe("directional window", /obj/structure/window/unanchored, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("fulltile window", /obj/structure/window/fulltile/unanchored, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("glass shard", /obj/item/shard, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC), \
new/datum/stack_recipe("glass tile", /obj/item/stack/tile/glass, 1, 4, 20, category = CAT_TILES) \
))
@@ -82,9 +82,9 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
return ..()
GLOBAL_LIST_INIT(pglass_recipes, list ( \
- new/datum/stack_recipe("directional window", /obj/structure/window/plasma/unanchored, time = 0.5 SECONDS, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("fulltile window", /obj/structure/window/plasma/fulltile/unanchored, 2, time = 2 SECONDS, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("plasma glass shard", /obj/item/shard/plasma, time = 20, on_solid_ground = TRUE, category = CAT_MISC), \
+ new/datum/stack_recipe("directional window", /obj/structure/window/plasma/unanchored, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("fulltile window", /obj/structure/window/plasma/fulltile/unanchored, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("plasma glass shard", /obj/item/shard/plasma, time = 20, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC), \
new/datum/stack_recipe("plasma glass tile", /obj/item/stack/tile/glass/plasma, 1, 4, 20, category = CAT_TILES) \
))
@@ -138,11 +138,11 @@ GLOBAL_LIST_INIT(pglass_recipes, list ( \
* Reinforced glass sheets
*/
GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \
- new/datum/stack_recipe("windoor frame", /obj/structure/windoor_assembly, 5, time = 0, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("windoor frame", /obj/structure/windoor_assembly, 5, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \
null, \
- new/datum/stack_recipe("directional reinforced window", /obj/structure/window/reinforced/unanchored, time = 0.5 SECONDS, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/reinforced/fulltile/unanchored, 2, time = 2 SECONDS, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("glass shard", /obj/item/shard, time = 10, on_solid_ground = TRUE, category = CAT_MISC), \
+ new/datum/stack_recipe("directional reinforced window", /obj/structure/window/reinforced/unanchored, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/reinforced/fulltile/unanchored, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("glass shard", /obj/item/shard, time = 10, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC), \
new/datum/stack_recipe("reinforced glass tile", /obj/item/stack/tile/rglass, 1, 4, 20, category = CAT_TILES) \
))
@@ -177,9 +177,9 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \
. += GLOB.reinforced_glass_recipes
GLOBAL_LIST_INIT(prglass_recipes, list ( \
- new/datum/stack_recipe("directional reinforced window", /obj/structure/window/reinforced/plasma/unanchored, time = 0.5 SECONDS, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/reinforced/plasma/fulltile/unanchored, 2, time = 2 SECONDS, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("plasma glass shard", /obj/item/shard/plasma, time = 40, on_solid_ground = TRUE, category = CAT_MISC), \
+ new/datum/stack_recipe("directional reinforced window", /obj/structure/window/reinforced/plasma/unanchored, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/reinforced/plasma/fulltile/unanchored, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("plasma glass shard", /obj/item/shard/plasma, time = 40, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC), \
new/datum/stack_recipe("reinforced plasma glass tile", /obj/item/stack/tile/rglass/plasma, 1, 4, 20, category = CAT_TILES) \
))
@@ -212,8 +212,8 @@ GLOBAL_LIST_INIT(prglass_recipes, list ( \
. += GLOB.prglass_recipes
GLOBAL_LIST_INIT(titaniumglass_recipes, list(
- new/datum/stack_recipe("shuttle window", /obj/structure/window/reinforced/shuttle/unanchored, 2, time = 0.5 SECONDS, on_solid_ground = TRUE, check_direction = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("titanium glass shard", /obj/item/shard/titanium, time = 40, on_solid_ground = TRUE, category = CAT_MISC) \
+ new/datum/stack_recipe("shuttle window", /obj/structure/window/reinforced/shuttle/unanchored, 2, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("titanium glass shard", /obj/item/shard/titanium, time = 40, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC) \
))
/obj/item/stack/sheet/titaniumglass
@@ -241,8 +241,8 @@ GLOBAL_LIST_INIT(titaniumglass_recipes, list(
. += GLOB.titaniumglass_recipes
GLOBAL_LIST_INIT(plastitaniumglass_recipes, list(
- new/datum/stack_recipe("plastitanium window", /obj/structure/window/reinforced/plasma/plastitanium/unanchored, 2, time = 2 SECONDS, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("plastitanium glass shard", /obj/item/shard/plastitanium, time = 60, on_solid_ground = TRUE, category = CAT_MISC) \
+ new/datum/stack_recipe("plastitanium window", /obj/structure/window/reinforced/plasma/plastitanium/unanchored, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("plastitanium glass shard", /obj/item/shard/plastitanium, time = 60, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC) \
))
/obj/item/stack/sheet/plastitaniumglass
diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm
index 851e544ff8a83..2d1636e9e165a 100644
--- a/code/game/objects/items/stacks/sheets/leather.dm
+++ b/code/game/objects/items/stacks/sheets/leather.dm
@@ -14,8 +14,8 @@
merge_type = /obj/item/stack/sheet/animalhide/human
GLOBAL_LIST_INIT(human_recipes, list( \
- new/datum/stack_recipe("bloated human costume", /obj/item/clothing/suit/hooded/bloated_human, 5, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("human skin hat", /obj/item/clothing/head/fedora/human_leather, 1, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("bloated human costume", /obj/item/clothing/suit/hooded/bloated_human, 5, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("human skin hat", /obj/item/clothing/head/fedora/human_leather, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
))
/obj/item/stack/sheet/animalhide/human/get_main_recipes()
@@ -55,9 +55,9 @@ GLOBAL_LIST_INIT(human_recipes, list( \
amount = 5
GLOBAL_LIST_INIT(gondola_recipes, list ( \
- new/datum/stack_recipe("gondola mask", /obj/item/clothing/mask/gondola, 1, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("gondola suit", /obj/item/clothing/under/costume/gondola, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("gondola bedsheet", /obj/item/bedsheet/gondola, 1, check_density = FALSE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("gondola mask", /obj/item/clothing/mask/gondola, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("gondola suit", /obj/item/clothing/under/costume/gondola, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("gondola bedsheet", /obj/item/bedsheet/gondola, 1, crafting_flags = NONE, category = CAT_FURNITURE), \
))
/obj/item/stack/sheet/animalhide/gondola
@@ -73,7 +73,7 @@ GLOBAL_LIST_INIT(gondola_recipes, list ( \
. += GLOB.gondola_recipes
GLOBAL_LIST_INIT(corgi_recipes, list ( \
- new/datum/stack_recipe("corgi costume", /obj/item/clothing/suit/hooded/ian_costume, 3, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("corgi costume", /obj/item/clothing/suit/hooded/ian_costume, 3, crafting_flags = NONE, category = CAT_CLOTHING), \
))
/obj/item/stack/sheet/animalhide/corgi/get_main_recipes()
@@ -100,8 +100,8 @@ GLOBAL_LIST_INIT(corgi_recipes, list ( \
merge_type = /obj/item/stack/sheet/animalhide/monkey
GLOBAL_LIST_INIT(monkey_recipes, list ( \
- new/datum/stack_recipe("monkey mask", /obj/item/clothing/mask/gas/monkeymask, 1, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("monkey suit", /obj/item/clothing/suit/costume/monkeysuit, 2, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("monkey mask", /obj/item/clothing/mask/gas/monkeymask, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("monkey suit", /obj/item/clothing/suit/costume/monkeysuit, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
))
/obj/item/stack/sheet/animalhide/monkey/get_main_recipes()
@@ -131,8 +131,8 @@ GLOBAL_LIST_INIT(monkey_recipes, list ( \
merge_type = /obj/item/stack/sheet/animalhide/xeno
GLOBAL_LIST_INIT(xeno_recipes, list ( \
- new/datum/stack_recipe("alien helmet", /obj/item/clothing/head/costume/xenos, 1, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("alien suit", /obj/item/clothing/suit/costume/xenos, 2, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("alien helmet", /obj/item/clothing/head/costume/xenos, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("alien suit", /obj/item/clothing/suit/costume/xenos, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
))
/obj/item/stack/sheet/animalhide/xeno/get_main_recipes()
@@ -151,11 +151,11 @@ GLOBAL_LIST_INIT(xeno_recipes, list ( \
merge_type = /obj/item/stack/sheet/animalhide/carp
GLOBAL_LIST_INIT(carp_recipes, list ( \
- new/datum/stack_recipe("carp costume", /obj/item/clothing/suit/hooded/carp_costume, 4, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("carp mask", /obj/item/clothing/mask/gas/carp, 1, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("carpskin chair", /obj/structure/chair/comfy/carp, 2, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("carpskin suit", /obj/item/clothing/under/suit/carpskin, 3, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("carpskin fedora", /obj/item/clothing/head/fedora/carpskin, 2, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("carp costume", /obj/item/clothing/suit/hooded/carp_costume, 4, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("carp mask", /obj/item/clothing/mask/gas/carp, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("carpskin chair", /obj/structure/chair/comfy/carp, 2, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("carpskin suit", /obj/item/clothing/under/suit/carpskin, 3, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("carpskin fedora", /obj/item/clothing/head/fedora/carpskin, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
))
/obj/item/stack/sheet/animalhide/carp/get_main_recipes()
@@ -193,33 +193,33 @@ GLOBAL_LIST_INIT(carp_recipes, list ( \
merge_type = /obj/item/stack/sheet/leather
GLOBAL_LIST_INIT(leather_recipes, list ( \
- new/datum/stack_recipe("wallet", /obj/item/storage/wallet, 1, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("muzzle", /obj/item/clothing/mask/muzzle, 2, check_density = FALSE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("basketball", /obj/item/toy/basketball, 20, check_density = FALSE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("baseball", /obj/item/toy/beach_ball/baseball, 3, check_density = FALSE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("saddle", /obj/item/goliath_saddle, 5, check_density = FALSE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("leather shoes", /obj/item/clothing/shoes/laceup, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("cowboy boots", /obj/item/clothing/shoes/cowboy, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("botany gloves", /obj/item/clothing/gloves/botanic_leather, 3, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("leather satchel", /obj/item/storage/backpack/satchel/leather, 5, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("sheriff vest", /obj/item/clothing/accessory/vest_sheriff, 4, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("leather jacket", /obj/item/clothing/suit/jacket/leather, 7, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("biker jacket", /obj/item/clothing/suit/jacket/leather/biker, 7, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("wallet", /obj/item/storage/wallet, 1, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("muzzle", /obj/item/clothing/mask/muzzle, 2, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("basketball", /obj/item/toy/basketball, 20, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("baseball", /obj/item/toy/beach_ball/baseball, 3, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("saddle", /obj/item/goliath_saddle, 5, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("leather shoes", /obj/item/clothing/shoes/laceup, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("cowboy boots", /obj/item/clothing/shoes/cowboy, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("botany gloves", /obj/item/clothing/gloves/botanic_leather, 3, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("leather satchel", /obj/item/storage/backpack/satchel/leather, 5, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("sheriff vest", /obj/item/clothing/accessory/vest_sheriff, 4, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("leather jacket", /obj/item/clothing/suit/jacket/leather, 7, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("biker jacket", /obj/item/clothing/suit/jacket/leather/biker, 7, crafting_flags = NONE, category = CAT_CLOTHING), \
new/datum/stack_recipe_list("belts", list( \
- new/datum/stack_recipe("tool belt", /obj/item/storage/belt/utility, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("botanical belt", /obj/item/storage/belt/plant, 2, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("janitorial belt", /obj/item/storage/belt/janitor, 2, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("medical belt", /obj/item/storage/belt/medical, 2, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("security belt", /obj/item/storage/belt/security, 2, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("shoulder holster", /obj/item/storage/belt/holster, 3, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("bandolier", /obj/item/storage/belt/bandolier, 5, check_density = FALSE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("tool belt", /obj/item/storage/belt/utility, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("botanical belt", /obj/item/storage/belt/plant, 2, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("janitorial belt", /obj/item/storage/belt/janitor, 2, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("medical belt", /obj/item/storage/belt/medical, 2, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("security belt", /obj/item/storage/belt/security, 2, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("shoulder holster", /obj/item/storage/belt/holster, 3, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("bandolier", /obj/item/storage/belt/bandolier, 5, crafting_flags = NONE, category = CAT_CONTAINERS), \
)),
new/datum/stack_recipe_list("cowboy hats", list( \
- new/datum/stack_recipe("sheriff hat", /obj/item/clothing/head/cowboy/brown, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("desperado hat", /obj/item/clothing/head/cowboy/black, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("ten-gallon hat", /obj/item/clothing/head/cowboy/white, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("deputy hat", /obj/item/clothing/head/cowboy/red, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("drifter hat", /obj/item/clothing/head/cowboy/grey, 2, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("sheriff hat", /obj/item/clothing/head/cowboy/brown, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("desperado hat", /obj/item/clothing/head/cowboy/black, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("ten-gallon hat", /obj/item/clothing/head/cowboy/white, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("deputy hat", /obj/item/clothing/head/cowboy/red, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("drifter hat", /obj/item/clothing/head/cowboy/grey, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
)),
))
@@ -263,7 +263,7 @@ GLOBAL_LIST_INIT(leather_recipes, list ( \
merge_type = /obj/item/stack/sheet/sinew/wolf
GLOBAL_LIST_INIT(sinew_recipes, list ( \
- new/datum/stack_recipe("sinew restraints", /obj/item/restraints/handcuffs/cable/sinew, 1, check_density = FALSE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("sinew restraints", /obj/item/restraints/handcuffs/cable/sinew, 1, crafting_flags = NONE, category = CAT_EQUIPMENT), \
))
/obj/item/stack/sheet/sinew/get_main_recipes()
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index 1b3d66a7dae92..f6e7d797fd95c 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -24,8 +24,8 @@ Mineral Sheets
*/
GLOBAL_LIST_INIT(sandstone_recipes, list ( \
- new/datum/stack_recipe("sandstone door", /obj/structure/mineral_door/sandstone, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("Breakdown into sand", /obj/item/stack/ore/glass, 1, one_per_turf = FALSE, on_solid_ground = TRUE, category = CAT_MISC) \
+ new/datum/stack_recipe("sandstone door", /obj/structure/mineral_door/sandstone, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \
+ new/datum/stack_recipe("Breakdown into sand", /obj/item/stack/ore/glass, 1, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC) \
))
/obj/item/stack/sheet/mineral/sandstone
@@ -62,7 +62,7 @@ GLOBAL_LIST_INIT(sandstone_recipes, list ( \
merge_type = /obj/item/stack/sheet/mineral/sandbags
GLOBAL_LIST_INIT(sandbag_recipes, list ( \
- new/datum/stack_recipe("sandbags", /obj/structure/barricade/sandbags, 1, time = 3 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("sandbags", /obj/structure/barricade/sandbags, 1, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
))
/obj/item/stack/sheet/mineral/sandbags/get_main_recipes()
@@ -105,8 +105,8 @@ GLOBAL_LIST_INIT(sandbag_recipes, list ( \
walltype = /turf/closed/wall/mineral/diamond
GLOBAL_LIST_INIT(diamond_recipes, list ( \
- new/datum/stack_recipe("diamond door", /obj/structure/mineral_door/transparent/diamond, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("diamond tile", /obj/item/stack/tile/mineral/diamond, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("diamond door", /obj/structure/mineral_door/transparent/diamond, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \
+ new/datum/stack_recipe("diamond tile", /obj/item/stack/tile/mineral/diamond, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/diamond/get_main_recipes()
@@ -130,8 +130,8 @@ GLOBAL_LIST_INIT(diamond_recipes, list ( \
walltype = /turf/closed/wall/mineral/uranium
GLOBAL_LIST_INIT(uranium_recipes, list ( \
- new/datum/stack_recipe("uranium door", /obj/structure/mineral_door/uranium, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("uranium tile", /obj/item/stack/tile/mineral/uranium, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("uranium door", /obj/structure/mineral_door/uranium, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \
+ new/datum/stack_recipe("uranium tile", /obj/item/stack/tile/mineral/uranium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/uranium/get_main_recipes()
@@ -167,8 +167,8 @@ GLOBAL_LIST_INIT(uranium_recipes, list ( \
return TOXLOSS//dont you kids know that stuff is toxic?
GLOBAL_LIST_INIT(plasma_recipes, list ( \
- new/datum/stack_recipe("plasma door", /obj/structure/mineral_door/transparent/plasma, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("plasma tile", /obj/item/stack/tile/mineral/plasma, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("plasma door", /obj/structure/mineral_door/transparent/plasma, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \
+ new/datum/stack_recipe("plasma tile", /obj/item/stack/tile/mineral/plasma, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/plasma/get_main_recipes()
@@ -198,10 +198,10 @@ GLOBAL_LIST_INIT(plasma_recipes, list ( \
walltype = /turf/closed/wall/mineral/gold
GLOBAL_LIST_INIT(gold_recipes, list ( \
- new/datum/stack_recipe("golden door", /obj/structure/mineral_door/gold, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("gold tile", /obj/item/stack/tile/mineral/gold, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
- new/datum/stack_recipe("blank plaque", /obj/item/plaque, 1, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("Simple Crown", /obj/item/clothing/head/costume/crown, 5, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("golden door", /obj/structure/mineral_door/gold, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \
+ new/datum/stack_recipe("gold tile", /obj/item/stack/tile/mineral/gold, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
+ new/datum/stack_recipe("blank plaque", /obj/item/plaque, 1, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("Simple Crown", /obj/item/clothing/head/costume/crown, 5, crafting_flags = NONE, category = CAT_CLOTHING), \
))
/obj/item/stack/sheet/mineral/gold/get_main_recipes()
@@ -226,8 +226,8 @@ GLOBAL_LIST_INIT(gold_recipes, list ( \
walltype = /turf/closed/wall/mineral/silver
GLOBAL_LIST_INIT(silver_recipes, list ( \
- new/datum/stack_recipe("silver door", /obj/structure/mineral_door/silver, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("silver tile", /obj/item/stack/tile/mineral/silver, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("silver door", /obj/structure/mineral_door/silver, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \
+ new/datum/stack_recipe("silver tile", /obj/item/stack/tile/mineral/silver, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/silver/get_main_recipes()
@@ -251,7 +251,7 @@ GLOBAL_LIST_INIT(silver_recipes, list ( \
walltype = /turf/closed/wall/mineral/bananium
GLOBAL_LIST_INIT(bananium_recipes, list ( \
- new/datum/stack_recipe("bananium tile", /obj/item/stack/tile/mineral/bananium, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("bananium tile", /obj/item/stack/tile/mineral/bananium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/bananium/get_main_recipes()
@@ -282,8 +282,8 @@ GLOBAL_LIST_INIT(bananium_recipes, list ( \
walltype = /turf/closed/wall/mineral/titanium
GLOBAL_LIST_INIT(titanium_recipes, list ( \
- new/datum/stack_recipe("Titanium tile", /obj/item/stack/tile/mineral/titanium, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
- new/datum/stack_recipe("Shuttle seat", /obj/structure/chair/comfy/shuttle, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("Titanium tile", /obj/item/stack/tile/mineral/titanium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
+ new/datum/stack_recipe("Shuttle seat", /obj/structure/chair/comfy/shuttle, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
))
/obj/item/stack/sheet/mineral/titanium/get_main_recipes()
@@ -315,7 +315,7 @@ GLOBAL_LIST_INIT(titanium_recipes, list ( \
walltype = /turf/closed/wall/mineral/plastitanium
GLOBAL_LIST_INIT(plastitanium_recipes, list ( \
- new/datum/stack_recipe("plastitanium tile", /obj/item/stack/tile/mineral/plastitanium, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("plastitanium tile", /obj/item/stack/tile/mineral/plastitanium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/plastitanium/get_main_recipes()
@@ -341,10 +341,10 @@ GLOBAL_LIST_INIT(plastitanium_recipes, list ( \
material_type = /datum/material/snow
GLOBAL_LIST_INIT(snow_recipes, list ( \
- new/datum/stack_recipe("snow wall", /turf/closed/wall/mineral/snow, 5, time = 4 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("snowman", /obj/structure/statue/snow/snowman, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("snowball", /obj/item/toy/snowball, 1, check_density = FALSE, category = CAT_WEAPON_RANGED), \
- new/datum/stack_recipe("snow tile", /obj/item/stack/tile/mineral/snow, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("snow wall", /turf/closed/wall/mineral/snow, 5, time = 4 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("snowman", /obj/structure/statue/snow/snowman, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("snowball", /obj/item/toy/snowball, 1, crafting_flags = NONE, category = CAT_WEAPON_RANGED), \
+ new/datum/stack_recipe("snow tile", /obj/item/stack/tile/mineral/snow, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/snow/Initialize(mapload, new_amount, merge, list/mat_override, mat_amt)
@@ -421,12 +421,12 @@ GLOBAL_LIST_INIT(adamantine_recipes, list(
walltype = /turf/closed/wall/mineral/abductor
GLOBAL_LIST_INIT(abductor_recipes, list ( \
- new/datum/stack_recipe("alien bed", /obj/structure/bed/abductor, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("alien locker", /obj/structure/closet/abductor, 2, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("alien table frame", /obj/structure/table_frame/abductor, 1, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("alien airlock assembly", /obj/structure/door_assembly/door_assembly_abductor, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
+ new/datum/stack_recipe("alien bed", /obj/structure/bed/abductor, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("alien locker", /obj/structure/closet/abductor, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("alien table frame", /obj/structure/table_frame/abductor, 1, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("alien airlock assembly", /obj/structure/door_assembly/door_assembly_abductor, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
null, \
- new/datum/stack_recipe("alien floor tile", /obj/item/stack/tile/mineral/abductor, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("alien floor tile", /obj/item/stack/tile/mineral/abductor, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/abductor/get_main_recipes()
@@ -469,10 +469,10 @@ GLOBAL_LIST_INIT(abductor_recipes, list ( \
//Metal Hydrogen
GLOBAL_LIST_INIT(metalhydrogen_recipes, list(
- new /datum/stack_recipe("incomplete servant golem shell", /obj/item/golem_shell/servant, req_amount=20, res_amount=1, check_density = FALSE, category = CAT_ROBOT),
- new /datum/stack_recipe("ancient armor", /obj/item/clothing/suit/armor/elder_atmosian, req_amount = 5, res_amount = 1, check_density = FALSE, category = CAT_CLOTHING),
- new /datum/stack_recipe("ancient helmet", /obj/item/clothing/head/helmet/elder_atmosian, req_amount = 3, res_amount = 1, check_density = FALSE, category = CAT_CLOTHING),
- new /datum/stack_recipe("metallic hydrogen axe", /obj/item/fireaxe/metal_h2_axe, req_amount = 15, res_amount = 1, check_density = FALSE, category = CAT_WEAPON_MELEE),
+ new /datum/stack_recipe("incomplete servant golem shell", /obj/item/golem_shell/servant, req_amount=20, res_amount=1, crafting_flags = NONE, category = CAT_ROBOT),
+ new /datum/stack_recipe("ancient armor", /obj/item/clothing/suit/armor/elder_atmosian, req_amount = 5, res_amount = 1, crafting_flags = NONE, category = CAT_CLOTHING),
+ new /datum/stack_recipe("ancient helmet", /obj/item/clothing/head/helmet/elder_atmosian, req_amount = 3, res_amount = 1, crafting_flags = NONE, category = CAT_CLOTHING),
+ new /datum/stack_recipe("metallic hydrogen axe", /obj/item/fireaxe/metal_h2_axe, req_amount = 15, res_amount = 1, crafting_flags = NONE, category = CAT_WEAPON_MELEE),
))
/obj/item/stack/sheet/mineral/metal_hydrogen
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index f00767217a493..be6226f49bf8e 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -15,127 +15,127 @@
* Iron
*/
GLOBAL_LIST_INIT(metal_recipes, list ( \
- new/datum/stack_recipe("stool", /obj/structure/chair/stool, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("bar stool", /obj/structure/chair/stool/bar, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("bed", /obj/structure/bed, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("double bed", /obj/structure/bed/double, 4, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("stool", /obj/structure/chair/stool, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("bar stool", /obj/structure/chair/stool/bar, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("bed", /obj/structure/bed, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("double bed", /obj/structure/bed/double, 4, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
null, \
new/datum/stack_recipe_list("office chairs", list( \
- new/datum/stack_recipe("dark office chair", /obj/structure/chair/office, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("light office chair", /obj/structure/chair/office/light, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("dark office chair", /obj/structure/chair/office, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("light office chair", /obj/structure/chair/office/light, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
)), \
new/datum/stack_recipe_list("comfy chairs", list( \
- new/datum/stack_recipe("beige comfy chair", /obj/structure/chair/comfy/beige, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("black comfy chair", /obj/structure/chair/comfy/black, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("brown comfy chair", /obj/structure/chair/comfy/brown, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("lime comfy chair", /obj/structure/chair/comfy/lime, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("teal comfy chair", /obj/structure/chair/comfy/teal, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("beige comfy chair", /obj/structure/chair/comfy/beige, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("black comfy chair", /obj/structure/chair/comfy/black, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("brown comfy chair", /obj/structure/chair/comfy/brown, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("lime comfy chair", /obj/structure/chair/comfy/lime, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("teal comfy chair", /obj/structure/chair/comfy/teal, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
)), \
new/datum/stack_recipe_list("sofas", list(
- new /datum/stack_recipe("sofa (middle)", /obj/structure/chair/sofa/middle, 1, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("sofa (left)", /obj/structure/chair/sofa/left, 1, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("sofa (right)", /obj/structure/chair/sofa/right, 1, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("sofa (corner)", /obj/structure/chair/sofa/corner, 1, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE)
+ new /datum/stack_recipe("sofa (middle)", /obj/structure/chair/sofa/middle, 1, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),
+ new /datum/stack_recipe("sofa (left)", /obj/structure/chair/sofa/left, 1, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),
+ new /datum/stack_recipe("sofa (right)", /obj/structure/chair/sofa/right, 1, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),
+ new /datum/stack_recipe("sofa (corner)", /obj/structure/chair/sofa/corner, 1, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE)
)), \
new/datum/stack_recipe_list("corporate sofas", list( \
- new /datum/stack_recipe("sofa (middle)", /obj/structure/chair/sofa/corp, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("sofa (left)", /obj/structure/chair/sofa/corp/left, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("sofa (right)", /obj/structure/chair/sofa/corp/right, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("sofa (corner)", /obj/structure/chair/sofa/corp/corner, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("sofa (middle)", /obj/structure/chair/sofa/corp, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("sofa (left)", /obj/structure/chair/sofa/corp/left, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("sofa (right)", /obj/structure/chair/sofa/corp/right, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("sofa (corner)", /obj/structure/chair/sofa/corp/corner, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
)), \
new /datum/stack_recipe_list("benches", list( \
- new /datum/stack_recipe("bench (middle)", /obj/structure/chair/sofa/bench, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("bench (left)", /obj/structure/chair/sofa/bench/left, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("bench (right)", /obj/structure/chair/sofa/bench/right, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("bench (corner)", /obj/structure/chair/sofa/bench/corner, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("tram bench (solo)", /obj/structure/chair/sofa/bench/tram/solo, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("tram bench (middle)", /obj/structure/chair/sofa/bench/tram, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("tram bench (left)", /obj/structure/chair/sofa/bench/tram/left, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("tram bench (right)", /obj/structure/chair/sofa/bench/tram/right, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("tram bench (corner)", /obj/structure/chair/sofa/bench/tram/corner, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("bench (middle)", /obj/structure/chair/sofa/bench, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("bench (left)", /obj/structure/chair/sofa/bench/left, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("bench (right)", /obj/structure/chair/sofa/bench/right, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("bench (corner)", /obj/structure/chair/sofa/bench/corner, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("tram bench (solo)", /obj/structure/chair/sofa/bench/tram/solo, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("tram bench (middle)", /obj/structure/chair/sofa/bench/tram, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("tram bench (left)", /obj/structure/chair/sofa/bench/tram/left, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("tram bench (right)", /obj/structure/chair/sofa/bench/tram/right, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("tram bench (corner)", /obj/structure/chair/sofa/bench/tram/corner, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
)), \
new /datum/stack_recipe_list("chess pieces", list( \
- new /datum/stack_recipe("White Pawn", /obj/structure/chess/whitepawn, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("White Rook", /obj/structure/chess/whiterook, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("White Knight", /obj/structure/chess/whiteknight, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("White Bishop", /obj/structure/chess/whitebishop, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("White Queen", /obj/structure/chess/whitequeen, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("White King", /obj/structure/chess/whiteking, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black Pawn", /obj/structure/chess/blackpawn, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black Rook", /obj/structure/chess/blackrook, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black Knight", /obj/structure/chess/blackknight, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black Bishop", /obj/structure/chess/blackbishop, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black Queen", /obj/structure/chess/blackqueen, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black King", /obj/structure/chess/blackking, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White Pawn", /obj/structure/chess/whitepawn, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White Rook", /obj/structure/chess/whiterook, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White Knight", /obj/structure/chess/whiteknight, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White Bishop", /obj/structure/chess/whitebishop, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White Queen", /obj/structure/chess/whitequeen, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White King", /obj/structure/chess/whiteking, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black Pawn", /obj/structure/chess/blackpawn, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black Rook", /obj/structure/chess/blackrook, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black Knight", /obj/structure/chess/blackknight, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black Bishop", /obj/structure/chess/blackbishop, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black Queen", /obj/structure/chess/blackqueen, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black King", /obj/structure/chess/blackking, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
)),
new /datum/stack_recipe_list("checkers pieces", list( \
- new /datum/stack_recipe("White Checker Man", /obj/structure/chess/checker/whiteman, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("White Checker King", /obj/structure/chess/checker/whiteking, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black Checker Man", /obj/structure/chess/checker/blackman, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black Checker King", /obj/structure/chess/checker/blackking, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White Checker Man", /obj/structure/chess/checker/whiteman, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White Checker King", /obj/structure/chess/checker/whiteking, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black Checker Man", /obj/structure/chess/checker/blackman, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black Checker King", /obj/structure/chess/checker/blackking, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
)),
null, \
new/datum/stack_recipe("rack parts", /obj/item/rack_parts, category = CAT_FURNITURE), \
- new/datum/stack_recipe("closet", /obj/structure/closet, 2, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("closet", /obj/structure/closet, 2, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
null, \
- new/datum/stack_recipe("atmos canister", /obj/machinery/portable_atmospherics/canister, 10, time = 3 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ATMOSPHERIC), \
- new/datum/stack_recipe("pipe", /obj/item/pipe/quaternary/pipe/crafted, 1, time = 4 SECONDS, check_density = FALSE, category = CAT_ATMOSPHERIC), \
+ new/datum/stack_recipe("atmos canister", /obj/machinery/portable_atmospherics/canister, 10, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ATMOSPHERIC), \
+ new/datum/stack_recipe("pipe", /obj/item/pipe/quaternary/pipe/crafted, 1, time = 4 SECONDS, crafting_flags = NONE, category = CAT_ATMOSPHERIC), \
null, \
new/datum/stack_recipe("floor tile", /obj/item/stack/tile/iron/base, 1, 4, 20, category = CAT_TILES), \
new/datum/stack_recipe("iron rod", /obj/item/stack/rods, 1, 2, 60, category = CAT_MISC), \
null, \
- new/datum/stack_recipe("wall girders (anchored)", /obj/structure/girder, 2, time = 4 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, placement_checks = STACK_CHECK_TRAM_FORBIDDEN, trait_booster = TRAIT_QUICK_BUILD, trait_modifier = 0.75, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("wall girders (anchored)", /obj/structure/girder, 2, time = 4 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, placement_checks = STACK_CHECK_TRAM_FORBIDDEN, trait_booster = TRAIT_QUICK_BUILD, trait_modifier = 0.75, category = CAT_STRUCTURE), \
null, \
null, \
- new/datum/stack_recipe("computer frame", /obj/structure/frame/computer, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("modular console", /obj/machinery/modular_computer, 10, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("machine frame", /obj/structure/frame/machine, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("computer frame", /obj/structure/frame/computer, 5, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("modular console", /obj/machinery/modular_computer, 10, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("machine frame", /obj/structure/frame/machine, 5, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
null, \
new /datum/stack_recipe_list("airlock assemblies", list( \
- new /datum/stack_recipe("standard airlock assembly", /obj/structure/door_assembly, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("public airlock assembly", /obj/structure/door_assembly/door_assembly_public, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("command airlock assembly", /obj/structure/door_assembly/door_assembly_com, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("security airlock assembly", /obj/structure/door_assembly/door_assembly_sec, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("engineering airlock assembly", /obj/structure/door_assembly/door_assembly_eng, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("mining airlock assembly", /obj/structure/door_assembly/door_assembly_min, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("atmospherics airlock assembly", /obj/structure/door_assembly/door_assembly_atmo, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("research airlock assembly", /obj/structure/door_assembly/door_assembly_research, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("freezer airlock assembly", /obj/structure/door_assembly/door_assembly_fre, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("science airlock assembly", /obj/structure/door_assembly/door_assembly_science, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("medical airlock assembly", /obj/structure/door_assembly/door_assembly_med, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("hydroponics airlock assembly", /obj/structure/door_assembly/door_assembly_hydro, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("virology airlock assembly", /obj/structure/door_assembly/door_assembly_viro, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_mai, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("external airlock assembly", /obj/structure/door_assembly/door_assembly_ext, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("external maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_extmai, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
+ new /datum/stack_recipe("standard airlock assembly", /obj/structure/door_assembly, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("public airlock assembly", /obj/structure/door_assembly/door_assembly_public, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("command airlock assembly", /obj/structure/door_assembly/door_assembly_com, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("security airlock assembly", /obj/structure/door_assembly/door_assembly_sec, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("engineering airlock assembly", /obj/structure/door_assembly/door_assembly_eng, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("mining airlock assembly", /obj/structure/door_assembly/door_assembly_min, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("atmospherics airlock assembly", /obj/structure/door_assembly/door_assembly_atmo, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("research airlock assembly", /obj/structure/door_assembly/door_assembly_research, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("freezer airlock assembly", /obj/structure/door_assembly/door_assembly_fre, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("science airlock assembly", /obj/structure/door_assembly/door_assembly_science, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("medical airlock assembly", /obj/structure/door_assembly/door_assembly_med, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("hydroponics airlock assembly", /obj/structure/door_assembly/door_assembly_hydro, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("virology airlock assembly", /obj/structure/door_assembly/door_assembly_viro, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_mai, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("external airlock assembly", /obj/structure/door_assembly/door_assembly_ext, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("external maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_extmai, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
)), \
null, \
- new/datum/stack_recipe("firelock frame", /obj/structure/firelock_frame, 3, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("meatspike frame", /obj/structure/kitchenspike_frame, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("reflector frame", /obj/structure/reflector, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("firelock frame", /obj/structure/firelock_frame, 3, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new/datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("meatspike frame", /obj/structure/kitchenspike_frame, 5, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("reflector frame", /obj/structure/reflector, 5, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
null, \
- new/datum/stack_recipe("grenade casing", /obj/item/grenade/chem_grenade, check_density = FALSE, category = CAT_CHEMISTRY), \
- new/datum/stack_recipe("light fixture frame", /obj/item/wallframe/light_fixture, 2, check_density = FALSE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("small light fixture frame", /obj/item/wallframe/light_fixture/small, 1, check_density = FALSE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("grenade casing", /obj/item/grenade/chem_grenade, crafting_flags = NONE, category = CAT_CHEMISTRY), \
+ new/datum/stack_recipe("light fixture frame", /obj/item/wallframe/light_fixture, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("small light fixture frame", /obj/item/wallframe/light_fixture/small, 1, crafting_flags = NONE, category = CAT_EQUIPMENT), \
null, \
- new/datum/stack_recipe("apc frame", /obj/item/wallframe/apc, 2, check_density = FALSE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("air alarm frame", /obj/item/wallframe/airalarm, 2, check_density = FALSE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("fire alarm frame", /obj/item/wallframe/firealarm, 2, check_density = FALSE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("extinguisher cabinet frame", /obj/item/wallframe/extinguisher_cabinet, 2, check_density = FALSE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("button frame", /obj/item/wallframe/button, 1, check_density = FALSE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("apc frame", /obj/item/wallframe/apc, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("air alarm frame", /obj/item/wallframe/airalarm, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("fire alarm frame", /obj/item/wallframe/firealarm, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("extinguisher cabinet frame", /obj/item/wallframe/extinguisher_cabinet, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("button frame", /obj/item/wallframe/button, 1, crafting_flags = NONE, category = CAT_EQUIPMENT), \
null, \
- new/datum/stack_recipe("iron door", /obj/structure/mineral_door/iron, 20, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("filing cabinet", /obj/structure/filingcabinet, 2, time = 10 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("desk bell", /obj/structure/desk_bell, 2, time = 3 SECONDS, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("floodlight frame", /obj/structure/floodlight_frame, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("voting box", /obj/structure/votebox, 15, time = 5 SECONDS, check_density = FALSE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("pestle", /obj/item/pestle, 1, time = 5 SECONDS, check_density = FALSE, category = CAT_CHEMISTRY), \
- new/datum/stack_recipe("hygienebot assembly", /obj/item/bot_assembly/hygienebot, 2, time = 5 SECONDS, check_density = FALSE, category = CAT_ROBOT), \
- new/datum/stack_recipe("shower frame", /obj/structure/showerframe, 2, time = 2 SECONDS, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("urinal", /obj/item/wallframe/urinal, 2, time = 1 SECONDS, check_density = FALSE, category = CAT_FURNITURE)
+ new/datum/stack_recipe("iron door", /obj/structure/mineral_door/iron, 20, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \
+ new/datum/stack_recipe("filing cabinet", /obj/structure/filingcabinet, 2, time = 10 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("desk bell", /obj/structure/desk_bell, 2, time = 3 SECONDS, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("floodlight frame", /obj/structure/floodlight_frame, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("voting box", /obj/structure/votebox, 15, time = 5 SECONDS, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("pestle", /obj/item/pestle, 1, time = 5 SECONDS, crafting_flags = NONE, category = CAT_CHEMISTRY), \
+ new/datum/stack_recipe("hygienebot assembly", /obj/item/bot_assembly/hygienebot, 2, time = 5 SECONDS, crafting_flags = NONE, category = CAT_ROBOT), \
+ new/datum/stack_recipe("shower frame", /obj/structure/showerframe, 2, time = 2 SECONDS, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("urinal", /obj/item/wallframe/urinal, 2, time = 1 SECONDS, crafting_flags = NONE, category = CAT_FURNITURE)
))
/obj/item/stack/sheet/iron
@@ -253,13 +253,14 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
* Plasteel
*/
GLOBAL_LIST_INIT(plasteel_recipes, list ( \
- new/datum/stack_recipe("AI core", /obj/structure/ai_core, 4, time = 5 SECONDS, one_per_turf = TRUE, check_density = FALSE, category = CAT_ROBOT),
- new/datum/stack_recipe("bomb assembly", /obj/machinery/syndicatebomb/empty, 10, time = 5 SECONDS, check_density = FALSE, category = CAT_CHEMISTRY),
- new/datum/stack_recipe("Large Gas Tank", /obj/structure/tank_frame, 4, time=1 SECONDS, one_per_turf=TRUE, check_density = FALSE, category = CAT_ATMOSPHERIC),
+ new/datum/stack_recipe("AI core", /obj/structure/ai_core, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF, category = CAT_ROBOT),
+ new/datum/stack_recipe("bomb assembly", /obj/machinery/syndicatebomb/empty, 10, time = 5 SECONDS, crafting_flags = NONE, category = CAT_CHEMISTRY),
+ new/datum/stack_recipe("Large Gas Tank", /obj/structure/tank_frame, 4, time=1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF, category = CAT_ATMOSPHERIC),
+ new/datum/stack_recipe("shutter assembly", /obj/machinery/door/poddoor/shutters/preopen/deconstructed, 5, time = 5 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF, category = CAT_DOORS),
null,
new /datum/stack_recipe_list("airlock assemblies", list( \
- new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS),
- new/datum/stack_recipe("vault door assembly", /obj/structure/door_assembly/door_assembly_vault, 6, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS),
+ new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS),
+ new/datum/stack_recipe("vault door assembly", /obj/structure/door_assembly/door_assembly_vault, 6, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS),
)), \
))
@@ -300,49 +301,49 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \
* Wood
*/
GLOBAL_LIST_INIT(wood_recipes, list ( \
- new/datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
- new/datum/stack_recipe("wood table frame", /obj/structure/table_frame/wood, 2, time = 1 SECONDS, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("rolling pin", /obj/item/kitchen/rollingpin, 2, time = 3 SECONDS, check_density = FALSE, category = CAT_TOOLS), \
- new/datum/stack_recipe("wooden chair", /obj/structure/chair/wood/, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("winged wooden chair", /obj/structure/chair/wood/wings, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("wooden barricade", /obj/structure/barricade/wooden, 5, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("wooden door", /obj/structure/mineral_door/wood, 10, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("wooden stairs frame", /obj/structure/stairs_frame/wood, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("wooden fence", /obj/structure/railing/wooden_fence, 2, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("cat house", /obj/structure/cat_house, 5, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("coffin", /obj/structure/closet/crate/coffin, 5, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("book case", /obj/structure/bookcase, 4, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("drying rack", /obj/machinery/smartfridge/drying_rack, 10, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), \
- new/datum/stack_recipe("wooden barrel", /obj/structure/fermenting_barrel, 8, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("dog bed", /obj/structure/bed/dogbed, 10, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("dresser", /obj/structure/dresser, 10, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("picture frame", /obj/item/wallframe/picture, 1, time = 1 SECONDS, check_density = FALSE, category = CAT_ENTERTAINMENT),\
- new/datum/stack_recipe("painting frame", /obj/item/wallframe/painting, 1, time = 1 SECONDS, check_density = FALSE, category = CAT_ENTERTAINMENT),\
- new/datum/stack_recipe("display case chassis", /obj/structure/displaycase_chassis, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("wooden buckler", /obj/item/shield/buckler, 20, time = 4 SECONDS, check_density = FALSE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 5 SECONDS, check_density = FALSE, category = CAT_TOOLS),\
- new/datum/stack_recipe("mannequin", /obj/structure/mannequin/wood, 25, time = 5 SECONDS, one_per_turf = TRUE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("tiki mask", /obj/item/clothing/mask/gas/tiki_mask, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("smoking pipe", /obj/item/clothing/mask/cigarette/pipe, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("honey frame", /obj/item/honey_frame, 5, time = 1 SECONDS, check_density = FALSE, category = CAT_TOOLS),\
- new/datum/stack_recipe("wooden bucket", /obj/item/reagent_containers/cup/bucket/wooden, 3, time = 1 SECONDS, check_density = FALSE, category = CAT_CONTAINERS),\
- new/datum/stack_recipe("rake", /obj/item/cultivator/rake, 5, time = 1 SECONDS, check_density = FALSE, category = CAT_TOOLS),\
- new/datum/stack_recipe("ore box", /obj/structure/ore_box, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_CONTAINERS),\
- new/datum/stack_recipe("wooden crate", /obj/structure/closet/crate/wooden, 6, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),\
- new/datum/stack_recipe("baseball bat", /obj/item/melee/baseball_bat, 5, time = 1.5 SECONDS, check_density = FALSE, category = CAT_WEAPON_MELEE),\
- new/datum/stack_recipe("loom", /obj/structure/loom, 10, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), \
- new/datum/stack_recipe("mortar", /obj/item/reagent_containers/cup/mortar, 3, check_density = FALSE, category = CAT_CHEMISTRY), \
- new/datum/stack_recipe("firebrand", /obj/item/match/firebrand, 2, time = 10 SECONDS, check_density = FALSE, category = CAT_TOOLS), \
- new/datum/stack_recipe("bonfire", /obj/structure/bonfire, 10, time = 6 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), \
- new/datum/stack_recipe("easel", /obj/structure/easel, 5, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("noticeboard", /obj/item/wallframe/noticeboard, 1, time = 1 SECONDS, one_per_turf = FALSE, on_solid_ground = FALSE, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("test tube rack", /obj/item/storage/test_tube_rack, 1, time = 1 SECONDS, check_density = FALSE, category = CAT_CHEMISTRY), \
+ new/datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
+ new/datum/stack_recipe("wood table frame", /obj/structure/table_frame/wood, 2, time = 1 SECONDS, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("rolling pin", /obj/item/kitchen/rollingpin, 2, time = 3 SECONDS, crafting_flags = NONE, category = CAT_TOOLS), \
+ new/datum/stack_recipe("wooden chair", /obj/structure/chair/wood/, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("winged wooden chair", /obj/structure/chair/wood/wings, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("wooden barricade", /obj/structure/barricade/wooden, 5, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("wooden door", /obj/structure/mineral_door/wood, 10, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new/datum/stack_recipe("wooden stairs frame", /obj/structure/stairs_frame/wood, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("wooden fence", /obj/structure/railing/wooden_fence, 2, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("cat house", /obj/structure/cat_house, 5, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("coffin", /obj/structure/closet/crate/coffin, 5, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("book case", /obj/structure/bookcase, 4, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("drying rack", /obj/machinery/smartfridge/drying_rack, 10, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), \
+ new/datum/stack_recipe("wooden barrel", /obj/structure/fermenting_barrel, 8, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("dog bed", /obj/structure/bed/dogbed, 10, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("dresser", /obj/structure/dresser, 10, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("picture frame", /obj/item/wallframe/picture, 1, time = 1 SECONDS, crafting_flags = NONE, category = CAT_ENTERTAINMENT),\
+ new/datum/stack_recipe("painting frame", /obj/item/wallframe/painting, 1, time = 1 SECONDS, crafting_flags = NONE, category = CAT_ENTERTAINMENT),\
+ new/datum/stack_recipe("display case chassis", /obj/structure/displaycase_chassis, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("wooden buckler", /obj/item/shield/buckler, 20, time = 4 SECONDS, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 5 SECONDS, crafting_flags = NONE, category = CAT_TOOLS),\
+ new/datum/stack_recipe("mannequin", /obj/structure/mannequin/wood, 25, time = 5 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("tiki mask", /obj/item/clothing/mask/gas/tiki_mask, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("smoking pipe", /obj/item/clothing/mask/cigarette/pipe, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("honey frame", /obj/item/honey_frame, 5, time = 1 SECONDS, crafting_flags = NONE, category = CAT_TOOLS),\
+ new/datum/stack_recipe("wooden bucket", /obj/item/reagent_containers/cup/bucket/wooden, 3, time = 1 SECONDS, crafting_flags = NONE, category = CAT_CONTAINERS),\
+ new/datum/stack_recipe("rake", /obj/item/cultivator/rake, 5, time = 1 SECONDS, crafting_flags = NONE, category = CAT_TOOLS),\
+ new/datum/stack_recipe("ore box", /obj/structure/ore_box, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_CONTAINERS),\
+ new/datum/stack_recipe("wooden crate", /obj/structure/closet/crate/wooden, 6, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),\
+ new/datum/stack_recipe("baseball bat", /obj/item/melee/baseball_bat, 5, time = 1.5 SECONDS, crafting_flags = NONE, category = CAT_WEAPON_MELEE),\
+ new/datum/stack_recipe("loom", /obj/structure/loom, 10, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), \
+ new/datum/stack_recipe("mortar", /obj/item/reagent_containers/cup/mortar, 3, crafting_flags = NONE, category = CAT_CHEMISTRY), \
+ new/datum/stack_recipe("firebrand", /obj/item/match/firebrand, 2, time = 10 SECONDS, crafting_flags = NONE, category = CAT_TOOLS), \
+ new/datum/stack_recipe("bonfire", /obj/structure/bonfire, 10, time = 6 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), \
+ new/datum/stack_recipe("easel", /obj/structure/easel, 5, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("noticeboard", /obj/item/wallframe/noticeboard, 1, time = 1 SECONDS, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("test tube rack", /obj/item/storage/test_tube_rack, 1, time = 1 SECONDS, crafting_flags = NONE, category = CAT_CHEMISTRY), \
null, \
new/datum/stack_recipe_list("pews", list(
- new /datum/stack_recipe("pew (middle)", /obj/structure/chair/pew, 3, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("pew (left)", /obj/structure/chair/pew/left, 3, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("pew (right)", /obj/structure/chair/pew/right, 3, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE)
+ new /datum/stack_recipe("pew (middle)", /obj/structure/chair/pew, 3, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),
+ new /datum/stack_recipe("pew (left)", /obj/structure/chair/pew/left, 3, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),
+ new /datum/stack_recipe("pew (right)", /obj/structure/chair/pew/right, 3, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE)
)),
null, \
))
@@ -379,19 +380,19 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
*/
GLOBAL_LIST_INIT(bamboo_recipes, list ( \
- new/datum/stack_recipe("punji sticks trap", /obj/structure/punji_sticks, 5, time = 3 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("bamboo spear", /obj/item/spear/bamboospear, 25, time = 9 SECONDS, check_density = FALSE, category = CAT_WEAPON_MELEE), \
- new/datum/stack_recipe("blow gun", /obj/item/gun/syringe/blowgun, 10, time = 7 SECONDS, check_density = FALSE, category = CAT_WEAPON_RANGED), \
- new/datum/stack_recipe("crude syringe", /obj/item/reagent_containers/syringe/crude, 5, time = 1 SECONDS, check_density = FALSE, category = CAT_CHEMISTRY), \
- new/datum/stack_recipe("rice hat", /obj/item/clothing/head/costume/rice_hat, 10, time = 7 SECONDS, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("punji sticks trap", /obj/structure/punji_sticks, 5, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("bamboo spear", /obj/item/spear/bamboospear, 25, time = 9 SECONDS, crafting_flags = NONE, category = CAT_WEAPON_MELEE), \
+ new/datum/stack_recipe("blow gun", /obj/item/gun/syringe/blowgun, 10, time = 7 SECONDS, crafting_flags = NONE, category = CAT_WEAPON_RANGED), \
+ new/datum/stack_recipe("crude syringe", /obj/item/reagent_containers/syringe/crude, 5, time = 1 SECONDS, crafting_flags = NONE, category = CAT_CHEMISTRY), \
+ new/datum/stack_recipe("rice hat", /obj/item/clothing/head/costume/rice_hat, 10, time = 7 SECONDS, crafting_flags = NONE, category = CAT_CLOTHING), \
null, \
- new/datum/stack_recipe("bamboo stool", /obj/structure/chair/stool/bamboo, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("bamboo mat piece", /obj/item/stack/tile/bamboo, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("bamboo stool", /obj/structure/chair/stool/bamboo, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("bamboo mat piece", /obj/item/stack/tile/bamboo, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
null, \
new/datum/stack_recipe_list("bamboo benches", list(
- new /datum/stack_recipe("bamboo bench (middle)", /obj/structure/chair/sofa/bamboo, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("bamboo bench (left)", /obj/structure/chair/sofa/bamboo/left, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("bamboo bench (right)", /obj/structure/chair/sofa/bamboo/right, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE)
+ new /datum/stack_recipe("bamboo bench (middle)", /obj/structure/chair/sofa/bamboo, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),
+ new /datum/stack_recipe("bamboo bench (left)", /obj/structure/chair/sofa/bamboo/left, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),
+ new /datum/stack_recipe("bamboo bench (right)", /obj/structure/chair/sofa/bamboo/right, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE)
)), \
))
@@ -426,41 +427,41 @@ GLOBAL_LIST_INIT(bamboo_recipes, list ( \
* Cloth
*/
GLOBAL_LIST_INIT(cloth_recipes, list ( \
- new/datum/stack_recipe("white jumpskirt", /obj/item/clothing/under/color/jumpskirt/white, 3, check_density = FALSE, category = CAT_CLOTHING), /*Ladies first*/ \
- new/datum/stack_recipe("white jumpsuit", /obj/item/clothing/under/color/white, 3, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("white shoes", /obj/item/clothing/shoes/sneakers/white, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("white scarf", /obj/item/clothing/neck/scarf, 1, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("white bandana", /obj/item/clothing/mask/bandana/white, 2, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("white jumpskirt", /obj/item/clothing/under/color/jumpskirt/white, 3, crafting_flags = NONE, category = CAT_CLOTHING), /*Ladies first*/ \
+ new/datum/stack_recipe("white jumpsuit", /obj/item/clothing/under/color/white, 3, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("white shoes", /obj/item/clothing/shoes/sneakers/white, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("white scarf", /obj/item/clothing/neck/scarf, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("white bandana", /obj/item/clothing/mask/bandana/white, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
null, \
- new/datum/stack_recipe("backpack", /obj/item/storage/backpack, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("satchel", /obj/item/storage/backpack/satchel, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("messenger bag", /obj/item/storage/backpack/messenger, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("duffel bag", /obj/item/storage/backpack/duffelbag, 6, check_density = FALSE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("backpack", /obj/item/storage/backpack, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("satchel", /obj/item/storage/backpack/satchel, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("messenger bag", /obj/item/storage/backpack/messenger, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("duffel bag", /obj/item/storage/backpack/duffelbag, 6, crafting_flags = NONE, category = CAT_CONTAINERS), \
null, \
- new/datum/stack_recipe("plant bag", /obj/item/storage/bag/plants, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("book bag", /obj/item/storage/bag/books, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("mining satchel", /obj/item/storage/bag/ore, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("chemistry bag", /obj/item/storage/bag/chemistry, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("bio bag", /obj/item/storage/bag/bio, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("science bag", /obj/item/storage/bag/xeno, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("construction bag", /obj/item/storage/bag/construction, 4, check_density = FALSE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("plant bag", /obj/item/storage/bag/plants, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("book bag", /obj/item/storage/bag/books, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("mining satchel", /obj/item/storage/bag/ore, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("chemistry bag", /obj/item/storage/bag/chemistry, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("bio bag", /obj/item/storage/bag/bio, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("science bag", /obj/item/storage/bag/xeno, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("construction bag", /obj/item/storage/bag/construction, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
null, \
- new/datum/stack_recipe("improvised gauze", /obj/item/stack/medical/gauze/improvised, 1, 2, 6, check_density = FALSE, category = CAT_TOOLS), \
- new/datum/stack_recipe("rag", /obj/item/reagent_containers/cup/rag, 1, check_density = FALSE, category = CAT_CHEMISTRY), \
- new/datum/stack_recipe("bedsheet", /obj/item/bedsheet, 3, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("double bedsheet", /obj/item/bedsheet/double, 6, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("empty sandbag", /obj/item/emptysandbag, 4, check_density = FALSE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("improvised gauze", /obj/item/stack/medical/gauze/improvised, 1, 2, 6, crafting_flags = NONE, category = CAT_TOOLS), \
+ new/datum/stack_recipe("rag", /obj/item/reagent_containers/cup/rag, 1, crafting_flags = NONE, category = CAT_CHEMISTRY), \
+ new/datum/stack_recipe("bedsheet", /obj/item/bedsheet, 3, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("double bedsheet", /obj/item/bedsheet/double, 6, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("empty sandbag", /obj/item/emptysandbag, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
null, \
- new/datum/stack_recipe("fingerless gloves", /obj/item/clothing/gloves/fingerless, 1, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("white gloves", /obj/item/clothing/gloves/color/white, 3, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("white softcap", /obj/item/clothing/head/soft/mime, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("white beanie", /obj/item/clothing/head/beanie, 2, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("fingerless gloves", /obj/item/clothing/gloves/fingerless, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("white gloves", /obj/item/clothing/gloves/color/white, 3, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("white softcap", /obj/item/clothing/head/soft/mime, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("white beanie", /obj/item/clothing/head/beanie, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
null, \
- new/datum/stack_recipe("blindfold", /obj/item/clothing/glasses/blindfold, 2, check_density = FALSE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("blindfold", /obj/item/clothing/glasses/blindfold, 2, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
null, \
- new/datum/stack_recipe("19x19 canvas", /obj/item/canvas/nineteen_nineteen, 3, check_density = FALSE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("23x19 canvas", /obj/item/canvas/twentythree_nineteen, 4, check_density = FALSE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("23x23 canvas", /obj/item/canvas/twentythree_twentythree, 5, check_density = FALSE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("19x19 canvas", /obj/item/canvas/nineteen_nineteen, 3, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("23x19 canvas", /obj/item/canvas/twentythree_nineteen, 4, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("23x23 canvas", /obj/item/canvas/twentythree_twentythree, 5, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
new/datum/stack_recipe("pillow", /obj/item/pillow, 3, category = CAT_FURNITURE), \
))
@@ -489,10 +490,10 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
amount = 5
GLOBAL_LIST_INIT(durathread_recipes, list ( \
- new/datum/stack_recipe("durathread jumpsuit", /obj/item/clothing/under/misc/durathread, 4, time = 4 SECONDS, check_density = FALSE, category = CAT_CLOTHING),
- new/datum/stack_recipe("durathread beret", /obj/item/clothing/head/beret/durathread, 2, time = 4 SECONDS, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("durathread beanie", /obj/item/clothing/head/beanie/durathread, 2, time = 4 SECONDS, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("durathread bandana", /obj/item/clothing/mask/bandana/durathread, 1, time = 2.5 SECONDS, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("durathread jumpsuit", /obj/item/clothing/under/misc/durathread, 4, time = 4 SECONDS, crafting_flags = NONE, category = CAT_CLOTHING),
+ new/datum/stack_recipe("durathread beret", /obj/item/clothing/head/beret/durathread, 2, time = 4 SECONDS, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("durathread beanie", /obj/item/clothing/head/beanie/durathread, 2, time = 4 SECONDS, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("durathread bandana", /obj/item/clothing/mask/bandana/durathread, 1, time = 2.5 SECONDS, crafting_flags = NONE, category = CAT_CLOTHING), \
))
/obj/item/stack/sheet/durathread
@@ -563,61 +564,61 @@ GLOBAL_LIST_INIT(durathread_recipes, list ( \
* Cardboard
*/
GLOBAL_LIST_INIT(cardboard_recipes, list ( \
- new/datum/stack_recipe("box", /obj/item/storage/box, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/costume/cardborg, 3, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/costume/cardborg, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("large box", /obj/structure/closet/cardboard, 4, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("cardboard cutout", /obj/item/cardboard_cutout, 5, check_density = FALSE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("box", /obj/item/storage/box, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/costume/cardborg, 3, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/costume/cardborg, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("large box", /obj/structure/closet/cardboard, 4, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("cardboard cutout", /obj/item/cardboard_cutout, 5, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
null, \
- new/datum/stack_recipe("pizza box", /obj/item/pizzabox, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("folder", /obj/item/folder, check_density = FALSE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("pizza box", /obj/item/pizzabox, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("folder", /obj/item/folder, crafting_flags = NONE, category = CAT_CONTAINERS), \
null, \
//TO-DO: Find a proper way to just change the illustration on the box. Code isn't the issue, input is.
new/datum/stack_recipe_list("fancy boxes", list(
- new /datum/stack_recipe("donut box", /obj/item/storage/fancy/donut_box, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("egg box", /obj/item/storage/fancy/egg_box, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("donk-pockets box", /obj/item/storage/box/donkpockets, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("donk-pockets spicy box", /obj/item/storage/box/donkpockets/donkpocketspicy, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("donk-pockets teriyaki box", /obj/item/storage/box/donkpockets/donkpocketteriyaki, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("donk-pockets pizza box", /obj/item/storage/box/donkpockets/donkpocketpizza, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("donk-pockets berry box", /obj/item/storage/box/donkpockets/donkpocketberry, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("donk-pockets honk box", /obj/item/storage/box/donkpockets/donkpockethonk, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("monkey cube box", /obj/item/storage/box/monkeycubes, check_density = FALSE, category = CAT_CONTAINERS),
- new /datum/stack_recipe("nugget box", /obj/item/storage/fancy/nugget_box, check_density = FALSE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("donut box", /obj/item/storage/fancy/donut_box, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("egg box", /obj/item/storage/fancy/egg_box, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("donk-pockets box", /obj/item/storage/box/donkpockets, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("donk-pockets spicy box", /obj/item/storage/box/donkpockets/donkpocketspicy, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("donk-pockets teriyaki box", /obj/item/storage/box/donkpockets/donkpocketteriyaki, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("donk-pockets pizza box", /obj/item/storage/box/donkpockets/donkpocketpizza, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("donk-pockets berry box", /obj/item/storage/box/donkpockets/donkpocketberry, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("donk-pockets honk box", /obj/item/storage/box/donkpockets/donkpockethonk, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("monkey cube box", /obj/item/storage/box/monkeycubes, crafting_flags = NONE, category = CAT_CONTAINERS),
+ new /datum/stack_recipe("nugget box", /obj/item/storage/fancy/nugget_box, crafting_flags = NONE, category = CAT_CONTAINERS), \
null, \
- new /datum/stack_recipe("lethal ammo box", /obj/item/storage/box/lethalshot, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("rubber shot ammo box", /obj/item/storage/box/rubbershot, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("bean bag ammo box", /obj/item/storage/box/beanbag, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("flashbang box", /obj/item/storage/box/flashbangs, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("flashes box", /obj/item/storage/box/flashes, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("handcuffs box", /obj/item/storage/box/handcuffs, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("ID card box", /obj/item/storage/box/ids, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("PDA box", /obj/item/storage/box/pdas, check_density = FALSE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("lethal ammo box", /obj/item/storage/box/lethalshot, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("rubber shot ammo box", /obj/item/storage/box/rubbershot, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("bean bag ammo box", /obj/item/storage/box/beanbag, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("flashbang box", /obj/item/storage/box/flashbangs, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("flashes box", /obj/item/storage/box/flashes, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("handcuffs box", /obj/item/storage/box/handcuffs, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("ID card box", /obj/item/storage/box/ids, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("PDA box", /obj/item/storage/box/pdas, crafting_flags = NONE, category = CAT_CONTAINERS), \
null, \
- new /datum/stack_recipe("pillbottle box", /obj/item/storage/box/pillbottles, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("beaker box", /obj/item/storage/box/beakers, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("syringe box", /obj/item/storage/box/syringes, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("latex gloves box", /obj/item/storage/box/gloves, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("sterile masks box", /obj/item/storage/box/masks, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("body bag box", /obj/item/storage/box/bodybags, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("perscription glasses box", /obj/item/storage/box/rxglasses, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("medipen box", /obj/item/storage/box/medipens, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("oxygen tank box", /obj/item/storage/box/emergencytank, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("extended oxygen tank box", /obj/item/storage/box/engitank, check_density = FALSE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("pillbottle box", /obj/item/storage/box/pillbottles, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("beaker box", /obj/item/storage/box/beakers, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("syringe box", /obj/item/storage/box/syringes, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("latex gloves box", /obj/item/storage/box/gloves, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("sterile masks box", /obj/item/storage/box/masks, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("body bag box", /obj/item/storage/box/bodybags, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("perscription glasses box", /obj/item/storage/box/rxglasses, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("medipen box", /obj/item/storage/box/medipens, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("oxygen tank box", /obj/item/storage/box/emergencytank, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("extended oxygen tank box", /obj/item/storage/box/engitank, crafting_flags = NONE, category = CAT_CONTAINERS), \
null, \
- new /datum/stack_recipe("survival box", /obj/item/storage/box/survival/crafted, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("extended tank survival box", /obj/item/storage/box/survival/engineer/crafted, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("disk box", /obj/item/storage/box/disks, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("light tubes box", /obj/item/storage/box/lights/tubes, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("light bulbs box", /obj/item/storage/box/lights/bulbs, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("mixed lights box", /obj/item/storage/box/lights/mixed, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("mouse traps box", /obj/item/storage/box/mousetraps, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("candle box", /obj/item/storage/fancy/candle_box, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("bandage box", /obj/item/storage/box/bandages, check_density = FALSE, category = CAT_CONTAINERS)
+ new /datum/stack_recipe("survival box", /obj/item/storage/box/survival/crafted, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("extended tank survival box", /obj/item/storage/box/survival/engineer/crafted, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("disk box", /obj/item/storage/box/disks, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("light tubes box", /obj/item/storage/box/lights/tubes, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("light bulbs box", /obj/item/storage/box/lights/bulbs, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("mixed lights box", /obj/item/storage/box/lights/mixed, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("mouse traps box", /obj/item/storage/box/mousetraps, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("candle box", /obj/item/storage/fancy/candle_box, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("bandage box", /obj/item/storage/box/bandages, crafting_flags = NONE, category = CAT_CONTAINERS)
)),
null, \
@@ -675,18 +676,18 @@ GLOBAL_LIST_INIT(cardboard_recipes, list ( \
*/
GLOBAL_LIST_INIT(bronze_recipes, list ( \
- new/datum/stack_recipe("wall gear", /obj/structure/girder/bronze, 2, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("wall gear", /obj/structure/girder/bronze, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
null,
- new/datum/stack_recipe("directional bronze window", /obj/structure/window/bronze/unanchored, time = 0, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("fulltile bronze window", /obj/structure/window/bronze/fulltile/unanchored, 2, time = 0, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("pinion airlock assembly", /obj/structure/door_assembly/door_assembly_bronze, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("bronze pinion airlock assembly", /obj/structure/door_assembly/door_assembly_bronze/seethru, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("bronze floor tile", /obj/item/stack/tile/bronze, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
- new/datum/stack_recipe("bronze hat", /obj/item/clothing/head/costume/bronze, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("bronze suit", /obj/item/clothing/suit/costume/bronze, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("bronze boots", /obj/item/clothing/shoes/bronze, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("directional bronze window", /obj/structure/window/bronze/unanchored, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("fulltile bronze window", /obj/structure/window/bronze/fulltile/unanchored, 2, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("pinion airlock assembly", /obj/structure/door_assembly/door_assembly_bronze, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new/datum/stack_recipe("bronze pinion airlock assembly", /obj/structure/door_assembly/door_assembly_bronze/seethru, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new/datum/stack_recipe("bronze floor tile", /obj/item/stack/tile/bronze, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
+ new/datum/stack_recipe("bronze hat", /obj/item/clothing/head/costume/bronze, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("bronze suit", /obj/item/clothing/suit/costume/bronze, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("bronze boots", /obj/item/clothing/shoes/bronze, crafting_flags = NONE, category = CAT_CLOTHING), \
null,
- new/datum/stack_recipe("bronze chair", /obj/structure/chair/bronze, 1, time = 0, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("bronze chair", /obj/structure/chair/bronze, 1, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
))
/obj/item/stack/sheet/bronze
@@ -773,29 +774,33 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \
// As bone and sinew have just a little too many recipes for this, we'll just split them up.
// Sinew slapcrafting will mostly-sinew recipes, and bones will have mostly-bones recipes.
- var/static/list/slapcraft_recipe_list = list(\
- /datum/crafting_recipe/bonedagger, /datum/crafting_recipe/bonespear, /datum/crafting_recipe/boneaxe,\
- /datum/crafting_recipe/bonearmor, /datum/crafting_recipe/skullhelm, /datum/crafting_recipe/bracers
- )
+ var/static/list/slapcraft_recipe_list = list(
+ /datum/crafting_recipe/bonearmor,
+ /datum/crafting_recipe/boneaxe,
+ /datum/crafting_recipe/bonedagger,
+ /datum/crafting_recipe/bonespear,
+ /datum/crafting_recipe/bracers,
+ /datum/crafting_recipe/skullhelm,
+ )
AddComponent(
/datum/component/slapcrafting,\
slapcraft_recipes = slapcraft_recipe_list,\
)
GLOBAL_LIST_INIT(plastic_recipes, list(
- new /datum/stack_recipe("plastic floor tile", /obj/item/stack/tile/plastic, 1, 4, 20, time = 2 SECONDS, check_density = FALSE, category = CAT_TILES), \
- new /datum/stack_recipe("light tram tile", /obj/item/stack/thermoplastic/light, 1, 4, 20, time = 2 SECONDS, check_density = FALSE, category = CAT_TILES), \
- new /datum/stack_recipe("dark tram tile", /obj/item/stack/thermoplastic, 1, 4, 20, time = 2 SECONDS, check_density = FALSE, category = CAT_TILES), \
- new /datum/stack_recipe("folding plastic chair", /obj/structure/chair/plastic, 2, check_density = FALSE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 5, one_per_turf = TRUE, on_solid_ground = TRUE, time = 4 SECONDS, category = CAT_FURNITURE), \
- new /datum/stack_recipe("water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/empty, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("large water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/large/empty, 3, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("colo cups", /obj/item/reagent_containers/cup/glass/colocup, 1, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("mannequin", /obj/structure/mannequin/plastic, 25, time = 5 SECONDS, one_per_turf = TRUE, check_density = FALSE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("wet floor sign", /obj/item/clothing/suit/caution, 2, check_density = FALSE, category = CAT_EQUIPMENT), \
- new /datum/stack_recipe("warning cone", /obj/item/clothing/head/cone, 2, check_density = FALSE, category = CAT_EQUIPMENT), \
- new /datum/stack_recipe("blank wall sign", /obj/item/sign, 1, check_density = FALSE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("rebellion mask", /obj/item/clothing/mask/rebellion, 1, check_density = FALSE, category = CAT_CLOTHING)))
+ new /datum/stack_recipe("plastic floor tile", /obj/item/stack/tile/plastic, 1, 4, 20, time = 2 SECONDS, crafting_flags = NONE, category = CAT_TILES), \
+ new /datum/stack_recipe("light tram tile", /obj/item/stack/thermoplastic/light, 1, 4, 20, time = 2 SECONDS, crafting_flags = NONE, category = CAT_TILES), \
+ new /datum/stack_recipe("dark tram tile", /obj/item/stack/thermoplastic, 1, 4, 20, time = 2 SECONDS, crafting_flags = NONE, category = CAT_TILES), \
+ new /datum/stack_recipe("folding plastic chair", /obj/structure/chair/plastic, 2, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, time = 4 SECONDS, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/empty, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("large water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/large/empty, 3, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("colo cups", /obj/item/reagent_containers/cup/glass/colocup, 1, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("mannequin", /obj/structure/mannequin/plastic, 25, time = 5 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("wet floor sign", /obj/item/clothing/suit/caution, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new /datum/stack_recipe("warning cone", /obj/item/clothing/head/cone, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new /datum/stack_recipe("blank wall sign", /obj/item/sign, 1, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("rebellion mask", /obj/item/clothing/mask/rebellion, 1, crafting_flags = NONE, category = CAT_CLOTHING)))
/obj/item/stack/sheet/plastic
name = "plastic"
@@ -819,8 +824,8 @@ GLOBAL_LIST_INIT(plastic_recipes, list(
. += GLOB.plastic_recipes
GLOBAL_LIST_INIT(paperframe_recipes, list(
-new /datum/stack_recipe("paper frame separator", /obj/structure/window/paperframe, 2, one_per_turf = TRUE, on_solid_ground = TRUE, is_fulltile = TRUE, time = 1 SECONDS), \
-new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperframe, 3, one_per_turf = TRUE, on_solid_ground = TRUE, time = 1 SECONDS )))
+new /datum/stack_recipe("paper frame separator", /obj/structure/window/paperframe, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, time = 1 SECONDS), \
+new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperframe, 3, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, time = 1 SECONDS )))
/obj/item/stack/sheet/paperframes
name = "paper frames"
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 18a95cd77d378..4258465f3a07e 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -1,9 +1,3 @@
-//stack recipe placement check types
-/// Checks if there is an object of the result type in any of the cardinal directions
-#define STACK_CHECK_CARDINALS (1<<0)
-/// Checks if there is an object of the result type within one tile
-#define STACK_CHECK_ADJACENT (1<<1)
-
/* Stack type objects!
* Contains:
* Stacks
@@ -423,7 +417,7 @@
return
var/turf/created_turf = covered_turf.place_on_top(recipe.result_type, flags = CHANGETURF_INHERIT_AIR)
builder.balloon_alert(builder, "placed [ispath(recipe.result_type, /turf/open) ? "floor" : "wall"]")
- if(recipe.applies_mats && LAZYLEN(mats_per_unit))
+ if((recipe.crafting_flags & CRAFT_APPLIES_MATS) && LAZYLEN(mats_per_unit))
created_turf.set_custom_materials(mats_per_unit, recipe.req_amount / recipe.res_amount)
else
@@ -439,7 +433,7 @@
builder.investigate_log("crafted [recipe.title]", INVESTIGATE_CRAFTING)
// Apply mat datums
- if(recipe.applies_mats && LAZYLEN(mats_per_unit))
+ if((recipe.crafting_flags & CRAFT_APPLIES_MATS) && LAZYLEN(mats_per_unit))
if(isstack(created))
var/obj/item/stack/crafted_stack = created
crafted_stack.set_mats_per_unit(mats_per_unit, recipe.req_amount / recipe.res_amount)
@@ -484,16 +478,16 @@
return FALSE
var/turf/dest_turf = get_turf(builder)
- if(recipe.one_per_turf && (locate(recipe.result_type) in dest_turf))
+ if((recipe.crafting_flags & CRAFT_ONE_PER_TURF) && (locate(recipe.result_type) in dest_turf))
builder.balloon_alert(builder, "already one here!")
return FALSE
- if(recipe.check_direction)
- if(!valid_build_direction(dest_turf, builder.dir, is_fulltile = recipe.is_fulltile))
+ if(recipe.crafting_flags & CRAFT_CHECK_DIRECTION)
+ if(!valid_build_direction(dest_turf, builder.dir, is_fulltile = (recipe.crafting_flags & CRAFT_IS_FULLTILE)))
builder.balloon_alert(builder, "won't fit here!")
return FALSE
- if(recipe.on_solid_ground)
+ if(recipe.crafting_flags & CRAFT_ON_SOLID_GROUND)
if(isclosedturf(dest_turf))
builder.balloon_alert(builder, "cannot be made on a wall!")
return FALSE
@@ -503,7 +497,7 @@
builder.balloon_alert(builder, "must be made on solid ground!")
return FALSE
- if(recipe.check_density)
+ if(recipe.crafting_flags & CRAFT_CHECK_DENSITY)
for(var/obj/object in dest_turf)
if(object.density && !(object.obj_flags & IGNORE_DENSITY) || object.obj_flags & BLOCKS_CONSTRUCTION)
builder.balloon_alert(builder, "something is in the way!")
@@ -742,6 +736,3 @@
add_hiddenprint_list(GET_ATOM_HIDDENPRINTS(from))
fingerprintslast = from.fingerprintslast
//TODO bloody overlay
-
-#undef STACK_CHECK_CARDINALS
-#undef STACK_CHECK_ADJACENT
diff --git a/code/game/objects/items/stacks/stack_recipe.dm b/code/game/objects/items/stacks/stack_recipe.dm
index bfdc3c8ca5717..eabaa706d8879 100644
--- a/code/game/objects/items/stacks/stack_recipe.dm
+++ b/code/game/objects/items/stacks/stack_recipe.dm
@@ -15,21 +15,8 @@
var/max_res_amount = 1
/// How long it takes to make
var/time = 0
- /// If only one of the resulting atom is allowed per turf
- var/one_per_turf = FALSE
- /// If the atom is fulltile, as in a fulltile window. This is used for the direction check to prevent fulltile windows from being able to be built over directional stuff.
- /// Setting this to true will effectively set check_direction to true.
- var/is_fulltile = FALSE
- /// If this atom should run the direction check, for use when building things like directional windows where you can have more than one per turf
- var/check_direction = FALSE
- /// If the atom requires a floor below
- var/on_solid_ground = FALSE
- /// If the atom checks that there are objects with density in the same turf when being built. TRUE by default
- var/check_density = TRUE
/// Bitflag of additional placement checks required to place. (STACK_CHECK_CARDINALS|STACK_CHECK_ADJACENT|STACK_CHECK_TRAM_FORBIDDEN|STACK_CHECK_TRAM_EXCLUSIVE)
var/placement_checks = NONE
- /// If TRUE, the created atom will gain custom mat datums
- var/applies_mats = FALSE
/// What trait, if any, boosts the construction speed of this item
var/trait_booster
/// How much the trait above, if supplied, boosts the construct speed of this item
@@ -37,6 +24,9 @@
/// Category for general crafting menu
var/category
+ ///crafting_flags var to hold bool values
+ var/crafting_flags = CRAFT_CHECK_DENSITY
+
/datum/stack_recipe/New(
title,
result_type,
@@ -44,13 +34,8 @@
res_amount = 1,
max_res_amount = 1,
time = 0,
- one_per_turf = FALSE,
- on_solid_ground = FALSE,
- is_fulltile = FALSE,
- check_direction = FALSE,
- check_density = TRUE,
+ crafting_flags = CRAFT_CHECK_DENSITY,
placement_checks = NONE,
- applies_mats = FALSE,
trait_booster,
trait_modifier = 1,
category,
@@ -62,13 +47,8 @@
src.res_amount = res_amount
src.max_res_amount = max_res_amount
src.time = time
- src.one_per_turf = one_per_turf
- src.on_solid_ground = on_solid_ground
- src.is_fulltile = is_fulltile
- src.check_direction = check_direction || is_fulltile
- src.check_density = check_density
+ src.crafting_flags = crafting_flags
src.placement_checks = placement_checks
- src.applies_mats = applies_mats
src.trait_booster = trait_booster
src.trait_modifier = trait_modifier
src.category = src.category || category || CAT_MISC
@@ -88,7 +68,6 @@
on_solid_ground = FALSE,
window_checks = FALSE,
placement_checks = NONE,
- applies_mats = FALSE,
trait_booster,
trait_modifier = 1,
desc,
diff --git a/code/game/objects/structures/beds_chairs/bed.dm b/code/game/objects/structures/beds_chairs/bed.dm
index 0e3845d2efa7f..e037043cc91a5 100644
--- a/code/game/objects/structures/beds_chairs/bed.dm
+++ b/code/game/objects/structures/beds_chairs/bed.dm
@@ -218,13 +218,12 @@
/obj/item/emergency_bed/attack_self(mob/user)
deploy_bed(user, user.loc)
-/obj/item/emergency_bed/afterattack(obj/target, mob/user, proximity)
- . = ..()
- if(!proximity)
- return
+/obj/item/emergency_bed/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ if(isopenturf(interacting_with))
+ deploy_bed(user, interacting_with)
+ return ITEM_INTERACT_SUCCESS
+ return NONE
- if(isopenturf(target))
- deploy_bed(user, target)
/obj/item/emergency_bed/proc/deploy_bed(mob/user, atom/location)
var/obj/structure/bed/medical/emergency/deployed = new /obj/structure/bed/medical/emergency(location)
diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm
index 4296ac3368443..cf3864b140059 100644
--- a/code/game/objects/structures/dresser.dm
+++ b/code/game/objects/structures/dresser.dm
@@ -40,7 +40,7 @@
return
switch(choice)
if("Underwear")
- var/new_undies = tgui_input_list(user, "Select your underwear", "Changing", GLOB.underwear_list)
+ var/new_undies = tgui_input_list(user, "Select your underwear", "Changing", SSaccessories.underwear_list)
if(new_undies)
dressing_human.underwear = new_undies
if("Underwear Color")
@@ -48,11 +48,11 @@
if(new_underwear_color)
dressing_human.underwear_color = sanitize_hexcolor(new_underwear_color)
if("Undershirt")
- var/new_undershirt = tgui_input_list(user, "Select your undershirt", "Changing", GLOB.undershirt_list)
+ var/new_undershirt = tgui_input_list(user, "Select your undershirt", "Changing", SSaccessories.undershirt_list)
if(new_undershirt)
dressing_human.undershirt = new_undershirt
if("Socks")
- var/new_socks = tgui_input_list(user, "Select your socks", "Changing", GLOB.socks_list)
+ var/new_socks = tgui_input_list(user, "Select your socks", "Changing", SSaccessories.socks_list)
if(new_socks)
dressing_human.socks = new_socks
diff --git a/code/game/objects/structures/headpike.dm b/code/game/objects/structures/headpike.dm
index b4cffdb654d23..fca325744554d 100644
--- a/code/game/objects/structures/headpike.dm
+++ b/code/game/objects/structures/headpike.dm
@@ -36,7 +36,7 @@
victim = locate() in parts_list
if(!victim) //likely a mapspawned one
victim = new(src)
- victim.real_name = random_unique_name(prob(50))
+ victim.real_name = generate_random_name()
spear = locate(speartype) in parts_list
if(!spear)
spear = new speartype(src)
diff --git a/code/game/objects/structures/mannequin.dm b/code/game/objects/structures/mannequin.dm
index bdb5344d7fe10..a47802273d5a0 100644
--- a/code/game/objects/structures/mannequin.dm
+++ b/code/game/objects/structures/mannequin.dm
@@ -95,19 +95,19 @@
var/mutable_appearance/pedestal = mutable_appearance(icon, "pedestal_[material]")
pedestal.pixel_y = -3
. += pedestal
- var/datum/sprite_accessory/underwear/underwear = GLOB.underwear_list[underwear_name]
+ var/datum/sprite_accessory/underwear/underwear = SSaccessories.underwear_list[underwear_name]
if(underwear)
if(body_type == FEMALE && underwear.gender == MALE)
. += wear_female_version(underwear.icon_state, underwear.icon, BODY_LAYER, FEMALE_UNIFORM_FULL)
else
. += mutable_appearance(underwear.icon, underwear.icon_state, -BODY_LAYER)
- var/datum/sprite_accessory/undershirt/undershirt = GLOB.undershirt_list[undershirt_name]
+ var/datum/sprite_accessory/undershirt/undershirt = SSaccessories.undershirt_list[undershirt_name]
if(undershirt)
if(body_type == FEMALE)
. += wear_female_version(undershirt.icon_state, undershirt.icon, BODY_LAYER)
else
. += mutable_appearance(undershirt.icon, undershirt.icon_state, -BODY_LAYER)
- var/datum/sprite_accessory/socks/socks = GLOB.socks_list[socks_name]
+ var/datum/sprite_accessory/socks/socks = SSaccessories.socks_list[socks_name]
if(socks)
. += mutable_appearance(socks.icon, socks.icon_state, -BODY_LAYER)
for(var/slot_flag in worn_items)
@@ -168,15 +168,15 @@
return
switch(choice)
if("Underwear")
- var/new_undies = tgui_input_list(user, "Select the mannequin's underwear", "Changing", GLOB.underwear_list)
+ var/new_undies = tgui_input_list(user, "Select the mannequin's underwear", "Changing", SSaccessories.underwear_list)
if(new_undies)
underwear_name = new_undies
if("Undershirt")
- var/new_undershirt = tgui_input_list(user, "Select the mannequin's undershirt", "Changing", GLOB.undershirt_list)
+ var/new_undershirt = tgui_input_list(user, "Select the mannequin's undershirt", "Changing", SSaccessories.undershirt_list)
if(new_undershirt)
undershirt_name = new_undershirt
if("Socks")
- var/new_socks = tgui_input_list(user, "Select the mannequin's socks", "Changing", GLOB.socks_list)
+ var/new_socks = tgui_input_list(user, "Select the mannequin's socks", "Changing", SSaccessories.socks_list)
if(new_socks)
socks_name = new_socks
update_appearance()
diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm
index f15cabd707ec8..7ea2330281413 100644
--- a/code/game/objects/structures/mirror.dm
+++ b/code/game/objects/structures/mirror.dm
@@ -118,7 +118,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28)
beard_dresser.set_facial_hairstyle("Shaved", update = TRUE)
return TRUE
- var/new_style = tgui_input_list(beard_dresser, "Select a facial hairstyle", "Grooming", GLOB.facial_hairstyles_list)
+ var/new_style = tgui_input_list(beard_dresser, "Select a facial hairstyle", "Grooming", SSaccessories.facial_hairstyles_list)
if(isnull(new_style))
return TRUE
@@ -131,7 +131,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28)
beard_dresser.set_facial_hairstyle(new_style, update = TRUE)
/obj/structure/mirror/proc/change_hair(mob/living/carbon/human/hairdresser)
- var/new_style = tgui_input_list(hairdresser, "Select a hairstyle", "Grooming", GLOB.hairstyles_list)
+ var/new_style = tgui_input_list(hairdresser, "Select a hairstyle", "Grooming", SSaccessories.hairstyles_list)
if(isnull(new_style))
return TRUE
if(HAS_TRAIT(hairdresser, TRAIT_BALD))
@@ -331,7 +331,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror/broken, 28)
selectable_races = sort_list(selectable_races)
/obj/structure/mirror/magic/change_beard(mob/living/carbon/human/beard_dresser) // magical mirrors do nothing but give you the damn beard
- var/new_style = tgui_input_list(beard_dresser, "Select a facial hairstyle", "Grooming", GLOB.facial_hairstyles_list)
+ var/new_style = tgui_input_list(beard_dresser, "Select a facial hairstyle", "Grooming", SSaccessories.facial_hairstyles_list)
if(isnull(new_style))
return TRUE
beard_dresser.set_facial_hairstyle(new_style, update = TRUE)
diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm
index fcf9693731e05..509787ffd3a56 100644
--- a/code/modules/admin/create_mob.dm
+++ b/code/modules/admin/create_mob.dm
@@ -16,7 +16,7 @@
/proc/randomize_human(mob/living/carbon/human/human, randomize_mutations = FALSE)
human.gender = human.dna.species.sexes ? pick(MALE, FEMALE, PLURAL, NEUTER) : PLURAL
human.physique = human.gender
- human.real_name = human.dna?.species.random_name(human.gender) || random_unique_name(human.gender)
+ human.real_name = human.generate_random_mob_name()
human.name = human.get_visible_name()
human.set_hairstyle(random_hairstyle(human.gender), update = FALSE)
human.set_facial_hairstyle(random_facial_hairstyle(human.gender), update = FALSE)
@@ -24,7 +24,7 @@
human.set_facial_haircolor(human.hair_color, update = FALSE)
human.eye_color_left = random_eye_color()
human.eye_color_right = human.eye_color_left
- human.skin_tone = random_skin_tone()
+ human.skin_tone = pick(GLOB.skin_tones)
human.dna.species.randomize_active_underwear_only(human)
// Needs to be called towards the end to update all the UIs just set above
human.dna.initialize_dna(newblood_type = random_blood_type(), create_mutation_blocks = randomize_mutations, randomize_features = TRUE)
diff --git a/code/modules/admin/verbs/anonymousnames.dm b/code/modules/admin/verbs/anonymousnames.dm
index 9a71d68637a88..10edb49d99336 100644
--- a/code/modules/admin/verbs/anonymousnames.dm
+++ b/code/modules/admin/verbs/anonymousnames.dm
@@ -131,8 +131,7 @@ GLOBAL_DATUM(current_anonymous_theme, /datum/anonymous_theme)
/datum/anonymous_theme/proc/anonymous_name(mob/target)
var/datum/client_interface/client = GET_CLIENT(target)
var/species_type = client.prefs.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
- return species.random_name(target.gender,1)
+ return generate_random_name_species_based(target.gender, TRUE, species_type)
/**
* anonymous_ai_name: generates a random name, based off of whatever the round's anonymousnames is set to (but for sillycones).
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index e56eb1e5101a7..20cdf3514598f 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -765,7 +765,7 @@ ADMIN_VERB(reestablish_tts_connection, R_DEBUG, "Re-establish Connection To TTS"
var/list/sorted = list()
for (var/source in per_source)
sorted += list(list("source" = source, "count" = per_source[source]))
- sorted = sortTim(sorted, GLOBAL_PROC_REF(cmp_timer_data))
+ sortTim(sorted, GLOBAL_PROC_REF(cmp_timer_data))
// Now that everything is sorted, compile them into an HTML output
var/output = ""
diff --git a/code/modules/admin/verbs/light_debug.dm b/code/modules/admin/verbs/light_debug.dm
index ae5b24ff38032..eac81f6ed294b 100644
--- a/code/modules/admin/verbs/light_debug.dm
+++ b/code/modules/admin/verbs/light_debug.dm
@@ -10,7 +10,7 @@
sum[source.source_atom.type] += 1
total += 1
- sum = sortTim(sum, /proc/cmp_numeric_asc, TRUE)
+ sortTim(sum, associative = TRUE)
var/text = ""
for(var/type in sum)
text += "[type] = [sum[type]]\n"
diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm
index b7aa16b6b5fd5..5f5b5f245bb5c 100644
--- a/code/modules/admin/verbs/secrets.dm
+++ b/code/modules/admin/verbs/secrets.dm
@@ -222,7 +222,7 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w
if("allspecies")
if(!is_funmin)
return
- var/result = input(holder, "Please choose a new species","Species") as null|anything in GLOB.species_list
+ var/result = input(holder, "Please choose a new species","Species") as null|anything in sortTim(GLOB.species_list, GLOBAL_PROC_REF(cmp_text_asc))
if(result)
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Mass Species Change", "[result]"))
log_admin("[key_name(holder)] turned all humans into [result]")
@@ -724,4 +724,3 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w
var/datum/antagonist/malf_ai/antag_datum = new
antag_datum.give_objectives = keep_generic_objecives
assign_admin_objective_and_antag(player, antag_datum)
-
diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm
index 49d0ab4ad2300..ca36585a1a1c4 100644
--- a/code/modules/antagonists/brother/brother.dm
+++ b/code/modules/antagonists/brother/brother.dm
@@ -167,13 +167,15 @@
member_name = "blood brother"
var/brothers_left = 2
-/datum/team/brother_team/New()
+/datum/team/brother_team/New(starting_members)
. = ..()
if (prob(10))
brothers_left += 1
/datum/team/brother_team/add_member(datum/mind/new_member)
. = ..()
+ if (!length(objectives))
+ forge_brother_objectives()
if (!new_member.has_antag_datum(/datum/antagonist/brother))
add_brother(new_member.current)
@@ -217,7 +219,7 @@
add_objective(new /datum/objective/convert_brother)
var/is_hijacker = prob(10)
- for(var/i = 1 to max(1, CONFIG_GET(number/brother_objectives_amount) + (members.len > 2) - is_hijacker))
+ for(var/i = 1 to max(1, CONFIG_GET(number/brother_objectives_amount) + (brothers_left > 2) - is_hijacker))
forge_single_objective()
if(is_hijacker)
if(!locate(/datum/objective/hijack) in objectives)
diff --git a/code/modules/antagonists/malf_ai/malf_ai_module_picker.dm b/code/modules/antagonists/malf_ai/malf_ai_module_picker.dm
index 51058f82ac02e..0ac27c14c97bf 100644
--- a/code/modules/antagonists/malf_ai/malf_ai_module_picker.dm
+++ b/code/modules/antagonists/malf_ai/malf_ai_module_picker.dm
@@ -24,7 +24,7 @@
filtered_modules[AM.category][AM] = AM
for(var/category in filtered_modules)
- filtered_modules[category] = sortTim(filtered_modules[category], GLOBAL_PROC_REF(cmp_malfmodules_priority))
+ sortTim(filtered_modules[category], GLOBAL_PROC_REF(cmp_malfmodules_priority))
return filtered_modules
diff --git a/code/modules/antagonists/pirate/pirate.dm b/code/modules/antagonists/pirate/pirate.dm
index 15a028b24d740..0fa80f5524776 100644
--- a/code/modules/antagonists/pirate/pirate.dm
+++ b/code/modules/antagonists/pirate/pirate.dm
@@ -85,7 +85,7 @@
//Lists notable loot.
if(!cargo_hold || !cargo_hold.total_report)
return "Nothing"
- cargo_hold.total_report.total_value = sortTim(cargo_hold.total_report.total_value, cmp = GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE)
+ sortTim(cargo_hold.total_report.total_value, cmp = GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE)
var/count = 0
var/list/loot_texts = list()
for(var/datum/export/E in cargo_hold.total_report.total_value)
diff --git a/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm b/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm
index eaa1de48b5865..16cad321853d9 100644
--- a/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm
+++ b/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm
@@ -428,7 +428,7 @@
/datum/export/pirate/ransom/sell_object(mob/living/carbon/human/sold_item, datum/export_report/report, dry_run = TRUE, apply_elastic = TRUE)
. = ..()
- if(. == EXPORT_NOT_SOLD)
+ if(. == EXPORT_NOT_SOLD || dry_run)
return
var/turf/picked_turf = pick(GLOB.holdingfacility)
sold_item.forceMove(picked_turf)
@@ -439,7 +439,7 @@
sold_item.flash_act()
sold_item.adjust_confusion(10 SECONDS)
sold_item.adjust_dizzy(10 SECONDS)
- addtimer(src, CALLBACK(src, PROC_REF(send_back_to_station), sold_item), COME_BACK_FROM_CAPTURE_TIME)
+ addtimer(CALLBACK(src, PROC_REF(send_back_to_station), sold_item), COME_BACK_FROM_CAPTURE_TIME)
to_chat(sold_item, span_hypnophrase("A million voices echo in your head... \"Yaarrr, thanks for the booty, landlubber. \
You will be ransomed back to your station, so it's only a matter of time before we ship you back... "))
diff --git a/code/modules/asset_cache/assets/uplink.dm b/code/modules/asset_cache/assets/uplink.dm
index e283b86c04299..e85ee1b35b5c1 100644
--- a/code/modules/asset_cache/assets/uplink.dm
+++ b/code/modules/asset_cache/assets/uplink.dm
@@ -9,7 +9,7 @@
var/list/items = list()
for(var/datum/uplink_category/category as anything in subtypesof(/datum/uplink_category))
categories += category
- categories = sortTim(categories, GLOBAL_PROC_REF(cmp_uplink_category_desc))
+ sortTim(categories, GLOBAL_PROC_REF(cmp_uplink_category_desc))
var/list/new_categories = list()
for(var/datum/uplink_category/category as anything in categories)
diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm
index d152cf09e711f..fa8b833234586 100644
--- a/code/modules/atmospherics/machinery/atmosmachinery.dm
+++ b/code/modules/atmospherics/machinery/atmosmachinery.dm
@@ -301,8 +301,8 @@
* * given_layer - the piping_layer we are checking
*/
/obj/machinery/atmospherics/proc/connection_check(obj/machinery/atmospherics/target, given_layer)
- //check if the target & src connect in the same direction
- if(!((initialize_directions & get_dir(src, target)) && (target.initialize_directions & get_dir(target, src))))
+ //if target is not multiz then we have to check if the target & src connect in the same direction
+ if(!istype(target, /obj/machinery/atmospherics/pipe/multiz) && !((initialize_directions & get_dir(src, target)) && (target.initialize_directions & get_dir(target, src))))
return FALSE
//both target & src can't be connected either way
diff --git a/code/modules/bitrunning/orders/bepis.dm b/code/modules/bitrunning/orders/bepis.dm
index 286e9817f3c52..4b7253bdaf24a 100644
--- a/code/modules/bitrunning/orders/bepis.dm
+++ b/code/modules/bitrunning/orders/bepis.dm
@@ -17,7 +17,3 @@
/datum/orderable_item/bepis/sprayoncan
item_path = /obj/item/toy/sprayoncan
cost_per_order = 750
-
-/datum/orderable_item/bepis/pristine
- item_path = /obj/item/disk/design_disk/bepis/remove_tech
- cost_per_order = 1000
diff --git a/code/modules/bitrunning/server/loot.dm b/code/modules/bitrunning/server/loot.dm
index cb4902abfe3ab..aa7b99d6e922a 100644
--- a/code/modules/bitrunning/server/loot.dm
+++ b/code/modules/bitrunning/server/loot.dm
@@ -1,3 +1,9 @@
+#define GRADE_D "D"
+#define GRADE_C "C"
+#define GRADE_B "B"
+#define GRADE_A "A"
+#define GRADE_S "S"
+
/// Handles calculating rewards based on number of players, parts, threats, etc
/obj/machinery/quantum_server/proc/calculate_rewards()
var/rewards_base = 0.8
@@ -28,8 +34,11 @@
var/bonus = calculate_rewards()
+ var/time_difference = world.time - generated_domain.start_time
+ var/grade = grade_completion(time_difference)
+
var/obj/item/paper/certificate = new()
- certificate.add_raw_text(get_completion_certificate())
+ certificate.add_raw_text(get_completion_certificate(time_difference, grade))
certificate.name = "certificate of domain completion"
certificate.update_appearance()
@@ -37,6 +46,10 @@
reward_cache.manifest = certificate
reward_cache.update_appearance()
+ if(can_generate_tech_disk(grade))
+ new /obj/item/disk/design_disk/bepis/remove_tech(reward_cache)
+ generated_domain.disk_reward_spawned = TRUE
+
chosen_forge.start_to_spawn(reward_cache)
return TRUE
@@ -50,7 +63,7 @@
return TRUE
/// Returns the markdown text containing domain completion information
-/obj/machinery/quantum_server/proc/get_completion_certificate()
+/obj/machinery/quantum_server/proc/get_completion_certificate(time_difference, grade)
var/base_points = generated_domain.reward_points
if(domain_randomized)
base_points -= 1
@@ -59,11 +72,9 @@
var/domain_threats = length(spawned_threat_refs)
- var/time_difference = world.time - generated_domain.start_time
-
var/completion_time = "### Completion Time: [DisplayTimeText(time_difference)]\n"
- var/grade = "\n---\n\n# Rating: [grade_completion(time_difference)]"
+ var/completion_grade = "\n---\n\n# Rating: [grade]"
var/text = "# Certificate of Domain Completion\n\n---\n\n"
@@ -75,7 +86,7 @@
if(bonuses <= 1)
text += completion_time
- text += grade
+ text += completion_grade
return text
text += "### Bonuses\n"
@@ -94,10 +105,24 @@
text += "- **Components:** + [servo_rating]\n"
text += completion_time
- text += grade
+ text += completion_grade
return text
+/// Checks if the players should get a bepis reward
+/obj/machinery/quantum_server/proc/can_generate_tech_disk(grade)
+ if(generated_domain.disk_reward_spawned)
+ return FALSE
+
+ if(!LAZYLEN(SSresearch.techweb_nodes_experimental))
+ return FALSE
+
+ var/static/list/passing_grades = list()
+ if(!passing_grades.len)
+ passing_grades = list(GRADE_A,GRADE_S)
+
+ return generated_domain.difficulty >= BITRUNNER_DIFFICULTY_MEDIUM && (grade in passing_grades)
+
/// Grades the player's run based on several factors
/obj/machinery/quantum_server/proc/grade_completion(completion_time)
var/score = length(spawned_threat_refs) * 5
@@ -124,13 +149,18 @@
switch(score)
if(1 to 4)
- return "D"
+ return GRADE_D
if(5 to 7)
- return "C"
+ return GRADE_C
if(8 to 10)
- return "B"
+ return GRADE_B
if(11 to 13)
- return "A"
+ return GRADE_A
else
- return "S"
+ return GRADE_S
+#undef GRADE_D
+#undef GRADE_C
+#undef GRADE_B
+#undef GRADE_A
+#undef GRADE_S
diff --git a/code/modules/bitrunning/virtual_domain/virtual_domain.dm b/code/modules/bitrunning/virtual_domain/virtual_domain.dm
index b316bb97cae1e..21898daad72d7 100644
--- a/code/modules/bitrunning/virtual_domain/virtual_domain.dm
+++ b/code/modules/bitrunning/virtual_domain/virtual_domain.dm
@@ -44,6 +44,8 @@
var/start_time
/// This map is specifically for unit tests. Shouldn't display in game
var/test_only = FALSE
+ /// Has this domain been beaten with high enough score to spawn a tech disk?
+ var/disk_reward_spawned = FALSE
/// Sends a point to any loot signals on the map
/datum/lazy_template/virtual_domain/proc/add_points(points_to_add)
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 2c8c63579e2f5..8e51fa917f4da 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -502,7 +502,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
"[key_name(src)] (IP: [address], ID: [computer_id]) is a new BYOND account [account_age] day[(account_age == 1?"":"s")] old, created on [account_join_date].[new_player_alert_role ? " <@&[new_player_alert_role]>" : ""]"
)
scream_about_watchlists(src)
- check_ip_intel()
validate_key_in_db()
// If we aren't already generating a ban cache, fire off a build request
// This way hopefully any users of request_ban_cache will never need to yield
@@ -532,6 +531,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
to_chat(src, span_warning("Unable to access asset cache browser, if you are using a custom skin file, please allow DS to download the updated version, if you are not, then make a bug report. This is not a critical issue but can cause issues with resource downloading, as it is impossible to know when extra resources arrived to you."))
update_ambience_pref()
+ check_ip_intel()
//This is down here because of the browse() calls in tooltip/New()
if(!tooltips)
diff --git a/code/modules/client/preferences/_preference.dm b/code/modules/client/preferences/_preference.dm
index 644d57b6d24d1..5fbf5c6953d6a 100644
--- a/code/modules/client/preferences/_preference.dm
+++ b/code/modules/client/preferences/_preference.dm
@@ -331,7 +331,7 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key())
)
var/species_type = preferences.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
if (!(savefile_key in species.get_features()))
return FALSE
diff --git a/code/modules/client/preferences/clothing.dm b/code/modules/client/preferences/clothing.dm
index cf200ad1ffd65..d0ec072ba472f 100644
--- a/code/modules/client/preferences/clothing.dm
+++ b/code/modules/client/preferences/clothing.dm
@@ -95,7 +95,7 @@
should_generate_icons = TRUE
/datum/preference/choiced/socks/init_possible_values()
- return assoc_to_keys_features(GLOB.socks_list)
+ return assoc_to_keys_features(SSaccessories.socks_list)
/datum/preference/choiced/socks/icon_for(value)
var/static/icon/lower_half
@@ -105,7 +105,7 @@
lower_half.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_r_leg"), ICON_OVERLAY)
lower_half.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_l_leg"), ICON_OVERLAY)
- return generate_underwear_icon(GLOB.socks_list[value], lower_half)
+ return generate_underwear_icon(SSaccessories.socks_list[value], lower_half)
/datum/preference/choiced/socks/apply_to_human(mob/living/carbon/human/target, value)
target.socks = value
@@ -119,7 +119,7 @@
should_generate_icons = TRUE
/datum/preference/choiced/undershirt/init_possible_values()
- return assoc_to_keys_features(GLOB.undershirt_list)
+ return assoc_to_keys_features(SSaccessories.undershirt_list)
/datum/preference/choiced/undershirt/icon_for(value)
var/static/icon/body
@@ -135,7 +135,7 @@
var/icon/icon_with_undershirt = icon(body)
if (value != "Nude")
- var/datum/sprite_accessory/accessory = GLOB.undershirt_list[value]
+ var/datum/sprite_accessory/accessory = SSaccessories.undershirt_list[value]
icon_with_undershirt.Blend(icon('icons/mob/clothing/underwear.dmi', accessory.icon_state), ICON_OVERLAY)
icon_with_undershirt.Crop(9, 9, 23, 23)
@@ -154,7 +154,7 @@
should_generate_icons = TRUE
/datum/preference/choiced/underwear/init_possible_values()
- return assoc_to_keys_features(GLOB.underwear_list)
+ return assoc_to_keys_features(SSaccessories.underwear_list)
/datum/preference/choiced/underwear/icon_for(value)
var/static/icon/lower_half
@@ -165,7 +165,7 @@
lower_half.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_r_leg"), ICON_OVERLAY)
lower_half.Blend(icon('icons/mob/human/bodyparts_greyscale.dmi', "human_l_leg"), ICON_OVERLAY)
- return generate_underwear_icon(GLOB.underwear_list[value], lower_half, COLOR_ALMOST_BLACK)
+ return generate_underwear_icon(SSaccessories.underwear_list[value], lower_half, COLOR_ALMOST_BLACK)
/datum/preference/choiced/underwear/apply_to_human(mob/living/carbon/human/target, value)
target.underwear = value
@@ -175,7 +175,7 @@
return FALSE
var/species_type = preferences.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
return !(TRAIT_NO_UNDERWEAR in species.inherent_traits)
/datum/preference/choiced/underwear/compile_constant_data()
diff --git a/code/modules/client/preferences/names.dm b/code/modules/client/preferences/names.dm
index 476fc7381a28f..9afc8da18c1aa 100644
--- a/code/modules/client/preferences/names.dm
+++ b/code/modules/client/preferences/names.dm
@@ -45,12 +45,11 @@
target.log_mob_tag("TAG: [target.tag] RENAMED: [key_name(target)]")
/datum/preference/name/real_name/create_informed_default_value(datum/preferences/preferences)
- var/species_type = preferences.read_preference(/datum/preference/choiced/species)
- var/gender = preferences.read_preference(/datum/preference/choiced/gender)
-
- var/datum/species/species = new species_type
-
- return species.random_name(gender, unique = TRUE)
+ return generate_random_name_species_based(
+ preferences.read_preference(/datum/preference/choiced/gender),
+ TRUE,
+ preferences.read_preference(/datum/preference/choiced/species),
+ )
/datum/preference/name/real_name/deserialize(input, datum/preferences/preferences)
input = ..(input)
@@ -73,9 +72,7 @@
savefile_key = "human_name"
/datum/preference/name/backup_human/create_informed_default_value(datum/preferences/preferences)
- var/gender = preferences.read_preference(/datum/preference/choiced/gender)
-
- return random_unique_name(gender)
+ return generate_random_name(preferences.read_preference(/datum/preference/choiced/gender))
/datum/preference/name/clown
savefile_key = "clown_name"
diff --git a/code/modules/client/preferences/species.dm b/code/modules/client/preferences/species.dm
index 9e4923d2b11da..1c74d7981b655 100644
--- a/code/modules/client/preferences/species.dm
+++ b/code/modules/client/preferences/species.dm
@@ -34,7 +34,7 @@
for (var/species_id in get_selectable_species())
var/species_type = GLOB.species_list[species_id]
- var/datum/species/species = new species_type()
+ var/datum/species/species = GLOB.species_prototypes[species_type]
data[species_id] = list()
data[species_id]["name"] = species.name
@@ -47,6 +47,4 @@
data[species_id]["perks"] = species.get_species_perks()
data[species_id]["diet"] = species.get_species_diet()
- qdel(species)
-
return data
diff --git a/code/modules/client/preferences/species_features/basic.dm b/code/modules/client/preferences/species_features/basic.dm
index abf4ea0e44e20..3f101ad9e44a5 100644
--- a/code/modules/client/preferences/species_features/basic.dm
+++ b/code/modules/client/preferences/species_features/basic.dm
@@ -7,7 +7,7 @@
var/icon/final_icon = new(head_icon)
if (!isnull(sprite_accessory))
ASSERT(istype(sprite_accessory))
-
+
var/icon/head_accessory_icon = icon(sprite_accessory.icon, sprite_accessory.icon_state)
if(y_offset)
head_accessory_icon.Shift(NORTH, y_offset)
@@ -61,10 +61,10 @@
relevant_head_flag = HEAD_FACIAL_HAIR
/datum/preference/choiced/facial_hairstyle/init_possible_values()
- return assoc_to_keys_features(GLOB.facial_hairstyles_list)
+ return assoc_to_keys_features(SSaccessories.facial_hairstyles_list)
/datum/preference/choiced/facial_hairstyle/icon_for(value)
- return generate_icon_with_head_accessory(GLOB.facial_hairstyles_list[value])
+ return generate_icon_with_head_accessory(SSaccessories.facial_hairstyles_list[value])
/datum/preference/choiced/facial_hairstyle/apply_to_human(mob/living/carbon/human/target, value)
target.set_facial_hairstyle(value, update = FALSE)
@@ -94,7 +94,7 @@
relevant_head_flag = HEAD_FACIAL_HAIR
/datum/preference/choiced/facial_hair_gradient/init_possible_values()
- return assoc_to_keys_features(GLOB.facial_hair_gradients_list)
+ return assoc_to_keys_features(SSaccessories.facial_hair_gradients_list)
/datum/preference/choiced/facial_hair_gradient/apply_to_human(mob/living/carbon/human/target, value)
target.set_facial_hair_gradient_style(new_style = value, update = FALSE)
@@ -137,10 +137,10 @@
relevant_head_flag = HEAD_HAIR
/datum/preference/choiced/hairstyle/init_possible_values()
- return assoc_to_keys_features(GLOB.hairstyles_list)
+ return assoc_to_keys_features(SSaccessories.hairstyles_list)
/datum/preference/choiced/hairstyle/icon_for(value)
- var/datum/sprite_accessory/hair/hairstyle = GLOB.hairstyles_list[value]
+ var/datum/sprite_accessory/hair/hairstyle = SSaccessories.hairstyles_list[value]
return generate_icon_with_head_accessory(hairstyle, hairstyle?.y_offset)
/datum/preference/choiced/hairstyle/apply_to_human(mob/living/carbon/human/target, value)
@@ -161,7 +161,7 @@
relevant_head_flag = HEAD_HAIR
/datum/preference/choiced/hair_gradient/init_possible_values()
- return assoc_to_keys_features(GLOB.hair_gradients_list)
+ return assoc_to_keys_features(SSaccessories.hair_gradients_list)
/datum/preference/choiced/hair_gradient/apply_to_human(mob/living/carbon/human/target, value)
target.set_hair_gradient_style(new_style = value, update = FALSE)
diff --git a/code/modules/client/preferences/species_features/felinid.dm b/code/modules/client/preferences/species_features/felinid.dm
index b9f3c7bfa337b..a6d43736cf46c 100644
--- a/code/modules/client/preferences/species_features/felinid.dm
+++ b/code/modules/client/preferences/species_features/felinid.dm
@@ -6,7 +6,7 @@
relevant_external_organ = /obj/item/organ/external/tail/cat
/datum/preference/choiced/tail_human/init_possible_values()
- return assoc_to_keys_features(GLOB.tails_list_human)
+ return assoc_to_keys_features(SSaccessories.tails_list_human)
/datum/preference/choiced/tail_human/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["tail_cat"] = value
@@ -23,7 +23,7 @@
relevant_mutant_bodypart = "ears"
/datum/preference/choiced/ears/init_possible_values()
- return assoc_to_keys_features(GLOB.ears_list)
+ return assoc_to_keys_features(SSaccessories.ears_list)
/datum/preference/choiced/ears/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["ears"] = value
diff --git a/code/modules/client/preferences/species_features/lizard.dm b/code/modules/client/preferences/species_features/lizard.dm
index 4ce09715483ad..bee57300ec4a4 100644
--- a/code/modules/client/preferences/species_features/lizard.dm
+++ b/code/modules/client/preferences/species_features/lizard.dm
@@ -32,10 +32,10 @@
relevant_mutant_bodypart = "body_markings"
/datum/preference/choiced/lizard_body_markings/init_possible_values()
- return assoc_to_keys_features(GLOB.body_markings_list)
+ return assoc_to_keys_features(SSaccessories.body_markings_list)
/datum/preference/choiced/lizard_body_markings/icon_for(value)
- var/datum/sprite_accessory/sprite_accessory = GLOB.body_markings_list[value]
+ var/datum/sprite_accessory/sprite_accessory = SSaccessories.body_markings_list[value]
var/icon/final_icon = icon('icons/mob/human/species/lizard/bodyparts.dmi', "lizard_chest_m")
@@ -65,10 +65,10 @@
should_generate_icons = TRUE
/datum/preference/choiced/lizard_frills/init_possible_values()
- return assoc_to_keys_features(GLOB.frills_list)
+ return assoc_to_keys_features(SSaccessories.frills_list)
/datum/preference/choiced/lizard_frills/icon_for(value)
- return generate_lizard_side_shot(GLOB.frills_list[value], "frills")
+ return generate_lizard_side_shot(SSaccessories.frills_list[value], "frills")
/datum/preference/choiced/lizard_frills/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["frills"] = value
@@ -81,10 +81,10 @@
should_generate_icons = TRUE
/datum/preference/choiced/lizard_horns/init_possible_values()
- return assoc_to_keys_features(GLOB.horns_list)
+ return assoc_to_keys_features(SSaccessories.horns_list)
/datum/preference/choiced/lizard_horns/icon_for(value)
- return generate_lizard_side_shot(GLOB.horns_list[value], "horns")
+ return generate_lizard_side_shot(SSaccessories.horns_list[value], "horns")
/datum/preference/choiced/lizard_horns/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["horns"] = value
@@ -96,7 +96,7 @@
relevant_mutant_bodypart = "legs"
/datum/preference/choiced/lizard_legs/init_possible_values()
- return assoc_to_keys_features(GLOB.legs_list)
+ return assoc_to_keys_features(SSaccessories.legs_list)
/datum/preference/choiced/lizard_legs/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["legs"] = value
@@ -109,10 +109,10 @@
should_generate_icons = TRUE
/datum/preference/choiced/lizard_snout/init_possible_values()
- return assoc_to_keys_features(GLOB.snouts_list)
+ return assoc_to_keys_features(SSaccessories.snouts_list)
/datum/preference/choiced/lizard_snout/icon_for(value)
- return generate_lizard_side_shot(GLOB.snouts_list[value], "snout", include_snout = FALSE)
+ return generate_lizard_side_shot(SSaccessories.snouts_list[value], "snout", include_snout = FALSE)
/datum/preference/choiced/lizard_snout/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["snout"] = value
@@ -124,7 +124,7 @@
relevant_mutant_bodypart = "spines"
/datum/preference/choiced/lizard_spines/init_possible_values()
- return assoc_to_keys_features(GLOB.spines_list)
+ return assoc_to_keys_features(SSaccessories.spines_list)
/datum/preference/choiced/lizard_spines/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["spines"] = value
@@ -136,7 +136,7 @@
relevant_external_organ = /obj/item/organ/external/tail/lizard
/datum/preference/choiced/lizard_tail/init_possible_values()
- return assoc_to_keys_features(GLOB.tails_list_lizard)
+ return assoc_to_keys_features(SSaccessories.tails_list_lizard)
/datum/preference/choiced/lizard_tail/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["tail_lizard"] = value
diff --git a/code/modules/client/preferences/species_features/monkey.dm b/code/modules/client/preferences/species_features/monkey.dm
index b25d2cdfab8e1..adf9e367723de 100644
--- a/code/modules/client/preferences/species_features/monkey.dm
+++ b/code/modules/client/preferences/species_features/monkey.dm
@@ -5,7 +5,7 @@
relevant_external_organ = /obj/item/organ/external/tail/monkey
/datum/preference/choiced/monkey_tail/init_possible_values()
- return assoc_to_keys_features(GLOB.tails_list_monkey)
+ return assoc_to_keys_features(SSaccessories.tails_list_monkey)
/datum/preference/choiced/monkey_tail/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["tail_monkey"] = value
diff --git a/code/modules/client/preferences/species_features/moth.dm b/code/modules/client/preferences/species_features/moth.dm
index 120a7ea822bec..745e6fb917b8f 100644
--- a/code/modules/client/preferences/species_features/moth.dm
+++ b/code/modules/client/preferences/species_features/moth.dm
@@ -6,7 +6,7 @@
should_generate_icons = TRUE
/datum/preference/choiced/moth_antennae/init_possible_values()
- return assoc_to_keys_features(GLOB.moth_antennae_list)
+ return assoc_to_keys_features(SSaccessories.moth_antennae_list)
/datum/preference/choiced/moth_antennae/icon_for(value)
var/static/icon/moth_head
@@ -16,7 +16,7 @@
moth_head.Blend(icon('icons/mob/human/human_face.dmi', "motheyes_l"), ICON_OVERLAY)
moth_head.Blend(icon('icons/mob/human/human_face.dmi', "motheyes_r"), ICON_OVERLAY)
- var/datum/sprite_accessory/antennae = GLOB.moth_antennae_list[value]
+ var/datum/sprite_accessory/antennae = SSaccessories.moth_antennae_list[value]
var/icon/icon_with_antennae = new(moth_head)
icon_with_antennae.Blend(icon(antennae.icon, "m_moth_antennae_[antennae.icon_state]_FRONT"), ICON_OVERLAY)
@@ -37,7 +37,7 @@
relevant_mutant_bodypart = "moth_markings"
/datum/preference/choiced/moth_markings/init_possible_values()
- return assoc_to_keys_features(GLOB.moth_markings_list)
+ return assoc_to_keys_features(SSaccessories.moth_markings_list)
/datum/preference/choiced/moth_markings/icon_for(value)
var/static/list/body_parts = list(
@@ -59,7 +59,7 @@
moth_body.Blend(icon('icons/mob/human/human_face.dmi', "motheyes_l"), ICON_OVERLAY)
moth_body.Blend(icon('icons/mob/human/human_face.dmi', "motheyes_r"), ICON_OVERLAY)
- var/datum/sprite_accessory/markings = GLOB.moth_markings_list[value]
+ var/datum/sprite_accessory/markings = SSaccessories.moth_markings_list[value]
var/icon/icon_with_markings = new(moth_body)
if (value != "None")
@@ -88,10 +88,10 @@
should_generate_icons = TRUE
/datum/preference/choiced/moth_wings/init_possible_values()
- return assoc_to_keys_features(GLOB.moth_wings_list)
+ return assoc_to_keys_features(SSaccessories.moth_wings_list)
/datum/preference/choiced/moth_wings/icon_for(value)
- var/datum/sprite_accessory/moth_wings = GLOB.moth_wings_list[value]
+ var/datum/sprite_accessory/moth_wings = SSaccessories.moth_wings_list[value]
var/icon/final_icon = icon(moth_wings.icon, "m_moth_wings_[moth_wings.icon_state]_BEHIND")
final_icon.Blend(icon(moth_wings.icon, "m_moth_wings_[moth_wings.icon_state]_FRONT"), ICON_OVERLAY)
return final_icon
diff --git a/code/modules/client/preferences/species_features/mushperson.dm b/code/modules/client/preferences/species_features/mushperson.dm
index f5e6a08ac92d2..45bd9c4b72620 100644
--- a/code/modules/client/preferences/species_features/mushperson.dm
+++ b/code/modules/client/preferences/species_features/mushperson.dm
@@ -5,7 +5,7 @@
relevant_mutant_bodypart = "cap"
/datum/preference/choiced/mushroom_cap/init_possible_values()
- return assoc_to_keys_features(GLOB.caps_list)
+ return assoc_to_keys_features(SSaccessories.caps_list)
/datum/preference/choiced/mushroom_cap/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["caps"] = value
diff --git a/code/modules/client/preferences/species_features/mutants.dm b/code/modules/client/preferences/species_features/mutants.dm
index 7ecf25d9abce5..1d18c78ee1ad1 100644
--- a/code/modules/client/preferences/species_features/mutants.dm
+++ b/code/modules/client/preferences/species_features/mutants.dm
@@ -9,7 +9,7 @@
return FALSE
var/species_type = preferences.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
return !(TRAIT_FIXED_MUTANT_COLORS in species.inherent_traits)
/datum/preference/color/mutant_color/create_default_value()
diff --git a/code/modules/client/preferences/species_features/pod.dm b/code/modules/client/preferences/species_features/pod.dm
index 5280308fa8930..de3d5221f7a41 100644
--- a/code/modules/client/preferences/species_features/pod.dm
+++ b/code/modules/client/preferences/species_features/pod.dm
@@ -6,10 +6,10 @@
should_generate_icons = TRUE
/datum/preference/choiced/pod_hair/init_possible_values()
- return assoc_to_keys_features(GLOB.pod_hair_list)
+ return assoc_to_keys_features(SSaccessories.pod_hair_list)
/datum/preference/choiced/pod_hair/icon_for(value)
- var/datum/sprite_accessory/pod_hair = GLOB.pod_hair_list[value]
+ var/datum/sprite_accessory/pod_hair = SSaccessories.pod_hair_list[value]
var/icon/icon_with_hair = icon('icons/mob/human/bodyparts_greyscale.dmi', "pod_head_m")
@@ -24,7 +24,7 @@
return icon_with_hair
/datum/preference/choiced/pod_hair/create_default_value()
- return pick(assoc_to_keys_features(GLOB.pod_hair_list))
+ return pick(assoc_to_keys_features(SSaccessories.pod_hair_list))
/datum/preference/choiced/pod_hair/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["pod_hair"] = value
diff --git a/code/modules/client/preferences/underwear_color.dm b/code/modules/client/preferences/underwear_color.dm
index 6e64b4423e50a..1304bdaf2da8d 100644
--- a/code/modules/client/preferences/underwear_color.dm
+++ b/code/modules/client/preferences/underwear_color.dm
@@ -8,7 +8,7 @@
return FALSE
var/species_type = preferences.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
return !(TRAIT_NO_UNDERWEAR in species.inherent_traits)
/datum/preference/color/underwear_color/apply_to_human(mob/living/carbon/human/target, value)
diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm
index 4f5d377ddac00..e0b06a5ab6e2f 100644
--- a/code/modules/clothing/head/jobs.dm
+++ b/code/modules/clothing/head/jobs.dm
@@ -166,6 +166,8 @@
desc = "An opulent hat that functions as a radio to God. Or as a lightning rod, depending on who you ask."
icon_state = "bishopmitre"
+#define CANDY_CD_TIME 2 MINUTES
+
//Detective
/obj/item/clothing/head/fedora/det_hat
name = "detective's fedora"
@@ -174,11 +176,12 @@
icon_state = "detective"
inhand_icon_state = "det_hat"
interaction_flags_click = NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING
- /// Cooldown for retrieving precious candy corn on alt click
- var/candy_cooldown = 0
dog_fashion = /datum/dog_fashion/head/detective
- ///Path for the flask that spawns inside their hat roundstart
+ /// Path for the flask that spawns inside their hat roundstart
var/flask_path = /obj/item/reagent_containers/cup/glass/flask/det
+ /// Cooldown for retrieving precious candy corn with rmb
+ COOLDOWN_DECLARE(candy_cooldown)
+
/datum/armor/fedora_det_hat
melee = 25
@@ -189,28 +192,46 @@
acid = 50
wound = 5
+
/obj/item/clothing/head/fedora/det_hat/Initialize(mapload)
. = ..()
create_storage(storage_type = /datum/storage/pockets/small/fedora/detective)
+ register_context()
+
new flask_path(src)
+
/obj/item/clothing/head/fedora/det_hat/examine(mob/user)
. = ..()
. += span_notice("Alt-click to take a candy corn.")
+
+/obj/item/clothing/head/fedora/det_hat/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+ . = ..()
+
+ context[SCREENTIP_CONTEXT_ALT_LMB] = "Candy Time"
+
+ return CONTEXTUAL_SCREENTIP_SET
+
+
+/// Now to solve where all these keep coming from
/obj/item/clothing/head/fedora/det_hat/click_alt(mob/user)
- if(candy_cooldown >= world.time)
+ if(!COOLDOWN_FINISHED(src, candy_cooldown))
to_chat(user, span_warning("You just took a candy corn! You should wait a couple minutes, lest you burn through your stash."))
return CLICK_ACTION_BLOCKING
- var/obj/item/food/candy_corn/CC = new /obj/item/food/candy_corn(src)
- user.put_in_hands(CC)
+ var/obj/item/food/candy_corn/sweets = new /obj/item/food/candy_corn(src)
+ user.put_in_hands(sweets)
to_chat(user, span_notice("You slip a candy corn from your hat."))
- candy_cooldown = world.time+1200
+ COOLDOWN_START(src, candy_cooldown, CANDY_CD_TIME)
+
return CLICK_ACTION_SUCCESS
+
+#undef CANDY_CD_TIME
+
/obj/item/clothing/head/fedora/det_hat/minor
flask_path = /obj/item/reagent_containers/cup/glass/flask/det/minor
diff --git a/code/modules/clothing/head/wig.dm b/code/modules/clothing/head/wig.dm
index 5ab2bcad2144c..ecd70742ba889 100644
--- a/code/modules/clothing/head/wig.dm
+++ b/code/modules/clothing/head/wig.dm
@@ -25,7 +25,7 @@
item_flags &= ~EXAMINE_SKIP
/obj/item/clothing/head/wig/update_icon_state()
- var/datum/sprite_accessory/hair/hair_style = GLOB.hairstyles_list[hairstyle]
+ var/datum/sprite_accessory/hair/hair_style = SSaccessories.hairstyles_list[hairstyle]
if(hair_style)
icon = hair_style.icon
icon_state = hair_style.icon_state
@@ -36,7 +36,7 @@
if(isinhands)
return
- var/datum/sprite_accessory/hair/hair = GLOB.hairstyles_list[hairstyle]
+ var/datum/sprite_accessory/hair/hair = SSaccessories.hairstyles_list[hairstyle]
if(!hair)
return
@@ -49,7 +49,7 @@
hair_overlay.overlays += emissive_blocker(hair_overlay.icon, hair_overlay.icon_state, src, alpha = hair_overlay.alpha)
/obj/item/clothing/head/wig/attack_self(mob/user)
- var/new_style = tgui_input_list(user, "Select a hairstyle", "Wig Styling", GLOB.hairstyles_list - "Bald")
+ var/new_style = tgui_input_list(user, "Select a hairstyle", "Wig Styling", SSaccessories.hairstyles_list - "Bald")
var/newcolor = adjustablecolor ? input(usr,"","Choose Color",color) as color|null : null
if(!user.can_perform_action(src))
return
@@ -92,7 +92,7 @@
update_appearance()
/obj/item/clothing/head/wig/random/Initialize(mapload)
- hairstyle = pick(GLOB.hairstyles_list - "Bald") //Don't want invisible wig
+ hairstyle = pick(SSaccessories.hairstyles_list - "Bald") //Don't want invisible wig
add_atom_colour("#[random_short_color()]", FIXED_COLOUR_PRIORITY)
. = ..()
@@ -104,7 +104,7 @@
custom_price = PAYCHECK_COMMAND
/obj/item/clothing/head/wig/natural/Initialize(mapload)
- hairstyle = pick(GLOB.hairstyles_list - "Bald")
+ hairstyle = pick(SSaccessories.hairstyles_list - "Bald")
. = ..()
/obj/item/clothing/head/wig/natural/visual_equipped(mob/living/carbon/human/user, slot)
diff --git a/code/modules/events/immovable_rod/immovable_rod.dm b/code/modules/events/immovable_rod/immovable_rod.dm
index 285a99cd31dd7..e9d2995218d56 100644
--- a/code/modules/events/immovable_rod/immovable_rod.dm
+++ b/code/modules/events/immovable_rod/immovable_rod.dm
@@ -76,11 +76,6 @@
if(istype(ghost))
ghost.ManualFollow(src)
-/obj/effect/immovablerod/proc/on_entered_over_movable(datum/source, atom/movable/atom_crossed_over)
- SIGNAL_HANDLER
- if((atom_crossed_over.density || isliving(atom_crossed_over)) && !QDELETED(atom_crossed_over))
- Bump(atom_crossed_over)
-
/obj/effect/immovablerod/proc/on_entering_atom(datum/source, atom/destination, atom/old_loc, list/atom/old_locs)
SIGNAL_HANDLER
if(destination.density && isturf(destination))
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm
index c05446d35218e..8f78cb01ebc23 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm
@@ -150,7 +150,7 @@
)
result = /obj/item/food/croissant/throwing
category = CAT_BREAD
- always_available = FALSE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/food/breaddog
name = "Living dog/bread hybrid"
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm
index b34cc5f36e965..4b56874eb7c6b 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm
@@ -184,7 +184,6 @@
/datum/crafting_recipe/food/clowncake
name = "clown cake"
- always_available = FALSE
reqs = list(
/obj/item/food/cake/plain = 1,
/obj/item/food/sundae = 2,
@@ -192,16 +191,17 @@
)
result = /obj/item/food/cake/clown_cake
category = CAT_CAKE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/food/vanillacake
name = "vanilla cake"
- always_available = FALSE
reqs = list(
/obj/item/food/cake/plain = 1,
/obj/item/food/grown/vanillapod = 2
)
result = /obj/item/food/cake/vanilla_cake
category = CAT_CAKE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/food/trumpetcake
name = "Spaceman's Cake"
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm
index a9f1ad23d8e26..c0c99bbe6523b 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm
@@ -132,7 +132,6 @@
/datum/crafting_recipe/food/mimetart
name = "Mime tart"
- always_available = FALSE
reqs = list(
/datum/reagent/consumable/milk = 5,
/datum/reagent/consumable/sugar = 5,
@@ -141,10 +140,10 @@
)
result = /obj/item/food/pie/mimetart
category = CAT_PIE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/food/berrytart
name = "Berry tart"
- always_available = FALSE
reqs = list(
/datum/reagent/consumable/milk = 5,
/datum/reagent/consumable/sugar = 5,
@@ -153,10 +152,10 @@
)
result = /obj/item/food/pie/berrytart
category = CAT_PIE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/food/cocolavatart
name = "Chocolate Lava tart"
- always_available = FALSE
reqs = list(
/datum/reagent/consumable/milk = 5,
/datum/reagent/consumable/sugar = 5,
@@ -166,6 +165,7 @@
)
result = /obj/item/food/pie/cocolavatart
category = CAT_PIE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/food/blumpkinpie
name = "Blumpkin pie"
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_sandwich.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_sandwich.dm
index b0c44629e1853..7761a57fcfdbd 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_sandwich.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_sandwich.dm
@@ -118,7 +118,6 @@
/datum/crafting_recipe/food/death_sandwich
name = "Death Sandwich"
- always_available = FALSE
reqs = list(
/obj/item/food/breadslice/plain = 2,
/obj/item/food/salami = 4,
@@ -127,6 +126,7 @@
)
result = /obj/item/food/sandwich/death
category = CAT_SANDWICH
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/food/toast_sandwich
name = "Toast Sandwich"
diff --git a/code/modules/food_and_drinks/restaurant/customers/_customer.dm b/code/modules/food_and_drinks/restaurant/customers/_customer.dm
index 47bb843d755c7..15e4659338d0c 100644
--- a/code/modules/food_and_drinks/restaurant/customers/_customer.dm
+++ b/code/modules/food_and_drinks/restaurant/customers/_customer.dm
@@ -306,7 +306,7 @@
/datum/customer_data/moth/proc/get_wings(mob/living/basic/robot_customer/customer)
var/customer_ref = WEAKREF(customer)
if (!LAZYACCESS(wings_chosen, customer_ref))
- LAZYSET(wings_chosen, customer_ref, GLOB.moth_wings_list[pick(GLOB.moth_wings_list)])
+ LAZYSET(wings_chosen, customer_ref, SSaccessories.moth_wings_list[pick(SSaccessories.moth_wings_list)])
return wings_chosen[customer_ref]
/datum/customer_data/moth/get_underlays(mob/living/basic/robot_customer/customer)
diff --git a/code/modules/hydroponics/grown/replicapod.dm b/code/modules/hydroponics/grown/replicapod.dm
index c4e3b27673ae4..31c0b7f81df64 100644
--- a/code/modules/hydroponics/grown/replicapod.dm
+++ b/code/modules/hydroponics/grown/replicapod.dm
@@ -197,7 +197,7 @@
if(!features["mcolor"])
features["mcolor"] = "#59CE00"
if(!features["pod_hair"])
- features["pod_hair"] = pick(GLOB.pod_hair_list)
+ features["pod_hair"] = pick(SSaccessories.pod_hair_list)
for(var/V in quirks)
new V(podman)
diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm
index 6c5c2f4f03967..9cbd711d98161 100644
--- a/code/modules/jobs/job_types/_job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -117,7 +117,7 @@
/// RPG job names, for the memes
var/rpg_title
- /// Alternate titles to register as pointing to this job.
+ /// Alternate titles to register as pointing to this job.
var/list/alternate_titles
/// Does this job ignore human authority?
@@ -543,11 +543,11 @@
dna.species.roundstart_changed = TRUE
apply_pref_name(/datum/preference/name/backup_human, player_client)
if(CONFIG_GET(flag/force_random_names))
- var/species_type = player_client.prefs.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
-
- var/gender = player_client.prefs.read_preference(/datum/preference/choiced/gender)
- real_name = species.random_name(gender, TRUE)
+ real_name = generate_random_name_species_based(
+ player_client.prefs.read_preference(/datum/preference/choiced/gender),
+ TRUE,
+ player_client.prefs.read_preference(/datum/preference/choiced/species),
+ )
dna.update_dna_identity()
@@ -569,9 +569,11 @@
if(!player_client)
return // Disconnected while checking the appearance ban.
- var/species_type = player_client.prefs.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
- organic_name = species.random_name(player_client.prefs.read_preference(/datum/preference/choiced/gender), TRUE)
+ organic_name = generate_random_name_species_based(
+ player_client.prefs.read_preference(/datum/preference/choiced/gender),
+ TRUE,
+ player_client.prefs.read_preference(/datum/preference/choiced/species),
+ )
else
if(!player_client)
return // Disconnected while checking the appearance ban.
diff --git a/code/modules/language/_language.dm b/code/modules/language/_language.dm
new file mode 100644
index 0000000000000..94ea4a6aa4027
--- /dev/null
+++ b/code/modules/language/_language.dm
@@ -0,0 +1,164 @@
+/// maximum of 50 specific scrambled lines per language
+#define SCRAMBLE_CACHE_LEN 50
+
+/// Datum based languages. Easily editable and modular.
+/datum/language
+ /// Fluff name of language if any.
+ var/name = "an unknown language"
+ /// Short description for 'Check Languages'.
+ var/desc = "A language."
+ /// Character used to speak in language
+ /// If key is null, then the language isn't real or learnable.
+ var/key
+ /// Various language flags.
+ var/flags = NONE
+ /// Used when scrambling text for a non-speaker.
+ var/list/syllables
+ /// List of characters that will randomly be inserted between syllables.
+ var/list/special_characters
+ /// Likelihood of making a new sentence after each syllable.
+ var/sentence_chance = 5
+ /// Likelihood of getting a space in the random scramble string
+ var/space_chance = 55
+ /// Spans to apply from this language
+ var/list/spans
+ /// Cache of recently scrambled text
+ /// This allows commonly reused words to not require a full re-scramble every time.
+ var/list/scramble_cache = list()
+ /// The language that an atom knows with the highest "default_priority" is selected by default.
+ var/default_priority = 0
+ /// If TRUE, when generating names, we will always use the default human namelist, even if we have syllables set.
+ /// This is to be used for languages with very outlandish syllable lists (like pirates).
+ var/always_use_default_namelist = FALSE
+ /// Icon displayed in the chat window when speaking this language.
+ /// if you are seeing someone speak popcorn language, then something is wrong.
+ var/icon = 'icons/misc/language.dmi'
+ /// Icon state displayed in the chat window when speaking this language.
+ var/icon_state = "popcorn"
+
+ /// By default, random names picks this many names
+ var/default_name_count = 2
+ /// By default, random names picks this many syllables (min)
+ var/default_name_syllable_min = 2
+ /// By default, random names picks this many syllables (max)
+ var/default_name_syllable_max = 4
+ /// What char to place in between randomly generated names
+ var/random_name_spacer = " "
+
+/// Checks whether we should display the language icon to the passed hearer.
+/datum/language/proc/display_icon(atom/movable/hearer)
+ var/understands = hearer.has_language(src.type)
+ if((flags & LANGUAGE_HIDE_ICON_IF_UNDERSTOOD) && understands)
+ return FALSE
+ if((flags & LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD) && !understands)
+ return FALSE
+ return TRUE
+
+/// Returns the icon to display in the chat window when speaking this language.
+/datum/language/proc/get_icon()
+ var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat)
+ return sheet.icon_tag("language-[icon_state]")
+
+/// Simple helper for getting a default firstname lastname
+/datum/language/proc/default_name(gender = NEUTER)
+ if(gender != MALE)
+ gender = pick(MALE, FEMALE)
+ if(gender == FEMALE)
+ return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names))
+ return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names))
+
+
+/**
+ * Generates a random name this language would use.
+ *
+ * * gender: What gender to generate from, if neuter / plural coin flips between male and female
+ * * name_count: How many names to generate in, by default 2, for firstname lastname
+ * * syllable_count: How many syllables to generate in each name, min
+ * * syllable_max: How many syllables to generate in each name, max
+ * * force_use_syllables: If the name should be generated from the syllables list.
+ * Only used for subtypes which implement custom name lists. Also requires the language has syllables set.
+ */
+/datum/language/proc/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(gender != MALE)
+ gender = pick(MALE, FEMALE)
+ if(!length(syllables) || always_use_default_namelist)
+ return default_name(gender)
+
+ var/list/full_name = list()
+ for(var/i in 1 to name_count)
+ var/new_name = ""
+ for(var/j in 1 to rand(default_name_syllable_min, default_name_syllable_max))
+ new_name += pick_weight_recursive(syllables)
+ full_name += capitalize(LOWER_TEXT(new_name))
+
+ return jointext(full_name, random_name_spacer)
+
+/// Generates a random name, and attempts to ensure it is unique (IE, no other mob in the world has it)
+/datum/language/proc/get_random_unique_name(...)
+ var/result = get_random_name(arglist(args))
+ for(var/i in 1 to 10)
+ if(!findname(result))
+ break
+ result = get_random_name(arglist(args))
+
+ return result
+
+/datum/language/proc/check_cache(input)
+ var/lookup = scramble_cache[input]
+ if(lookup)
+ scramble_cache -= input
+ scramble_cache[input] = lookup
+ . = lookup
+
+/datum/language/proc/add_to_cache(input, scrambled_text)
+ // Add it to cache, cutting old entries if the list is too long
+ scramble_cache[input] = scrambled_text
+ if(scramble_cache.len > SCRAMBLE_CACHE_LEN)
+ scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1)
+
+/datum/language/proc/scramble(input)
+
+ if(!length(syllables))
+ return stars(input)
+
+ // If the input is cached already, move it to the end of the cache and return it
+ var/lookup = check_cache(input)
+ if(lookup)
+ return lookup
+
+ var/input_size = length_char(input)
+ var/scrambled_text = ""
+ var/capitalize = TRUE
+
+ while(length_char(scrambled_text) < input_size)
+ var/next = (length(scrambled_text) && length(special_characters) && prob(1)) ? pick(special_characters) : pick_weight_recursive(syllables)
+ if(capitalize)
+ next = capitalize(next)
+ capitalize = FALSE
+ scrambled_text += next
+ var/chance = rand(100)
+ if(chance <= sentence_chance)
+ scrambled_text += ". "
+ capitalize = TRUE
+ else if(chance > sentence_chance && chance <= space_chance)
+ scrambled_text += " "
+
+ scrambled_text = trim(scrambled_text)
+ var/ending = copytext_char(scrambled_text, -1)
+ if(ending == ".")
+ scrambled_text = copytext_char(scrambled_text, 1, -2)
+ var/input_ending = copytext_char(input, -1)
+ if(input_ending in list("!","?","."))
+ scrambled_text += input_ending
+
+ add_to_cache(input, scrambled_text)
+
+ return scrambled_text
+
+#undef SCRAMBLE_CACHE_LEN
diff --git a/code/modules/language/language_holder.dm b/code/modules/language/_language_holder.dm
similarity index 100%
rename from code/modules/language/language_holder.dm
rename to code/modules/language/_language_holder.dm
diff --git a/code/modules/language/language_manuals.dm b/code/modules/language/_language_manuals.dm
similarity index 100%
rename from code/modules/language/language_manuals.dm
rename to code/modules/language/_language_manuals.dm
diff --git a/code/modules/language/language_menu.dm b/code/modules/language/_language_menu.dm
similarity index 100%
rename from code/modules/language/language_menu.dm
rename to code/modules/language/_language_menu.dm
diff --git a/code/modules/language/aphasia.dm b/code/modules/language/aphasia.dm
index 9d4e317c4d881..2d82b79892ee7 100644
--- a/code/modules/language/aphasia.dm
+++ b/code/modules/language/aphasia.dm
@@ -7,3 +7,4 @@
space_chance = 20
default_priority = 10
icon_state = "aphasia"
+ always_use_default_namelist = TRUE // Shouldn't generate names for this anyways
diff --git a/code/modules/language/beachbum.dm b/code/modules/language/beachbum.dm
index d78be9788f35b..bd319e717ffd0 100644
--- a/code/modules/language/beachbum.dm
+++ b/code/modules/language/beachbum.dm
@@ -17,5 +17,5 @@
"heavy", "stellar", "excellent", "triumphant", "babe", "four",
"tail", "trim", "tube", "wobble", "roll", "gnarly", "epic",
)
-
icon_state = "beach"
+ always_use_default_namelist = TRUE
diff --git a/code/modules/language/buzzwords.dm b/code/modules/language/buzzwords.dm
index c46088c0ad5b9..2ed033bca345b 100644
--- a/code/modules/language/buzzwords.dm
+++ b/code/modules/language/buzzwords.dm
@@ -8,3 +8,4 @@
)
icon_state = "buzz"
default_priority = 90
+ always_use_default_namelist = TRUE // Otherwise we get Bzzbzbz Zzzbzbz.
diff --git a/code/modules/language/calcic.dm b/code/modules/language/calcic.dm
index f4882e1105b95..477e442203bc1 100644
--- a/code/modules/language/calcic.dm
+++ b/code/modules/language/calcic.dm
@@ -13,4 +13,16 @@
icon_state = "calcic"
default_priority = 90
+/datum/language/calcic/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
+
+ return "[pick(GLOB.plasmaman_names)] \Roman[rand(1, 99)]"
+
// Yeah, this goes to skeletons too, since it's basically just skeleton clacking.
diff --git a/code/modules/language/codespeak.dm b/code/modules/language/codespeak.dm
index 09db7ef511b4b..242095b3bb7fa 100644
--- a/code/modules/language/codespeak.dm
+++ b/code/modules/language/codespeak.dm
@@ -5,6 +5,7 @@
default_priority = 0
flags = TONGUELESS_SPEECH | LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD
icon_state = "codespeak"
+ always_use_default_namelist = TRUE // No syllables anyways
/datum/language/codespeak/scramble(input)
var/lookup = check_cache(input)
diff --git a/code/modules/language/common.dm b/code/modules/language/common.dm
index 2dc7294983c0a..6bad808fef262 100644
--- a/code/modules/language/common.dm
+++ b/code/modules/language/common.dm
@@ -7,50 +7,51 @@
default_priority = 100
icon_state = "galcom"
-
-//Syllable Lists
-/*
- This list really long, mainly because I can't make up my mind about which mandarin syllables should be removed,
- and the english syllables had to be duplicated so that there is roughly a 50-50 weighting.
-
- Sources:
- http://www.sttmedia.com/syllablefrequency-english
- http://www.chinahighlights.com/travelguide/learning-chinese/pinyin-syllables.htm
-*/
-/datum/language/common/syllables = list(
- // each sublist has an equal chance of being picked, so each syllable has an equal chance of being english or chinese
- list(
- "a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao",
- "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai",
- "chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun",
- "chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei",
- "den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e",
- "ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang",
- "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha",
- "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan",
- "huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan",
- "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai",
- "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian",
- "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang",
- "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na",
- "nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning",
- "niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng",
- "pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin",
- "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou",
- "ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha",
- "shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui",
- "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te",
- "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan",
- "wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu",
- "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan",
- "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao",
- "zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi",
- "zong", "zou", "zuan", "zui", "zun", "zuo", "zu",
- ),
- list(
- "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it",
- "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to",
- "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin",
- "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi",
- ),
-)
+ // Default namelist is the human namelist, and common is the human language, so might as well.
+ // Feel free to remove this at some point because common can generate some pretty cool names.
+ always_use_default_namelist = TRUE
+ /**
+ * This list really long, mainly because I can't make up my mind about which mandarin syllables should be removed,
+ * and the english syllables had to be duplicated so that there is roughly a 50-50 weighting.
+ *
+ * Sources:
+ * http://www.sttmedia.com/syllablefrequency-english
+ * http://www.chinahighlights.com/travelguide/learning-chinese/pinyin-syllables.htm
+ */
+ syllables = list(
+ // each sublist has an equal chance of being picked, so each syllable has an equal chance of being english or chinese
+ list(
+ "a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao",
+ "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai",
+ "chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun",
+ "chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei",
+ "den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e",
+ "ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang",
+ "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha",
+ "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan",
+ "huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan",
+ "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai",
+ "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian",
+ "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang",
+ "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na",
+ "nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning",
+ "niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng",
+ "pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin",
+ "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou",
+ "ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha",
+ "shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui",
+ "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te",
+ "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan",
+ "wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu",
+ "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan",
+ "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao",
+ "zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi",
+ "zong", "zou", "zuan", "zui", "zun", "zuo", "zu",
+ ),
+ list(
+ "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it",
+ "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to",
+ "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin",
+ "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi",
+ ),
+ )
diff --git a/code/modules/language/draconic.dm b/code/modules/language/draconic.dm
index f812c8dc1311a..55ebd1ec20267 100644
--- a/code/modules/language/draconic.dm
+++ b/code/modules/language/draconic.dm
@@ -13,5 +13,25 @@
"ra", "ar", "re", "er", "ri", "ir", "ro", "or", "ru", "ur", "rs", "sr",
"a", "a", "e", "e", "i", "i", "o", "o", "u", "u", "s", "s"
)
+ special_characters = list("-")
icon_state = "lizard"
default_priority = 90
+ default_name_syllable_min = 3
+ default_name_syllable_max = 5
+ random_name_spacer = "-"
+
+/datum/language/draconic/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
+ if(gender != MALE)
+ gender = pick(MALE, FEMALE)
+
+ if(gender == MALE)
+ return "[pick(GLOB.lizard_names_male)][random_name_spacer][pick(GLOB.lizard_names_male)]"
+ return "[pick(GLOB.lizard_names_female)][random_name_spacer][pick(GLOB.lizard_names_female)]"
diff --git a/code/modules/language/drone.dm b/code/modules/language/drone.dm
index 5b47533d45e3a..09fb6546e4a16 100644
--- a/code/modules/language/drone.dm
+++ b/code/modules/language/drone.dm
@@ -11,3 +11,4 @@
default_priority = 20
icon_state = "drone"
+ always_use_default_namelist = TRUE // Nonsense language
diff --git a/code/modules/language/language.dm b/code/modules/language/language.dm
deleted file mode 100644
index 9fc2abf0f5a9f..0000000000000
--- a/code/modules/language/language.dm
+++ /dev/null
@@ -1,107 +0,0 @@
-#define SCRAMBLE_CACHE_LEN 50 //maximum of 50 specific scrambled lines per language
-
-/*
- Datum based languages. Easily editable and modular.
-*/
-
-/datum/language
- var/name = "an unknown language" // Fluff name of language if any.
- var/desc = "A language." // Short description for 'Check Languages'.
- var/key // Character used to speak in language
- // If key is null, then the language isn't real or learnable.
- var/flags // Various language flags.
- var/list/syllables // Used when scrambling text for a non-speaker.
- var/sentence_chance = 5 // Likelihood of making a new sentence after each syllable.
- var/space_chance = 55 // Likelihood of getting a space in the random scramble string
- var/list/spans = list()
- var/list/scramble_cache = list()
- var/default_priority = 0 // the language that an atom knows with the highest "default_priority" is selected by default.
-
- // if you are seeing someone speak popcorn language, then something is wrong.
- var/icon = 'icons/misc/language.dmi'
- var/icon_state = "popcorn"
-
-/datum/language/proc/display_icon(atom/movable/hearer)
- var/understands = hearer.has_language(src.type)
- if(flags & LANGUAGE_HIDE_ICON_IF_UNDERSTOOD && understands)
- return FALSE
- if(flags & LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD && !understands)
- return FALSE
- return TRUE
-
-/datum/language/proc/get_icon()
- var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat)
- return sheet.icon_tag("language-[icon_state]")
-
-/datum/language/proc/get_random_name(gender, name_count=2, syllable_count=4, syllable_divisor=2)
- if(!syllables || !syllables.len)
- if(gender == FEMALE)
- return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names))
- else
- return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names))
-
- var/full_name = ""
- var/new_name = ""
-
- for(var/i in 0 to name_count)
- new_name = ""
- var/Y = rand(FLOOR(syllable_count/syllable_divisor, 1), syllable_count)
- for(var/x in Y to 0)
- new_name += pick_weight_recursive(syllables)
- full_name += " [capitalize(LOWER_TEXT(new_name))]"
-
- return "[trim(full_name)]"
-
-/datum/language/proc/check_cache(input)
- var/lookup = scramble_cache[input]
- if(lookup)
- scramble_cache -= input
- scramble_cache[input] = lookup
- . = lookup
-
-/datum/language/proc/add_to_cache(input, scrambled_text)
- // Add it to cache, cutting old entries if the list is too long
- scramble_cache[input] = scrambled_text
- if(scramble_cache.len > SCRAMBLE_CACHE_LEN)
- scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1)
-
-/datum/language/proc/scramble(input)
-
- if(!syllables || !syllables.len)
- return stars(input)
-
- // If the input is cached already, move it to the end of the cache and return it
- var/lookup = check_cache(input)
- if(lookup)
- return lookup
-
- var/input_size = length_char(input)
- var/scrambled_text = ""
- var/capitalize = TRUE
-
- while(length_char(scrambled_text) < input_size)
- var/next = pick_weight_recursive(syllables)
- if(capitalize)
- next = capitalize(next)
- capitalize = FALSE
- scrambled_text += next
- var/chance = rand(100)
- if(chance <= sentence_chance)
- scrambled_text += ". "
- capitalize = TRUE
- else if(chance > sentence_chance && chance <= space_chance)
- scrambled_text += " "
-
- scrambled_text = trim(scrambled_text)
- var/ending = copytext_char(scrambled_text, -1)
- if(ending == ".")
- scrambled_text = copytext_char(scrambled_text, 1, -2)
- var/input_ending = copytext_char(input, -1)
- if(input_ending in list("!","?","."))
- scrambled_text += input_ending
-
- add_to_cache(input, scrambled_text)
-
- return scrambled_text
-
-#undef SCRAMBLE_CACHE_LEN
diff --git a/code/modules/language/machine.dm b/code/modules/language/machine.dm
index 36962a712a1b5..4be282a5e2812 100644
--- a/code/modules/language/machine.dm
+++ b/code/modules/language/machine.dm
@@ -14,7 +14,16 @@
icon_state = "eal"
-/datum/language/machine/get_random_name()
+/datum/language/machine/get_random_name(
+ gender = NEUTER,
+ name_count = 2,
+ syllable_min = 2,
+ syllable_max = 4,
+ unique = FALSE,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
if(prob(70))
return "[pick(GLOB.posibrain_names)]-[rand(100, 999)]"
return pick(GLOB.ai_names)
diff --git a/code/modules/language/moffic.dm b/code/modules/language/moffic.dm
index 1d0aea96697fb..fb8dea63dcc83 100644
--- a/code/modules/language/moffic.dm
+++ b/code/modules/language/moffic.dm
@@ -13,4 +13,20 @@
icon_state = "moth"
default_priority = 90
+ default_name_syllable_min = 5
+ default_name_syllable_max = 10
+
+/datum/language/moffic/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
+
+ return "[pick(GLOB.moth_first)] [pick(GLOB.moth_last)]"
+
+
// Fuck guest accounts, and fuck language testing.
diff --git a/code/modules/language/monkey.dm b/code/modules/language/monkey.dm
index e44f6a6268e25..423e94f22bd8c 100644
--- a/code/modules/language/monkey.dm
+++ b/code/modules/language/monkey.dm
@@ -7,3 +7,12 @@
default_priority = 80
icon_state = "animal"
+
+/datum/language/monkey/get_random_name(
+ gender = NEUTER,
+ name_count = 2,
+ syllable_min = 2,
+ syllable_max = 4,
+ force_use_syllables = FALSE,
+)
+ return "monkey ([rand(1, 999)])"
diff --git a/code/modules/language/mushroom.dm b/code/modules/language/mushroom.dm
index 08d494cc04d64..910489fd6dd9e 100644
--- a/code/modules/language/mushroom.dm
+++ b/code/modules/language/mushroom.dm
@@ -5,3 +5,5 @@
sentence_chance = 0
default_priority = 80
syllables = list("poof", "pff", "pFfF", "piff", "puff", "pooof", "pfffff", "piffpiff", "puffpuff", "poofpoof", "pifpafpofpuf")
+ default_name_syllable_min = 1
+ default_name_syllable_max = 2
diff --git a/code/modules/language/nekomimetic.dm b/code/modules/language/nekomimetic.dm
index 82edc2afcb57a..4be943f84417a 100644
--- a/code/modules/language/nekomimetic.dm
+++ b/code/modules/language/nekomimetic.dm
@@ -12,3 +12,16 @@
)
icon_state = "neko"
default_priority = 90
+ default_name_syllable_min = 2
+ default_name_syllable_max = 2
+
+/datum/language/nekomimetic/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(prob(33))
+ return default_name(gender)
+ return ..()
diff --git a/code/modules/language/piratespeak.dm b/code/modules/language/piratespeak.dm
index 5f6cb4897715d..a2faddb544f7c 100644
--- a/code/modules/language/piratespeak.dm
+++ b/code/modules/language/piratespeak.dm
@@ -10,3 +10,4 @@
"shiver", "timbers", "matey", "swashbuckler"
)
icon_state = "pirate"
+ always_use_default_namelist = TRUE
diff --git a/code/modules/language/shadowtongue.dm b/code/modules/language/shadowtongue.dm
index 9c0adb5eea3ff..351589393856b 100644
--- a/code/modules/language/shadowtongue.dm
+++ b/code/modules/language/shadowtongue.dm
@@ -16,3 +16,5 @@
)
icon_state = "shadow"
default_priority = 90
+ default_name_syllable_min = 2
+ default_name_syllable_max = 3
diff --git a/code/modules/language/slime.dm b/code/modules/language/slime.dm
index fcb471774118a..15960898673d6 100644
--- a/code/modules/language/slime.dm
+++ b/code/modules/language/slime.dm
@@ -2,7 +2,8 @@
name = "Slime"
desc = "A melodic and complex language spoken by slimes. Some of the notes are inaudible to humans."
key = "k"
- syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix","*","!")
+ syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix")
+ special_characters = list("!","*")
default_priority = 70
icon_state = "slime"
diff --git a/code/modules/language/sylvan.dm b/code/modules/language/sylvan.dm
index 68cb73f9d525a..4f66fb5931c1a 100644
--- a/code/modules/language/sylvan.dm
+++ b/code/modules/language/sylvan.dm
@@ -13,3 +13,5 @@
)
icon_state = "plant"
default_priority = 90
+ default_name_syllable_min = 2
+ default_name_syllable_max = 3
diff --git a/code/modules/language/terrum.dm b/code/modules/language/terrum.dm
index 361106ed16c93..63b527202f4ca 100644
--- a/code/modules/language/terrum.dm
+++ b/code/modules/language/terrum.dm
@@ -7,8 +7,25 @@
"sha", "vu", "nah", "ha", "yom", "ma", "cha", "ar", "et", "mol", "lua",
"ch", "na", "sh", "ni", "yah", "bes", "ol", "hish", "ev", "la", "ot", "la",
"khe", "tza", "chak", "hak", "hin", "hok", "lir", "tov", "yef", "yfe",
- "cho", "ar", "kas", "kal", "ra", "lom", "im", "'", "'", "'", "'", "bok",
+ "cho", "ar", "kas", "kal", "ra", "lom", "im", "bok",
"erev", "shlo", "lo", "ta", "im", "yom"
)
+ special_characters = list("'")
icon_state = "golem"
default_priority = 90
+
+/datum/language/terrum/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
+
+ var/name = pick(GLOB.golem_names)
+ // 3% chance to be given a human surname for "lore reasons"
+ if (prob(3))
+ name += " [pick(GLOB.last_names)]"
+ return name
diff --git a/code/modules/language/voltaic.dm b/code/modules/language/voltaic.dm
index 40fa9dcb1e826..90ab90dbe48e0 100644
--- a/code/modules/language/voltaic.dm
+++ b/code/modules/language/voltaic.dm
@@ -12,3 +12,21 @@
)
icon_state = "volt"
default_priority = 90
+ default_name_syllable_min = 2
+ default_name_syllable_max = 3
+
+
+/datum/language/voltaic/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
+
+ var/picked = "[pick(GLOB.ethereal_names)] [random_capital_letter()]"
+ if(prob(65))
+ picked += random_capital_letter()
+ return picked
diff --git a/code/modules/language/xenocommon.dm b/code/modules/language/xenocommon.dm
index c5e6366715d8e..f4949b7d73cb4 100644
--- a/code/modules/language/xenocommon.dm
+++ b/code/modules/language/xenocommon.dm
@@ -6,3 +6,4 @@
default_priority = 50
icon_state = "xeno"
+ always_use_default_namelist = TRUE // Sssss Ssss?
diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm
index a2ffa244679b6..ff46cfc0b64e7 100644
--- a/code/modules/mapping/mapping_helpers.dm
+++ b/code/modules/mapping/mapping_helpers.dm
@@ -914,8 +914,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
var/datum/species/new_human_species = GLOB.species_list[species_to_pick]
if(new_human_species)
new_human.set_species(new_human_species)
- new_human_species = new_human.dna.species
- new_human.fully_replace_character_name(new_human.real_name, new_human_species.random_name(new_human.gender, TRUE, TRUE))
+ new_human.fully_replace_character_name(new_human.real_name, new_human.generate_random_mob_name())
else
stack_trace("failed to spawn cadaver with species ID [species_to_pick]") //if it's invalid they'll just be a human, so no need to worry too much aside from yelling at the server owner lol.
else
diff --git a/code/modules/mining/lavaland/tendril_loot.dm b/code/modules/mining/lavaland/tendril_loot.dm
index c8d0f5580d724..8a90f0e548c30 100644
--- a/code/modules/mining/lavaland/tendril_loot.dm
+++ b/code/modules/mining/lavaland/tendril_loot.dm
@@ -566,7 +566,7 @@
var/list/name2type = list()
for(var/obj/item/organ/external/wings/functional/possible_type as anything in wing_types)
var/datum/sprite_accessory/accessory = initial(possible_type.sprite_accessory_override) //get the type
- accessory = GLOB.wings_list[initial(accessory.name)] //get the singleton instance
+ accessory = SSaccessories.wings_list[initial(accessory.name)] //get the singleton instance
var/image/img = image(icon = accessory.icon, icon_state = "m_wingsopen_[accessory.icon_state]_BEHIND") //Process the HUD elements
img.transform *= 0.5
img.pixel_x = -32
diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm
index e94b8d981ffeb..65644b00cc87a 100644
--- a/code/modules/mining/ores_coins.dm
+++ b/code/modules/mining/ores_coins.dm
@@ -107,9 +107,9 @@
merge_type = /obj/item/stack/ore/glass
GLOBAL_LIST_INIT(sand_recipes, list(\
- new /datum/stack_recipe("pile of dirt", /obj/machinery/hydroponics/soil, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), \
- new /datum/stack_recipe("sandstone", /obj/item/stack/sheet/mineral/sandstone, 1, 1, 50, check_density = FALSE, category = CAT_MISC),\
- new /datum/stack_recipe("aesthetic volcanic floor tile", /obj/item/stack/tile/basalt, 2, 1, 50, check_density = FALSE, category = CAT_TILES)\
+ new /datum/stack_recipe("pile of dirt", /obj/machinery/hydroponics/soil, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), \
+ new /datum/stack_recipe("sandstone", /obj/item/stack/sheet/mineral/sandstone, 1, 1, 50, crafting_flags = NONE, category = CAT_MISC),\
+ new /datum/stack_recipe("aesthetic volcanic floor tile", /obj/item/stack/tile/basalt, 2, 1, 50, crafting_flags = NONE, category = CAT_TILES)\
))
/obj/item/stack/ore/glass/Initialize(mapload, new_amount, merge, list/mat_override, mat_amt)
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 18b55cd6a5f07..1d2a8d1570f0f 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -89,15 +89,10 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
gender = body.gender
if(body.mind && body.mind.name)
- if(body.mind.ghostname)
- name = body.mind.ghostname
- else
- name = body.mind.name
+ name = body.mind.ghostname || body.mind.name
else
- if(body.real_name)
- name = body.real_name
- else
- name = random_unique_name(gender)
+ name = body.real_name || generate_random_mob_name(gender)
+
mind = body.mind //we don't transfer the mind but we keep a reference to it.
@@ -125,8 +120,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
abstract_move(T)
- if(!name) //To prevent nameless ghosts
- name = random_unique_name(gender)
+ //To prevent nameless ghosts
+ name ||= generate_random_mob_name(FALSE)
real_name = name
if(!fun_verbs)
@@ -221,7 +216,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
if(ghost_accs == GHOST_ACCS_FULL && (icon_state in GLOB.ghost_forms_with_accessories_list)) //check if this form supports accessories and if the client wants to show them
if(facial_hairstyle)
- var/datum/sprite_accessory/S = GLOB.facial_hairstyles_list[facial_hairstyle]
+ var/datum/sprite_accessory/S = SSaccessories.facial_hairstyles_list[facial_hairstyle]
if(S)
facial_hair_overlay = mutable_appearance(S.icon, "[S.icon_state]", -HAIR_LAYER)
if(facial_hair_color)
@@ -229,7 +224,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
facial_hair_overlay.alpha = 200
add_overlay(facial_hair_overlay)
if(hairstyle)
- var/datum/sprite_accessory/hair/S = GLOB.hairstyles_list[hairstyle]
+ var/datum/sprite_accessory/hair/S = SSaccessories.hairstyles_list[hairstyle]
if(S)
hair_overlay = mutable_appearance(S.icon, "[S.icon_state]", -HAIR_LAYER)
if(hair_color)
@@ -838,7 +833,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
client.prefs.apply_character_randomization_prefs()
var/species_type = client.prefs.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
if(species.check_head_flags(HEAD_HAIR))
hairstyle = client.prefs.read_preference(/datum/preference/choiced/hairstyle)
hair_color = ghostify_color(client.prefs.read_preference(/datum/preference/color/hair_color))
@@ -847,8 +842,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
facial_hairstyle = client.prefs.read_preference(/datum/preference/choiced/facial_hairstyle)
facial_hair_color = ghostify_color(client.prefs.read_preference(/datum/preference/color/facial_hair_color))
- qdel(species)
-
update_appearance()
/mob/dead/observer/can_perform_action(atom/movable/target, action_bitflags)
diff --git a/code/modules/mob/living/basic/space_fauna/ghost.dm b/code/modules/mob/living/basic/space_fauna/ghost.dm
index 7545f9cfea394..728c5ead9f4a8 100644
--- a/code/modules/mob/living/basic/space_fauna/ghost.dm
+++ b/code/modules/mob/living/basic/space_fauna/ghost.dm
@@ -71,7 +71,7 @@
ghost_facial_hair_color = ghost_hair_color
if(!isnull(ghost_hairstyle) && ghost_hairstyle != "Bald") //Bald hairstyle and the Shaved facial hairstyle lack an associated sprite and will not properly generate hair, and just cause runtimes.
- var/datum/sprite_accessory/hair/hair_style = GLOB.hairstyles_list[ghost_hairstyle] //We use the hairstyle name to get the sprite accessory, which we copy the icon_state from.
+ var/datum/sprite_accessory/hair/hair_style = SSaccessories.hairstyles_list[ghost_hairstyle] //We use the hairstyle name to get the sprite accessory, which we copy the icon_state from.
ghost_hair = mutable_appearance('icons/mob/human/human_face.dmi', "[hair_style.icon_state]", -HAIR_LAYER)
ghost_hair.alpha = 200
ghost_hair.color = ghost_hair_color
@@ -79,7 +79,7 @@
add_overlay(ghost_hair)
if(!isnull(ghost_facial_hairstyle) && ghost_facial_hairstyle != "Shaved")
- var/datum/sprite_accessory/facial_hair_style = GLOB.facial_hairstyles_list[ghost_facial_hairstyle]
+ var/datum/sprite_accessory/facial_hair_style = SSaccessories.facial_hairstyles_list[ghost_facial_hairstyle]
ghost_facial_hair = mutable_appearance('icons/mob/human/human_face.dmi', "[facial_hair_style.icon_state]", -HAIR_LAYER)
ghost_facial_hair.alpha = 200
ghost_facial_hair.color = ghost_facial_hair_color
diff --git a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm
index 21943d39d3d1b..d2b5edc58cced 100644
--- a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm
+++ b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm
@@ -102,7 +102,7 @@
RegisterSignal(src, COMSIG_LIVING_BANED, PROC_REF(on_baned))
RegisterSignal(src, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_move))
RegisterSignal(src, COMSIG_LIVING_LIFE, PROC_REF(on_life))
- set_random_revenant_name()
+ name = generate_random_mob_name()
GLOB.revenant_relay_mobs |= src
@@ -357,13 +357,13 @@
returnable_list += span_bold("Be sure to read the wiki page to learn more.")
return returnable_list
-/mob/living/basic/revenant/proc/set_random_revenant_name()
+/mob/living/basic/revenant/generate_random_mob_name()
var/list/built_name_strings = list()
built_name_strings += pick(strings(REVENANT_NAME_FILE, "spirit_type"))
built_name_strings += " of "
built_name_strings += pick(strings(REVENANT_NAME_FILE, "adverb"))
built_name_strings += pick(strings(REVENANT_NAME_FILE, "theme"))
- name = built_name_strings.Join("")
+ return built_name_strings.Join("")
/mob/living/basic/revenant/proc/on_baned(obj/item/weapon, mob/living/user)
SIGNAL_HANDLER
diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm
index 26b0b1b8c223f..24a35e683e36d 100644
--- a/code/modules/mob/living/carbon/human/_species.dm
+++ b/code/modules/mob/living/carbon/human/_species.dm
@@ -222,14 +222,12 @@ GLOBAL_LIST_EMPTY(features_by_species)
var/list/selectable_species = list()
for(var/species_type in subtypesof(/datum/species))
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
if(species.check_roundstart_eligible())
selectable_species += species.id
- var/datum/language_holder/temp_holder = new species.species_language_holder
+ var/datum/language_holder/temp_holder = GLOB.prototype_language_holders[species.species_language_holder]
for(var/datum/language/spoken_language as anything in temp_holder.understood_languages)
GLOB.uncommon_roundstart_languages |= spoken_language
- qdel(temp_holder)
- qdel(species)
GLOB.uncommon_roundstart_languages -= /datum/language/common
if(!selectable_species.len)
@@ -248,32 +246,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
return TRUE
return FALSE
-/**
- * Generates a random name for a carbon.
- *
- * This generates a random unique name based on a human's species and gender.
- * Arguments:
- * * gender - The gender that the name should adhere to. Use MALE for male names, use anything else for female names.
- * * unique - If true, ensures that this new name is not a duplicate of anyone else's name currently on the station.
- * * last_name - Do we use a given last name or pick a random new one?
- */
-/datum/species/proc/random_name(gender, unique, last_name)
- if(unique)
- return random_unique_name(gender)
-
- var/randname
- if(gender == MALE)
- randname = pick(GLOB.first_names_male)
- else
- randname = pick(GLOB.first_names_female)
-
- if(last_name)
- randname += " [last_name]"
- else
- randname += " [pick(GLOB.last_names)]"
-
- return randname
-
/**
* Copies some vars and properties over that should be kept when creating a copy of this species.
*
@@ -595,8 +567,9 @@ GLOBAL_LIST_EMPTY(features_by_species)
var/obj/item/bodypart/arm/left/left_arm = species_human.get_bodypart(BODY_ZONE_L_ARM)
var/obj/item/bodypart/leg/right/right_leg = species_human.get_bodypart(BODY_ZONE_R_LEG)
var/obj/item/bodypart/leg/left/left_leg = species_human.get_bodypart(BODY_ZONE_L_LEG)
- var/datum/sprite_accessory/markings = GLOB.moth_markings_list[species_human.dna.features["moth_markings"]]
+ var/datum/sprite_accessory/markings = SSaccessories.moth_markings_list[species_human.dna.features["moth_markings"]]
var/mutable_appearance/marking = mutable_appearance(layer = -BODY_LAYER, appearance_flags = KEEP_TOGETHER)
+
if(noggin && (IS_ORGANIC_LIMB(noggin)))
var/mutable_appearance/markings_head_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_head")
marking.overlays += markings_head_overlay
@@ -626,7 +599,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
//Underwear, Undershirts & Socks
if(!HAS_TRAIT(species_human, TRAIT_NO_UNDERWEAR))
if(species_human.underwear)
- var/datum/sprite_accessory/underwear/underwear = GLOB.underwear_list[species_human.underwear]
+ var/datum/sprite_accessory/underwear/underwear = SSaccessories.underwear_list[species_human.underwear]
var/mutable_appearance/underwear_overlay
if(underwear)
if(species_human.dna.species.sexes && species_human.physique == FEMALE && (underwear.gender == MALE))
@@ -638,7 +611,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
standing += underwear_overlay
if(species_human.undershirt)
- var/datum/sprite_accessory/undershirt/undershirt = GLOB.undershirt_list[species_human.undershirt]
+ var/datum/sprite_accessory/undershirt/undershirt = SSaccessories.undershirt_list[species_human.undershirt]
if(undershirt)
var/mutable_appearance/working_shirt
if(species_human.dna.species.sexes && species_human.physique == FEMALE)
@@ -648,7 +621,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
standing += working_shirt
if(species_human.socks && species_human.num_legs >= 2 && !(species_human.bodyshape & BODYSHAPE_DIGITIGRADE))
- var/datum/sprite_accessory/socks/socks = GLOB.socks_list[species_human.socks]
+ var/datum/sprite_accessory/socks/socks = SSaccessories.socks_list[species_human.socks]
if(socks)
standing += mutable_appearance(socks.icon, socks.icon_state, -BODY_LAYER)
@@ -698,11 +671,11 @@ GLOBAL_LIST_EMPTY(features_by_species)
var/datum/sprite_accessory/accessory
switch(bodypart)
if("ears")
- accessory = GLOB.ears_list[source.dna.features["ears"]]
+ accessory = SSaccessories.ears_list[source.dna.features["ears"]]
if("body_markings")
- accessory = GLOB.body_markings_list[source.dna.features["body_markings"]]
+ accessory = SSaccessories.body_markings_list[source.dna.features["body_markings"]]
if("legs")
- accessory = GLOB.legs_list[source.dna.features["legs"]]
+ accessory = SSaccessories.legs_list[source.dna.features["legs"]]
if(!accessory || accessory.icon_state == "none")
continue
diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm
index d17661cf5629e..627745cba929e 100644
--- a/code/modules/mob/living/carbon/human/dummy.dm
+++ b/code/modules/mob/living/carbon/human/dummy.dm
@@ -103,19 +103,19 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
/proc/create_consistent_human_dna(mob/living/carbon/human/target)
target.dna.features["mcolor"] = COLOR_VIBRANT_LIME
target.dna.features["ethcolor"] = COLOR_WHITE
- target.dna.features["body_markings"] = get_consistent_feature_entry(GLOB.body_markings_list)
- target.dna.features["ears"] = get_consistent_feature_entry(GLOB.ears_list)
- target.dna.features["frills"] = get_consistent_feature_entry(GLOB.frills_list)
- target.dna.features["horns"] = get_consistent_feature_entry(GLOB.horns_list)
- target.dna.features["moth_antennae"] = get_consistent_feature_entry(GLOB.moth_antennae_list)
- target.dna.features["moth_markings"] = get_consistent_feature_entry(GLOB.moth_markings_list)
- target.dna.features["moth_wings"] = get_consistent_feature_entry(GLOB.moth_wings_list)
- target.dna.features["snout"] = get_consistent_feature_entry(GLOB.snouts_list)
- target.dna.features["spines"] = get_consistent_feature_entry(GLOB.spines_list)
- target.dna.features["tail_cat"] = get_consistent_feature_entry(GLOB.tails_list_human) // it's a lie
- target.dna.features["tail_lizard"] = get_consistent_feature_entry(GLOB.tails_list_lizard)
- target.dna.features["tail_monkey"] = get_consistent_feature_entry(GLOB.tails_list_monkey)
- target.dna.features["pod_hair"] = get_consistent_feature_entry(GLOB.pod_hair_list)
+ target.dna.features["body_markings"] = get_consistent_feature_entry(SSaccessories.body_markings_list)
+ target.dna.features["ears"] = get_consistent_feature_entry(SSaccessories.ears_list)
+ target.dna.features["frills"] = get_consistent_feature_entry(SSaccessories.frills_list)
+ target.dna.features["horns"] = get_consistent_feature_entry(SSaccessories.horns_list)
+ target.dna.features["moth_antennae"] = get_consistent_feature_entry(SSaccessories.moth_antennae_list)
+ target.dna.features["moth_markings"] = get_consistent_feature_entry(SSaccessories.moth_markings_list)
+ target.dna.features["moth_wings"] = get_consistent_feature_entry(SSaccessories.moth_wings_list)
+ target.dna.features["snout"] = get_consistent_feature_entry(SSaccessories.snouts_list)
+ target.dna.features["spines"] = get_consistent_feature_entry(SSaccessories.spines_list)
+ target.dna.features["tail_cat"] = get_consistent_feature_entry(SSaccessories.tails_list_human) // it's a lie
+ target.dna.features["tail_lizard"] = get_consistent_feature_entry(SSaccessories.tails_list_lizard)
+ target.dna.features["tail_monkey"] = get_consistent_feature_entry(SSaccessories.tails_list_monkey)
+ target.dna.features["pod_hair"] = get_consistent_feature_entry(SSaccessories.pod_hair_list)
target.dna.initialize_dna(create_mutation_blocks = FALSE, randomize_features = FALSE)
// UF and UI are nondeterministic, even though the features are the same some blocks will randomize slightly
// In practice this doesn't matter, but this is for the sake of 100%(ish) consistency
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 07135351a91f2..9d3d8c2d5a81b 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -815,7 +815,7 @@
if(href_list[VV_HK_SET_SPECIES])
if(!check_rights(R_SPAWN))
return
- var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list
+ var/result = input(usr, "Please choose a new species","Species") as null|anything in sortTim(GLOB.species_list, GLOBAL_PROC_REF(cmp_text_asc))
if(result)
var/newtype = GLOB.species_list[result]
admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [src] to [result]")
@@ -1019,7 +1019,7 @@
/mob/living/carbon/human/species/set_species(datum/species/mrace, icon_update, pref_load)
. = ..()
if(use_random_name)
- fully_replace_character_name(real_name, dna.species.random_name())
+ fully_replace_character_name(real_name, generate_random_mob_name())
/mob/living/carbon/human/species/abductor
race = /datum/species/abductor
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index c7069ad056d4d..3315c5421d376 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -259,7 +259,7 @@
if (preference.is_randomizable())
preference.apply_to_human(src, preference.create_random_value(preferences))
- fully_replace_character_name(real_name, dna.species.random_name())
+ fully_replace_character_name(real_name, generate_random_mob_name())
/**
* Setter for mob height
diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
index e37e7ca81447f..4c307107f153d 100644
--- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm
+++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
@@ -80,14 +80,6 @@
QDEL_NULL(ethereal_light)
return ..()
-/datum/species/ethereal/random_name(gender,unique,lastname)
- if(unique)
- return random_unique_ethereal_name()
-
- var/randname = ethereal_name()
-
- return randname
-
/datum/species/ethereal/randomize_features()
var/list/features = ..()
features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)]
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 4e860014554e8..13471b2872b98 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -51,15 +51,6 @@
BODY_ZONE_CHEST = /obj/item/bodypart/chest/golem,
)
- /// Chance that we will generate a human surname, for lore reasons
- var/human_surname_chance = 3
-
-/datum/species/golem/random_name(gender,unique,lastname)
- var/name = pick(GLOB.golem_names)
- if (prob(human_surname_chance))
- name += " [pick(GLOB.last_names)]"
- return name
-
/datum/species/golem/get_physical_attributes()
return "Golems are hardy creatures made out of stone, which are thus naturally resistant to many dangers, including asphyxiation, fire, radiation, electricity, and viruses.\
They gain special abilities depending on the type of material consumed, but they need to consume material to keep their body animated."
diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
index 93167cb689c3e..488d76cbd2136 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -47,21 +47,9 @@
/datum/species/lizard/body_temperature_core(mob/living/carbon/human/humi, seconds_per_tick, times_fired)
return
-/datum/species/lizard/random_name(gender,unique,lastname)
- if(unique)
- return random_unique_lizard_name(gender)
-
- var/randname = lizard_name(gender)
-
- if(lastname)
- randname += " [lastname]"
-
- return randname
-
-
/datum/species/lizard/randomize_features()
var/list/features = ..()
- features["body_markings"] = pick(GLOB.body_markings_list)
+ features["body_markings"] = pick(SSaccessories.body_markings_list)
return features
/datum/species/lizard/get_scream_sound(mob/living/carbon/human/lizard)
diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm
index 159824f2ef33f..ddf0963bb5d24 100644
--- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm
+++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm
@@ -41,9 +41,6 @@
payday_modifier = 1.5
ai_controlled_species = TRUE
-/datum/species/monkey/random_name(gender,unique,lastname)
- return "monkey ([rand(1, 999)])"
-
/datum/species/monkey/on_species_gain(mob/living/carbon/human/human_who_gained_species, datum/species/old_species, pref_load)
. = ..()
passtable_on(human_who_gained_species, SPECIES_TRAIT)
@@ -168,24 +165,17 @@
/obj/item/organ/internal/brain/primate/on_mob_insert(mob/living/carbon/primate)
. = ..()
- RegisterSignal(primate, COMSIG_MOVABLE_CROSS, PROC_REF(on_crossed))
+ RegisterSignal(primate, COMSIG_LIVING_MOB_BUMPED, PROC_REF(on_mob_bump))
/obj/item/organ/internal/brain/primate/on_mob_remove(mob/living/carbon/primate)
. = ..()
- UnregisterSignal(primate, COMSIG_MOVABLE_CROSS)
+ UnregisterSignal(primate, COMSIG_LIVING_MOB_BUMPED)
-/obj/item/organ/internal/brain/primate/proc/on_crossed(datum/source, atom/movable/crossed)
+/obj/item/organ/internal/brain/primate/proc/on_mob_bump(mob/source, mob/living/crossing_mob)
SIGNAL_HANDLER
- if(!tripping)
- return
- if(IS_DEAD_OR_INCAP(owner) || !isliving(crossed))
- return
- var/mob/living/in_the_way_mob = crossed
- if(iscarbon(in_the_way_mob) && !in_the_way_mob.combat_mode)
- return
- if(in_the_way_mob.pass_flags & PASSMOB)
+ if(!tripping || !crossing_mob.combat_mode)
return
- in_the_way_mob.knockOver(owner)
+ crossing_mob.knockOver(owner)
/obj/item/organ/internal/brain/primate/get_attacking_limb(mob/living/carbon/human/target)
if(!HAS_TRAIT(owner, TRAIT_ADVANCEDTOOLUSER))
diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm
index 86a9180ed07e3..54d6fe027e32f 100644
--- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm
@@ -34,17 +34,6 @@
var/mob/living/carbon/human/H = C
handle_mutant_bodyparts(H)
-/datum/species/moth/random_name(gender,unique,lastname)
- if(unique)
- return random_unique_moth_name()
-
- var/randname = moth_name()
-
- if(lastname)
- randname += " [lastname]"
-
- return randname
-
/datum/species/moth/on_species_gain(mob/living/carbon/human/human_who_gained_species, datum/species/old_species, pref_load)
. = ..()
RegisterSignal(human_who_gained_species, COMSIG_MOB_APPLY_DAMAGE_MODIFIERS, PROC_REF(damage_weakness))
@@ -61,7 +50,7 @@
/datum/species/moth/randomize_features()
var/list/features = ..()
- features["moth_markings"] = pick(GLOB.moth_markings_list)
+ features["moth_markings"] = pick(SSaccessories.moth_markings_list)
return features
/datum/species/moth/get_scream_sound(mob/living/carbon/human)
diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
index f3486f1342f68..14d6c1437f0da 100644
--- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
@@ -83,7 +83,7 @@
feature_key = "caps"
/datum/bodypart_overlay/mutant/mushroom_cap/get_global_feature_list()
- return GLOB.caps_list
+ return SSaccessories.caps_list
/datum/bodypart_overlay/mutant/mushroom_cap/can_draw_on_bodypart(mob/living/carbon/human/human)
if((human.head?.flags_inv & HIDEHAIR) || (human.wear_mask?.flags_inv & HIDEHAIR))
diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
index 2d053813e5b83..e63e3c39c4885 100644
--- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
@@ -129,17 +129,6 @@
else
give_important_for_life(equipping)
-/datum/species/plasmaman/random_name(gender,unique,lastname)
- if(unique)
- return random_unique_plasmaman_name()
-
- var/randname = plasmaman_name()
-
- if(lastname)
- randname += " [lastname]"
-
- return randname
-
/datum/species/plasmaman/get_scream_sound(mob/living/carbon/human)
return pick(
'sound/voice/plasmaman/plasmeme_scream_1.ogg',
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 5981fbb390300..5f5889ae0a3b4 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -156,6 +156,7 @@
return TRUE
SEND_SIGNAL(src, COMSIG_LIVING_MOB_BUMP, M)
+ SEND_SIGNAL(M, COMSIG_LIVING_MOB_BUMPED, src)
//Even if we don't push/swap places, we "touched" them, so spread fire
spreadFire(M)
@@ -1289,9 +1290,9 @@
return FALSE
if(invisibility || alpha <= 50)//cloaked
return FALSE
- if(!isturf(src.loc)) //The reason why we don't just use get_turf is because they could be in a closet, disposals, or a vehicle.
+ if(!isturf(loc)) //The reason why we don't just use get_turf is because they could be in a closet, disposals, or a vehicle.
return FALSE
- var/turf/T = src.loc
+ var/turf/T = loc
if(is_centcom_level(T.z)) //dont detect mobs on centcom
return FALSE
if(is_away_level(T.z))
diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm
index 36a020ce3e759..bbcf77986ac79 100644
--- a/code/modules/mob/living/living_say.dm
+++ b/code/modules/mob/living/living_say.dm
@@ -208,9 +208,9 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
spans |= speech_span
- if(language)
- var/datum/language/L = GLOB.language_datum_instances[language]
- spans |= L.spans
+ var/datum/language/spoken_lang = GLOB.language_datum_instances[language]
+ if(LAZYLEN(spoken_lang?.spans))
+ spans |= spoken_lang.spans
if(message_mods[MODE_SING])
var/randomnote = pick("\u2669", "\u266A", "\u266B")
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 5c47c4e5bb829..95e2e6ed13379 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -480,3 +480,11 @@
stack_trace("Silicon [src] ( [type] ) was somehow missing their integrated tablet. Please make a bug report.")
create_modularInterface()
modularInterface.imprint_id(name = newname)
+
+/mob/living/silicon/can_track(mob/living/user)
+ //if their camera is online, it's safe to assume they are in cameranets
+ //since it takes a while for camera vis to update, this lets us bypass that so AIs can always see their borgs,
+ //without making cameras constantly update every time a borg moves.
+ if(builtInCamera && builtInCamera.can_use())
+ return TRUE
+ return ..()
diff --git a/code/modules/mob_spawn/ghost_roles/golem_roles.dm b/code/modules/mob_spawn/ghost_roles/golem_roles.dm
index b3475e9207f83..5fc643bffa622 100644
--- a/code/modules/mob_spawn/ghost_roles/golem_roles.dm
+++ b/code/modules/mob_spawn/ghost_roles/golem_roles.dm
@@ -36,8 +36,7 @@
if(forced_name || !iscarbon(spawned_mob))
return ..()
- var/datum/species/golem/golem_species = new()
- forced_name = golem_species.random_name()
+ forced_name = generate_random_name_species_based(spawned_mob.gender, TRUE, species_type = /datum/species/golem)
return ..()
/obj/effect/mob_spawn/ghost_role/human/golem/special(mob/living/new_spawn, mob/mob_possessor)
diff --git a/code/modules/mob_spawn/ghost_roles/mining_roles.dm b/code/modules/mob_spawn/ghost_roles/mining_roles.dm
index 208a74a3edbf5..53fa001097039 100644
--- a/code/modules/mob_spawn/ghost_roles/mining_roles.dm
+++ b/code/modules/mob_spawn/ghost_roles/mining_roles.dm
@@ -194,9 +194,9 @@
/obj/structure/ash_walker_eggshell/Destroy()
if(!egg)
return ..()
- var/mob/living/carbon/human/yolk = new /mob/living/carbon/human/(get_turf(src))
- yolk.fully_replace_character_name(null,random_unique_lizard_name(gender))
+ var/mob/living/carbon/human/yolk = new(get_turf(src))
yolk.set_species(/datum/species/lizard/ashwalker)
+ yolk.fully_replace_character_name(null, yolk.generate_random_mob_name(TRUE))
yolk.underwear = "Nude"
yolk.equipOutfit(/datum/outfit/ashwalker)//this is an authentic mess we're making
yolk.update_body()
@@ -235,7 +235,7 @@
/obj/effect/mob_spawn/ghost_role/human/ash_walker/special(mob/living/carbon/human/spawned_human)
. = ..()
- spawned_human.fully_replace_character_name(null,random_unique_lizard_name(gender))
+ spawned_human.fully_replace_character_name(null, spawned_human.generate_random_mob_name(TRUE))
to_chat(spawned_human, "Drag the corpses of men and beasts to your nest. It will absorb them to create more of your kind. Invade the strange structure of the outsiders if you must. Do not cause unnecessary destruction, as littering the wastes with ugly wreckage is certain to not gain you favor. Glory to the Necropolis! ")
spawned_human.mind.add_antag_datum(/datum/antagonist/ashwalker, team)
diff --git a/code/modules/mob_spawn/mob_spawn.dm b/code/modules/mob_spawn/mob_spawn.dm
index 086254aae3881..ad8c7e6a03ef0 100644
--- a/code/modules/mob_spawn/mob_spawn.dm
+++ b/code/modules/mob_spawn/mob_spawn.dm
@@ -78,7 +78,7 @@
if(skin_tone)
spawned_human.skin_tone = skin_tone
else
- spawned_human.skin_tone = random_skin_tone()
+ spawned_human.skin_tone = pick(GLOB.skin_tones)
spawned_human.update_body(is_creating = TRUE)
/obj/effect/mob_spawn/proc/name_mob(mob/living/spawned_mob, forced_name)
diff --git a/code/modules/modular_computers/file_system/programs/emojipedia.dm b/code/modules/modular_computers/file_system/programs/emojipedia.dm
index 6e9bf56a381c8..10be69cc34976 100644
--- a/code/modules/modular_computers/file_system/programs/emojipedia.dm
+++ b/code/modules/modular_computers/file_system/programs/emojipedia.dm
@@ -14,7 +14,7 @@
/datum/computer_file/program/emojipedia/New()
. = ..()
// Sort the emoji list so it's easier to find things and we don't have to keep sorting on ui_data since the number of emojis can not change in-game.
- emoji_list = sortTim(emoji_list, /proc/cmp_text_asc)
+ sortTim(emoji_list, /proc/cmp_text_asc)
/datum/computer_file/program/emojipedia/ui_static_data(mob_user)
var/list/data = list()
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 605e88f1e483b..5dd5515c47c4c 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -441,8 +441,8 @@
// Handle stamping items.
if(writing_stats["interaction_mode"] == MODE_STAMPING)
if(!user.can_read(src) || user.is_blind())
- //The paper's stampable window area is assumed approx 400x500
- add_stamp(writing_stats["stamp_class"], rand(0, 400), rand(0, 500), rand(0, 360), writing_stats["stamp_icon_state"])
+ //The paper's stampable window area is assumed approx 300x400
+ add_stamp(writing_stats["stamp_class"], rand(0, 300), rand(0, 400), rand(0, 360), writing_stats["stamp_icon_state"])
user.visible_message(span_notice("[user] blindly stamps [src] with \the [attacking_item]!"))
to_chat(user, span_notice("You stamp [src] with \the [attacking_item] the best you can!"))
playsound(src, 'sound/items/handling/standard_stamp.ogg', 50, vary = TRUE)
@@ -454,6 +454,25 @@
ui_interact(user)
return ..()
+/// Secondary right click interaction to quickly stamp things
+/obj/item/paper/item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers)
+ var/list/writing_stats = tool.get_writing_implement_details()
+
+ if(!length(writing_stats))
+ return NONE
+ if(writing_stats["interaction_mode"] != MODE_STAMPING)
+ return NONE
+ if(!user.can_read(src) || user.is_blind()) // Just leftclick instead
+ return NONE
+
+ add_stamp(writing_stats["stamp_class"], rand(1, 300), rand(1, 400), stamp_icon_state = writing_stats["stamp_icon_state"])
+ user.visible_message(
+ span_notice("[user] quickly stamps [src] with [tool] without looking."),
+ span_notice("You quickly stamp [src] with [tool] without looking."),
+ )
+ playsound(src, 'sound/items/handling/standard_stamp.ogg', 50, vary = TRUE)
+
+ return ITEM_INTERACT_BLOCKING // Stop the UI from opening.
/**
* Attempts to ui_interact the paper to the given user, with some sanity checking
* to make sure the camera still exists via the weakref and that this paper is still
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index d47d75360946a..74b7bfdbcdcb4 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -340,7 +340,7 @@
if(STAGE_ONE)
steps = 1
if(STAGE_TWO)
- steps = 3//Yes this is right
+ steps = 2
if(STAGE_THREE)
steps = 3
if(STAGE_FOUR)
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 991cd5d3098bd..9859617ce4271 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -2201,10 +2201,10 @@
var/mob/living/carbon/human/exposed_human = exposed_mob
if(!HAS_TRAIT(exposed_human, TRAIT_SHAVED))
- var/datum/sprite_accessory/facial_hair/picked_beard = pick(GLOB.facial_hairstyles_list)
+ var/datum/sprite_accessory/facial_hair/picked_beard = pick(SSaccessories.facial_hairstyles_list)
exposed_human.set_facial_hairstyle(picked_beard, update = FALSE)
if(!HAS_TRAIT(exposed_human, TRAIT_BALD))
- var/datum/sprite_accessory/hair/picked_hair = pick(GLOB.hairstyles_list)
+ var/datum/sprite_accessory/hair/picked_hair = pick(SSaccessories.hairstyles_list)
exposed_human.set_hairstyle(picked_hair, update = TRUE)
to_chat(exposed_human, span_notice("Hair starts sprouting from your [HAS_TRAIT(exposed_human, TRAIT_BALD) ? "face" : "scalp"]."))
diff --git a/code/modules/recycling/conveyor.dm b/code/modules/recycling/conveyor.dm
index 8271298a0e638..6ef15929ecc5e 100644
--- a/code/modules/recycling/conveyor.dm
+++ b/code/modules/recycling/conveyor.dm
@@ -350,8 +350,6 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
/// The current state of the switch.
var/position = CONVEYOR_OFF
- /// Last direction setting.
- var/last_pos = CONVEYOR_BACKWARDS
/// If the switch only operates the conveyor belts in a single direction.
var/oneway = FALSE
/// If the level points the opposite direction when it's turned on.
@@ -372,6 +370,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
AddComponent(/datum/component/usb_port, list(
/obj/item/circuit_component/conveyor_switch,
))
+ register_context()
/obj/machinery/conveyor_switch/Destroy()
LAZYREMOVE(GLOB.conveyors_by_id[id], src)
@@ -397,6 +396,27 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
icon_state = "[base_icon_state]-[invert_icon ? "rev" : "fwd"]"
return ..()
+/obj/machinery/conveyor_switch/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+ . = ..()
+ if(!held_item)
+ context[SCREENTIP_CONTEXT_LMB] = "Toggle forwards"
+ if(!oneway)
+ context[SCREENTIP_CONTEXT_RMB] = "Toggle backwards"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(held_item.tool_behaviour == TOOL_MULTITOOL)
+ context[SCREENTIP_CONTEXT_LMB] = "Set speed"
+ context[SCREENTIP_CONTEXT_RMB] = "View wires"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(held_item.tool_behaviour == TOOL_SCREWDRIVER)
+ context[SCREENTIP_CONTEXT_LMB] = "Toggle oneway"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(held_item.tool_behaviour == TOOL_CROWBAR)
+ context[SCREENTIP_CONTEXT_LMB] = "Detach"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(held_item.tool_behaviour == TOOL_WRENCH)
+ context[SCREENTIP_CONTEXT_LMB] = "Invert"
+ return CONTEXTUAL_SCREENTIP_SET
+
/// Updates all conveyor belts that are linked to this switch, and tells them to start processing.
/obj/machinery/conveyor_switch/proc/update_linked_conveyors()
for(var/obj/machinery/conveyor/belt in GLOB.conveyors_by_id[id])
@@ -414,28 +434,29 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
CHECK_TICK
/// Updates the switch's `position` and `last_pos` variable. Useful so that the switch can properly cycle between the forwards, backwards and neutral positions.
-/obj/machinery/conveyor_switch/proc/update_position()
+/obj/machinery/conveyor_switch/proc/update_position(direction)
if(position == CONVEYOR_OFF)
if(oneway) //is it a oneway switch
position = oneway
else
- if(last_pos < CONVEYOR_OFF)
+ if(direction == CONVEYOR_FORWARD)
position = CONVEYOR_FORWARD
- last_pos = CONVEYOR_OFF
else
position = CONVEYOR_BACKWARDS
- last_pos = CONVEYOR_OFF
else
- last_pos = position
position = CONVEYOR_OFF
/// Called when a user clicks on this switch with an open hand.
-/obj/machinery/conveyor_switch/interact(mob/user)
+/obj/machinery/conveyor_switch/attack_hand(mob/living/user, list/modifiers)
add_fingerprint(user)
- update_position()
+ if(LAZYACCESS(modifiers, RIGHT_CLICK))
+ update_position(CONVEYOR_BACKWARDS)
+ else
+ update_position(CONVEYOR_FORWARD)
update_appearance()
update_linked_conveyors()
update_linked_switches()
+ return TRUE
/obj/machinery/conveyor_switch/attackby(obj/item/attacking_item, mob/user, params)
if(is_wire_tool(attacking_item))
@@ -588,14 +609,19 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
/obj/item/circuit_component/conveyor_switch
display_name = "Conveyor Switch"
desc = "Allows to control connected conveyor belts."
- circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL
+ /// Direction input ports.
+ var/datum/port/input/stop
+ var/datum/port/input/active
+ var/datum/port/input/reverse
/// The current direction of the conveyor attached to the component.
var/datum/port/output/direction
/// The switch this conveyor switch component is attached to.
var/obj/machinery/conveyor_switch/attached_switch
/obj/item/circuit_component/conveyor_switch/populate_ports()
+ active = add_input_port("Activate", PORT_TYPE_SIGNAL, trigger = PROC_REF(activate))
+ stop = add_input_port("Stop", PORT_TYPE_SIGNAL, trigger = PROC_REF(stop))
direction = add_output_port("Conveyor Direction", PORT_TYPE_NUMBER)
/obj/item/circuit_component/conveyor_switch/get_ui_notices()
@@ -606,27 +632,34 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
. = ..()
if(istype(shell, /obj/machinery/conveyor_switch))
attached_switch = shell
+ if(!attached_switch.oneway)
+ reverse = add_input_port("Reverse", PORT_TYPE_SIGNAL, trigger = PROC_REF(reverse))
/obj/item/circuit_component/conveyor_switch/unregister_usb_parent(atom/movable/shell)
attached_switch = null
return ..()
-/obj/item/circuit_component/conveyor_switch/input_received(datum/port/input/port)
- if(!attached_switch)
- return
-
- INVOKE_ASYNC(src, PROC_REF(update_conveyors), port)
-
-/obj/item/circuit_component/conveyor_switch/proc/update_conveyors(datum/port/input/port)
- if(!attached_switch)
- return
-
- attached_switch.update_position()
+/obj/item/circuit_component/conveyor_switch/proc/on_switch_changed()
attached_switch.update_appearance()
attached_switch.update_linked_conveyors()
attached_switch.update_linked_switches()
direction.set_output(attached_switch.position)
+/obj/item/circuit_component/conveyor_switch/proc/activate()
+ SIGNAL_HANDLER
+ attached_switch.position = CONVEYOR_FORWARD
+ INVOKE_ASYNC(src, PROC_REF(on_switch_changed))
+
+/obj/item/circuit_component/conveyor_switch/proc/stop()
+ SIGNAL_HANDLER
+ attached_switch.position = CONVEYOR_OFF
+ INVOKE_ASYNC(src, PROC_REF(on_switch_changed))
+
+/obj/item/circuit_component/conveyor_switch/proc/reverse()
+ SIGNAL_HANDLER
+ attached_switch.position = CONVEYOR_BACKWARDS
+ INVOKE_ASYNC(src, PROC_REF(on_switch_changed))
+
#undef CONVEYOR_BACKWARDS
#undef CONVEYOR_OFF
#undef CONVEYOR_FORWARD
diff --git a/code/modules/religion/rites.dm b/code/modules/religion/rites.dm
index d907191c33ddd..d7d0fa818441c 100644
--- a/code/modules/religion/rites.dm
+++ b/code/modules/religion/rites.dm
@@ -128,13 +128,36 @@
/datum/religion_rites/machine_blessing/invoke_effect(mob/living/user, atom/movable/religious_tool)
..()
var/altar_turf = get_turf(religious_tool)
- var/blessing = pick(
- /obj/item/organ/internal/cyberimp/arm/surgery,
- /obj/item/organ/internal/cyberimp/eyes/hud/diagnostic,
- /obj/item/organ/internal/cyberimp/eyes/hud/medical,
- /obj/item/organ/internal/cyberimp/mouth/breathing_tube,
- /obj/item/organ/internal/cyberimp/chest/thrusters,
- /obj/item/organ/internal/eyes/robotic/glow,
+ var/blessing = pick_weight_recursive(
+ list(
+ // Arms
+ list(
+ /obj/item/organ/internal/cyberimp/arm/combat = 1,
+ /obj/item/organ/internal/cyberimp/arm/surgery = 1000000,
+ /obj/item/organ/internal/cyberimp/arm/toolset = 1500000,
+ ) = 15,
+ // Eyes
+ list(
+ /obj/item/organ/internal/cyberimp/eyes/hud/diagnostic = 1,
+ /obj/item/organ/internal/cyberimp/eyes/hud/medical = 1,
+ /obj/item/organ/internal/eyes/robotic/glow = 1,
+ /obj/item/organ/internal/eyes/robotic/shield = 2,
+ ) = 15,
+ // Chest
+ list(
+ /obj/item/organ/internal/cyberimp/chest/reviver = 1,
+ /obj/item/organ/internal/cyberimp/chest/thrusters = 2,
+ ) = 9,
+ // Brain / Head
+ list(
+ /obj/item/organ/internal/cyberimp/brain/anti_drop = 100,
+ /obj/item/organ/internal/cyberimp/brain/anti_stun = 10,
+ ) = 10,
+ // Misc
+ list(
+ /obj/item/organ/internal/cyberimp/mouth/breathing_tube = 1,
+ ) = 5,
+ )
)
new blessing(altar_turf)
return TRUE
diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm
index 79d24b9c55ab9..d4cb4afefdaf0 100644
--- a/code/modules/research/stock_parts.dm
+++ b/code/modules/research/stock_parts.dm
@@ -207,7 +207,7 @@ If you create T5+ please take a pass at mech_fabricator.dm. The parts being good
continue
part_list += component_part
//Sort the parts. This ensures that higher tier items are applied first.
- part_list = sortTim(part_list, GLOBAL_PROC_REF(cmp_rped_sort))
+ sortTim(part_list, GLOBAL_PROC_REF(cmp_rped_sort))
return part_list
/proc/cmp_rped_sort(obj/item/first_item, obj/item/second_item)
diff --git a/code/modules/research/xenobiology/crossbreeding/_misc.dm b/code/modules/research/xenobiology/crossbreeding/_misc.dm
index 7b85a878ec39b..0e6a37ce3d0ba 100644
--- a/code/modules/research/xenobiology/crossbreeding/_misc.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_misc.dm
@@ -93,8 +93,8 @@ Slimecrossing Items
icon_state = "yellow slime extract"
rating = 7
custom_materials = null
- maxcharge = 50000
- chargerate = 2500
+ maxcharge = 50 * STANDARD_CELL_CHARGE
+ chargerate = 2.5 * STANDARD_CELL_RATE
charge_light_type = null
connector_type = "slimecore"
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index 62e13ecb7f9e0..6ac45f9424d99 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -293,13 +293,12 @@
obj_flags |= EMAGGED
SSshuttle.emergency.movement_force = list("KNOCKDOWN" = 60, "THROW" = 20)//YOUR PUNY SEATBELTS can SAVE YOU NOW, MORTAL
- var/datum/species/S = new
for(var/i in 1 to 10)
// the shuttle system doesn't know who these people are, but they
// must be important, surely
var/obj/item/card/id/ID = new(src)
var/datum/job/J = pick(SSjob.joinable_occupations)
- ID.registered_name = S.random_name(pick(MALE, FEMALE))
+ ID.registered_name = generate_random_name_species_based(species_type = /datum/species/human)
ID.assignment = J.title
authorized += ID
diff --git a/code/modules/surgery/bodyparts/head_hair_and_lips.dm b/code/modules/surgery/bodyparts/head_hair_and_lips.dm
index aa0196b187a54..453bd79ee22e9 100644
--- a/code/modules/surgery/bodyparts/head_hair_and_lips.dm
+++ b/code/modules/surgery/bodyparts/head_hair_and_lips.dm
@@ -84,7 +84,7 @@
var/image/facial_hair_overlay
if(!facial_hair_hidden && facial_hairstyle && (head_flags & HEAD_FACIAL_HAIR))
- sprite_accessory = GLOB.facial_hairstyles_list[facial_hairstyle]
+ sprite_accessory = SSaccessories.facial_hairstyles_list[facial_hairstyle]
if(sprite_accessory)
//Overlay
facial_hair_overlay = image(sprite_accessory.icon, sprite_accessory.icon_state, -HAIR_LAYER, image_dir)
@@ -99,12 +99,12 @@
var/facial_hair_gradient_style = LAZYACCESS(gradient_styles, GRADIENT_FACIAL_HAIR_KEY)
if(facial_hair_gradient_style)
var/facial_hair_gradient_color = LAZYACCESS(gradient_colors, GRADIENT_FACIAL_HAIR_KEY)
- var/image/facial_hair_gradient_overlay = get_gradient_overlay(sprite_accessory.icon, sprite_accessory.icon_state, -HAIR_LAYER, GLOB.facial_hair_gradients_list[facial_hair_gradient_style], facial_hair_gradient_color, image_dir)
+ var/image/facial_hair_gradient_overlay = get_gradient_overlay(sprite_accessory.icon, sprite_accessory.icon_state, -HAIR_LAYER, SSaccessories.facial_hair_gradients_list[facial_hair_gradient_style], facial_hair_gradient_color, image_dir)
. += facial_hair_gradient_overlay
var/image/hair_overlay
if(!(show_debrained && (head_flags & HEAD_DEBRAIN)) && !hair_hidden && hairstyle && (head_flags & HEAD_HAIR))
- var/datum/sprite_accessory/hair/hair_sprite_accessory = GLOB.hairstyles_list[hairstyle]
+ var/datum/sprite_accessory/hair/hair_sprite_accessory = SSaccessories.hairstyles_list[hairstyle]
if(hair_sprite_accessory)
//Overlay
hair_overlay = image(hair_sprite_accessory.icon, hair_sprite_accessory.icon_state, -HAIR_LAYER, image_dir)
@@ -120,7 +120,7 @@
var/hair_gradient_style = LAZYACCESS(gradient_styles, GRADIENT_HAIR_KEY)
if(hair_gradient_style)
var/hair_gradient_color = LAZYACCESS(gradient_colors, GRADIENT_HAIR_KEY)
- var/image/hair_gradient_overlay = get_gradient_overlay(hair_sprite_accessory.icon, hair_sprite_accessory.icon_state, -HAIR_LAYER, GLOB.hair_gradients_list[hair_gradient_style], hair_gradient_color, image_dir)
+ var/image/hair_gradient_overlay = get_gradient_overlay(hair_sprite_accessory.icon, hair_sprite_accessory.icon_state, -HAIR_LAYER, SSaccessories.hair_gradients_list[hair_gradient_style], hair_gradient_color, image_dir)
hair_gradient_overlay.pixel_y = hair_sprite_accessory.y_offset
. += hair_gradient_overlay
diff --git a/code/modules/surgery/organs/external/_external_organ.dm b/code/modules/surgery/organs/external/_external_organ.dm
index b58f08fe97d7e..a054bc741e632 100644
--- a/code/modules/surgery/organs/external/_external_organ.dm
+++ b/code/modules/surgery/organs/external/_external_organ.dm
@@ -182,7 +182,7 @@
return TRUE
/datum/bodypart_overlay/mutant/horns/get_global_feature_list()
- return GLOB.horns_list
+ return SSaccessories.horns_list
///The frills of a lizard (like weird fin ears)
/obj/item/organ/external/frills
@@ -209,7 +209,7 @@
return FALSE
/datum/bodypart_overlay/mutant/frills/get_global_feature_list()
- return GLOB.frills_list
+ return SSaccessories.frills_list
///Guess what part of the lizard this is?
/obj/item/organ/external/snout
@@ -238,7 +238,7 @@
return FALSE
/datum/bodypart_overlay/mutant/snout/get_global_feature_list()
- return GLOB.snouts_list
+ return SSaccessories.snouts_list
///A moth's antennae
/obj/item/organ/external/antennae
@@ -315,7 +315,7 @@
burn_datum = fetch_sprite_datum(burn_datum) //turn the path into the singleton instance
/datum/bodypart_overlay/mutant/antennae/get_global_feature_list()
- return GLOB.moth_antennae_list
+ return SSaccessories.moth_antennae_list
/datum/bodypart_overlay/mutant/antennae/get_base_icon_state()
return burnt ? burn_datum.icon_state : sprite_datum.icon_state
@@ -347,7 +347,7 @@
var/color_inverse_base = 255
/datum/bodypart_overlay/mutant/pod_hair/get_global_feature_list()
- return GLOB.pod_hair_list
+ return SSaccessories.pod_hair_list
/datum/bodypart_overlay/mutant/pod_hair/color_image(image/overlay, draw_layer, obj/item/bodypart/limb)
if(draw_layer != bitflag_to_layer(color_swapped_layer))
diff --git a/code/modules/surgery/organs/external/spines.dm b/code/modules/surgery/organs/external/spines.dm
index 743b7fa8d47f2..86bff9a768939 100644
--- a/code/modules/surgery/organs/external/spines.dm
+++ b/code/modules/surgery/organs/external/spines.dm
@@ -32,7 +32,7 @@
feature_key = "spines"
/datum/bodypart_overlay/mutant/spines/get_global_feature_list()
- return GLOB.spines_list
+ return SSaccessories.spines_list
/datum/bodypart_overlay/mutant/spines/can_draw_on_bodypart(mob/living/carbon/human/human)
. = ..()
diff --git a/code/modules/surgery/organs/external/tails.dm b/code/modules/surgery/organs/external/tails.dm
index ab71e3ac9f35f..38b35bce45cb3 100644
--- a/code/modules/surgery/organs/external/tails.dm
+++ b/code/modules/surgery/organs/external/tails.dm
@@ -151,7 +151,7 @@
wag_flags = WAG_ABLE
/datum/bodypart_overlay/mutant/tail/get_global_feature_list()
- return GLOB.tails_list_human
+ return SSaccessories.tails_list_human
/obj/item/organ/external/tail/cat/get_butt_sprite()
return BUTT_SPRITE_CAT
@@ -175,7 +175,7 @@
feature_key = "tail_monkey"
/datum/bodypart_overlay/mutant/tail/monkey/get_global_feature_list()
- return GLOB.tails_list_monkey
+ return SSaccessories.tails_list_monkey
/obj/item/organ/external/tail/lizard
name = "lizard tail"
@@ -192,7 +192,7 @@
feature_key = "tail_lizard"
/datum/bodypart_overlay/mutant/tail/lizard/get_global_feature_list()
- return GLOB.tails_list_lizard
+ return SSaccessories.tails_list_lizard
/obj/item/organ/external/tail/lizard/fake
name = "fabricated lizard tail"
@@ -208,7 +208,7 @@
var/tail_spine_key = NONE
/datum/bodypart_overlay/mutant/tail_spines/get_global_feature_list()
- return GLOB.tail_spines_list
+ return SSaccessories.tail_spines_list
/datum/bodypart_overlay/mutant/tail_spines/get_base_icon_state()
return (!isnull(tail_spine_key) ? "[tail_spine_key]_" : "") + (wagging ? "wagging_" : "") + sprite_datum.icon_state // Select the wagging state if appropriate
diff --git a/code/modules/surgery/organs/external/wings/functional_wings.dm b/code/modules/surgery/organs/external/wings/functional_wings.dm
index aacf6f08f6a5c..5f2851b467635 100644
--- a/code/modules/surgery/organs/external/wings/functional_wings.dm
+++ b/code/modules/surgery/organs/external/wings/functional_wings.dm
@@ -139,9 +139,9 @@
/datum/bodypart_overlay/mutant/wings/functional/get_global_feature_list()
if(wings_open)
- return GLOB.wings_open_list
+ return SSaccessories.wings_open_list
else
- return GLOB.wings_list
+ return SSaccessories.wings_list
///Update our wingsprite to the open wings variant
/datum/bodypart_overlay/mutant/wings/functional/proc/open_wings()
diff --git a/code/modules/surgery/organs/external/wings/moth_wings.dm b/code/modules/surgery/organs/external/wings/moth_wings.dm
index f4e0f156e703e..11aebf4e8f1b5 100644
--- a/code/modules/surgery/organs/external/wings/moth_wings.dm
+++ b/code/modules/surgery/organs/external/wings/moth_wings.dm
@@ -84,7 +84,7 @@
burn_datum = fetch_sprite_datum(burn_datum)
/datum/bodypart_overlay/mutant/wings/moth/get_global_feature_list()
- return GLOB.moth_wings_list
+ return SSaccessories.moth_wings_list
/datum/bodypart_overlay/mutant/wings/moth/can_draw_on_bodypart(mob/living/carbon/human/human)
if(!(human.wear_suit?.flags_inv & HIDEMUTWINGS))
diff --git a/code/modules/surgery/plastic_surgery.dm b/code/modules/surgery/plastic_surgery.dm
index 9224c29b2db63..8be13802e7cbb 100644
--- a/code/modules/surgery/plastic_surgery.dm
+++ b/code/modules/surgery/plastic_surgery.dm
@@ -94,11 +94,11 @@
else
user.visible_message(span_warning("You have no picture to base the appearance on, reverting to random appearances."))
for(var/i in 1 to 10)
- names += target.dna.species.random_name(target.gender, TRUE)
+ names += target.generate_random_mob_name(TRUE)
else
- for(var/_i in 1 to 9)
+ for(var/j in 1 to 9)
names += "Subject [target.gender == MALE ? "i" : "o"]-[pick("a", "b", "c", "d", "e")]-[rand(10000, 99999)]"
- names += target.dna.species.random_name(target.gender, TRUE) //give one normal name in case they want to do regular plastic surgery
+ names += target.generate_random_mob_name(TRUE) //give one normal name in case they want to do regular plastic surgery
var/chosen_name = tgui_input_list(user, "New name to assign", "Plastic Surgery", names)
if(isnull(chosen_name))
return
diff --git a/code/modules/unit_tests/preference_species.dm b/code/modules/unit_tests/preference_species.dm
index 8e49f49cdd6a4..8d913cc8fb64d 100644
--- a/code/modules/unit_tests/preference_species.dm
+++ b/code/modules/unit_tests/preference_species.dm
@@ -12,7 +12,7 @@
for(var/species_id in get_selectable_species())
var/species_type = GLOB.species_list[species_id]
- var/datum/species/species = new species_type()
+ var/datum/species/species = GLOB.species_prototypes[species_type]
// Check the species decription.
// If it's not overridden, a stack trace will be thrown (and fail the test).
@@ -29,5 +29,3 @@
TEST_FAIL("Species [species] ([species_type]) is selectable, but did not properly implement get_species_lore().")
else if(!islist(species_lore))
TEST_FAIL("Species [species] ([species_type]) is selectable, but did not properly implement get_species_lore() (Did not return a list).")
-
- qdel(species)
diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm
index 332005070d5b6..9a6f89fddc353 100644
--- a/code/modules/unit_tests/unit_test.dm
+++ b/code/modules/unit_tests/unit_test.dm
@@ -340,7 +340,7 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
if(length(focused_tests))
tests_to_run = focused_tests
- tests_to_run = sortTim(tests_to_run, GLOBAL_PROC_REF(cmp_unit_test_priority))
+ sortTim(tests_to_run, GLOBAL_PROC_REF(cmp_unit_test_priority))
var/list/test_results = list()
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index f0f7b0accaf5e..e17488bc96a6d 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -71,7 +71,7 @@
/// If this uplink item is only available to certain roles. Roles are dependent on the frequency chip or stored ID.
var/list/restricted_roles = list()
/// The species able to purchase this uplink item.
- var/restricted_species = list()
+ var/list/restricted_species = list()
/// The minimum amount of progression needed for this item to be added to uplinks.
var/progression_minimum = 0
/// Whether this purchase is visible in the purchase log.
diff --git a/code/modules/vehicles/wheelchair.dm b/code/modules/vehicles/wheelchair.dm
index 92fcb995f7643..d40b57276c0e4 100644
--- a/code/modules/vehicles/wheelchair.dm
+++ b/code/modules/vehicles/wheelchair.dm
@@ -126,7 +126,7 @@
. = ..()
if(over_object != usr || !Adjacent(usr) || !foldabletype)
return FALSE
- if(!ishuman(usr) || !usr.can_perform_action(src))
+ if(!ishuman(usr) || !usr.can_perform_action(src, ALLOW_RESTING))
return FALSE
if(has_buckled_mobs())
return FALSE
@@ -138,6 +138,12 @@
/obj/item/wheelchair/attack_self(mob/user) //Deploys wheelchair on in-hand use
deploy_wheelchair(user, user.loc)
+/obj/item/wheelchair/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ if(isopenturf(interacting_with))
+ deploy_wheelchair(user, interacting_with)
+ return ITEM_INTERACT_SUCCESS
+ return NONE
+
/obj/item/wheelchair/proc/deploy_wheelchair(mob/user, atom/location)
var/obj/vehicle/ridden/wheelchair/wheelchair_unfolded = new unfolded_type(location)
wheelchair_unfolded.add_fingerprint(user)
diff --git a/code/modules/wiremod/shell/gun.dm b/code/modules/wiremod/shell/gun.dm
index 9f196e6c1fcce..283815fb3346b 100644
--- a/code/modules/wiremod/shell/gun.dm
+++ b/code/modules/wiremod/shell/gun.dm
@@ -30,7 +30,7 @@
range = 7
/obj/item/stock_parts/cell/emproof/wiremod_gun
- maxcharge = 100
+ maxcharge = 0.1 * STANDARD_CELL_CHARGE
/obj/item/gun/energy/wiremod_gun/Initialize(mapload)
. = ..()
diff --git a/config/game_options.txt b/config/game_options.txt
index a606519765421..4d545500e0285 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -146,6 +146,13 @@ EVENTS_MIN_TIME_MUL 1
## Set to 0 to make dangerous events avaliable for all populations.
EVENTS_MIN_PLAYERS_MUL 1
+## The lower bound, in deciseconds, for how soon another random event can be scheduled.
+## Defaults to 1500 deciseconds or 2.5 minutes
+EVENTS_FREQUENCY_LOWER 1500
+
+## The upper bound, in deciseconds, for how soon another random event can be scheduled.
+## Defaults to 4200 deciseconds or 7 minutes
+EVENTS_FREQUENCY_UPPER 4200
## AI ###
diff --git a/html/changelogs/AutoChangeLog-pr-82966.yml b/html/changelogs/AutoChangeLog-pr-82966.yml
deleted file mode 100644
index 8602d867b5faa..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-82966.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "JohnFulpWillard"
-delete-after: True
-changes:
- - bugfix: "Monkey changelings that are disguised as someone can now take off their flesh clothes."
\ No newline at end of file
diff --git a/html/changelogs/archive/2024-05.yml b/html/changelogs/archive/2024-05.yml
index ae546e168c13f..0137f16cb44b7 100644
--- a/html/changelogs/archive/2024-05.yml
+++ b/html/changelogs/archive/2024-05.yml
@@ -39,3 +39,103 @@
necromanceranne:
- bugfix: If you are a freerunner, you don't end up faceplanting despite having
catlike grace.
+2024-05-02:
+ Echriser:
+ - qol: conveyor switches now have direction-specific input signals
+ Fluffles:
+ - qol: you can pick up wheelchairs while on the ground
+ - qol: you can place wheelchairs a tile away from you, like roller beds
+ JohnFulpWillard:
+ - bugfix: Monkey changelings that are disguised as someone can now take off their
+ flesh clothes.
+ - bugfix: You can now re-construct pod doors that had deconstruction started.
+ - qol: You can now make pod door assemblies using plasteel in-hand.
+ - bugfix: Monkeys can no longer be knocked over by walking into a windoor on combat
+ mode while they're behind it.
+ - admin: Debug uplinks now shows all categories and won't lock upon buying items
+ like his grace and the syndicate balloon.
+ - bugfix: Constantly fleeing in Battle Arcade will no longer give you a very large
+ amount of decimals due to halving your gold every time.
+ - bugfix: AIs can now track Silicon as long as their built-in camera is online.
+ Melbert:
+ - admin: Custom Single and Custom Multi votes are now combined into one vote
+ - admin: Admins can now end votes instantly, rather than cancelling them
+ - admin: Admins can now reset the vote cooldown
+ - bugfix: Vote cooldown actually applies now
+ Pickle-Coding:
+ - bugfix: Fixes hypercharged slime core cells and circuit guns having 1,000 times
+ less energy than intended.
+ Watermelon914:
+ - bugfix: Fixed the ipintel subsystem not working.
+ kawoppi:
+ - bugfix: the civilian bounty control terminal displays the payout of new bounty
+ options again
+ - qol: the civilian bounty control terminal displays the description of new bounty
+ options
+ nikothedude:
+ - bugfix: Jousting no longer bypasses pacifism
+2024-05-03:
+ Echriser:
+ - qol: conveyors now use left and right click controls
+ - qol: add screentips for conveyor switches
+ - rscdel: removes circuit conveyor circuit default trigger behavior in favor in
+ favor of the three state triggers
+ Gaxeer:
+ - bugfix: fix runtime when no events were drafted to be picked from
+ - config: make events frequency configurable
+ StrangeWeirdKitten:
+ - qol: You can now quickly stamp papers with a right click
+ Zenog400:
+ - rscadd: increased the size of the pool that Machine Blessing draws from
+ - balance: weighted some of the implants that Machine Blessing can give
+ mc-oofert:
+ - image: added directional sprites for radiation shutters
+2024-05-04:
+ Ben10Omintrix:
+ - bugfix: mobs in the same faction will no longer be at odds against one another
+ - bugfix: mobs can now perform behaviors alongside searching for targets
+ - bugfix: mobs will no longer be starting and stopping when chasing targets
+ Ghommie:
+ - rscadd: Adds an Icebox-specific station trait that brightens outdoors areas on
+ the surface level.
+ Ikalpo:
+ - bugfix: Stage 2 singularities should no longer escape containment
+ Melbert:
+ - bugfix: New machine god blessings now actually works probably
+ Profakos:
+ - balance: Bitrunners can now earn Bepis disks, once per medium domain or above,
+ if they scored at least an A.
+ - rscdel: Bitrunners can not buy Bepis disks from their vendors.
+ Ryll/Shaps:
+ - bugfix: Pacifists can no longer endlessly spam the backblast functionality of
+ loaded rocket launchers that they cannot actually fire
+ Watermelon914:
+ - bugfix: Fixed lua scripts breaking when turfs with registered signals get deleted.
+ Xander3359:
+ - bugfix: You can no longer bypass construction restrictions via the crafting menu
+ cnleth:
+ - bugfix: Fire ant colonies created by burning regular ants will now contain fire
+ ants as their reagent
+ jlsnow301:
+ - bugfix: Candy corn is once again available to detective fedoras
+ mogeoko:
+ - bugfix: Ventcrawling mobs can change Z-level using multiz-decks again.
+2024-05-05:
+ Isratosh:
+ - bugfix: If kidnapped and ransomed by pirates, you will now properly return to
+ the station automatically after 6 minutes.
+ - bugfix: You can no longer be kidnapped and held for ransom by cargo technicians
+ posing as pirates.
+ Jacquerel:
+ - bugfix: Blood Brothers should spawn knowing what their objectives are.
+ - bugfix: Teams of 3 Blood Brothers will once more have an additional objective.
+ Melbert:
+ - refactor: Random Name Generation has been refactored. Report any instances of
+ people having weird (or "Unknown") names.
+ - qol: Felinids, Slimepeople, Podpeople, and some other species without defined
+ namelists now automatically generate names based on their primary language(s).
+ - qol: More non-human names can be generated in codewords (and other misc. areas)
+ than just lizard names.
+ larentoun:
+ - bugfix: Materials are now correctly applied to crafted items (chairs, toilets,
+ etc)
diff --git a/icons/obj/doors/shutters_radiation.dmi b/icons/obj/doors/shutters_radiation.dmi
index 657b613b0ccde..2e70b24a4aa2a 100644
Binary files a/icons/obj/doors/shutters_radiation.dmi and b/icons/obj/doors/shutters_radiation.dmi differ
diff --git a/lua/SS13_base.lua b/lua/SS13_base.lua
index f49908f094261..ea04c8c6503dd 100644
--- a/lua/SS13_base.lua
+++ b/lua/SS13_base.lua
@@ -100,7 +100,8 @@ function SS13.register_signal(datum, signal, func)
callback:call_proc("RegisterSignal", datum, signal, "Invoke")
local path = { "__SS13_signal_handlers", datumWeakRef, signal, callbackWeakRef, "func" }
callback.vars.arguments = { path }
- if not __SS13_signal_handlers[datumWeakRef]._cleanup then
+ -- Turfs don't remove their signals on deletion.
+ if not __SS13_signal_handlers[datumWeakRef]._cleanup and not SS13.istype(datum, "/turf") then
local cleanupCallback = SS13.new("/datum/callback", SS13.state, "call_function_return_first")
local cleanupPath = { "__SS13_signal_handlers", datumWeakRef, "_cleanup"}
cleanupCallback.vars.arguments = { cleanupPath }
@@ -134,6 +135,11 @@ function SS13.unregister_signal(datum, signal, callback)
local callbackWeakRef = dm.global_proc("WEAKREF", handler_callback)
if not SS13.istype(datum, "/datum/weakref") then
handler_callback:call_proc("UnregisterSignal", datum, signal)
+ else
+ local actualDatum = datum:call_proc("hard_resolve")
+ if SS13.is_valid(actualDatum) then
+ handler_callback:call_proc("UnregisterSignal", actualDatum, signal)
+ end
end
SS13.stop_tracking(handler_callback)
end
diff --git a/lua/handler_group.lua b/lua/handler_group.lua
index fff63ad18e427..0246d33c74488 100644
--- a/lua/handler_group.lua
+++ b/lua/handler_group.lua
@@ -14,7 +14,7 @@ function HandlerGroup:register_signal(datum, signal, func)
if not callback then
return
end
- table.insert(self.registered, { datum = datum, signal = signal, callback = callback })
+ table.insert(self.registered, { datum = dm.global_proc("WEAKREF", datum), signal = signal, callback = callback })
end
-- Clears all the signals that have been registered on this HandlerGroup
diff --git a/tgstation.dme b/tgstation.dme
index 70f0986b3a773..cdab78a6ce609 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -504,10 +504,8 @@
#include "code\__HELPERS\paths\jps.dm"
#include "code\__HELPERS\paths\path.dm"
#include "code\__HELPERS\paths\sssp.dm"
-#include "code\__HELPERS\sorts\__main.dm"
-#include "code\__HELPERS\sorts\InsertSort.dm"
-#include "code\__HELPERS\sorts\MergeSort.dm"
-#include "code\__HELPERS\sorts\TimSort.dm"
+#include "code\__HELPERS\sorts\helpers.dm"
+#include "code\__HELPERS\sorts\sort_instance.dm"
#include "code\_globalvars\_regexes.dm"
#include "code\_globalvars\admin.dm"
#include "code\_globalvars\arcade.dm"
@@ -651,7 +649,6 @@
#include "code\controllers\subsystem\ipintel.dm"
#include "code\controllers\subsystem\job.dm"
#include "code\controllers\subsystem\lag_switch.dm"
-#include "code\controllers\subsystem\language.dm"
#include "code\controllers\subsystem\library.dm"
#include "code\controllers\subsystem\lighting.dm"
#include "code\controllers\subsystem\lua.dm"
@@ -690,6 +687,7 @@
#include "code\controllers\subsystem\sounds.dm"
#include "code\controllers\subsystem\spatial_gridmap.dm"
#include "code\controllers\subsystem\speech_controller.dm"
+#include "code\controllers\subsystem\sprite_accessories.dm"
#include "code\controllers\subsystem\statpanel.dm"
#include "code\controllers\subsystem\stickyban.dm"
#include "code\controllers\subsystem\stock_market.dm"
@@ -4332,6 +4330,10 @@
#include "code\modules\keybindings\bindings_client.dm"
#include "code\modules\keybindings\focus.dm"
#include "code\modules\keybindings\setup.dm"
+#include "code\modules\language\_language.dm"
+#include "code\modules\language\_language_holder.dm"
+#include "code\modules\language\_language_manuals.dm"
+#include "code\modules\language\_language_menu.dm"
#include "code\modules\language\aphasia.dm"
#include "code\modules\language\beachbum.dm"
#include "code\modules\language\buzzwords.dm"
@@ -4340,10 +4342,6 @@
#include "code\modules\language\common.dm"
#include "code\modules\language\draconic.dm"
#include "code\modules\language\drone.dm"
-#include "code\modules\language\language.dm"
-#include "code\modules\language\language_holder.dm"
-#include "code\modules\language\language_manuals.dm"
-#include "code\modules\language\language_menu.dm"
#include "code\modules\language\machine.dm"
#include "code\modules\language\moffic.dm"
#include "code\modules\language\monkey.dm"
diff --git a/tgui/packages/tgui/interfaces/CivCargoHoldTerminal.jsx b/tgui/packages/tgui/interfaces/CivCargoHoldTerminal.jsx
index 386f3c5721a0c..438030e39472c 100644
--- a/tgui/packages/tgui/interfaces/CivCargoHoldTerminal.jsx
+++ b/tgui/packages/tgui/interfaces/CivCargoHoldTerminal.jsx
@@ -96,41 +96,66 @@ const BountyTextBox = (props) => {
const BountyPickBox = (props) => {
const { act, data } = useBackend();
- const { id_bounty_names, id_bounty_values } = data;
+ const { id_bounty_names, id_bounty_infos, id_bounty_values } = data;
return (
- act('pick', { value: 1 })}
- >
- Payout: {id_bounty_values[0]} cr
-
+
- act('pick', { value: 2 })}
- >
- Payout: {id_bounty_values[1]} cr
-
+
- act('pick', { value: 3 })}
- >
- Payout: {id_bounty_values[2]} cr
-
+
);
};
+
+const BountyPickButton = (props) => {
+ return (
+ props.act('pick', { value: props.pick_value })}
+ style={{
+ display: 'flex',
+ textWrap: 'wrap',
+ whiteSpace: 'normal',
+ paddingLeft: '0',
+ paddingRight: '0',
+ }}
+ >
+ {props.bounty_name}
+
+ {props.bounty_info}
+
+ Payout: {props.bounty_value} cr
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/Uplink/index.tsx b/tgui/packages/tgui/interfaces/Uplink/index.tsx
index a8b2e7d477b2a..4949fc94ee7f5 100644
--- a/tgui/packages/tgui/interfaces/Uplink/index.tsx
+++ b/tgui/packages/tgui/interfaces/Uplink/index.tsx
@@ -137,13 +137,15 @@ export class Uplink extends Component<{}, UplinkState> {
uplinkData.items = uplinkData.items.filter((value) => {
if (
value.restricted_roles.length > 0 &&
- !value.restricted_roles.includes(uplinkRole)
+ !value.restricted_roles.includes(uplinkRole) &&
+ !data.debug
) {
return false;
}
if (
value.restricted_species.length > 0 &&
- !value.restricted_species.includes(uplinkSpecies)
+ !value.restricted_species.includes(uplinkSpecies) &&
+ !data.debug
) {
return false;
}
@@ -455,7 +457,7 @@ export class Uplink extends Component<{}, UplinkState> {
}
}}
/>
- {(shop_locked && (
+ {(shop_locked && !data.debug && (
{
- const { data } = useBackend();
- const { currentVote, user } = data;
+ const { act, data } = useBackend();
+ const { currentVote, user, LastVoteTime, VoteCD } = data;
/**
* Adds the voting type to title if there is an ongoing vote.
@@ -81,7 +84,19 @@ export const VotePanel = (props) => {
-
+ act('resetCooldown')}
+ />
+ )
+ }
+ >
{!!user.isLowerAdmin && currentVote && }
@@ -93,51 +108,86 @@ export const VotePanel = (props) => {
);
};
+const VoteOptionDimmer = (props) => {
+ const { data } = useBackend();
+ const { LastVoteTime, VoteCD } = data;
+
+ return (
+
+
+
+ Vote Cooldown
+
+ {Math.floor((VoteCD + LastVoteTime) / 10)}s
+
+
+ );
+};
+
/**
* The create vote options menu. Only upper admins can disable voting.
* @returns A section visible to everyone with vote options.
*/
const VoteOptions = (props) => {
const { act, data } = useBackend();
- const { possibleVotes, user } = data;
+ const { possibleVotes, user, LastVoteTime, VoteCD } = data;
return (
-
- {possibleVotes.map((option) => (
-
- {!!user.isLowerAdmin && option.config !== VoteConfig.None && (
-
- act('toggleVote', {
- voteName: option.name,
- })
- }
- />
- )}
-
- act('callVote', {
- voteName: option.name,
- })
- }
- />
-
- ))}
-
+
+ {LastVoteTime + VoteCD > 0 && }
+
+ {possibleVotes.map((option) => (
+
+
+ {!!user.isLowerAdmin && (
+
+
+ act('toggleVote', {
+ voteName: option.name,
+ })
+ }
+ />
+
+ )}
+
+
+ act('callVote', {
+ voteName: option.name,
+ })
+ }
+ />
+
+
+
+ ))}
+
+
);
@@ -153,11 +203,11 @@ const VotersList = (props) => {
return (
-
+
{data.voting.map((voter) => {
return {voter} ;
})}
@@ -275,13 +325,26 @@ const TimePanel = (props) => {
{currentVote?.timeRemaining || 0}s
{!!user.isLowerAdmin && (
- act('cancel')}
- >
- Cancel Vote
-
+
+
+ act('endNow')}
+ >
+ End Now
+
+
+
+ act('cancel')}
+ >
+ Cancel Vote
+
+
+
)}
diff --git a/tools/build/build.js b/tools/build/build.js
index fc5307bcc4182..03e21aab3b126 100644
--- a/tools/build/build.js
+++ b/tools/build/build.js
@@ -86,7 +86,7 @@ export const WarningParameter = new Juke.Parameter({
export const NoWarningParameter = new Juke.Parameter({
type: 'string[]',
- alias: 'NW',
+ alias: 'I',
});
export const CutterTarget = new Juke.Target({
diff --git a/tools/build/lib/byond.js b/tools/build/lib/byond.js
index e4809e3e9a7a7..8b6abcf8fe831 100644
--- a/tools/build/lib/byond.js
+++ b/tools/build/lib/byond.js
@@ -166,13 +166,21 @@ export const DreamMaker = async (dmeFile, options = {}) => {
await testDmVersion(dmPath);
testOutputFile(`${dmeBaseName}.dmb`);
testOutputFile(`${dmeBaseName}.rsc`);
+
const runWithWarningChecks = async (dmPath, args) => {
const execReturn = await Juke.exec(dmPath, args);
- const ignoredWarningCodes = options.ignoreWarningCodes ?? [];
- const reg = ignoredWarningCodes.length > 0 ? new RegExp(`\d+:warning: (?!(${ignoredWarningCodes.join('|')}))`) : /\d+:warning: /;
- if (options.warningsAsErrors && execReturn.combined.match(reg)) {
- Juke.logger.error(`Compile warnings treated as errors`);
- throw new Juke.ExitCode(2);
+ if(options.warningsAsErrors){
+ const ignoredWarningCodes = options.ignoreWarningCodes ?? [];
+ if(ignoredWarningCodes.length > 0 ){
+ Juke.logger.info('Ignored warning codes:', ignoredWarningCodes.join(', '));
+ }
+ const base_regex = '\\d+:warning( \\([a-z_]*\\))?:'
+ const with_ignores = `\\d+:warning( \\([a-z_]*\\))?:(?!(${ignoredWarningCodes.map(x => `.*${x}.*$`).join('|')}))`
+ const reg = ignoredWarningCodes.length > 0 ? new RegExp(with_ignores, "m") : new RegExp(base_regex,"m")
+ if (options.warningsAsErrors && execReturn.combined.match(reg)) {
+ Juke.logger.error(`Compile warnings treated as errors`);
+ throw new Juke.ExitCode(2);
+ }
}
return execReturn;
}
@@ -180,8 +188,8 @@ export const DreamMaker = async (dmeFile, options = {}) => {
const { defines } = options;
if (defines && defines.length > 0) {
Juke.logger.info('Using defines:', defines.join(', '));
-
}
+
await runWithWarningChecks(dmPath, [...defines.map(def => `-D${def}`), dmeFile]);
};