Generalizes mining voucher behavior (#90297)

## About The Pull Request

Adds `/datum/element/voucher_redeemer`, expands `/datum/voucher_set` a
bit, bumps all mining stuff down a level to `/datum/voucher_set/mining`.

## Why It's Good For The Game

Having a generic way to 
`input item -> output a choice of a set of items`
would be really handy. 

## Changelog

🆑 Melbert
refactor: Minor mining voucher refactor, report any oddities.
/🆑
This commit is contained in:
MrMelbert
2025-04-02 22:37:34 +01:00
committed by GitHub
parent 5fc182a267
commit f7d44e38ae
4 changed files with 124 additions and 78 deletions
+77
View File
@@ -0,0 +1,77 @@
/**
* Accepts a [voucher_type] and a [set_type] and allows the user to redeem the voucher for items from a set.
*/
/datum/element/voucher_redeemer
element_flags = ELEMENT_BESPOKE
argument_hash_start_idx = 2
/// Typepath to what voucher sets are available to us
var/set_type
/// Typepath to what item must be redeemed
var/voucher_type
/// Cached set of radial options for redeeming a voucher
var/list/cached_options
/// Cached set of voucher sets
var/list/set_instances
/datum/element/voucher_redeemer/Attach(datum/target, voucher_type = /obj/item/coin, set_type = /datum/voucher_set)
. = ..()
if(!ismovable(target))
return ELEMENT_INCOMPATIBLE
if(!ispath(voucher_type, /obj/item))
stack_trace("Invalid voucher type for voucher_redeemer [voucher_type || "null"]")
return ELEMENT_INCOMPATIBLE
if(!ispath(set_type, /datum/voucher_set))
stack_trace("Invalid set type for voucher_redeemer [set_type || "null"]")
return ELEMENT_INCOMPATIBLE
src.voucher_type = voucher_type
src.set_type = set_type
RegisterSignal(target, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(redeem_voucher))
/datum/element/voucher_redeemer/Detach(datum/target)
. = ..()
UnregisterSignal(target, COMSIG_ATOM_ITEM_INTERACTION)
/datum/element/voucher_redeemer/proc/redeem_voucher(atom/source, mob/living/redeemer, obj/item/voucher, list/modifiers)
SIGNAL_HANDLER
INVOKE_ASYNC(src, PROC_REF(redeem_voucher_async), source, redeemer, voucher)
return ITEM_INTERACT_SUCCESS
/datum/element/voucher_redeemer/proc/redeem_voucher_async(atom/source, mob/living/redeemer, obj/item/voucher)
if(!set_instances)
set_instances = list()
for(var/datum/voucher_set/static_set as anything in subtypesof(set_type))
set_instances[initial(static_set.name)] = new static_set()
if(!cached_options)
cached_options = list()
for(var/set_name in set_instances)
var/datum/voucher_set/current_set = set_instances[set_name]
var/datum/radial_menu_choice/option = new()
option.image = image(icon = current_set.icon, icon_state = current_set.icon_state)
if(current_set.description)
option.info = span_boldnotice(current_set.description)
cached_options[set_name] = option
var/selection = show_radial_menu(redeemer, source, cached_options, custom_check = CALLBACK(src, PROC_REF(check_menu), voucher, redeemer), radius = 38, require_near = TRUE, tooltips = TRUE)
if(!selection)
return
var/datum/voucher_set/chosen_set = set_instances[selection]
chosen_set.spawn_set(source.drop_location())
if(chosen_set.blackbox_key)
SSblackbox.record_feedback("tally", chosen_set.blackbox_key, 1, selection)
source.balloon_alert(redeemer, "redeemed [LOWER_TEXT(selection)]")
qdel(voucher)
/datum/element/voucher_redeemer/proc/check_menu(obj/item/voucher, mob/living/redeemer)
if(!istype(redeemer))
return FALSE
if(redeemer.incapacitated)
return FALSE
if(QDELETED(voucher))
return FALSE
if(!redeemer.is_holding(voucher))
return FALSE
return TRUE
@@ -26,6 +26,10 @@
blackbox_key = "mining"
announcement_line = "A shaft miner has ordered equipment which will arrive on the cargo shuttle! Please make sure it gets to them as soon as possible!"
/obj/machinery/computer/order_console/mining/Initialize(mapload)
. = ..()
AddElement(/datum/element/voucher_redeemer, /obj/item/mining_voucher, /datum/voucher_set/mining)
/obj/machinery/computer/order_console/mining/subtract_points(final_cost, obj/item/card/id/card)
if(final_cost <= card.registered_account.mining_points)
card.registered_account.mining_points -= final_cost
@@ -68,68 +72,10 @@
if(!.)
flick("mining-deny", src)
/obj/machinery/computer/order_console/mining/attackby(obj/item/weapon, mob/user, params)
if(istype(weapon, /obj/item/mining_voucher))
redeem_voucher(weapon, user)
return
return ..()
/obj/machinery/computer/order_console/mining/update_icon_state()
icon_state = "[initial(icon_state)][powered() ? null : "-off"]"
return ..()
/**
* Allows user to redeem a mining voucher for one set of a mining equipment
*
* * Arguments:
* * voucher The mining voucher that is being used to redeem the mining equipment
* * redeemer The mob that is redeeming the mining equipment
*/
/obj/machinery/computer/order_console/mining/proc/redeem_voucher(obj/item/mining_voucher/voucher, mob/redeemer)
var/static/list/set_types
if(!set_types)
set_types = list()
for(var/datum/voucher_set/static_set as anything in subtypesof(/datum/voucher_set))
set_types[initial(static_set.name)] = new static_set
var/list/items = list()
for(var/set_name in set_types)
var/datum/voucher_set/current_set = set_types[set_name]
var/datum/radial_menu_choice/option = new
option.image = image(icon = current_set.icon, icon_state = current_set.icon_state)
option.info = span_boldnotice(current_set.description)
items[set_name] = option
var/selection = show_radial_menu(redeemer, src, items, custom_check = CALLBACK(src, PROC_REF(check_menu), voucher, redeemer), radius = 38, require_near = TRUE, tooltips = TRUE)
if(!selection)
return
var/datum/voucher_set/chosen_set = set_types[selection]
for(var/item in chosen_set.set_items)
new item(drop_location())
SSblackbox.record_feedback("tally", "mining_voucher_redeemed", 1, selection)
qdel(voucher)
/**
* Checks if we are allowed to interact with a radial menu
*
* * Arguments:
* * voucher The mining voucher that is being used to redeem a mining equipment
* * redeemer The living mob interacting with the menu
*/
/obj/machinery/computer/order_console/mining/proc/check_menu(obj/item/mining_voucher/voucher, mob/living/redeemer)
if(!istype(redeemer))
return FALSE
if(redeemer.incapacitated)
return FALSE
if(QDELETED(voucher))
return FALSE
if(!redeemer.is_holding(voucher))
return FALSE
return TRUE
/**********************Mining Equipment Voucher**********************/
/obj/item/mining_voucher
+42 -20
View File
@@ -1,32 +1,54 @@
/**
* # Voucher Set
*
* A set consisting of a various equipment that can be then used as a reward for redeeming a mining voucher.
* A set consisting of a various equipment that can be then used as a reward for redeeming a voucher.
*
* See [Voucher Redeemer](/datum/element/voucher_redeemer) for where these sets are handled.
*/
/datum/voucher_set
/// Name of the set
/// Required, Name of the set.
var/name
/// Description of the set
/// Optional, description of the set
var/description
/// Icon of the set
/// Optional, Icon of the set. Defaults to first item if not set.
var/icon
/// Icon state of the set
/// Optional, Icon state of the set. Defaults to first item if not set.
var/icon_state
/// List of items contained in the set
var/list/set_items = list()
/// Required, List of items contained in the set
var/list/atom/set_items
/// Optional, what key to use for blackbox feedback. No data will be recorded if not set.
var/blackbox_key
/datum/voucher_set/crusher_kit
/datum/voucher_set/New()
. = ..()
if(!length(set_items))
stack_trace("Voucher set [type] has no items set.")
return
if(isnull(icon))
icon = initial(set_items[1].icon)
if(isnull(icon_state))
icon_state = initial(set_items[1].icon_state)
if(isnull(name))
stack_trace("Voucher set [type] has no name set.")
/datum/voucher_set/proc/spawn_set(atom/spawn_loc)
for(var/item in set_items)
new item(spawn_loc)
/datum/voucher_set/mining
blackbox_key = "mining_voucher_redeemed"
/datum/voucher_set/mining/crusher_kit
name = "Crusher Kit"
description = "Contains a kinetic crusher and a pocket fire extinguisher. Kinetic crusher is a versatile melee mining tool capable both of mining and fighting local fauna, however it is difficult to use effectively for anyone but most skilled and/or suicidal miners."
icon = 'icons/obj/mining.dmi'
icon_state = "crusher"
set_items = list(
/obj/item/extinguisher/mini,
/obj/item/kinetic_crusher,
)
/obj/item/extinguisher/mini,
)
/datum/voucher_set/extraction_kit
/datum/voucher_set/mining/extraction_kit
name = "Extraction and Rescue Kit"
description = "Contains a fulton extraction pack and a beacon signaller, which allows you to send back home minerals, items and dead bodies without having to use the mining shuttle. And as a bonus, you get 30 marker beacons to help you better mark your path."
icon = 'icons/obj/fulton.dmi'
@@ -35,28 +57,28 @@
/obj/item/extraction_pack,
/obj/item/fulton_core,
/obj/item/stack/marker_beacon/thirty,
)
)
/datum/voucher_set/resonator_kit
/datum/voucher_set/mining/resonator_kit
name = "Resonator Kit"
description = "Contains a resonator and a pocket fire extinguisher. Resonator is a handheld device that creates small fields of energy that resonate until they detonate, crushing rock. It does increased damage in low pressure."
icon = 'icons/obj/mining.dmi'
icon_state = "resonator"
set_items = list(
/obj/item/extinguisher/mini,
/obj/item/resonator,
)
/obj/item/extinguisher/mini,
)
/datum/voucher_set/survival_capsule
/datum/voucher_set/mining/survival_capsule
name = "Survival Capsule and Explorer's Webbing"
description = "Contains an explorer's webbing, which allows you to carry even more mining equipment and already has a spare shelter capsule in it."
icon = 'icons/obj/clothing/belts.dmi'
icon_state = "explorer1"
set_items = list(
/obj/item/storage/belt/mining/vendor,
)
)
/datum/voucher_set/minebot_kit
/datum/voucher_set/mining/minebot_kit
name = "Minebot Kit"
description = "Contains a little minebot companion that helps you in storing ore and hunting wildlife. Also comes with an upgraded industrial welding tool (80u), a welding mask and a KA modkit that allows shots to pass through the minebot."
icon = 'icons/mob/silicon/aibots.dmi'
@@ -66,9 +88,9 @@
/obj/item/weldingtool/hugetank,
/obj/item/clothing/head/utility/welding,
/obj/item/borg/upgrade/modkit/minebot_passthrough,
)
)
/datum/voucher_set/conscription_kit
/datum/voucher_set/mining/conscription_kit
name = "Mining Conscription Kit"
description = "Contains a whole new mining starter kit for one crewmember, consisting of a proto-kinetic accelerator, a survival knife, a seclite, an explorer's suit, mesons, an automatic mining scanner, a mining satchel, a gas mask, a mining radio key and a special ID card with a basic mining access."
icon = 'icons/obj/storage/backpack.dmi'
+1
View File
@@ -1623,6 +1623,7 @@
#include "code\datums\elements\uplink_reimburse.dm"
#include "code\datums\elements\venomous.dm"
#include "code\datums\elements\volatile_gas_storage.dm"
#include "code\datums\elements\voucher_redeemer.dm"
#include "code\datums\elements\waddling.dm"
#include "code\datums\elements\wall_engraver.dm"
#include "code\datums\elements\wall_smasher.dm"