diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index f5cfd67f33b..c6fd3d2e466 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -131,11 +131,20 @@ #define PROJECTILE_CONTINUE -1 //if the projectile should continue flying after calling bullet_act() #define PROJECTILE_FORCE_MISS -2 //if the projectile should treat the attack as a miss (suppresses attack and admin logs) - only applies to mobs. -//objectives +// Objective config enum values. #define CONFIG_OBJECTIVE_NONE 2 #define CONFIG_OBJECTIVE_VERB 1 #define CONFIG_OBJECTIVE_ALL 0 +// Server whitelist config enums. +#define CONFIG_SERVER_NO_WHITELIST 1 +#define CONFIG_SERVER_JOBS_WHITELIST 2 +#define CONFIG_SERVER_JOIN_WHITELIST 3 +#define CONFIG_SERVER_CONNECT_WHITELIST 4 + +// Location for server whitelist file to load from. +#define CONFIG_SERVER_WHITELIST_FILE "config/server_whitelist.txt" + // How many times an AI tries to connect to APC before switching to low power mode. #define AI_POWER_RESTORE_MAX_ATTEMPTS 3 @@ -365,4 +374,4 @@ #define RADIAL_LABELS_NONE 0 #define RADIAL_LABELS_OFFSET 1 -#define RADIAL_LABELS_CENTERED 2 \ No newline at end of file +#define RADIAL_LABELS_CENTERED 2 diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index e2d75b36771..045bb1e7b33 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -221,6 +221,9 @@ if(check_dexterity(DEXTERITY_HOLD_ITEM, silent = TRUE)) return A.attack_hand(src) + // TODO: some way to check if we SHOULD be doing an attack windup here; + // corgis attacking a tree, for example, will do the windup animation despite + // having no interaction or message shown at the end of it. // AI driven mobs have a melee telegraph that needs to be handled here. if(a_intent == I_HURT && istype(A) && !do_attack_windup_checking(A)) return TRUE diff --git a/code/controllers/subsystems/jobs.dm b/code/controllers/subsystems/jobs.dm index cc8593c941e..b900dcf8c32 100644 --- a/code/controllers/subsystems/jobs.dm +++ b/code/controllers/subsystems/jobs.dm @@ -330,6 +330,8 @@ SUBSYSTEM_DEF(jobs) //Get the players who are ready for(var/mob/new_player/player in global.player_list) if(player.ready && player.mind && !player.mind.assigned_role) + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_JOIN_WHITELIST && !check_server_whitelist(player)) + continue unassigned_roundstart += player if(unassigned_roundstart.len == 0) return 0 //Shuffle players and jobs diff --git a/code/datums/config/config_types/config_server.dm b/code/datums/config/config_types/config_server.dm index 21527e323d1..47239568235 100644 --- a/code/datums/config/config_types/config_server.dm +++ b/code/datums/config/config_types/config_server.dm @@ -43,7 +43,6 @@ /decl/config/toggle/on/allow_ai, /decl/config/toggle/on/allow_drone_spawn, /decl/config/toggle/hub_visibility, - /decl/config/toggle/usewhitelist, /decl/config/toggle/load_jobs_from_txt, /decl/config/toggle/disable_player_mice, /decl/config/toggle/uneducated_mice, @@ -61,7 +60,8 @@ /decl/config/toggle/guests_allowed, /decl/config/toggle/on/jobs_have_minimal_access, /decl/config/toggle/on/admin_legacy_system, - /decl/config/toggle/on/ban_legacy_system + /decl/config/toggle/on/ban_legacy_system, + /decl/config/enum/server_whitelist ) /decl/config/num/kick_inactive @@ -293,13 +293,6 @@ . = ..() world.update_hub_visibility() -/decl/config/toggle/usewhitelist - uid = "usewhitelist" - desc = list( - "Set to jobban everyone who's key is not listed in data/whitelist.txt from Captain, HoS, HoP, CE, RD, CMO, Warden, Security, Detective, and AI positions.", - "Uncomment to 1 to jobban, leave commented out to allow these positions for everyone (but see GUEST_JOBBAN above and regular jobbans)." - ) - /decl/config/toggle/load_jobs_from_txt uid = "load_jobs_from_txt" desc = "Toggle for having jobs load up from the .txt" @@ -369,3 +362,14 @@ /decl/config/toggle/on/jobs_have_minimal_access uid = "jobs_have_minimal_access" desc = "Add a # here if you wish to use the setup where jobs have more access. This is intended for servers with low populations - where there are not enough players to fill all roles, so players need to do more than just one job. Also for servers where they don't want people to hide in their own departments." + +/decl/config/enum/server_whitelist + uid = "server_whitelist" + desc = "Determines how the server should handle whitelisting for ckeys. Whitelisted ckeys are found in '" + CONFIG_SERVER_WHITELIST_FILE + "'. Set to 'none' for no whitelisting, 'jobs' to whitelist sensitive jobs, 'join' to whitelist joining the round (observing and OOC are still available, or 'connect' to whitelist access to the server." + default_value = CONFIG_SERVER_NO_WHITELIST + enum_map = list( + "none" = CONFIG_SERVER_NO_WHITELIST, + "jobs" = CONFIG_SERVER_JOBS_WHITELIST, + "join" = CONFIG_SERVER_JOIN_WHITELIST, + "connect" = CONFIG_SERVER_CONNECT_WHITELIST + ) diff --git a/code/game/jobs/whitelist.dm b/code/game/jobs/server_whitelist.dm similarity index 72% rename from code/game/jobs/whitelist.dm rename to code/game/jobs/server_whitelist.dm index 604d32eb895..083876ecad3 100644 --- a/code/game/jobs/whitelist.dm +++ b/code/game/jobs/server_whitelist.dm @@ -1,21 +1,34 @@ -#define WHITELISTFILE "data/whitelist.txt" +var/global/list/server_whitelist -var/global/list/whitelist = list() - -/hook/startup/proc/loadWhitelist() - if(get_config_value(/decl/config/toggle/usewhitelist)) - load_whitelist() - return 1 - -/proc/load_whitelist() - whitelist = file2list(WHITELISTFILE) - if(!length(whitelist)) - whitelist = null - -/proc/check_whitelist(mob/M /*, var/rank*/) - if(!whitelist) - return 0 - return ("[M.ckey]" in whitelist) +/proc/check_server_whitelist(ckey) + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_NO_WHITELIST) + return TRUE + if(ismob(ckey)) + var/mob/checking = ckey + ckey = checking.ckey + if(!istext(ckey)) + return FALSE + if(!global.server_whitelist) + global.server_whitelist = file2list(CONFIG_SERVER_WHITELIST_FILE) || list() + return (ckey in global.server_whitelist) + +/proc/save_server_whitelist() + // Ensure we have the server whitelist loaded regardless of config or prior call. + if(!global.server_whitelist) + global.server_whitelist = file2list(CONFIG_SERVER_WHITELIST_FILE) || list() + + // Clear blank rows. + while(null in global.server_whitelist) + global.server_whitelist -= null + while("" in global.server_whitelist) + global.server_whitelist -= "" + + // Remove old list rather than append. + if(fexists(CONFIG_SERVER_WHITELIST_FILE)) + fdel(CONFIG_SERVER_WHITELIST_FILE) + // Write our list out. + var/write_file = file(CONFIG_SERVER_WHITELIST_FILE) + to_file(write_file, jointext(global.server_whitelist, "\n")) var/global/list/alien_whitelist = list() /hook/startup/proc/loadAlienWhitelist() @@ -106,5 +119,3 @@ var/global/list/alien_whitelist = list() if(findtext(s,"[ckey] - All")) return TRUE return FALSE - -#undef WHITELISTFILE diff --git a/code/game/objects/items/waterskin.dm b/code/game/objects/items/waterskin.dm index fb56f507c4e..298388f36ec 100644 --- a/code/game/objects/items/waterskin.dm +++ b/code/game/objects/items/waterskin.dm @@ -8,23 +8,54 @@ atom_flags = ATOM_FLAG_OPEN_CONTAINER volume = 120 material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME + var/decl/material/stopper_material = /decl/material/solid/organic/cloth/hemp + +/obj/item/chems/waterskin/proc/get_stopper_message() + var/decl/material/stopper_material_instance = GET_DECL(stopper_material) + return "You tie the neck of \the [src] closed with \a [stopper_material_instance.adjective_name] cord." + +/obj/item/chems/waterskin/proc/get_unstopper_message() + var/decl/material/stopper_material_instance = GET_DECL(stopper_material) + return "You untie \the [stopper_material_instance.adjective_name] cord from around the neck of \the [src]." + +/obj/item/chems/waterskin/proc/get_stopper_overlay() + if(ATOM_IS_OPEN_CONTAINER(src)) + return null + var/decl/material/stopper_material_instance = GET_DECL(stopper_material) + return overlay_image(icon, "[icon_state]-stopper", stopper_material_instance.color, RESET_COLOR | RESET_ALPHA) /obj/item/chems/waterskin/attack_self() . = ..() if(!.) if(ATOM_IS_OPEN_CONTAINER(src)) - to_chat(usr, SPAN_NOTICE("You cork \the [src].")) - atom_flags ^= ATOM_FLAG_OPEN_CONTAINER + to_chat(usr, SPAN_NOTICE(get_stopper_message())) + atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER else - to_chat(usr, SPAN_NOTICE("You remove the cork from \the [src].")) + to_chat(usr, SPAN_NOTICE(get_unstopper_message())) atom_flags |= ATOM_FLAG_OPEN_CONTAINER - update_icon() // TODO: filled/empty and corked/uncorked sprites + update_icon() + +/obj/item/chems/waterskin/on_update_icon() // TODO: filled/empty sprites + . = ..() // cuts overlays + var/image/stopper_overlay = get_stopper_overlay() + if(stopper_overlay) + add_overlay(stopper_overlay) /obj/item/chems/waterskin/crafted desc = "A long and rather unwieldly water-carrying vessel." + icon = 'icons/obj/items/waterskin_crafted.dmi' material = /decl/material/solid/organic/leather color = /decl/material/solid/organic/leather::color material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC + stopper_material = /decl/material/solid/organic/wood/maple + +/obj/item/chems/waterskin/crafted/get_stopper_message() + var/decl/material/stopper_material_instance = GET_DECL(stopper_material) + return "You insert \a [stopper_material_instance.adjective_name] stopper in the neck of \the [src]." + +/obj/item/chems/waterskin/crafted/get_unstopper_message() + var/decl/material/stopper_material_instance = GET_DECL(stopper_material) + return "You remove \the [stopper_material_instance.adjective_name] stopper from the neck of \the [src]." /obj/item/chems/waterskin/crafted/wine name = "wineskin" diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index a780eadc0f5..8294312ba59 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -1,5 +1,6 @@ //Blocks an attempt to connect before even creating our client datum thing. /world/IsBanned(key, address, computer_id, type) + var/static/key_cache = list() if(type == "world") return ..() @@ -10,6 +11,11 @@ var/ckeytext = ckey(key) + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_CONNECT_WHITELIST && !check_server_whitelist(ckeytext)) + log_access("Failed Login: [key] - Not server whitelisted") + message_admins("Failed Login: [key] - Not server whitelisted") + return list("reason"="whitelist", "desc"="\nReason: This server requires players to be whitelisted to join.") + if(admin_datums[ckeytext]) key_cache[key] = 0 return ..() @@ -19,7 +25,7 @@ log_access("Failed Login: [key] - Guests not allowed") message_admins("Failed Login: [key] - Guests not allowed") key_cache[key] = 0 - return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a byond account.") + return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a BYOND account.") var/client/C = global.ckey_directory[ckeytext] //If this isn't here, then topic call spam will result in all clients getting kicked with a connecting too fast error. diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 40b4bf35e92..79c44208bc0 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -1497,3 +1497,34 @@ var/global/BSACooldown = 0 LAZYADD(global.adminfaxes, P) faxreply = null + +/datum/admins/proc/addserverwhitelist(ckey as text) + set category = "Admin" + set name = "Add Ckey To Server Whitelist" + set desc = "Permanently adds the specified ckey to the server whitelist." + + ckey = ckey(ckey) + + if(!ckey) + to_chat(usr, SPAN_WARNING("Please specify a ckey to insert.")) + else if(check_server_whitelist(ckey)) // This will also preload the server whitelist. + to_chat(usr, SPAN_WARNING("That ckey is already server whitelisted.")) + else + global.server_whitelist |= ckey + save_server_whitelist() + log_and_message_admins("has added [ckey] to the server whitelist.", usr) + +/datum/admins/proc/removeserverwhitelist(ckey as text) + set category = "Admin" + set name = "Remove Ckey From Server Whitelist" + set desc = "Permanently removes the specified ckey from the server whitelist." + + ckey = ckey(ckey) + if(!ckey) + to_chat(usr, SPAN_WARNING("Please specify a ckey to remove.")) + else if(!check_server_whitelist(ckey)) // This will also preload the server whitelist. + to_chat(usr, SPAN_WARNING("That ckey is not server whitelisted.")) + else + global.server_whitelist -= ckey + save_server_whitelist() + log_and_message_admins("has removed [ckey] from the server whitelist.", usr) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 063c728dd38..b93ccd2bde9 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -154,6 +154,8 @@ var/global/list/admin_verbs_server = list( /datum/admins/proc/toggle_aliens, /client/proc/toggle_random_events, /client/proc/nanomapgen_DumpImage, + /datum/admins/proc/addserverwhitelist, + /datum/admins/proc/removeserverwhitelist, /datum/admins/proc/panicbunker, /datum/admins/proc/addbunkerbypass, /datum/admins/proc/revokebunkerbypass diff --git a/code/modules/admin/banjob.dm b/code/modules/admin/banjob.dm index 9bb638e0ee6..f6f7baff9c3 100644 --- a/code/modules/admin/banjob.dm +++ b/code/modules/admin/banjob.dm @@ -21,7 +21,7 @@ var/global/jobban_keylist[0] //to store the keys & ranks if (SSjobs.guest_jobbans(rank)) if(get_config_value(/decl/config/toggle/on/guest_jobban) && IsGuestKey(M.key)) return "Guest Job-ban" - if(get_config_value(/decl/config/toggle/usewhitelist) && !check_whitelist(M)) + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_JOBS_WHITELIST && !check_server_whitelist(M)) return "Whitelisted Job" return ckey_is_jobbanned(M.ckey, rank) return 0 diff --git a/code/modules/client/preference_setup/loadout/gear_tweaks.dm b/code/modules/client/preference_setup/loadout/gear_tweaks.dm index c45f408356c..c7c50e1603f 100644 --- a/code/modules/client/preference_setup/loadout/gear_tweaks.dm +++ b/code/modules/client/preference_setup/loadout/gear_tweaks.dm @@ -194,6 +194,7 @@ else reagent = valid_reagents[metadata] if(reagent && gear.reagents) + gear.reagents?.clear_reagents() // in case we're applying to an existing item with reagents gear.add_to_reagents(reagent, REAGENTS_FREE_SPACE(gear.reagents)) return GEAR_TWEAK_SUCCESS diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm index a5f8edab61d..1555f26fd22 100644 --- a/code/modules/client/preference_setup/loadout/loadout.dm +++ b/code/modules/client/preference_setup/loadout/loadout.dm @@ -497,13 +497,27 @@ src.location = location src.material = material -/decl/loadout_option/proc/spawn_item(user, location, metadata, obj/item/existing_item) +/datum/gear_data/proc/can_replace_existing(obj/item/candidate) + return istype(candidate, path) + +/decl/loadout_option/proc/spawn_item(mob/user, location, metadata) var/datum/gear_data/gd = new(path, location) for(var/datum/gear_tweak/gt in gear_tweaks) gt.tweak_gear_data(islist(metadata) && metadata["[gt]"], gd) var/obj/item/item - if(isitem(existing_item)) - item = existing_item + if(apply_to_existing_if_possible) // This was moved here from an argument so that geartweaks will affect the path used for checking. + for(var/obj/item/candidate in user.get_equipped_items(include_carried = TRUE)) + if(gd.can_replace_existing(candidate)) + item = candidate + break + if(candidate.storage) + for(var/obj/item/child_candidate in candidate.storage.get_contents()) + if(gd.can_replace_existing(child_candidate)) + item = child_candidate + break + if(item) + break + if(isitem(item)) if(gd.material) item.set_material(gd.material) else @@ -564,14 +578,7 @@ /decl/loadout_option/proc/spawn_and_validate_item(mob/living/human/H, metadata) PRIVATE_PROC(TRUE) - var/obj/item/item - if(apply_to_existing_if_possible) - for(var/obj/item/candidate in H.get_equipped_items(include_carried = TRUE)) - if(can_replace_existing(candidate)) - item = candidate - break - - item = spawn_item(H, H, metadata, item) + var/obj/item/item = spawn_item(H, H, metadata) if(QDELETED(item)) return diff --git a/code/modules/ghosttrap/trap.dm b/code/modules/ghosttrap/trap.dm index bc3fbea82fd..da2c66433b4 100644 --- a/code/modules/ghosttrap/trap.dm +++ b/code/modules/ghosttrap/trap.dm @@ -15,7 +15,9 @@ // Check for bans, proper atom types, etc. /decl/ghosttrap/proc/assess_candidate(var/mob/observer/ghost/candidate, var/mob/target, var/feedback = TRUE) . = TRUE - if(!candidate.MayRespawn(feedback, minutes_since_death)) + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_JOIN_WHITELIST && !check_server_whitelist(candidate)) + . = FALSE + else if(!candidate.MayRespawn(feedback, minutes_since_death)) . = FALSE else if(islist(ban_checks)) for(var/bantype in ban_checks) diff --git a/code/modules/materials/definitions/solids/materials_solid_organic.dm b/code/modules/materials/definitions/solids/materials_solid_organic.dm index 09f9e242689..14d26af5535 100644 --- a/code/modules/materials/definitions/solids/materials_solid_organic.dm +++ b/code/modules/materials/definitions/solids/materials_solid_organic.dm @@ -154,10 +154,11 @@ has_textile_fibers = TRUE /decl/material/solid/organic/cloth/hemp - name = "hemp" - lore_text = "Sturdy fibers from the hemp plant, woven into strong cloth." - uid = "solid_hemp" - color = "#b4a374" + name = "hemp" + adjective_name = "hempen" + lore_text = "Sturdy fibers from the hemp plant, woven into strong cloth." + uid = "solid_hemp" + color = "#b4a374" /decl/material/solid/organic/cloth/linen name = "linen" @@ -166,16 +167,18 @@ color = "#eee4c7" /decl/material/solid/organic/cloth/wool - name = "wool" - lore_text = "Fibers from the wooly fleece of a sheep or similar animal." - uid = "solid_wool" - color = "#fbfcdb" + name = "wool" + adjective_name = "woolen" + lore_text = "Fibers from the wooly fleece of a sheep or similar animal." + uid = "solid_wool" + color = "#fbfcdb" /decl/material/solid/organic/cloth/wool/diyaab - name = "diyaab wool" - lore_text = "Fibers from the wooly fleece of a diyaab." - uid = "solid_wool_diyaab" - color = "#c9eeff" + name = "diyaab wool" + adjective_name = null // override base wool + lore_text = "Fibers from the wooly fleece of a diyaab." + uid = "solid_wool_diyaab" + color = "#c9eeff" /decl/material/solid/organic/cloth/synthetic name = "nylon" @@ -263,6 +266,7 @@ /decl/material/solid/organic/leather/gut name = "dried gut" uid = "solid_dried_gut" + color = "#736754" /decl/material/solid/organic/leather/synth name = "synthleather" diff --git a/code/modules/materials/material_stack_cloth.dm b/code/modules/materials/material_stack_cloth.dm index 6a968ad4beb..2bc3692b6a7 100644 --- a/code/modules/materials/material_stack_cloth.dm +++ b/code/modules/materials/material_stack_cloth.dm @@ -44,10 +44,6 @@ plural_icon_state = "thread-mult" max_icon_state = "thread-max" -/obj/item/stack/material/thread/cotton - material = /decl/material/solid/organic/cloth - is_spawnable_type = TRUE - /obj/item/stack/material/thread/yellow SET_COLOR("#ffbf00") /obj/item/stack/material/thread/teal diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 42c7fa1425a..9c9ed33d687 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1836,6 +1836,7 @@ default behaviour is: reset_offsets(anim_time = 2) return FALSE + reset_offsets(anim_time = 2) return TRUE /mob/living/proc/prepare_for_despawn() diff --git a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm index da19e46697c..fcf266c47ee 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm @@ -107,20 +107,24 @@ /proc/try_drone_spawn(var/mob/user, var/obj/machinery/drone_fabricator/fabricator) if(GAME_STATE < RUNLEVEL_GAME) - to_chat(user, "The game hasn't started yet!") + to_chat(user, SPAN_WARNING("The game hasn't started yet!")) + return + + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_JOIN_WHITELIST && !check_server_whitelist(user)) + to_chat(user, SPAN_WARNING("Non-whitelisted players cannot join rounds except as observers.")) return if(!get_config_value(/decl/config/toggle/on/allow_drone_spawn)) - to_chat(user, "That verb is not currently permitted.") + to_chat(user, SPAN_WARNING("That verb is not currently permitted.")) return if(jobban_isbanned(user,ASSIGNMENT_ROBOT)) - to_chat(user, "You are banned from playing synthetics and cannot spawn as a drone.") + to_chat(user, SPAN_WARNING("You are banned from playing synthetics and cannot spawn as a drone.")) return if(get_config_value(/decl/config/num/use_age_restriction_for_jobs) && isnum(user.client.player_age)) if(user.client.player_age <= 3) - to_chat(user, " Your account is not old enough to play as a maintenance drone.") + to_chat(user, SPAN_WARNING("Your account is not old enough to play as a maintenance drone.")) return if(!user.MayRespawn(1, DRONE_SPAWN_DELAY)) @@ -135,7 +139,7 @@ all_fabricators[DF.fabricator_tag] = DF if(!all_fabricators.len) - to_chat(user, "There are no available drone spawn points, sorry.") + to_chat(user, SPAN_WARNING("There are no available drone spawn points, sorry.")) return var/choice = input(user,"Which fabricator do you wish to use?") as null|anything in all_fabricators diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 6bd8fc980a3..f03372203ad 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -183,11 +183,15 @@ INITIALIZE_IMMEDIATE(/mob/new_player) return 0 if(GAME_STATE != RUNLEVEL_GAME) - to_chat(usr, "The round is either not ready, or has already finished...") + to_chat(usr, SPAN_WARNING("The round is either not ready, or has already finished.")) + return 0 + + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_JOIN_WHITELIST && !check_server_whitelist(usr)) + alert("Non-whitelisted players are not permitted to join rounds except as observers.") return 0 if(!get_config_value(/decl/config/toggle/on/enter_allowed)) - to_chat(usr, "There is an administrative lock on entering the game!") + to_chat(usr, SPAN_WARNING("There is an administrative lock on entering the game!")) return 0 if(!job || !job.is_available(client)) diff --git a/code/modules/mob/observer/ghost/ghost.dm b/code/modules/mob/observer/ghost/ghost.dm index 4ba4b80ad53..acf4b0af582 100644 --- a/code/modules/mob/observer/ghost/ghost.dm +++ b/code/modules/mob/observer/ghost/ghost.dm @@ -372,14 +372,18 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(ishuman(following)) to_chat(src, medical_scan_results(following, 1, SKILL_MAX)) - else to_chat(src, "Not a scannable target.") + else to_chat(src, SPAN_WARNING("\The [following] is not a scannable target.")) /mob/observer/ghost/verb/become_mouse() set name = "Become mouse" set category = "Ghost" + if(get_config_value(/decl/config/enum/server_whitelist) == CONFIG_SERVER_JOIN_WHITELIST && !check_server_whitelist(src)) + to_chat(src, SPAN_WARNING("Non-whitelisted players cannot join rounds except as observers.")) + return + if(get_config_value(/decl/config/toggle/disable_player_mice)) - to_chat(src, "Spawning as a mouse is currently disabled.") + to_chat(src, SPAN_WARNING("Spawning as a mouse is currently disabled.")) return if(!MayRespawn(1, ANIMAL_SPAWN_DELAY)) @@ -387,12 +391,12 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp var/turf/T = get_turf(src) if(!T || isAdminLevel(T.z)) - to_chat(src, "You may not spawn as a mouse on this Z-level.") + to_chat(src, SPAN_WARNING("You may not spawn as a mouse on this Z-level.")) return var/response = alert(src, "Are you -sure- you want to become a mouse?","Are you sure you want to squeek?","Squeek!","Nope!") - if(response != "Squeek!") return //Hit the wrong key...again. - + if(response != "Squeek!") + return //find a viable mouse candidate var/mob/living/simple_animal/passive/mouse/host @@ -405,14 +409,16 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp vent_found = pick(found_vents) host = new /mob/living/simple_animal/passive/mouse(vent_found.loc) else - to_chat(src, "Unable to find any unwelded vents to spawn mice at.") + to_chat(src, SPAN_WARNING("Unable to find any unwelded vents to spawn mice at.")) + if(host) if(get_config_value(/decl/config/toggle/uneducated_mice)) host.universal_understand = FALSE announce_ghost_joinleave(src, 0, "They are now a mouse.") host.ckey = src.ckey host.status_flags |= NO_ANTAG - to_chat(host, "You are now a mouse. Try to avoid interaction with players, and do not give hints away that you are more than a simple rodent.") + to_chat(host, SPAN_INFO("You are now a mouse. Try to avoid interaction with players, and do not give hints away that you are more than a simple rodent.")) + /mob/observer/ghost/verb/view_manfiest() set name = "Show Crew Manifest" set category = "Ghost" diff --git a/code/modules/reagents/reactions/reaction_alcohol.dm b/code/modules/reagents/reactions/reaction_alcohol.dm index b72e14799c1..87ac55aacef 100644 --- a/code/modules/reagents/reactions/reaction_alcohol.dm +++ b/code/modules/reagents/reactions/reaction_alcohol.dm @@ -132,14 +132,14 @@ name = "Apple Cider" result = /decl/material/liquid/ethanol/cider_apple required_reagents = list(/decl/material/liquid/drink/juice/apple = 2, /decl/material/liquid/nutriment/sugar = 1) - catalysts = list(/decl/material/liquid/nutriment = 5) + catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 3 /decl/chemical_reaction/recipe/cider_pear name = "Pear Cider" result = /decl/material/liquid/ethanol/cider_pear required_reagents = list(/decl/material/liquid/drink/juice/pear = 2, /decl/material/liquid/nutriment/sugar = 1) - catalysts = list(/decl/material/liquid/nutriment = 5) + catalysts = list(/decl/material/liquid/enzyme = 5) result_amount = 3 /decl/chemical_reaction/recipe/kvass diff --git a/code/modules/reagents/reactions/reaction_recipe.dm b/code/modules/reagents/reactions/reaction_recipe.dm index a2478bd7353..f8a9797da15 100644 --- a/code/modules/reagents/reactions/reaction_recipe.dm +++ b/code/modules/reagents/reactions/reaction_recipe.dm @@ -72,6 +72,7 @@ result = /decl/material/liquid/nutriment/vinegar required_reagents = list(/decl/material/liquid/drink/juice/apple = 10) catalysts = list(/decl/material/liquid/enzyme = 5) + inhibitors = list(/decl/material/liquid/nutriment/sugar = 1) result_amount = 10 mix_message = "The solution roils as it rapidly ferments into a sharp-smelling liquid." diff --git a/config/example/configuration.txt b/config/example/configuration.txt index ae459e24fc0..13bfd6b1c6d 100644 --- a/config/example/configuration.txt +++ b/config/example/configuration.txt @@ -68,8 +68,8 @@ # Configuration options relating to event timers and probabilities. ## -## Hash out to disable random events during the round. Uncomment to enable. -#ALLOW_RANDOM_EVENTS +## Hash out to disable random events during the round. +#ALLOW_RANDOM_EVENTS 1 ## The lower delay between events in minutes. ## Affect mundane, moderate, and major events respectively. @@ -99,8 +99,8 @@ OBJECTIVES_DISABLED all ## Remove the # to allow people to leave public comments on each other's characters via the comments system. Uncomment to enable. #ALLOW_CHARACTER_COMMENTS -## Allow multiple input keys to be pressed for diagonal movement. Uncomment to enable. -#ALLOW_DIAGONAL_MOVEMENT +## Allow multiple input keys to be pressed for diagonal movement. +#ALLOW_DIAGONAL_MOVEMENT 1 ## These modify the run/walk speed of all mobs before the mob-specific modifiers are applied. #ANIMAL_DELAY 0 @@ -162,9 +162,6 @@ OBJECTIVES_DISABLED all ## Minimum stamina recovered per tick when resting. #MINIMUM_STAMINA_RECOVERY 1 -## Remove the # to let ninjas spawn. Uncomment to enable. -#NINJAS_ALLOWED - ## These modify the run/walk speed of all mobs before the mob-specific modifiers are applied. #ROBOT_DELAY 0 @@ -194,6 +191,9 @@ OBJECTIVES_DISABLED all ## Determines if players can print copy/pasted integrated circuits. #ALLOW_IC_PRINTING 1 +## If true, when bodytype is changed in character creation, selected pronouns are also changed. +#CISNORMATIVITY 1 + ## Determines if ghosts are permitted to write in blood during cult rounds. #CULT_GHOSTWRITER 1 @@ -221,6 +221,9 @@ OBJECTIVES_DISABLED all ## Defines how Law Zero is phrased. Primarily used in the Malfunction gamemode. #LAW_ZERO ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4'ALL LAWS OVERRIDDEN#*?&110010 +## If true, most lightswitches start on by default. Otherwise, they start off. Uncomment to enable. +#LIGHTS_START_ON + ## After this amount alive, walking mushrooms spawned from botany will not reproduce. #MAXIMUM_MUSHROOMS 15 @@ -319,9 +322,6 @@ ROUNDSTART_LEVEL_GENERATION ## log OOC channel Uncomment to enable. #LOG_OOC -## Log PDA messages. Uncomment to enable. -#LOG_PDA - ## Log world.log and runtime errors to a file. Uncomment to enable. #LOG_RUNTIME @@ -354,13 +354,13 @@ ROUNDSTART_LEVEL_GENERATION #FEATURE_OBJECT_SPELL_SYSTEM ## Allowed modes. -#MODES ["crossfire","cult","extended","god","heist","mercenary","ninja","revolution","siege","spyvspy","traitor","uprising","wizard"] +#MODES ["crossfire","cult","extended","heist","mercenary","ninja","revolution","spyvspy","traitor","wizard"] ## Mode names. -#MODE_NAMES {"calamity":"Calamity","cult":"Cult","extended":"Extended","god":"Deity","heist":"Heist","meteor":"Meteor","crossfire":"Mercenary & heist","siege":"Mercenary & revolution","spyvspy":"Spy v. spy","uprising":"Cult & revolution","ninja":"Ninja","mercenary":"Mercenary","revolution":"Revolution","traitor":"Traitor","wizard":"Wizard"} +#MODE_NAMES {"calamity":"Calamity","extended":"Extended","mercenary":"Mercenary","wizard":"Wizard","cult":"Cult","heist":"Heist","ninja":"Ninja","revolution":"Revolution","traitor":"Traitor","spyvspy":"Spy v. spy","crossfire":"Crossfire"} ## Relative probability of each mode. -#PROBABILITIES {"calamity":0,"cult":1,"extended":1,"god":0,"heist":0,"meteor":0,"crossfire":0,"siege":0,"spyvspy":0,"uprising":0,"ninja":0,"mercenary":1,"revolution":0,"traitor":0,"wizard":1} +#PROBABILITIES {"calamity":0,"extended":1,"mercenary":1,"wizard":1,"cult":1,"heist":0,"ninja":0,"revolution":0,"traitor":0,"spyvspy":0,"crossfire":0} ## If security is prohibited from being most antagonists. Uncomment to enable. #PROTECT_ROLES_FROM_ANTAGONIST @@ -369,7 +369,7 @@ ROUNDSTART_LEVEL_GENERATION #TRAITOR_SCALING ## A list of modes that should be votable. -#VOTABLE_MODES ["crossfire","cult","extended","god","heist","mercenary","meteor","ninja","revolution","secret","siege","spyvspy","traitor","uprising","wizard"] +#VOTABLE_MODES ["crossfire","cult","extended","heist","mercenary","ninja","revolution","secret","spyvspy","traitor","wizard"] ## # PROTECTED @@ -377,13 +377,13 @@ ROUNDSTART_LEVEL_GENERATION ## ## Password used for authorizing external tools that can apply bans. -#BAN_COMMS_PASSWORD +#BAN_COMMS_PASSWORD ## Password used for authorizing ircbot and other external tools. -#COMMS_PASSWORD +#COMMS_PASSWORD ## Export address where external tools that monitor logins are located. -#LOGIN_EXPORT_ADDR +#LOGIN_EXPORT_ADDR ## # RESOURCES @@ -413,7 +413,7 @@ ROUNDSTART_LEVEL_GENERATION #ABANDON_ALLOWED 1 ## IRC channel to send adminhelps to. Leave blank to disable adminhelps-to-irc. -#ADMIN_IRC +#ADMIN_IRC ## Add a # infront of this if you want to use the SQL based admin system, the legacy system uses admins.txt. You need to set up your database to use the SQL based system. #ADMIN_LEGACY_SYSTEM 1 @@ -431,7 +431,7 @@ ROUNDSTART_LEVEL_GENERATION #AOOC_ALLOWED 1 ## Ban appeals URL - usually for a forum or wherever people should go to contact your admins. -#BANAPPEALS +#BANAPPEALS ## Add a # infront of this if you want to use the SQL based banning system. The legacy systems use the files in the data folder. You need to set up your database to use the SQL based system. #BAN_LEGACY_SYSTEM 1 @@ -442,7 +442,7 @@ ROUNDSTART_LEVEL_GENERATION ## Sets the minimum number of cultists needed for ghosts to write in blood. #CULT_GHOSTWRITER_REQ_CULTISTS 10 -## Determines if the server should hide itself from the hub when no admins are online.. Uncomment to enable. +## Determines if the server should hide itself from the hub when no admins are online. Uncomment to enable. #DELIST_WHEN_NO_ADMINS ## Uncomment to enable. @@ -452,7 +452,7 @@ ROUNDSTART_LEVEL_GENERATION #DISABLE_WEBHOOK_EMBEDS ## Discord server permanent invite address. -#DISCORDURL +#DISCORDURL ## Comment to disable the dead OOC channel by default. #DOOC_ALLOWED 1 @@ -473,20 +473,20 @@ ROUNDSTART_LEVEL_GENERATION #FORBID_SINGULO_POSSESSION ## Discussion forum address. -#FORUMURL +#FORUMURL ## Defines world FPS. Defaults to 20. ## Can also accept ticklag values (0.9, 0.5, etc) which will automatically be converted to FPS. #FPS 20 ## GitHub address. -#GITHUBURL +#GITHUBURL ## Determines whether or not people without a registered ckey (i.e. guest-*) can connect to your server. Uncomment to enable. #GUESTS_ALLOWED ## Set a hosted by name for UNIX platforms. -#HOSTEDBY +#HOSTEDBY ## Hub visibility: If you want to be visible on the hub, uncomment the below line and be sure that Dream Daemon is set to visible. This can be changed in-round as well with toggle-hub-visibility if Dream Daemon is set correctly. Uncomment to enable. #HUB_VISIBILITY @@ -495,7 +495,7 @@ ROUNDSTART_LEVEL_GENERATION #IRC_BOT_HOST localhost ## GitHub new issue address. -#ISSUEREPORTURL +#ISSUEREPORTURL ## Add a # here if you wish to use the setup where jobs have more access. This is intended for servers with low populations - where there are not enough players to fill all roles, so players need to do more than just one job. Also for servers where they don't want people to hide in their own departments. #JOBS_HAVE_MINIMAL_ACCESS 1 @@ -515,8 +515,11 @@ ROUNDSTART_LEVEL_GENERATION ## IRC channel to send information to. Leave blank to disable. #MAIN_IRC #main -## Remove the # to define a different cap for aspect points in chargen. -#MAX_CHARACTER_ASPECTS 5 +## Remove the # to define a different maximum for alternate language selection in chargen. +#MAX_ALTERNATE_LANGUAGES 3 + +## Remove the # to define a different cap for trait points in chargen. +#MAX_CHARACTER_TRAITS 5 ## This many drones can be active at the same time. #MAX_MAINT_DRONES 5 @@ -551,15 +554,18 @@ ROUNDSTART_LEVEL_GENERATION #RESPAWN_DELAY 30 ## Set a server location for world reboot. Don't include the byond://, just give the address and port. -#SERVER +#SERVER ## Set a server URL for the IRC bot to use; like SERVER, don't include the byond:// ## Unlike SERVER, this one shouldn't break auto-reconnect. -#SERVERURL +#SERVERURL ## Server name: This appears at the top of the screen in-game. #SERVER_NAME Nebula 13 +## Determines how the server should handle whitelisting for ckeys. Whitelisted ckeys are found in 'config/whitelist.txt'. Set to 'none' for no whitelisting, 'jobs' to whitelist sensitive jobs, 'join' to whitelist joining the round (observing and OOC are still available, or 'connect' to whitelist access to the server. Valid values: none, jobs, join, and connect. +#SERVER_WHITELIST none + ## Determinese if a typing indicator shows overhead for people currently writing whispers. Uncomment to enable. #SHOW_TYPING_INDICATOR_FOR_WHISPERS @@ -570,16 +576,11 @@ ROUNDSTART_LEVEL_GENERATION #UNEDUCATED_MICE ## Determines if non-admins are restricted from using humanoid alien races. Uncomment to enable. -#USEALIENWHITELIST +USEALIENWHITELIST ## Determines if the alien whitelist should use SQL instead of the legacy system. (requires the above uncommented as well). Uncomment to enable. #USEALIENWHITELIST_SQL -## Set to jobban everyone who's key is not listed in data/whitelist.txt from Captain, HoS, HoP, CE, RD, CMO, Warden, Security, Detective, and AI positions. -## Uncomment to 1 to jobban, leave commented out to allow these positions for everyone (but see GUEST_JOBBAN above and regular jobbans). -## Uncomment to enable. -#USEWHITELIST - ## Determines if data is sent to the IRC bot. Generally requires MAIN_IRC and associated setup. Uncomment to enable. #USE_IRC_BOT @@ -590,7 +591,7 @@ ROUNDSTART_LEVEL_GENERATION #WAIT_FOR_SIGUSR1_REBOOT ## Wiki address. -#WIKIURL +#WIKIURL ## # VOTING diff --git a/config/example/gamemodes/ninja.txt b/config/example/gamemodes/ninja.txt new file mode 100644 index 00000000000..54175a871c0 --- /dev/null +++ b/config/example/gamemodes/ninja.txt @@ -0,0 +1,7 @@ +## +# NINJA +# Configuration options relating to the Ninja gamemode and antagonist. +## + +## Remove the # to let ninjas spawn in random antag events. Uncomment to enable. +#RANDOM_NINJAS_ALLOWED diff --git a/config/example/server_whitelist.txt b/config/example/server_whitelist.txt new file mode 100644 index 00000000000..e54651129c8 --- /dev/null +++ b/config/example/server_whitelist.txt @@ -0,0 +1 @@ +# Enter ckeys line by line with no whitespace or other formatting for them to be loaded into the server whitelist at runtime. diff --git a/html/changelog.html b/html/changelog.html index 2e5ebf2d793..9c08468f154 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -52,6 +52,13 @@ -->
+

27 September 2024

+

Penelope Haze updated:

+ +

23 September 2024

MistakeNot4892 updated:

diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 9539e2a9211..22eb0c8edb0 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -14875,3 +14875,7 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. 2024-09-23: MistakeNot4892: - tweak: You can now resist out of straightjackets. +2024-09-27: + Penelope Haze: + - imageadd: added overlays to show when a crafted or dried waterskin is closed + - imageadd: added a new sprite for waterskins made from dried ruminant stomachs diff --git a/icons/obj/items/waterskin.dmi b/icons/obj/items/waterskin.dmi index cfce691ae7f..51c693ce7f2 100644 Binary files a/icons/obj/items/waterskin.dmi and b/icons/obj/items/waterskin.dmi differ diff --git a/icons/obj/items/waterskin_crafted.dmi b/icons/obj/items/waterskin_crafted.dmi new file mode 100644 index 00000000000..eca28d255b4 Binary files /dev/null and b/icons/obj/items/waterskin_crafted.dmi differ diff --git a/mods/content/fantasy/items/clothing/_loadout.dm b/mods/content/fantasy/items/clothing/_loadout.dm index a878a4db0af..b1fb27c0c1e 100644 --- a/mods/content/fantasy/items/clothing/_loadout.dm +++ b/mods/content/fantasy/items/clothing/_loadout.dm @@ -262,6 +262,32 @@ ) uid = "gear_fantasy_bandoler" +/decl/loadout_option/fantasy/utility/waterskin + name = "waterskin selection" + path = /obj/item/chems/waterskin + available_materials = null + loadout_flags = null + apply_to_existing_if_possible = TRUE // overwrite beggar knight's wineskin + uid = "gear_fantasy_waterskin" + +/decl/loadout_option/fantasy/utility/waterskin/get_gear_tweak_options() + . = ..() + LAZYDISTINCTADD(.[/datum/gear_tweak/path], list( + "crafted leather waterskin" = /obj/item/chems/waterskin/crafted, + "dried stomach waterskin" = /obj/item/chems/waterskin, + )) + LAZYDISTINCTADD(.[/datum/gear_tweak/reagents], list( + "ale" = /decl/material/liquid/ethanol/ale, + "apple cider" = /decl/material/liquid/ethanol/cider_apple, + "beer" = /decl/material/liquid/ethanol/beer, + "kvass" = /decl/material/liquid/ethanol/kvass, + "pear cider" = /decl/material/liquid/ethanol/cider_pear, + "red wine" = /decl/material/liquid/ethanol/wine, + "sake" = /decl/material/liquid/ethanol/sake, + "water" = /decl/material/liquid/water, + "white wine" = /decl/material/liquid/ethanol/wine/premium, + )) + /decl/loadout_option/fantasy/eyes abstract_type = /decl/loadout_option/fantasy/eyes slot = slot_glasses_str @@ -289,6 +315,7 @@ path = /obj/item/clothing/glasses/prescription/pincenez uid = "gear_fantasy_eyes_glasses" available_materials = null + loadout_flags = null /decl/loadout_option/fantasy/eyes/glasses/get_gear_tweak_options() . = ..() diff --git a/nebula.dme b/nebula.dme index 2ac06947f67..88dab10b95a 100644 --- a/nebula.dme +++ b/nebula.dme @@ -805,7 +805,7 @@ #include "code\game\jobs\_access_defs.dm" #include "code\game\jobs\access.dm" #include "code\game\jobs\access_datum.dm" -#include "code\game\jobs\whitelist.dm" +#include "code\game\jobs\server_whitelist.dm" #include "code\game\jobs\job\_job.dm" #include "code\game\machinery\ai_slipper.dm" #include "code\game\machinery\air_sensor.dm"