Skip to content

Commit 84c5d13

Browse files
authored
Merge pull request #5157 from MistakeNot4892/feature/quern
Generalizes some structure reagent handling, adds a quern.
2 parents 5a9ba3d + 3989f99 commit 84c5d13

File tree

11 files changed

+191
-80
lines changed

11 files changed

+191
-80
lines changed

code/game/objects/items/_item_reagents.dm

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
/obj/item/proc/standard_dispenser_refill(mob/user, obj/structure/reagent_dispensers/target, skip_container_check = FALSE) // This goes into afterattack
2-
if(!istype(target) || (!skip_container_check && (target.atom_flags & ATOM_FLAG_OPEN_CONTAINER)))
1+
/obj/item/proc/standard_dispenser_refill(mob/user, obj/structure/target, skip_container_check = FALSE) // This goes into afterattack
2+
if(!istype(target) || isnull(target.get_reagent_amount_dispensed()) || (!skip_container_check && (target.atom_flags & ATOM_FLAG_OPEN_CONTAINER)))
33
return FALSE
44

55
if(!target.reagents || !target.reagents.total_volume)
@@ -10,7 +10,7 @@
1010
to_chat(user, SPAN_NOTICE("[src] is full of reagents."))
1111
return TRUE
1212

13-
var/trans = target.reagents.trans_to_obj(src, target.amount_dispensed)
13+
var/trans = target.reagents.trans_to_obj(src, target.get_reagent_amount_dispensed())
1414
to_chat(user, SPAN_NOTICE("You fill [src] with [trans] units of the contents of [target]."))
1515
return TRUE
1616

code/game/objects/structures/__structure.dm

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,32 @@
6969
lock = new /datum/lock(src, lock)
7070
if(!CanFluidPass())
7171
fluid_update(TRUE)
72+
if (!isnull(get_possible_reagent_transfer_amounts()))
73+
verbs |= /obj/structure/proc/set_reagent_amount_dispensed_verb
7274

7375
/obj/structure/get_examine_strings(mob/user, distance, infix, suffix)
7476
. = ..()
75-
if(distance <= 3)
76-
if(distance <= 1 && lock)
77-
. += SPAN_NOTICE("\The [src] appears to have a lock, opened by '[lock.lock_data]'.")
78-
var/damage_desc = get_examined_damage_string()
79-
if(length(damage_desc))
80-
. += damage_desc
81-
if(paint_color)
82-
var/decl/pronouns/structure_pronouns = get_pronouns() // so we can do 'have' for plural objects like sheets
83-
. += "\The [src] [structure_pronouns.has] been <font color='[paint_color]'>[paint_verb]</font>."
77+
if(distance > 3)
78+
return
79+
if(distance <= 1 && lock)
80+
. += SPAN_NOTICE("\The [src] appears to have a lock, opened by '[lock.lock_data]'.")
81+
var/damage_desc = get_examined_damage_string()
82+
if(length(damage_desc))
83+
. += damage_desc
84+
if(paint_color)
85+
var/decl/pronouns/structure_pronouns = get_pronouns() // so we can do 'have' for plural objects like sheets
86+
. += "\The [src] [structure_pronouns.has] been <font color='[paint_color]'>[paint_verb]</font>."
87+
if(distance <= 2 && !isnull(get_possible_reagent_transfer_amounts()) && reagents)
88+
. += SPAN_NOTICE("It contains:")
89+
if(LAZYLEN(reagents.reagent_volumes))
90+
for(var/decl/material/reagent as anything in reagents.liquid_volumes)
91+
. += SPAN_NOTICE("[LIQUID_VOLUME(reagents, reagent)] unit\s of [reagent.get_reagent_name(reagents, MAT_PHASE_LIQUID)].")
92+
for(var/decl/material/reagent as anything in reagents.solid_volumes)
93+
. += SPAN_NOTICE("[SOLID_VOLUME(reagents, reagent)] unit\s of [reagent.get_reagent_name(reagents, MAT_PHASE_SOLID)].")
94+
else
95+
. += SPAN_NOTICE("Nothing.")
96+
if(reagents.maximum_volume)
97+
. += "It may contain up to [reagents.maximum_volume] unit\s."
8498

8599
/obj/structure/get_examine_hints(mob/user, distance, infix, suffix)
86100
. = ..()
@@ -345,3 +359,8 @@ Note: This proc can be overwritten to allow for different types of auto-alignmen
345359
visible_message(SPAN_DANGER("\The [src] was hit by \the [AM]."))
346360
playsound(src.loc, hitsound, 100, 1)
347361
take_damage(AM.get_thrown_attack_force() * (TT.speed/THROWFORCE_SPEED_DIVISOR), AM.atom_damage_type)
362+
363+
/obj/structure/get_alt_interactions(var/mob/user)
364+
. = ..()
365+
if(!isnull(get_possible_reagent_transfer_amounts()))
366+
LAZYADD(., /decl/interaction_handler/set_transfer/structure)

code/game/objects/structures/_structure_construction.dm

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@
6161

6262
/obj/structure/attackby(obj/item/used_item, mob/user)
6363

64+
// We do this here to avoid putting the vessel straight into storage.
65+
// This is usually handled by afterattack on /chems.
66+
if(storage && !isnull(get_possible_reagent_transfer_amounts()) && ATOM_IS_OPEN_CONTAINER(used_item) && user.check_intent(I_FLAG_HELP))
67+
if(used_item.standard_dispenser_refill(user, src))
68+
return TRUE
69+
if(used_item.standard_pour_into(user, src))
70+
return TRUE
71+
6472
if(used_item.user_can_attack_with(user, silent = TRUE))
6573
var/force = used_item.expend_attack_force(user)
6674
if(force && user.check_intent(I_FLAG_HARM))
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/obj/structure/receive_mouse_drop(atom/dropping, mob/user, params)
2+
if((. = ..()) || user?.get_active_held_item() != dropping || !isitem(dropping) || isnull(get_possible_reagent_transfer_amounts()))
3+
return
4+
// Awful. Sorry.
5+
var/obj/item/item = dropping
6+
var/old_atom_flags = atom_flags
7+
atom_flags |= ATOM_FLAG_OPEN_CONTAINER
8+
if(item.standard_pour_into(user, src))
9+
. = TRUE
10+
atom_flags = old_atom_flags
11+
12+
/obj/structure/proc/get_reagent_amount_dispensed()
13+
return null
14+
15+
/obj/structure/proc/set_reagent_amount_dispensed()
16+
return null
17+
18+
/obj/structure/proc/set_reagent_amount_dispensed_verb()
19+
set name = "Set amount dispensed"
20+
set category = "Object"
21+
set src in view(1)
22+
if(!CanPhysicallyInteract(usr))
23+
to_chat(usr, SPAN_NOTICE("You're in no condition to do that!"))
24+
return
25+
var/new_amount = input("Amount dispensed:","[src]") as null|anything in get_possible_reagent_transfer_amounts()
26+
if(!CanPhysicallyInteract(usr)) // because input takes time and the situation can change
27+
to_chat(usr, SPAN_NOTICE("You're in no condition to do that!'"))
28+
return
29+
if (new_amount)
30+
set_reagent_amount_dispensed(new_amount)
31+
32+
/obj/structure/proc/get_possible_reagent_transfer_amounts()
33+
return null
34+
35+
//Set amount dispensed. Added manually to querns and reagent dispensers.
36+
/decl/interaction_handler/set_transfer/structure
37+
expected_target_type = /obj/structure
38+
39+
/decl/interaction_handler/set_transfer/structure/is_possible(var/atom/target, var/mob/user)
40+
. = ..()
41+
if(.)
42+
var/obj/structure/dispenser = target
43+
return !isnull(dispenser.get_possible_reagent_transfer_amounts())
44+
45+
/decl/interaction_handler/set_transfer/structure/invoked(atom/target, mob/user, obj/item/prop)
46+
var/obj/structure/dispenser = target
47+
dispenser.set_reagent_amount_dispensed_verb()

code/modules/assembly/igniter.dm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
if(location)
2424
location.hotspot_expose(1000,1000)
2525
if (istype(src.loc,/obj/item/assembly_holder))
26-
if (istype(src.loc.loc, /obj/structure/reagent_dispensers/fueltank/))
26+
if (istype(src.loc.loc, /obj/structure/reagent_dispensers/fueltank))
2727
var/obj/structure/reagent_dispensers/fueltank/tank = src.loc.loc
2828
if(tank)
2929
tank.try_detonate_reagents()
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/datum/storage/hopper/mortar/quern
2+
max_w_class = ITEM_SIZE_SMALL
3+
max_storage_space = DEFAULT_BOX_STORAGE
4+
5+
/obj/structure/working/quern
6+
name = "quern-stone"
7+
desc = "A pair of heavy stones connected by an axle, used to grind plants and minerals into powder."
8+
icon = 'icons/obj/structures/quern.dmi'
9+
material = /decl/material/solid/stone/granite
10+
color = /decl/material/solid/stone/granite::color
11+
storage = /datum/storage/hopper/mortar/quern
12+
work_skill = SKILL_COOKING // Maybe?
13+
var/tmp/volume = 1000 // Same as reagent dispensers. Possibly too large?
14+
var/amount_dispensed = 10
15+
var/tmp/possible_transfer_amounts = @"[10,25,50,100,500]"
16+
17+
/obj/structure/working/quern/Initialize()
18+
. = ..()
19+
atom_flags |= ATOM_FLAG_OPEN_CONTAINER
20+
initialize_reagents()
21+
22+
/obj/structure/working/quern/try_start_working(mob/user)
23+
24+
if(!length(get_stored_inventory()))
25+
to_chat(user, SPAN_WARNING("There is nothing in \the [src] to grind."))
26+
return TRUE
27+
28+
start_working()
29+
while(length(get_stored_inventory()) && user.do_skilled(1.5 SECONDS, work_skill, src))
30+
if(QDELETED(src) || QDELETED(user) || user.get_stamina() < 25 || !user.get_empty_hand_slot())
31+
break
32+
var/list/stored = get_stored_inventory()
33+
var/obj/item/grinding = stored[1]
34+
if(!istype(grinding))
35+
break
36+
if(!grind_item(grinding, user))
37+
visible_message(SPAN_WARNING("\The [src] clunks and grinds loudly, unable to crush \the [grinding]."))
38+
break
39+
user.adjust_stamina(-25)
40+
41+
if(!QDELETED(user))
42+
to_chat(user, SPAN_NOTICE("You stop working \the [src]."))
43+
44+
stop_working()
45+
return TRUE
46+
47+
/obj/structure/working/quern/proc/grind_item(obj/item/grinding, mob/user)
48+
if(!istype(grinding))
49+
return
50+
var/decl/material/attacking_material = get_material()
51+
var/decl/material/crushing_material = grinding.get_material()
52+
if(!attacking_material || !crushing_material || attacking_material.hardness <= crushing_material.hardness)
53+
return FALSE
54+
if(REAGENTS_FREE_SPACE(reagents) < grinding.reagents?.total_volume)
55+
return FALSE
56+
if(grinding.reagents?.total_volume) // if it has no reagents, skip all the fluff and destroy it instantly
57+
grinding.reagents.trans_to(src, grinding.reagents.total_volume)
58+
QDEL_NULL(grinding)
59+
return TRUE
60+
61+
/obj/structure/working/quern/initialize_reagents(populate = TRUE)
62+
if(!reagents)
63+
create_reagents(volume)
64+
else
65+
reagents.maximum_volume = max(reagents.maximum_volume, volume)
66+
. = ..()
67+
68+
/obj/structure/working/quern/set_reagent_amount_dispensed(new_amount)
69+
amount_dispensed = new_amount
70+
71+
/obj/structure/working/quern/get_reagent_amount_dispensed()
72+
return amount_dispensed
73+
74+
/obj/structure/working/quern/get_possible_reagent_transfer_amounts()
75+
return cached_json_decode(possible_transfer_amounts)

code/modules/interactions/interactions_reagents.dm

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,19 @@
2727
return
2828
if(target == prop || target.reagents?.total_volume < FLUID_PUDDLE)
2929
return FALSE
30-
if(!istype(prop) || (!isitem(target) && !istype(target, /obj/structure/reagent_dispensers)))
30+
if(!istype(prop) || (!isitem(target) && !istype(target, /obj/structure)))
3131
return FALSE
32+
if(istype(target, /obj/structure))
33+
var/obj/structure/struct = target
34+
if(isnull(struct.get_possible_reagent_transfer_amounts()))
35+
return FALSE // Not a dispenser
3236
return target.can_be_poured_from(user, prop) && prop.can_be_poured_into(user, target)
3337

3438
/decl/interaction_handler/fill_from/invoked(atom/target, mob/user, obj/item/prop)
3539
if(isitem(target))
3640
var/obj/item/vessel = target
3741
return vessel.standard_pour_into(user, prop)
38-
if(istype(target, /obj/structure/reagent_dispensers))
42+
if(istype(target, /obj/structure))
3943
// Reagent dispensers have some wonky assumptions due to old UX around filling/emptying so we skip the atom flags check.
4044
return prop.standard_dispenser_refill(user, target, skip_container_check = TRUE)
4145
return FALSE

code/modules/reagents/reagent_dispenser.dm

Lines changed: 8 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,14 @@
1818
var/can_toggle_open = TRUE
1919
var/tmp/possible_transfer_amounts = @"[10,25,50,100,500]"
2020

21-
/obj/structure/reagent_dispensers/Initialize(ml, _mat, _reinf_mat)
22-
. = ..()
23-
if (!possible_transfer_amounts)
24-
verbs -= /obj/structure/reagent_dispensers/verb/set_amount_dispensed
25-
26-
/obj/structure/reagent_dispensers/receive_mouse_drop(atom/dropping, mob/user, params)
27-
if(!(. = ..()) && user?.get_active_held_item() == dropping && isitem(dropping))
28-
// Awful. Sorry.
29-
var/obj/item/item = dropping
30-
var/old_atom_flags = atom_flags
31-
atom_flags |= ATOM_FLAG_OPEN_CONTAINER
32-
if(item.standard_pour_into(user, src))
33-
. = TRUE
34-
atom_flags = old_atom_flags
21+
/obj/structure/reagent_dispensers/get_reagent_amount_dispensed()
22+
return amount_dispensed
23+
24+
/obj/structure/reagent_dispensers/set_reagent_amount_dispensed(new_amount)
25+
amount_dispensed = new_amount
26+
27+
/obj/structure/reagent_dispensers/get_possible_reagent_transfer_amounts()
28+
return cached_json_decode(possible_transfer_amounts)
3529

3630
/obj/structure/reagent_dispensers/on_reagent_change()
3731
if(!(. = ..()))
@@ -61,27 +55,9 @@
6155
. += "Its refilling cap is open."
6256
else
6357
. += "Its refilling cap is closed."
64-
. += SPAN_NOTICE("It contains:")
65-
if(LAZYLEN(reagents?.reagent_volumes))
66-
for(var/decl/material/reagent as anything in reagents.liquid_volumes)
67-
. += SPAN_NOTICE("[LIQUID_VOLUME(reagents, reagent)] unit\s of [reagent.get_reagent_name(reagents, MAT_PHASE_LIQUID)].")
68-
for(var/decl/material/reagent as anything in reagents.solid_volumes)
69-
. += SPAN_NOTICE("[SOLID_VOLUME(reagents, reagent)] unit\s of [reagent.get_reagent_name(reagents, MAT_PHASE_SOLID)].")
70-
else
71-
. += SPAN_NOTICE("Nothing.")
72-
if(reagents?.maximum_volume)
73-
. += "It may contain up to [reagents.maximum_volume] unit\s of fluid."
7458

7559
/obj/structure/reagent_dispensers/attackby(obj/item/used_item, mob/user)
7660

77-
// We do this here to avoid putting the vessel straight into storage.
78-
// This is usually handled by afterattack on /chems.
79-
if(storage && ATOM_IS_OPEN_CONTAINER(used_item) && user.check_intent(I_FLAG_HELP))
80-
if(used_item.standard_dispenser_refill(user, src))
81-
return TRUE
82-
if(used_item.standard_pour_into(user, src))
83-
return TRUE
84-
8561
if(wrenchable && IS_WRENCH(used_item))
8662
unwrenched = !unwrenched
8763
visible_message(SPAN_NOTICE("\The [user] wrenches \the [src]'s tap [unwrenched ? "open" : "shut"]."))
@@ -92,20 +68,6 @@
9268

9369
. = ..()
9470

95-
/obj/structure/reagent_dispensers/verb/set_amount_dispensed()
96-
set name = "Set amount dispensed"
97-
set category = "Object"
98-
set src in view(1)
99-
if(!CanPhysicallyInteract(usr))
100-
to_chat(usr, SPAN_NOTICE("You're in no condition to do that!'"))
101-
return
102-
var/N = input("Amount dispensed:","[src]") as null|anything in cached_json_decode(possible_transfer_amounts)
103-
if(!CanPhysicallyInteract(usr)) // because input takes time and the situation can change
104-
to_chat(usr, SPAN_NOTICE("You're in no condition to do that!'"))
105-
return
106-
if (N)
107-
amount_dispensed = N
108-
10971
/obj/structure/reagent_dispensers/explosion_act(severity)
11072
. = ..()
11173
if(. && (severity == 1) || (severity == 2 && prob(50)) || (severity == 3 && prob(5)))
@@ -320,24 +282,9 @@
320282
//Interactions
321283
/obj/structure/reagent_dispensers/get_alt_interactions(var/mob/user)
322284
. = ..()
323-
LAZYADD(., /decl/interaction_handler/set_transfer/reagent_dispenser)
324285
if(can_toggle_open)
325286
LAZYADD(., /decl/interaction_handler/toggle_open/reagent_dispenser)
326287

327-
//Set amount dispensed
328-
/decl/interaction_handler/set_transfer/reagent_dispenser
329-
expected_target_type = /obj/structure/reagent_dispensers
330-
331-
/decl/interaction_handler/set_transfer/reagent_dispenser/is_possible(var/atom/target, var/mob/user)
332-
. = ..()
333-
if(.)
334-
var/obj/structure/reagent_dispensers/R = target
335-
return !!R.possible_transfer_amounts
336-
337-
/decl/interaction_handler/set_transfer/reagent_dispenser/invoked(atom/target, mob/user, obj/item/prop)
338-
var/obj/structure/reagent_dispensers/R = target
339-
R.set_amount_dispensed()
340-
341288
//Allows normal refilling, or toggle back to normal reagent dispenser operation
342289
/decl/interaction_handler/toggle_open/reagent_dispenser
343290
name = "Toggle refilling cap"

icons/obj/structures/quern.dmi

539 Bytes
Binary file not shown.

maps/shaded_hills/shaded_hills-inn.dmm

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,6 +1195,10 @@
11951195
},
11961196
/turf/floor/wood/rough/walnut,
11971197
/area/shaded_hills/shrine/kitchen)
1198+
"Fz" = (
1199+
/obj/structure/working/quern,
1200+
/turf/floor/wood/rough/walnut,
1201+
/area/shaded_hills/storehouse)
11981202
"FD" = (
11991203
/obj/structure/reagent_dispensers/barrel/ebony,
12001204
/obj/item/seeds/extracted/rice,
@@ -1293,6 +1297,11 @@
12931297
/obj/structure/wall_sconce/lantern,
12941298
/turf/floor/path/herringbone/basalt,
12951299
/area/shaded_hills/inn/kitchen)
1300+
"Hp" = (
1301+
/obj/structure/table/wood/reinforced/ebony,
1302+
/obj/item/chems/glass/bucket/wood,
1303+
/turf/floor/wood/rough/walnut,
1304+
/area/shaded_hills/storehouse)
12961305
"Hv" = (
12971306
/obj/structure/railing/mapped/wooden/walnut,
12981307
/obj/structure/flora/bush/sparsegrass,
@@ -9547,7 +9556,7 @@ uJ
95479556
dH
95489557
HI
95499558
QQ
9550-
fR
9559+
Hp
95519560
fR
95529561
fR
95539562
fR
@@ -9699,7 +9708,7 @@ uJ
96999708
Wg
97009709
HI
97019710
QQ
9702-
fR
9711+
Fz
97039712
fR
97049713
fR
97059714
fR
@@ -10003,7 +10012,7 @@ yz
1000310012
Wg
1000410013
HI
1000510014
UY
10006-
fR
10015+
Hp
1000710016
fR
1000810017
fR
1000910018
fR
@@ -10155,7 +10164,7 @@ BL
1015510164
dH
1015610165
HI
1015710166
QQ
10158-
fR
10167+
Fz
1015910168
fR
1016010169
fR
1016110170
fR

0 commit comments

Comments
 (0)