#define BASE_POINT_MULT 0.65
#define BASE_SHEET_MULT 0.65
#define POINT_MULT_ADD_PER_RATING 0.35
#define SHEET_MULT_ADD_PER_RATING 0.35
/**
* # Ore Redemption Machine
*
* Turns all the various mining machines into a single unit to speed up tmining and establish a point system.
*/
/obj/machinery/mineral/ore_redemption
name = "ore redemption machine"
desc = "A machine that accepts ore and instantly transforms it into workable material sheets. Points for ore are generated based on type and can be redeemed at a mining equipment vendor."
icon = 'icons/obj/machines/mining_machines.dmi'
icon_state = "ore_redemption"
density = TRUE
anchored = TRUE
input_dir = NORTH
output_dir = SOUTH
req_access = list(ACCESS_MINERAL_STOREROOM)
speed_process = TRUE
layer = BELOW_OBJ_LAYER
// Settings
/// The access number required to claim points from the machine.
var/req_access_claim = ACCESS_MINING_STATION
/// If TRUE, [/obj/machinery/mineral/ore_redemption/var/req_access_claim] is ignored and any ID may be used to claim points.
var/anyone_claim = FALSE
/// List of supply console department names that can receive a notification about ore dumps.
/// A list may be provided as entry value to only notify when specific ore is dumped.
var/list/supply_consoles = list(
"Science",
"Robotics",
"Research Director's Desk",
"Engineering" = list(MAT_METAL, MAT_GLASS, MAT_PLASMA),
"Chief Engineer's Desk" = list(MAT_METAL, MAT_GLASS, MAT_PLASMA),
"Atmospherics" = list(MAT_METAL, MAT_GLASS, MAT_PLASMA),
"Bar" = list(MAT_URANIUM, MAT_PLASMA),
"Virology" = list(MAT_PLASMA, MAT_URANIUM, MAT_GOLD)
)
// Variables
/// The currently inserted ID.
var/obj/item/card/id/inserted_id = null
/// The number of unclaimed points.
var/points = 0
/// Sheet multiplier applied when smelting ore. Updated by [/obj/machinery/proc/RefreshParts].
var/sheet_per_ore = 1
/// Point multiplier applied when smelting ore. Updated by [/obj/machinery/proc/RefreshParts].
var/point_upgrade = 1
/// Whether the message to relevant supply consoles was sent already or not for an ore dump. If FALSE, another will be sent.
var/message_sent = TRUE
/// List of ore yet to process.
var/list/obj/item/stack/ore/ore_buffer = null
/// Locally known R&D designs.
var/datum/research/files
/// The currently inserted design disk.
var/obj/item/disk/design_disk/inserted_disk
/obj/machinery/mineral/ore_redemption/Initialize(mapload)
. = ..()
AddComponent(/datum/component/material_container, list(MAT_METAL, MAT_GLASS, MAT_SILVER, MAT_GOLD, MAT_DIAMOND, MAT_PLASMA, MAT_URANIUM, MAT_BANANIUM, MAT_TRANQUILLITE, MAT_TITANIUM, MAT_BLUESPACE), INFINITY, FALSE, /obj/item/stack, null, CALLBACK(src, PROC_REF(on_material_insert)))
ore_buffer = list()
files = new /datum/research/smelter(src)
// Stock parts
component_parts = list()
component_parts += new /obj/item/circuitboard/ore_redemption(null)
component_parts += new /obj/item/stock_parts/matter_bin(null)
component_parts += new /obj/item/stock_parts/manipulator(null)
component_parts += new /obj/item/stock_parts/micro_laser(null)
component_parts += new /obj/item/assembly/igniter(null)
component_parts += new /obj/item/stack/sheet/glass(null)
RefreshParts()
/obj/machinery/mineral/ore_redemption/upgraded/Initialize(mapload)
. = ..()
component_parts = list()
component_parts += new /obj/item/circuitboard/ore_redemption(null)
component_parts += new /obj/item/stock_parts/matter_bin/super(null)
component_parts += new /obj/item/stock_parts/manipulator/pico(null)
component_parts += new /obj/item/stock_parts/micro_laser/ultra(null)
component_parts += new /obj/item/assembly/igniter(null)
component_parts += new /obj/item/stack/sheet/glass(null)
RefreshParts()
/**
* # Ore Redemption Machine (Golem)
*
* Golem variant of the ORM.
*/
/obj/machinery/mineral/ore_redemption/golem
req_access = list(ACCESS_FREE_GOLEMS)
req_access_claim = ACCESS_FREE_GOLEMS
/obj/machinery/mineral/ore_redemption/golem/Initialize(mapload)
. = ..()
component_parts = list()
component_parts += new /obj/item/circuitboard/ore_redemption/golem(null)
component_parts += new /obj/item/stock_parts/matter_bin(null)
component_parts += new /obj/item/stock_parts/manipulator(null)
component_parts += new /obj/item/stock_parts/micro_laser(null)
component_parts += new /obj/item/assembly/igniter(null)
component_parts += new /obj/item/stack/sheet/glass(null)
RefreshParts()
/**
* # Ore Redemption Machine (Labor Camp)
*
* Labor camp variant of the ORM. Points can be claimed by anyone.
*/
/obj/machinery/mineral/ore_redemption/labor
name = "labor camp ore redemption machine"
req_access = list()
anyone_claim = TRUE
/obj/machinery/mineral/ore_redemption/labor/Initialize(mapload)
. = ..()
component_parts = list()
component_parts += new /obj/item/circuitboard/ore_redemption/labor(null)
component_parts += new /obj/item/stock_parts/matter_bin(null)
component_parts += new /obj/item/stock_parts/manipulator(null)
component_parts += new /obj/item/stock_parts/micro_laser(null)
component_parts += new /obj/item/assembly/igniter(null)
component_parts += new /obj/item/stack/sheet/glass(null)
RefreshParts()
/obj/machinery/mineral/ore_redemption/Destroy()
// Move any stuff inside us out
var/turf/T = get_turf(src)
inserted_id?.forceMove(T)
inserted_disk?.forceMove(T)
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.retrieve_all()
// Clean up
QDEL_NULL(files)
return ..()
/obj/machinery/mineral/ore_redemption/RefreshParts()
var/P = BASE_POINT_MULT
var/S = BASE_SHEET_MULT
for(var/obj/item/stock_parts/micro_laser/M in component_parts)
P += POINT_MULT_ADD_PER_RATING * M.rating
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
S += SHEET_MULT_ADD_PER_RATING * M.rating
// Manipulators do nothing
// Update our values
point_upgrade = P
sheet_per_ore = S
SStgui.update_uis(src)
/obj/machinery/mineral/ore_redemption/power_change()
if(!..())
return
update_icon(UPDATE_ICON_STATE)
if(inserted_id && !(stat & NOPOWER))
visible_message("The ID slot indicator light flickers on [src] as it spits out a card before powering down.")
inserted_id.forceMove(get_turf(src))
inserted_id = null
/obj/machinery/mineral/ore_redemption/update_icon_state()
if(has_power())
icon_state = initial(icon_state)
else
icon_state = "[initial(icon_state)]-off"
/obj/machinery/mineral/ore_redemption/process()
if(panel_open || !has_power())
return
// Check if the input turf has a [/obj/structure/ore_box] to draw ore from. Otherwise suck ore from the turf
var/atom/input = get_step(src, input_dir)
var/obj/structure/ore_box/OB = locate() in input
if(OB)
input = OB
// Suck the ore in
for(var/obj/item/stack/ore/O in input)
if(QDELETED(O))
continue
ore_buffer |= O
O.forceMove(src)
CHECK_TICK
// Process it
if(length(ore_buffer))
message_sent = FALSE
process_ores(ore_buffer)
else if(!message_sent)
SStgui.update_uis(src)
send_console_message()
message_sent = TRUE
// Interactions
/obj/machinery/mineral/ore_redemption/attackby(obj/item/I, mob/user, params)
if(exchange_parts(user, I))
return
if(!has_power())
return ..()
if(istype(I, /obj/item/card/id))
try_insert_id(user)
return
else if(istype(I, /obj/item/disk/design_disk))
if(!user.drop_item())
return
I.forceMove(src)
inserted_disk = I
SStgui.update_uis(src)
interact(user)
user.visible_message("[user] inserts [I] into [src].",
"You insert [I] into [src].")
return
return ..()
/obj/machinery/mineral/ore_redemption/crowbar_act(mob/user, obj/item/I)
if(default_deconstruction_crowbar(user, I))
return TRUE
/obj/machinery/mineral/ore_redemption/multitool_act(mob/user, obj/item/I)
if(!panel_open)
return
. = TRUE
if(!has_power())
return
if(!I.tool_start_check(src, user, 0))
return
input_dir = turn(input_dir, -90)
output_dir = turn(output_dir, -90)
to_chat(user, "You change [src]'s I/O settings, setting the input to [dir2text(input_dir)] and the output to [dir2text(output_dir)].")
/obj/machinery/mineral/ore_redemption/screwdriver_act(mob/user, obj/item/I)
if(default_deconstruction_screwdriver(user, "ore_redemption-open", "ore_redemption", I))
SStgui.update_uis(src)
return TRUE
/obj/machinery/mineral/ore_redemption/wrench_act(mob/user, obj/item/I)
if(default_unfasten_wrench(user, I, time = 6 SECONDS))
return TRUE
/obj/machinery/mineral/ore_redemption/attack_ghost(mob/user)
ui_interact(user)
/obj/machinery/mineral/ore_redemption/attack_hand(mob/user)
if(..())
return
ui_interact(user)
/obj/machinery/mineral/ore_redemption/ex_act(severity)
do_sparks(5, TRUE, src)
..()
// UI
/obj/machinery/mineral/ore_redemption/ui_data(mob/user)
var/list/data = list()
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
// General info
data["id"] = inserted_id ? list("name" = "[inserted_id.registered_name] ([inserted_id.assignment])", "points" = inserted_id.mining_points, "total_points" = inserted_id.total_mining_points) : null
data["points"] = points
data["disk"] = inserted_disk ? list(
"name" = inserted_disk.name,
"design" = inserted_disk.blueprint?.name,
"compatible" = (inserted_disk.blueprint?.build_type & SMELTER)
) : null
// Sheets
var/list/sheets = list()
for(var/MAT in materials.materials)
var/datum/material/M = materials.materials[MAT]
if(!M)
continue
var/obj/item/stack/ore/O = M.ore_type
sheets += list(list(
"id" = MAT,
"name" = M.name,
"amount" = M.amount / MINERAL_MATERIAL_AMOUNT,
"value" = initial(O.points) * point_upgrade
))
data["sheets"] = sheets
// Alloys
var/list/alloys = list()
for(var/v in files.known_designs)
var/datum/design/D = files.known_designs[v]
alloys += list(list(
"id" = D.id,
"name" = D.name,
"description" = D.desc,
"amount" = get_num_smeltable_alloy(D)
))
data["alloys"] = alloys
return data
/obj/machinery/mineral/ore_redemption/ui_act(action, list/params)
if(..())
return
. = TRUE
switch(action)
if("claim")
if(!inserted_id || !points)
return
if(anyone_claim || (req_access_claim in inserted_id.access))
inserted_id.mining_points += points
inserted_id.total_mining_points += points
to_chat(usr, "[points] Mining Points claimed. You have earned a total of [inserted_id.total_mining_points] Mining Points this Shift!")
points = 0
else
to_chat(usr, "Required access not found.")
if("sheet", "alloy")
if(!(check_access(inserted_id) || allowed(usr)))
to_chat(usr, "Required access not found.")
return FALSE
var/id = params["id"]
var/amount = round(text2num(params["amount"]))
if(!amount || amount < 1)
return FALSE
var/out_loc = get_step(src, output_dir)
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
if(action == "sheet")
var/datum/material/M = materials.materials[id]
if(!M)
return FALSE
var/stored = M.amount / MINERAL_MATERIAL_AMOUNT
var/desired = min(amount, stored, MAX_STACK_SIZE)
materials.retrieve_sheets(desired, id, out_loc)
else
var/datum/design/D = files.FindDesignByID(id)
if(!D)
return FALSE
var/stored = get_num_smeltable_alloy(D)
var/desired = min(amount, stored, MAX_STACK_SIZE)
if(!desired)
return FALSE
materials.use_amount(D.materials, desired)
// Spawn the alloy
var/result = new D.build_path(src)
if(istype(result, /obj/item/stack/sheet))
var/obj/item/stack/sheet/mineral/A = result
A.amount = desired
unload_mineral(A)
else
unload_mineral(result)
if("insert_id")
try_insert_id(usr)
if("eject_id")
if(!inserted_id)
return FALSE
if(ishuman(usr))
usr.put_in_hands(inserted_id)
usr.visible_message("[usr] retrieves [inserted_id] from [src].", \
"You retrieve [inserted_id] from [src].")
else
inserted_id.forceMove(get_turf(src))
inserted_id = null
if("eject_disk")
if(!inserted_disk)
return FALSE
if(ishuman(usr))
usr.put_in_hands(inserted_disk)
usr.visible_message("[usr] retrieves [inserted_disk] from [src].", \
"You retrieve [inserted_disk] from [src].")
else
inserted_disk.forceMove(get_turf(src))
inserted_disk = null
if("download")
if(inserted_disk?.blueprint?.build_type & SMELTER)
files.AddDesign2Known(inserted_disk.blueprint)
atom_say("Design \"[inserted_disk.blueprint.name]\" downloaded successfully.")
else
return FALSE
add_fingerprint(usr)
/obj/machinery/mineral/ore_redemption/ui_state(mob/user)
return GLOB.default_state
/obj/machinery/mineral/ore_redemption/ui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "OreRedemption", name)
ui.open()
ui.set_autoupdate(FALSE)
/obj/machinery/mineral/ore_redemption/ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/spritesheet/materials),
get_asset_datum(/datum/asset/spritesheet/alloys)
)
/**
* Smelts the given stack of ore.
*
* Arguments:
* * O - The ore stack to smelt.
*/
/obj/machinery/mineral/ore_redemption/proc/smelt_ore(obj/item/stack/ore/O)
// Award points if the ore actually smelts to something
give_points(O.type, O.amount)
// Insert materials
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/amount_compatible = materials.get_item_material_amount(O)
if(amount_compatible)
// Prevents duping
if(O.refined_type)
materials.insert_item(O, sheet_per_ore)
else
materials.insert_item(O, 1)
// Delete the stack
ore_buffer -= O
qdel(O)
/**
* Adds a set number of mining points, based on the ore points, the ore amount, and the ORM upgrade state.
*
* Arguments:
* * ore_path - The typepath of the inserted ore.
* * ore_amount - The amount of ore which has been inserted.
*/
/obj/machinery/mineral/ore_redemption/proc/give_points(obj/item/stack/ore/ore_path, ore_amount)
if(initial(ore_path.refined_type))
points += initial(ore_path.points) * point_upgrade * ore_amount
/**
* Returns the amount of alloy sheets that can be produced from the given design.
*
* Arguments:
* * D - The smelting design.
*/
/obj/machinery/mineral/ore_redemption/proc/get_num_smeltable_alloy(datum/design/D)
if(length(D.make_reagents))
return 0
var/result = 0
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
for(var/MAT in D.materials)
var/M = D.materials[MAT]
var/datum/material/stored = materials.materials[MAT]
if(!M || !stored)
return FALSE
var/smeltable = round(stored.amount / M)
if(!smeltable)
return FALSE
if(!result)
result = smeltable
result = min(result, smeltable)
return result
/**
* Processes the given list of ores.
*
* Arguments:
* * L - List of ores to process.
*/
/obj/machinery/mineral/ore_redemption/proc/process_ores(list/obj/item/stack/ore/L)
for(var/ore in L)
smelt_ore(ore)
/**
* Notifies all relevant supply consoles with the machine's contents.
*/
/obj/machinery/mineral/ore_redemption/proc/send_console_message()
if(!is_station_level(z))
return
var/list/msg = list("Now available in [get_area_name(src, TRUE) || "Unknown"]:")
var/mats_in_stock = list()
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
for(var/MAT in materials.materials)
var/datum/material/M = materials.materials[MAT]
var/mineral_amount = M.amount / MINERAL_MATERIAL_AMOUNT
if(mineral_amount)
mats_in_stock += M.id
msg.Add("[capitalize(M.name)]: [mineral_amount] sheets")
// No point sending a message if we're dry
if(!length(mats_in_stock))
return
// Notify
for(var/c in GLOB.allRequestConsoles)
var/obj/machinery/requests_console/C = c
if(!(C.department in supply_consoles))
continue
if(!supply_consoles[C.department] || length(supply_consoles[C.department] - mats_in_stock))
C.createMessage("Ore Redemption Machine", "New Minerals Available!", msg, RQ_NORMALPRIORITY)
/**
* Tries to insert the ID card held by the given user into the machine.
*
* Arguments:
* * user - The ID whose active hand to check for an ID card to insert.
*/
/obj/machinery/mineral/ore_redemption/proc/try_insert_id(mob/user)
. = FALSE
var/obj/item/card/id/I = user.get_active_hand()
if(!istype(I))
return
if(inserted_id)
to_chat(user, "There is already an ID inside!")
return
if(!user.drop_item())
return
I.forceMove(src)
inserted_id = I
SStgui.update_uis(src)
interact(user)
user.visible_message("[user] inserts [I] into [src].", \
"You insert [I] into [src].")
return TRUE
/**
* Called when an item is inserted manually as material.
*
* Arguments:
* * inserted_type - The type of the inserted item.
* * last_inserted_id - The ID of the last material to have been inserted.
* * inserted - The amount of material inserted.
*/
/obj/machinery/mineral/ore_redemption/proc/on_material_insert(inserted_type, last_inserted_id, inserted)
give_points(inserted_type, inserted)
SStgui.update_uis(src)
#undef BASE_POINT_MULT
#undef BASE_SHEET_MULT
#undef POINT_MULT_ADD_PER_RATING
#undef SHEET_MULT_ADD_PER_RATING