diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 4b2d36ab229..efdae5c8da7 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -513,6 +513,7 @@ text = replacetext(text, "\[cell\]", "") text = replacetext(text, "\[logo\]", "​") text = replacetext(text, "\[time\]", "[station_time_timestamp()]") // TO DO + text = replacetext(text, "\[date\]", "[GLOB.current_date_string]") if(!no_font) if(P) text = "[text]" @@ -651,3 +652,22 @@ // return the split html object to the caller return s + +/** + * Proc to generate a "rank colour" from a client + * + * This takes the client and looks at various factors in order, such as patreon status, staff rank, and more + * Arguments: + * * C - The client were looking up + */ +/proc/client2rankcolour(client/C) + // First check if end user is an admin + if(C.holder) + if(C.holder.rank in GLOB.rank_colour_map) + // Return their rank colour if they are in here + return GLOB.rank_colour_map[C.holder.rank] + + // If they arent an admin, see if they are a patreon. Just accept any level + if(C.donator_level) + return "#e67e22" // Patreon orange + return null diff --git a/code/_globalvars/lists/misc.dm b/code/_globalvars/lists/misc.dm index ebdf2017900..b5fd84ef6d6 100644 --- a/code/_globalvars/lists/misc.dm +++ b/code/_globalvars/lists/misc.dm @@ -54,4 +54,7 @@ GLOBAL_LIST_INIT(cooking_recipes, list(RECIPE_MICROWAVE = list(), RECIPE_OVEN = GLOBAL_LIST_INIT(cooking_ingredients, list(RECIPE_MICROWAVE = list(), RECIPE_OVEN = list(), RECIPE_GRILL = list(), RECIPE_CANDY = list())) GLOBAL_LIST_INIT(cooking_reagents, list(RECIPE_MICROWAVE = list(), RECIPE_OVEN = list(), RECIPE_GRILL = list(), RECIPE_CANDY = list())) +/// Associative list of admin rank to colour. Set in config/rank_colours.txt +GLOBAL_LIST_EMPTY(rank_colour_map) + #define EGG_LAYING_MESSAGES list("lays an egg.", "squats down and croons.", "begins making a huge racket.", "begins clucking raucously.") diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 1636385006b..ec449fa86aa 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -622,3 +622,34 @@ runnable_modes[M] = probabilities[M.config_tag] // to_chat(world, "DEBUG: runnable_mode\[[runnable_modes.len]\] = [M.config_tag]") return runnable_modes + +/datum/configuration/proc/load_rank_colour_map() + var/list/lines = file2list("config/rank_colours.txt") + + for(var/line in lines) + // Skip newlines + if(!length(line)) + continue + // Skip comments + if(line[1] == "#") + continue + + //Split the line at every " - " + var/list/split_holder = splittext(line, " - ") + if(!length(split_holder)) + continue + + // Rank is before the " - " + var/rank = split_holder[1] + if(!rank) + continue + + // Color is after the " - " + var/colour = "" + if(length(split_holder) >= 2) + colour = split_holder[2] + + if(rank && colour) + GLOB.rank_colour_map[rank] = colour + else + stack_trace("Invalid colour for rank '[rank]' in config/rank_colours.txt") diff --git a/code/game/objects/structures/crates_lockers/closets/secure/chaplain.dm b/code/game/objects/structures/crates_lockers/closets/secure/chaplain.dm index ef80d50371a..55e44163a06 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/chaplain.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/chaplain.dm @@ -22,6 +22,7 @@ new /obj/item/storage/backpack/cultpack(src) new /obj/item/clothing/head/helmet/riot/knight/templar(src) new /obj/item/clothing/suit/armor/riot/knight/templar(src) + new /obj/item/clothing/suit/storage/labcoat(src) new /obj/item/soulstone/anybody/purified/chaplain(src) new /obj/item/storage/fancy/candle_box/eternal(src) new /obj/item/storage/fancy/candle_box/eternal(src) diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm index 4a0429dd576..4c21afebdd2 100644 --- a/code/game/verbs/who.dm +++ b/code/game/verbs/who.dm @@ -1,63 +1,98 @@ - /client/verb/who() set name = "Who" set category = "OOC" - var/msg = "Current Players:\n" + var/list/lines = list() + var/list/temp = list() + for(var/client/C in GLOB.clients) + if(C.holder && C.holder.big_brother) // BB doesn't show up at all + continue + + if(C.holder && C.holder.fakekey) + temp += C.holder.fakekey + else + temp += C.key + + temp = sortList(temp) // Sort it. We dont do this above because fake keys would be out of order, which would be a giveaway + + var/list/output_players = list() + + // Now go over it again to apply colours. + for(var/p in temp) + var/client/C = GLOB.directory[ckey(p)] + if(!C) + // This should NEVER happen, but better to be safe + continue + // Get the colour + var/colour = client2rankcolour(C) + var/out = "[p]" + if(C.holder) + out = "[out]" + if(colour) + out = "[out]" + + output_players += out + + lines += "Current Players ([length(output_players)]): " + lines += output_players.Join(", ") // Turn players into a comma separated list + + if(check_rights(R_ADMIN, FALSE)) + lines += "Click here for detailed (old) who." + + var/msg = lines.Join("\n") + + to_chat(src, msg) + +// Advanced version of `who` to show player age, antag status and more. Lags the chat when loading, so its in its own proc +/client/proc/who_advanced() + if(!check_rights(R_ADMIN)) + return var/list/Lines = list() - if(check_rights(R_ADMIN,0)) - for(var/client/C in GLOB.clients) - if(C.holder && C.holder.big_brother && !check_rights(R_PERMISSIONS, 0)) // need PERMISSIONS to see BB - continue + for(var/client/C in GLOB.clients) + if(C.holder && C.holder.big_brother && !check_rights(R_PERMISSIONS, FALSE)) // need PERMISSIONS to see BB + continue - var/entry = "\t[C.key]" - if(C.holder && C.holder.fakekey) - entry += " (as [C.holder.fakekey])" - entry += " - Playing as [C.mob.real_name]" - switch(C.mob.stat) - if(UNCONSCIOUS) - entry += " - Unconscious" - if(DEAD) - if(isobserver(C.mob)) - var/mob/dead/observer/O = C.mob - if(O.started_as_observer) - entry += " - Observing" - else - entry += " - DEAD" - else if(isnewplayer(C.mob)) - entry += " - New Player" + var/entry = "\t[C.key]" + if(C.holder && C.holder.fakekey) + entry += " (as [C.holder.fakekey])" + entry += " - Playing as [C.mob.real_name]" + switch(C.mob.stat) + if(UNCONSCIOUS) + entry += " - Unconscious" + if(DEAD) + if(isobserver(C.mob)) + var/mob/dead/observer/O = C.mob + if(O.started_as_observer) + entry += " - Observing" else entry += " - DEAD" + else if(isnewplayer(C.mob)) + entry += " - New Player" + else + entry += " - DEAD" - var/age - if(isnum(C.player_age)) - age = C.player_age - else - age = 0 + var/age + if(isnum(C.player_age)) + age = C.player_age + else + age = 0 - if(age <= 1) - age = "[age]" - else if(age < 10) - age = "[age]" + if(age <= 1) + age = "[age]" + else if(age < 10) + age = "[age]" - entry += " - [age]" + entry += " - [age]" - if(is_special_character(C.mob)) - entry += " - Antagonist" - entry += " ([ADMIN_QUE(C.mob,"?")])" - Lines += entry - else - for(var/client/C in GLOB.clients) - if(C.holder && C.holder.big_brother) // BB doesn't show up at all - continue + if(is_special_character(C.mob)) + entry += " - Antagonist" + entry += " ([ADMIN_QUE(C.mob, "?")])" + Lines += entry - if(C.holder && C.holder.fakekey) - Lines += C.holder.fakekey - else - Lines += C.key + var/msg = "" for(var/line in sortList(Lines)) msg += "[line]\n" @@ -83,7 +118,12 @@ if(C.holder.big_brother && !check_rights(R_PERMISSIONS, 0)) // normal admins can't see BB continue - msg += "\t[C] is a [C.holder.rank]" + // Their rank may not have a defined colour, only set colour if so + var/rank_colour = client2rankcolour(C) + if(rank_colour) + msg += "[C] is a [C.holder.rank]" + else + msg += "[C] is a [C.holder.rank]" if(C.holder.fakekey) msg += " (as [C.holder.fakekey])" @@ -102,7 +142,12 @@ num_admins_online++ else if(check_rights(R_MENTOR|R_MOD, 0, C.mob)) - modmsg += "\t[C] is a [C.holder.rank]" + // Their rank may not have a defined colour, only set colour if so + var/rank_colour = client2rankcolour(C) + if(rank_colour) + modmsg += "[C] is a [C.holder.rank]" + else + modmsg += "[C] is a [C.holder.rank]" if(isobserver(C.mob)) modmsg += " - Observing" @@ -120,10 +165,20 @@ if(check_rights(R_ADMIN, 0, C.mob)) if(!C.holder.fakekey) - msg += "\t[C] is a [C.holder.rank]\n" + var/rank_colour = client2rankcolour(C) + if(rank_colour) + msg += "[C] is a [C.holder.rank]" + else + msg += "[C] is a [C.holder.rank]" + msg += "\n" num_admins_online++ else if(check_rights(R_MOD|R_MENTOR, 0, C.mob) && !check_rights(R_ADMIN, 0, C.mob)) - modmsg += "\t[C] is a [C.holder.rank]\n" + var/rank_colour = client2rankcolour(C) + if(rank_colour) + modmsg += "[C] is a [C.holder.rank]" + else + modmsg += "[C] is a [C.holder.rank]" + modmsg += "\n" num_mods_online++ var/noadmins_info = "\nIf no admins or mentors are online, make a ticket anyways. Adminhelps and mentorhelps will be relayed to discord, and staff will still be informed." diff --git a/code/game/world.dm b/code/game/world.dm index d327057082b..9386f856dac 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -196,6 +196,7 @@ GLOBAL_LIST_EMPTY(world_topic_handlers) config = new /datum/configuration() config.load("config/config.txt") config.load("config/game_options.txt","game_options") + config.load_rank_colour_map() // apply some settings from config.. /world/proc/update_status() diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 754b4c45924..e1c3b3c4e97 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -3556,6 +3556,8 @@ var/datum/browser/popup = new(usr, "view_karma", "Karma stats for [target_ckey]", 600, 300) popup.set_content(dat) popup.open(FALSE) + else if(href_list["who_advanced"]) + usr.client.who_advanced() /client/proc/create_eventmob_for(mob/living/carbon/human/H, killthem = 0) if(!check_rights(R_EVENT)) diff --git a/code/modules/food_and_drinks/food/condiment.dm b/code/modules/food_and_drinks/food/condiment.dm index 898d3f3cc71..897e11443ff 100644 --- a/code/modules/food_and_drinks/food/condiment.dm +++ b/code/modules/food_and_drinks/food/condiment.dm @@ -23,6 +23,7 @@ "sodiumchloride" = list("saltshakersmall", "salt shaker", "Salt. From space oceans, presumably"), "blackpepper" = list("peppermillsmall", "pepper mill", "Often used to flavor food or make people sneeze"), "cornoil" = list("oliveoil", "corn oil bottle", "A delicious oil used in cooking. Made from corn"), + "wasabi" = list("wasabitube", "wasabi bottle", "A pungent paste commonly served in tiny amounts with sushi. Spicy!"), "sugar" = list("emptycondiment", "sugar bottle", "Tasty spacey sugar!")) var/originalname = "condiment" //Can't use initial(name) for this. This stores the name set by condimasters. diff --git a/code/modules/hydroponics/grown/nettle.dm b/code/modules/hydroponics/grown/nettle.dm index 97d35aa4eed..da7c63393b2 100644 --- a/code/modules/hydroponics/grown/nettle.dm +++ b/code/modules/hydroponics/grown/nettle.dm @@ -11,7 +11,7 @@ growthstages = 5 genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/plant_type/weed_hardy) mutatelist = list(/obj/item/seeds/nettle/death) - reagents_add = list("sacid" = 0.5) + reagents_add = list("wasabi" = 0.15) /obj/item/seeds/nettle/death name = "pack of death-nettle seeds" diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index 85efba9e5dd..543989bb146 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -1,6 +1,6 @@ /obj/item/gun/energy/laser name = "laser gun" - desc = "A basic energy-based laser gun that fires concentrated beams of light which pass through glass and thin metal." + desc = "A WT-650 'Sentinel' laser carbine manufactured by Warp-Tac Inc. The golden shield of Nanotrasen Security is visible." icon_state = "laser" item_state = "laser" w_class = WEIGHT_CLASS_NORMAL @@ -8,7 +8,7 @@ origin_tech = "combat=4;magnets=2" ammo_type = list(/obj/item/ammo_casing/energy/lasergun) ammo_x_offset = 1 - shaded_charge = 1 + shaded_charge = TRUE /obj/item/gun/energy/laser/practice name = "practice laser gun" diff --git a/code/modules/projectiles/guns/energy/nuclear.dm b/code/modules/projectiles/guns/energy/nuclear.dm index 3d9925da974..a39e018909a 100644 --- a/code/modules/projectiles/guns/energy/nuclear.dm +++ b/code/modules/projectiles/guns/energy/nuclear.dm @@ -1,15 +1,15 @@ /obj/item/gun/energy/gun name = "energy gun" - desc = "A basic energy-based gun with two settings: kill and disable." + desc = "An E-07 energy gun manufactured by Shellguard Munitions. The fire selector has 'kill' and 'disable' settings." icon_state = "energy" item_state = null //so the human update icon uses the icon_state instead. ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser) origin_tech = "combat=4;magnets=3" modifystate = 2 can_flashlight = 1 - ammo_x_offset = 3 - flight_x_offset = 15 + flight_x_offset = 20 flight_y_offset = 10 + shaded_charge = TRUE /obj/item/gun/energy/gun/cyborg desc = "An energy-based laser gun that draws power from the cyborg's internal energy cell directly. So this is what freedom looks like?" @@ -30,6 +30,7 @@ charge_sections = 3 can_flashlight = 0 // Can't attach or detach the flashlight, and override it's icon update actions_types = list(/datum/action/item_action/toggle_gunlight) + shaded_charge = FALSE /obj/item/gun/energy/gun/mini/Initialize(mapload, ...) gun_light = new /obj/item/flashlight/seclite(src) @@ -51,6 +52,7 @@ ammo_type = list(/obj/item/ammo_casing/energy/electrode/hos, /obj/item/ammo_casing/energy/laser/hos, /obj/item/ammo_casing/energy/disabler) ammo_x_offset = 4 resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF + shaded_charge = FALSE /obj/item/gun/energy/gun/blueshield name = "advanced stun revolver" @@ -60,7 +62,7 @@ force = 7 ammo_type = list(/obj/item/ammo_casing/energy/electrode/hos, /obj/item/ammo_casing/energy/laser/hos) ammo_x_offset = 1 - shaded_charge = 1 + shaded_charge = TRUE /obj/item/gun/energy/gun/blueshield/pdw9 name = "PDW-9 taser pistol" @@ -79,6 +81,7 @@ can_flashlight = 0 trigger_guard = TRIGGER_GUARD_NONE ammo_x_offset = 2 + shaded_charge = FALSE /obj/item/gun/energy/gun/nuclear name = "advanced energy gun" @@ -92,3 +95,4 @@ ammo_x_offset = 1 ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/laser, /obj/item/ammo_casing/energy/disabler) selfcharge = 1 + shaded_charge = FALSE diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm index 141366dd5d9..2247a1a6c9c 100644 --- a/code/modules/projectiles/guns/energy/stun.dm +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -15,7 +15,7 @@ origin_tech = "combat=4;materials=4;powerstorage=4" ammo_type = list(/obj/item/ammo_casing/energy/shock_revolver) can_flashlight = 0 - shaded_charge = 1 + shaded_charge = FALSE /obj/item/gun/energy/gun/advtaser name = "hybrid taser" @@ -24,6 +24,8 @@ ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/disabler) origin_tech = "combat=4" ammo_x_offset = 2 + flight_x_offset = 15 + shaded_charge = FALSE /obj/item/gun/energy/gun/advtaser/cyborg name = "cyborg taser" diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm index 2422c7a143d..1c6981ff0b5 100644 --- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm +++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm @@ -30,7 +30,7 @@ /obj/item/stack/sheet/mineral/tranquillite = list("nothing" = 20), /obj/item/stack/sheet/mineral/silver = list("silver" = 20), /obj/item/stack/sheet/mineral/gold = list("gold" = 20), - /obj/item/grown/nettle/basic = list("sacid" = 0), + /obj/item/grown/nettle/basic = list("wasabi" = 0), /obj/item/grown/nettle/death = list("facid" = 0, "sacid" = 0), /obj/item/grown/novaflower = list("capsaicin" = 0, "condensedcapsaicin" = 0), diff --git a/code/modules/reagents/chemistry/reagents/food.dm b/code/modules/reagents/chemistry/reagents/food.dm index d22adff060d..38430bc3dce 100644 --- a/code/modules/reagents/chemistry/reagents/food.dm +++ b/code/modules/reagents/chemistry/reagents/food.dm @@ -794,6 +794,21 @@ color = "#B4641B" taste_description = "gravy" +/datum/reagent/consumable/wasabi + name = "Wasabi" + id = "wasabi" + description = "A pungent green paste often served with sushi. Consuming too much causes an uncomfortable burning sensation in the nostrils." + reagent_state = LIQUID + color = "#80942F" + taste_description = "pungency" + +/datum/reagent/consumable/wasabi/reaction_mob(mob/living/M, method=REAGENT_TOUCH, volume) + if(method == REAGENT_INGEST) + if(volume <= 1) + to_chat(M, "Your nostrils tingle briefly.") + else + to_chat(M, "Your nostrils burn uncomfortably!") + M.adjustFireLoss(1) ///Food Related, but non-nutritious diff --git a/config/example/rank_colours.txt b/config/example/rank_colours.txt new file mode 100644 index 00000000000..b35641c39f4 --- /dev/null +++ b/config/example/rank_colours.txt @@ -0,0 +1,11 @@ +# Use this file to denote colours for ingame admin ranks, using the following format +# Rankname - #12A5F4 +# Colours dont have to be in hex, since this colour string is thrown into the style -aa +Head of Staff - #e74c3c +Maintainer - #992d22 +Server Dev - #1abc9c +Community Manager - #e91e63 +Game Admin - #238afa +Trial Admin - #7fb6fc +PR Reviewer - #c27c0e +Mentor - #f1c40f diff --git a/icons/mob/inhands/guns_lefthand.dmi b/icons/mob/inhands/guns_lefthand.dmi index 52a1adef4b2..d69dd8a988b 100644 Binary files a/icons/mob/inhands/guns_lefthand.dmi and b/icons/mob/inhands/guns_lefthand.dmi differ diff --git a/icons/mob/inhands/guns_righthand.dmi b/icons/mob/inhands/guns_righthand.dmi index 9a1ee42f32b..44968461e65 100644 Binary files a/icons/mob/inhands/guns_righthand.dmi and b/icons/mob/inhands/guns_righthand.dmi differ diff --git a/icons/obj/food/containers.dmi b/icons/obj/food/containers.dmi index ed71b4d3c1d..8a317b9edb0 100644 Binary files a/icons/obj/food/containers.dmi and b/icons/obj/food/containers.dmi differ diff --git a/icons/obj/guns/energy.dmi b/icons/obj/guns/energy.dmi index a0c6981f7c8..812b0bfba23 100644 Binary files a/icons/obj/guns/energy.dmi and b/icons/obj/guns/energy.dmi differ