mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-17 18:09:26 +01:00
https://www.youtube.com/watch?v=ZpUYjpKg9KY As per title. The goal is to add health to most objects in the game and thus allow them to be dynamically destructible, while also avoiding shitcode like each structure having its own snowflake health update proc. --------- Signed-off-by: Matt Atlas <mattiathebest2000@hotmail.it> Co-authored-by: Matt Atlas <liermattia@gmail.com> Co-authored-by: SleepyGemmy <99297919+SleepyGemmy@users.noreply.github.com>
310 lines
10 KiB
Plaintext
310 lines
10 KiB
Plaintext
/obj/machinery/r_n_d/protolathe
|
|
name = "protolathe"
|
|
desc = "An upgraded variant of a common Autolathe, this can only be operated via a nearby RnD console, but can manufacture cutting edge technology, provided it has the design and the correct materials."
|
|
icon_state = "protolathe"
|
|
atom_flags = ATOM_FLAG_OPEN_CONTAINER
|
|
|
|
idle_power_usage = 30 WATTS
|
|
active_power_usage = 25 KILO WATTS
|
|
|
|
var/max_material_storage = 100000
|
|
var/list/materials = list(DEFAULT_WALL_MATERIAL = 0, MATERIAL_GLASS = 0, MATERIAL_GOLD = 0, MATERIAL_SILVER = 0, MATERIAL_PHORON = 0, MATERIAL_URANIUM = 0, MATERIAL_DIAMOND = 0)
|
|
|
|
/**
|
|
* A `/list` of enqueued `/datum/design` to be printed, processed in the queue
|
|
*/
|
|
var/list/datum/design/queue = list()
|
|
|
|
/**
|
|
* How much efficient (or inefficient) the protolathe is at manufacturing things
|
|
*/
|
|
var/mat_efficiency = 1
|
|
|
|
/**
|
|
* The production speed of this specific protolathe, a factor
|
|
*/
|
|
var/production_speed = 1
|
|
|
|
///The timer id for the build callback, if we're building something
|
|
var/build_callback_timer
|
|
|
|
component_types = list(
|
|
/obj/item/circuitboard/protolathe,
|
|
/obj/item/stock_parts/matter_bin = 2,
|
|
/obj/item/stock_parts/manipulator = 2,
|
|
/obj/item/reagent_containers/glass/beaker = 2
|
|
)
|
|
|
|
/obj/machinery/r_n_d/protolathe/upgrade_hints(mob/user, distance, is_adjacent)
|
|
. += ..()
|
|
. += "- Upgraded <b>matter bins</b> will increase material storage capacity."
|
|
. += SPAN_NOTICE(" - The current storage capacity is <b>[max_material_storage / 2000]</b> sheets")
|
|
. += "- Upgraded <b>manipulators</b> will improve material use efficiency and increase fabrication speed."
|
|
. += SPAN_NOTICE(" - The current speed increase is <b>[round((1 - (1 / production_speed)) * 100)]%</b>")
|
|
. += SPAN_NOTICE(" - The current cost reduction is <b>[round((1 - mat_efficiency) * 100)]%</b>")
|
|
|
|
///Returns the total of all the stored materials
|
|
/obj/machinery/r_n_d/protolathe/proc/TotalMaterials()
|
|
var/t = 0
|
|
for(var/f in materials)
|
|
t += materials[f]
|
|
return t
|
|
|
|
/obj/machinery/r_n_d/protolathe/RefreshParts()
|
|
..()
|
|
// Adjust reagent container volume to match combined volume of the inserted beakers
|
|
var/T = 0
|
|
for(var/obj/item/reagent_containers/glass/G in component_parts)
|
|
T += G.reagents.maximum_volume
|
|
create_reagents(T)
|
|
// Transfer all reagents from the beakers to internal reagent container
|
|
for(var/obj/item/reagent_containers/glass/G in component_parts)
|
|
G.reagents.trans_to_obj(src, G.reagents.total_volume)
|
|
|
|
// Adjust material storage capacity to scale with matter bin rating
|
|
max_material_storage = 0
|
|
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
|
|
max_material_storage += M.rating * 75000
|
|
|
|
// Adjust production speed to increase with manipulator rating
|
|
T = 0
|
|
for(var/obj/item/stock_parts/manipulator/M in component_parts)
|
|
T += M.rating
|
|
mat_efficiency = 1 - (T - 2) / 8
|
|
production_speed = T / 2
|
|
update_icon()
|
|
|
|
/obj/machinery/r_n_d/protolathe/dismantle()
|
|
for(var/obj/I in component_parts)
|
|
if(istype(I, /obj/item/reagent_containers/glass/beaker))
|
|
reagents.trans_to_obj(I, reagents.total_volume)
|
|
for(var/f in materials)
|
|
if(materials[f] >= SHEET_MATERIAL_AMOUNT)
|
|
var/path = getMaterialType(f)
|
|
if(path)
|
|
var/obj/item/stack/S = new path(loc)
|
|
S.amount = round(materials[f] / SHEET_MATERIAL_AMOUNT)
|
|
..()
|
|
|
|
/obj/machinery/r_n_d/protolathe/power_change()
|
|
. = ..()
|
|
update_icon()
|
|
|
|
/obj/machinery/r_n_d/protolathe/update_icon()
|
|
ClearOverlays()
|
|
if(panel_open)
|
|
AddOverlays("[icon_state]_panel")
|
|
if(!(stat & (NOPOWER|BROKEN)))
|
|
AddOverlays(emissive_appearance(icon, "[icon_state]_lights"))
|
|
AddOverlays("[icon_state]_lights")
|
|
if(build_callback_timer)
|
|
AddOverlays("[icon_state]_working")
|
|
AddOverlays(emissive_appearance(icon, "[icon_state]_lights_working"))
|
|
AddOverlays("[icon_state]_lights_working")
|
|
|
|
/obj/machinery/r_n_d/protolathe/attackby(obj/item/attacking_item, mob/user)
|
|
if(user.a_intent == I_HURT)
|
|
return ..()
|
|
|
|
if(build_callback_timer)
|
|
to_chat(user, SPAN_NOTICE("\The [src] is busy. Please wait for completion of previous operation."))
|
|
return TRUE
|
|
if(default_deconstruction_screwdriver(user, attacking_item))
|
|
if(linked_console)
|
|
linked_console.linked_lathe = null
|
|
linked_console = null
|
|
return TRUE
|
|
if(default_deconstruction_crowbar(user, attacking_item))
|
|
return TRUE
|
|
if(default_part_replacement(user, attacking_item))
|
|
return TRUE
|
|
if(attacking_item.is_open_container())
|
|
return TRUE
|
|
if(panel_open)
|
|
to_chat(user, SPAN_NOTICE("You can't load \the [src] while it's opened."))
|
|
return TRUE
|
|
if(!linked_console)
|
|
to_chat(user, SPAN_NOTICE("The [src] must be linked to an R&D console first!"))
|
|
return TRUE
|
|
if(!istype(attacking_item, /obj/item/stack/material))
|
|
to_chat(user, SPAN_NOTICE("You cannot insert this item into \the [src]!"))
|
|
return TRUE
|
|
if(stat)
|
|
return TRUE
|
|
|
|
if(TotalMaterials() + SHEET_MATERIAL_AMOUNT > max_material_storage)
|
|
to_chat(user, SPAN_NOTICE("The [src]'s material bin is full. Please remove material before adding more."))
|
|
return TRUE
|
|
|
|
var/obj/item/stack/material/stack = attacking_item
|
|
if(!stack.default_type)
|
|
to_chat(user, SPAN_WARNING("This stack cannot be used!"))
|
|
return
|
|
|
|
var/max_value = min(stack.get_amount(), round((max_material_storage - TotalMaterials()) / SHEET_MATERIAL_AMOUNT))
|
|
var/amount = tgui_input_number(user, "How many sheets do you want to add?", "Add sheets", min(10, max_value), max_value = max_value, min_value = 1, round_value = TRUE)
|
|
|
|
if(!attacking_item)
|
|
return
|
|
if(!Adjacent(user))
|
|
to_chat(user, SPAN_NOTICE("The [src] is too far away for you to insert this."))
|
|
return
|
|
if(amount <= 0)//No negative numbers, no nulls
|
|
return
|
|
|
|
var/mutable_appearance/M = mutable_appearance(icon, "material_insertion")
|
|
M.color = stack.material.icon_colour
|
|
//first play the insertion animation
|
|
flick_overlay_view(M, 1 SECONDS)
|
|
|
|
//now play the progress bar animation
|
|
flick_overlay_view(mutable_appearance(icon, "protolathe_progress"), 1 SECONDS)
|
|
|
|
//Use some power and add the materials
|
|
use_power_oneoff(max(1000, (SHEET_MATERIAL_AMOUNT * amount / 10)))
|
|
if(do_after(user, 1.6 SECONDS))
|
|
if(stack.use(amount))
|
|
if(amount>1)
|
|
to_chat(user, SPAN_NOTICE("You add [amount] [stack.material.sheet_plural_name] of [stack.material.name] to \the [src]."))
|
|
else
|
|
to_chat(user, SPAN_NOTICE("You add [amount] [stack.material.sheet_singular_name] of [stack.material.name] to \the [src]."))
|
|
materials[stack.default_type] += amount * SHEET_MATERIAL_AMOUNT
|
|
|
|
//In case there's things queued up, we run the queue handler
|
|
handle_queue()
|
|
|
|
//Give an update on the UIs
|
|
updateUsrDialog()
|
|
if(linked_console)
|
|
linked_console.updateUsrDialog()
|
|
|
|
/**
|
|
* Adds a design to the queue
|
|
*
|
|
* * design_to_add: The design to add
|
|
*/
|
|
/obj/machinery/r_n_d/protolathe/proc/addToQueue(datum/design/design_to_add)
|
|
queue += design_to_add
|
|
|
|
//Wake up, we have things to do
|
|
handle_queue()
|
|
|
|
/**
|
|
* Removes a design from the queue
|
|
*
|
|
* * index: The index of the design to remove
|
|
*/
|
|
/obj/machinery/r_n_d/protolathe/proc/removeFromQueue(index)
|
|
queue.Cut(index, index + 1)
|
|
|
|
//Wake up, we have things to do
|
|
handle_queue()
|
|
|
|
/**
|
|
* Handle the construction queue
|
|
*/
|
|
/obj/machinery/r_n_d/protolathe/proc/handle_queue()
|
|
|
|
//No work to do or already busy, stop
|
|
if(!length(queue) || build_callback_timer)
|
|
update_icon()
|
|
return
|
|
|
|
//If there's no power, there's no building
|
|
if(stat & NOPOWER)
|
|
queue = list()
|
|
update_icon()
|
|
return
|
|
|
|
//Get the first design in the queue
|
|
var/datum/design/D = queue[1]
|
|
|
|
//If we can build it, process the request
|
|
if(canBuild(D))
|
|
build_callback_timer = addtimer(CALLBACK(src, PROC_REF(build), D), (D.time / production_speed), TIMER_UNIQUE)
|
|
removeFromQueue(1)
|
|
|
|
else
|
|
visible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] \The [src] flashes: Insufficient materials: [getLackingMaterials(D)]."))
|
|
|
|
update_icon()
|
|
|
|
|
|
/**
|
|
* Checks if the protolathe can build the given design
|
|
*
|
|
* * design_to_check: The design to check
|
|
*
|
|
* Returns `TRUE` if the design can be built, `FALSE` otherwise
|
|
*/
|
|
/obj/machinery/r_n_d/protolathe/proc/canBuild(datum/design/design_to_check)
|
|
for(var/M in design_to_check.materials)
|
|
if(materials[M] < design_to_check.materials[M])
|
|
return FALSE
|
|
|
|
for(var/C in design_to_check.chemicals)
|
|
if(!reagents.has_reagent(C, design_to_check.chemicals[C]))
|
|
return FALSE
|
|
|
|
return TRUE
|
|
|
|
/**
|
|
* Get what materials (chemicals included) are lacking from being able to build the given design
|
|
*
|
|
* * design_to_check: The design to check
|
|
*
|
|
* Returns a string of the materials that are missing
|
|
*/
|
|
/obj/machinery/r_n_d/protolathe/proc/getLackingMaterials(var/datum/design/design_to_check)
|
|
var/ret = ""
|
|
for(var/M in design_to_check.materials)
|
|
if(materials[M] < design_to_check.materials[M])
|
|
if(ret != "")
|
|
ret += ", "
|
|
ret += "[design_to_check.materials[M] - materials[M]] [M]"
|
|
for(var/C in design_to_check.chemicals)
|
|
if(!reagents.has_reagent(C, design_to_check.chemicals[C]))
|
|
var/singleton/reagent/R = GET_SINGLETON(C)
|
|
if(ret != "")
|
|
ret += ", "
|
|
ret += "[R.name]"
|
|
return ret
|
|
|
|
/**
|
|
* Builds the given design, assuming all the necessary conditions are met
|
|
*
|
|
* * design_to_build: The design to build
|
|
*/
|
|
/obj/machinery/r_n_d/protolathe/proc/build(datum/design/design_to_build)
|
|
//Consume some power
|
|
var/power = active_power_usage
|
|
for(var/M in design_to_build.materials)
|
|
power += round(design_to_build.materials[M] / 2)
|
|
power = max(active_power_usage, power)
|
|
use_power_oneoff(power)
|
|
|
|
//Consume the materials
|
|
for(var/M in design_to_build.materials)
|
|
materials[M] = max(0, materials[M] - design_to_build.materials[M] * mat_efficiency)
|
|
for(var/C in design_to_build.chemicals)
|
|
reagents.remove_reagent(C, design_to_build.chemicals[C] * mat_efficiency)
|
|
|
|
intent_message(MACHINE_SOUND)
|
|
|
|
if(design_to_build.build_path)
|
|
var/obj/new_item = design_to_build.Fabricate(src, src)
|
|
new_item.forceMove(loc)
|
|
if(mat_efficiency != 1) // No matter out of nowhere
|
|
if(new_item.matter && new_item.matter.len > 0)
|
|
for(var/i in new_item.matter)
|
|
new_item.matter[i] = new_item.matter[i] * mat_efficiency
|
|
|
|
if(linked_console)
|
|
linked_console.updateUsrDialog()
|
|
|
|
//We finished building, clear the timer
|
|
build_callback_timer = null
|
|
|
|
//Do the queue handling for the next item, or to stop
|
|
handle_queue()
|