Merge branch 'master' into upstream-merge-31727
This commit is contained in:
@@ -59,6 +59,11 @@
|
||||
recharge()
|
||||
dispensable_reagents = sortList(dispensable_reagents)
|
||||
|
||||
/obj/machinery/chem_dispenser/Destroy()
|
||||
QDEL_NULL(beaker)
|
||||
QDEL_NULL(cell)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/chem_dispenser/process()
|
||||
|
||||
if(recharged < 0)
|
||||
@@ -303,6 +308,7 @@
|
||||
if(beaker)
|
||||
beaker.forceMove(drop_location())
|
||||
beaker = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/chem_dispenser/drinks
|
||||
name = "soda dispenser"
|
||||
|
||||
@@ -13,6 +13,28 @@
|
||||
var/heater_coefficient = 0.1
|
||||
var/on = FALSE
|
||||
|
||||
/obj/machinery/chem_heater/Destroy()
|
||||
QDEL_NULL(beaker)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/chem_heater/handle_atom_del(atom/A)
|
||||
. = ..()
|
||||
if(A == beaker)
|
||||
beaker = null
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/chem_heater/update_icon()
|
||||
if(beaker)
|
||||
icon_state = "mixer1b"
|
||||
else
|
||||
icon_state = "mixer0b"
|
||||
|
||||
/obj/machinery/chem_heater/proc/eject_beaker()
|
||||
if(beaker)
|
||||
beaker.forceMove(drop_location())
|
||||
beaker = null
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/chem_heater/RefreshParts()
|
||||
heater_coefficient = 0.1
|
||||
for(var/obj/item/stock_parts/micro_laser/M in component_parts)
|
||||
@@ -52,12 +74,13 @@
|
||||
return
|
||||
beaker = I
|
||||
to_chat(user, "<span class='notice'>You add [I] to [src].</span>")
|
||||
icon_state = "mixer1b"
|
||||
update_icon()
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/machinery/chem_heater/on_deconstruction()
|
||||
eject_beaker()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/chem_heater/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
@@ -108,10 +131,3 @@
|
||||
on = FALSE
|
||||
eject_beaker()
|
||||
. = TRUE
|
||||
|
||||
/obj/machinery/chem_heater/proc/eject_beaker()
|
||||
if(beaker)
|
||||
beaker.forceMove(drop_location())
|
||||
beaker.reagents.handle_reactions()
|
||||
beaker = null
|
||||
icon_state = "mixer0b"
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
var/obj/item/reagent_containers/beaker = null
|
||||
var/obj/item/storage/pill_bottle/bottle = null
|
||||
var/mode = 1
|
||||
var/condi = 0
|
||||
var/condi = FALSE
|
||||
var/screen = "home"
|
||||
var/analyzeVars[0]
|
||||
var/useramount = 30 // Last used amount
|
||||
@@ -23,6 +23,11 @@
|
||||
add_overlay("waitlight")
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/chem_master/Destroy()
|
||||
QDEL_NULL(beaker)
|
||||
QDEL_NULL(bottle)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/chem_master/RefreshParts()
|
||||
reagents.maximum_volume = 0
|
||||
for(var/obj/item/reagent_containers/glass/beaker/B in component_parts)
|
||||
@@ -44,10 +49,22 @@
|
||||
if(A == beaker)
|
||||
beaker = null
|
||||
reagents.clear_reagents()
|
||||
icon_state = "mixer0"
|
||||
update_icon()
|
||||
else if(A == bottle)
|
||||
bottle = null
|
||||
|
||||
/obj/machinery/chem_master/update_icon()
|
||||
if(beaker)
|
||||
icon_state = "mixer1"
|
||||
else
|
||||
icon_state = "mixer0"
|
||||
|
||||
/obj/machinery/chem_master/proc/eject_beaker()
|
||||
if(beaker)
|
||||
beaker.forceMove(drop_location())
|
||||
adjust_item_drop_location(beaker)
|
||||
beaker = null
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/chem_master/blob_act(obj/structure/blob/B)
|
||||
if (prob(50))
|
||||
@@ -61,15 +78,6 @@
|
||||
|
||||
/obj/machinery/chem_master/attackby(obj/item/I, mob/user, params)
|
||||
if(default_deconstruction_screwdriver(user, "mixer0_nopower", "mixer0", I))
|
||||
if(beaker)
|
||||
beaker.forceMove(drop_location())
|
||||
adjust_item_drop_location(beaker)
|
||||
beaker = null
|
||||
reagents.clear_reagents()
|
||||
if(bottle)
|
||||
bottle.forceMove(drop_location())
|
||||
adjust_item_drop_location(bottle)
|
||||
bottle = null
|
||||
return
|
||||
|
||||
else if(exchange_parts(user, I))
|
||||
@@ -94,7 +102,7 @@
|
||||
beaker = I
|
||||
to_chat(user, "<span class='notice'>You add [I] to [src].</span>")
|
||||
src.updateUsrDialog()
|
||||
icon_state = "mixer1"
|
||||
update_icon()
|
||||
|
||||
else if(!condi && istype(I, /obj/item/storage/pill_bottle))
|
||||
if(bottle)
|
||||
@@ -109,6 +117,13 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/chem_master/on_deconstruction()
|
||||
eject_beaker()
|
||||
if(bottle)
|
||||
bottle.forceMove(drop_location())
|
||||
adjust_item_drop_location(bottle)
|
||||
bottle = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/chem_master/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
@@ -154,13 +169,8 @@
|
||||
return
|
||||
switch(action)
|
||||
if("eject")
|
||||
if(beaker)
|
||||
beaker.forceMove(drop_location())
|
||||
adjust_item_drop_location(beaker)
|
||||
beaker = null
|
||||
reagents.clear_reagents()
|
||||
icon_state = "mixer0"
|
||||
. = TRUE
|
||||
eject_beaker()
|
||||
. = TRUE
|
||||
|
||||
if("ejectp")
|
||||
if(bottle)
|
||||
@@ -348,7 +358,7 @@
|
||||
#if DM_VERSION >= 513
|
||||
#warning 512 is definitely stable now, remove the old code
|
||||
#endif
|
||||
|
||||
|
||||
#if DM_VERSION >= 512
|
||||
. += hex2num(md5[i])
|
||||
#else
|
||||
@@ -361,4 +371,4 @@
|
||||
/obj/machinery/chem_master/condimaster
|
||||
name = "CondiMaster 3000"
|
||||
desc = "Used to create condiments and other cooking supplies."
|
||||
condi = 1
|
||||
condi = TRUE
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
QDEL_NULL(beaker)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/pandemic/handle_atom_del(atom/A)
|
||||
. = ..()
|
||||
if(A == beaker)
|
||||
beaker = null
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/computer/pandemic/proc/get_by_index(thing, index)
|
||||
if(!beaker || !beaker.reagents)
|
||||
return
|
||||
@@ -121,9 +127,10 @@
|
||||
add_overlay("waitlight")
|
||||
|
||||
/obj/machinery/computer/pandemic/proc/eject_beaker()
|
||||
beaker.forceMove(drop_location())
|
||||
beaker = null
|
||||
update_icon()
|
||||
if(beaker)
|
||||
beaker.forceMove(drop_location())
|
||||
beaker = null
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/computer/pandemic/ui_interact(mob/user, ui_key = "main", datum/tgui/ui, force_open = FALSE, datum/tgui/master_ui, datum/ui_state/state = GLOB.default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
@@ -159,8 +166,7 @@
|
||||
return
|
||||
switch(action)
|
||||
if("eject_beaker")
|
||||
if(beaker)
|
||||
eject_beaker()
|
||||
eject_beaker()
|
||||
. = TRUE
|
||||
if("empty_beaker")
|
||||
if(beaker)
|
||||
@@ -236,7 +242,5 @@
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/pandemic/on_deconstruction()
|
||||
if(beaker)
|
||||
beaker.forceMove(drop_location())
|
||||
beaker = null
|
||||
eject_beaker()
|
||||
. = ..()
|
||||
|
||||
@@ -109,7 +109,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
|
||||
color = "#664300" // rgb: 102, 67, 0
|
||||
boozepwr = 45
|
||||
glass_icon_state = "kahluaglass"
|
||||
glass_name = "glass of RR Coffee Liquor"
|
||||
glass_name = "glass of RR coffee liquor"
|
||||
glass_desc = "DAMN, THIS THING LOOKS ROBUST!"
|
||||
shot_glass_icon_state = "shotglasscream"
|
||||
|
||||
@@ -341,7 +341,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
|
||||
boozepwr = 25
|
||||
taste_description = "burning cinnamon"
|
||||
glass_icon_state = "goldschlagerglass"
|
||||
glass_name = "glass of Goldschlager"
|
||||
glass_name = "glass of goldschlager"
|
||||
glass_desc = "100% proof that teen girls will drink anything with gold in it."
|
||||
shot_glass_icon_state = "shotglassgold"
|
||||
|
||||
@@ -396,7 +396,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
|
||||
boozepwr = 70
|
||||
taste_description = "cola"
|
||||
glass_icon_state = "whiskeycolaglass"
|
||||
glass_name = "Whiskey Cola"
|
||||
glass_name = "whiskey cola"
|
||||
glass_desc = "An innocent-looking mixture of cola and Whiskey. Delicious."
|
||||
|
||||
/datum/reagent/consumable/ethanol/martini
|
||||
@@ -706,7 +706,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
|
||||
boozepwr = 70
|
||||
taste_description = "soda"
|
||||
glass_icon_state = "whiskeysodaglass2"
|
||||
glass_name = "Whiskey Soda"
|
||||
glass_name = "whiskey soda"
|
||||
glass_desc = "Ultimate refreshment."
|
||||
|
||||
/datum/reagent/consumable/ethanol/antifreeze
|
||||
@@ -785,7 +785,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
|
||||
boozepwr = 70
|
||||
taste_description = "tart bitterness"
|
||||
glass_icon_state = "vodkatonicglass"
|
||||
glass_name = "Vodka and Tonic"
|
||||
glass_name = "vodka and tonic"
|
||||
glass_desc = "For when a gin and tonic isn't Russian enough."
|
||||
|
||||
|
||||
@@ -797,7 +797,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
|
||||
boozepwr = 45
|
||||
taste_description = "dry, tart lemons"
|
||||
glass_icon_state = "ginfizzglass"
|
||||
glass_name = "Gin Fizz"
|
||||
glass_name = "gin fizz"
|
||||
glass_desc = "Refreshingly lemony, deliciously dry."
|
||||
|
||||
|
||||
@@ -870,7 +870,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
|
||||
boozepwr = 15
|
||||
taste_description = "refreshingly cold"
|
||||
glass_icon_state = "iced_beerglass"
|
||||
glass_name = "Iced Beer"
|
||||
glass_name = "iced beer"
|
||||
glass_desc = "A beer so frosty, the air around it freezes."
|
||||
|
||||
/datum/reagent/consumable/ethanol/iced_beer/on_mob_life(mob/living/M)
|
||||
@@ -1069,7 +1069,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
|
||||
boozepwr = 35
|
||||
taste_description = "sour lemons"
|
||||
glass_icon_state = "whiskey_sour"
|
||||
glass_name = "Whiskey Sour"
|
||||
glass_name = "whiskey sour"
|
||||
glass_desc = "Lemon juice mixed with whiskey and a dash of sugar. Surprisingly satisfying."
|
||||
|
||||
/datum/reagent/consumable/ethanol/hcider
|
||||
@@ -1081,7 +1081,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
|
||||
boozepwr = 25
|
||||
taste_description = "apples"
|
||||
glass_icon_state = "whiskeyglass"
|
||||
glass_name = "Hard Cider"
|
||||
glass_name = "hard cider"
|
||||
glass_desc = "Tastes like autumn."
|
||||
shot_glass_icon_state = "shotglassbrown"
|
||||
|
||||
@@ -1279,5 +1279,5 @@ All effects don't start immediately, but rather get worse over time; the rate is
|
||||
boozepwr = 1
|
||||
taste_description = "custard and alcohol"
|
||||
glass_icon_state = "glass_yellow"
|
||||
glass_name = "Eggnog"
|
||||
glass_name = "eggnog"
|
||||
glass_desc = "For enjoying the most wonderful time of the year."
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
description = "Absolutely nothing."
|
||||
taste_description = "nothing"
|
||||
glass_icon_state = "nothing"
|
||||
glass_name = "Nothing"
|
||||
glass_name = "nothing"
|
||||
glass_desc = "Absolutely nothing."
|
||||
shot_glass_icon_state = "shotglass"
|
||||
|
||||
@@ -319,7 +319,7 @@
|
||||
nutriment_factor = 0
|
||||
taste_description = "bitter coldness"
|
||||
glass_icon_state = "icedcoffeeglass"
|
||||
glass_name = "Iced Coffee"
|
||||
glass_name = "iced coffee"
|
||||
glass_desc = "A drink to perk you up and refresh you!"
|
||||
|
||||
/datum/reagent/consumable/icecoffee/on_mob_life(mob/living/M)
|
||||
@@ -340,7 +340,7 @@
|
||||
nutriment_factor = 0
|
||||
taste_description = "sweet tea"
|
||||
glass_icon_state = "icedteaglass"
|
||||
glass_name = "Iced Tea"
|
||||
glass_name = "iced tea"
|
||||
glass_desc = "All natural, antioxidant-rich flavour sensation."
|
||||
|
||||
/datum/reagent/consumable/icetea/on_mob_life(mob/living/M)
|
||||
@@ -361,7 +361,7 @@
|
||||
color = "#100800" // rgb: 16, 8, 0
|
||||
taste_description = "cola"
|
||||
glass_icon_state = "glass_brown"
|
||||
glass_name = "glass of space Cola"
|
||||
glass_name = "glass of Space Cola"
|
||||
glass_desc = "A glass of refreshing Space Cola."
|
||||
|
||||
/datum/reagent/consumable/space_cola/on_mob_life(mob/living/M)
|
||||
@@ -377,7 +377,7 @@
|
||||
color = "#100800" // rgb: 16, 8, 0
|
||||
taste_description = "the future"
|
||||
glass_icon_state = "nuka_colaglass"
|
||||
glass_name = "Nuka Cola"
|
||||
glass_name = "glass of Nuka Cola"
|
||||
glass_desc = "Don't cry, Don't raise your eye, It's only nuclear wasteland."
|
||||
|
||||
/datum/reagent/consumable/nuka_cola/on_mob_life(mob/living/M)
|
||||
@@ -434,7 +434,7 @@
|
||||
color = "#00FF00" // rgb: 0, 255, 0
|
||||
taste_description = "cherry soda"
|
||||
glass_icon_state = "space-up_glass"
|
||||
glass_name = "glass of Space-up"
|
||||
glass_name = "glass of Space-Up"
|
||||
glass_desc = "Space-up. It helps you keep your cool."
|
||||
|
||||
|
||||
@@ -450,7 +450,7 @@
|
||||
color = "#8CFF00" // rgb: 135, 255, 0
|
||||
taste_description = "tangy lime and lemon soda"
|
||||
glass_icon_state = "glass_yellow"
|
||||
glass_name = "glass of Lemon-Lime"
|
||||
glass_name = "glass of lemon-lime"
|
||||
glass_desc = "You're pretty certain a real fruit has never actually touched this."
|
||||
|
||||
|
||||
@@ -481,7 +481,7 @@
|
||||
color = "#f00060" // rgb: 94, 0, 38
|
||||
taste_description = "carbonated metallic soda"
|
||||
glass_icon_state = "glass_red"
|
||||
glass_name = "glass of Shambler's Juice"
|
||||
glass_name = "glass of Shambler's juice"
|
||||
glass_desc = "Mmm mm, shambly."
|
||||
|
||||
/datum/reagent/consumable/shamblers/on_mob_life(mob/living/M)
|
||||
@@ -495,7 +495,7 @@
|
||||
color = "#619494" // rgb: 97, 148, 148
|
||||
taste_description = "carbonated water"
|
||||
glass_icon_state = "glass_clear"
|
||||
glass_name = "glass of Soda Water"
|
||||
glass_name = "glass of soda water"
|
||||
glass_desc = "Soda water. Why not make a scotch and soda?"
|
||||
|
||||
/datum/reagent/consumable/sodawater/on_mob_life(mob/living/M)
|
||||
@@ -512,7 +512,7 @@
|
||||
color = "#0064C8" // rgb: 0, 100, 200
|
||||
taste_description = "tart and fresh"
|
||||
glass_icon_state = "glass_clear"
|
||||
glass_name = "glass of Tonic Water"
|
||||
glass_name = "glass of tonic water"
|
||||
glass_desc = "Quinine tastes funny, but at least it'll keep that Space Malaria away."
|
||||
|
||||
/datum/reagent/consumable/tonic/on_mob_life(mob/living/M)
|
||||
@@ -546,7 +546,7 @@
|
||||
color = "#664300" // rgb: 102, 67, 0
|
||||
taste_description = "creamy coffee"
|
||||
glass_icon_state = "soy_latte"
|
||||
glass_name = "Soy Latte"
|
||||
glass_name = "soy latte"
|
||||
glass_desc = "A nice and refreshing beverage while you're reading."
|
||||
|
||||
/datum/reagent/consumable/soy_latte/on_mob_life(mob/living/M)
|
||||
@@ -568,7 +568,7 @@
|
||||
color = "#664300" // rgb: 102, 67, 0
|
||||
taste_description = "bitter cream"
|
||||
glass_icon_state = "cafe_latte"
|
||||
glass_name = "Cafe Latte"
|
||||
glass_name = "cafe latte"
|
||||
glass_desc = "A nice, strong and refreshing beverage while you're reading."
|
||||
|
||||
/datum/reagent/consumable/cafe_latte/on_mob_life(mob/living/M)
|
||||
@@ -612,7 +612,7 @@
|
||||
nutriment_factor = 4 * REAGENTS_METABOLISM
|
||||
taste_description = "sweet chocolate"
|
||||
glass_icon_state = "chocolatepudding"
|
||||
glass_name = "Chocolate Pudding"
|
||||
glass_name = "chocolate pudding"
|
||||
glass_desc = "Tasty."
|
||||
|
||||
/datum/reagent/consumable/vanillapudding
|
||||
@@ -623,7 +623,7 @@
|
||||
nutriment_factor = 4 * REAGENTS_METABOLISM
|
||||
taste_description = "sweet vanilla"
|
||||
glass_icon_state = "vanillapudding"
|
||||
glass_name = "Vanilla Pudding"
|
||||
glass_name = "vanilla pudding"
|
||||
glass_desc = "Tasty."
|
||||
|
||||
/datum/reagent/consumable/cherryshake
|
||||
@@ -634,7 +634,7 @@
|
||||
nutriment_factor = 4 * REAGENTS_METABOLISM
|
||||
taste_description = "creamy cherry"
|
||||
glass_icon_state = "cherryshake"
|
||||
glass_name = "Cherry Shake"
|
||||
glass_name = "cherry shake"
|
||||
glass_desc = "A cherry flavored milkshake."
|
||||
|
||||
/datum/reagent/consumable/bluecherryshake
|
||||
@@ -645,7 +645,7 @@
|
||||
nutriment_factor = 4 * REAGENTS_METABOLISM
|
||||
taste_description = "creamy blue cherry"
|
||||
glass_icon_state = "bluecherryshake"
|
||||
glass_name = "Blue Cherry Shake"
|
||||
glass_name = "blue cherry shake"
|
||||
glass_desc = "An exotic blue milkshake."
|
||||
|
||||
/datum/reagent/consumable/pumpkin_latte
|
||||
@@ -656,7 +656,7 @@
|
||||
nutriment_factor = 3 * REAGENTS_METABOLISM
|
||||
taste_description = "creamy pumpkin"
|
||||
glass_icon_state = "pumpkin_latte"
|
||||
glass_name = "Pumpkin Latte"
|
||||
glass_name = "pumpkin latte"
|
||||
glass_desc = "A mix of coffee and pumpkin juice."
|
||||
|
||||
/datum/reagent/consumable/gibbfloats
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
taste_description = "water"
|
||||
var/cooling_temperature = 2
|
||||
glass_icon_state = "glass_clear"
|
||||
glass_name = "glass of Water"
|
||||
glass_name = "glass of water"
|
||||
glass_desc = "The father of all refreshments."
|
||||
shot_glass_icon_state = "shotglassclear"
|
||||
|
||||
@@ -188,7 +188,7 @@
|
||||
description = "Water blessed by some deity."
|
||||
color = "#E0E8EF" // rgb: 224, 232, 239
|
||||
glass_icon_state = "glass_clear"
|
||||
glass_name = "glass of Holy Water"
|
||||
glass_name = "glass of holy water"
|
||||
glass_desc = "A glass of holy water."
|
||||
|
||||
/datum/reagent/water/holywater/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
|
||||
|
||||
@@ -139,7 +139,6 @@
|
||||
/datum/chemical_reaction/reagent_explosion/methsplosion
|
||||
name = "Meth explosion"
|
||||
id = "methboom1"
|
||||
results = list("methboom1" = 1)
|
||||
required_temp = 380 //slightly above the meth mix time.
|
||||
required_reagents = list("methamphetamine" = 1)
|
||||
strengthdiv = 6
|
||||
@@ -154,9 +153,9 @@
|
||||
..()
|
||||
|
||||
/datum/chemical_reaction/reagent_explosion/methsplosion/methboom2
|
||||
id = "methboom2"
|
||||
required_reagents = list("diethylamine" = 1, "iodine" = 1, "phosphorus" = 1, "hydrogen" = 1) //diethylamine is often left over from mixing the ephedrine.
|
||||
required_temp = 300 //room temperature, chilling it even a little will prevent the explosion
|
||||
results = list("methboom1" = 4) // this is ugly. Sorry goof.
|
||||
required_temp = 300 //room temperature, chilling it even a little will prevent the explosion
|
||||
|
||||
/datum/chemical_reaction/sorium
|
||||
name = "Sorium"
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
if(51 to INFINITY)
|
||||
icon_state = "full"
|
||||
|
||||
/obj/item/reagent_containers/blood/random
|
||||
icon_state = "random_bloodpack"
|
||||
|
||||
/obj/item/reagent_containers/blood/random/Initialize()
|
||||
blood_type = pick("A+", "A-", "B+", "B-", "O+", "O-", "L")
|
||||
. = ..()
|
||||
|
||||
Reference in New Issue
Block a user