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 (
- + - + - +
); }; + +const BountyPickButton = (props) => { + return ( + + ); +}; 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, - }) - } - /> - )} -
); @@ -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 && ( - + + + + + + + + )}
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]); };