mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 10:43:20 +00:00
Moar whitespace normalization [MDB IGNORE] (#7750)
Co-authored-by: Raeschen <rycoop29@gmail.com>
This commit is contained in:
@@ -1,217 +1,217 @@
|
||||
/*///////////////Circuit Imprinter (By Darem)////////////////////////
|
||||
Used to print new circuit boards (for computers and similar systems) and AI modules. Each circuit board pattern are stored in
|
||||
a /datum/desgin on the linked R&D console. You can then print them out in a fasion similar to a regular lathe. However, instead of
|
||||
using metal and glass, it uses glass and reagents (usually sulphuric acid).
|
||||
*/
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter
|
||||
name = "Circuit Imprinter"
|
||||
icon_state = "circuit_imprinter"
|
||||
flags = OPENCONTAINER
|
||||
circuit = /obj/item/weapon/circuitboard/circuit_imprinter
|
||||
var/list/datum/design/queue = list()
|
||||
var/progress = 0
|
||||
|
||||
var/max_material_storage = 75000
|
||||
var/mat_efficiency = 1
|
||||
var/speed = 1
|
||||
|
||||
materials = list(MAT_STEEL = 0, MAT_GLASS = 0, MAT_PLASTEEL = 0, MAT_PLASTIC = 0, MAT_GRAPHITE = 0, MAT_GOLD = 0, MAT_SILVER = 0, MAT_OSMIUM = 0, MAT_LEAD = 0, MAT_PHORON = 0, MAT_URANIUM = 0, MAT_DIAMOND = 0, MAT_DURASTEEL = 0, MAT_VERDANTIUM = 0, MAT_MORPHIUM = 0, MAT_METALHYDROGEN = 0, MAT_SUPERMATTER = 0)
|
||||
|
||||
hidden_materials = list(MAT_PLASTEEL, MAT_DURASTEEL, MAT_GRAPHITE, MAT_VERDANTIUM, MAT_MORPHIUM, MAT_METALHYDROGEN, MAT_SUPERMATTER)
|
||||
|
||||
use_power = USE_POWER_IDLE
|
||||
idle_power_usage = 30
|
||||
active_power_usage = 2500
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/Initialize()
|
||||
. = ..()
|
||||
|
||||
spawn() // Go through all materials, and add them to the possible storage, but hide them unless we contain them.
|
||||
for(var/Name in name_to_material)
|
||||
if(Name in materials)
|
||||
continue
|
||||
|
||||
hidden_materials |= Name
|
||||
|
||||
materials[Name] = 0
|
||||
|
||||
default_apply_parts()
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/process()
|
||||
..()
|
||||
if(stat)
|
||||
update_icon()
|
||||
return
|
||||
if(queue.len == 0)
|
||||
busy = 0
|
||||
update_icon()
|
||||
return
|
||||
var/datum/design/D = queue[1]
|
||||
if(canBuild(D))
|
||||
busy = 1
|
||||
progress += speed
|
||||
if(progress >= D.time)
|
||||
build(D)
|
||||
progress = 0
|
||||
removeFromQueue(1)
|
||||
if(linked_console)
|
||||
linked_console.updateUsrDialog()
|
||||
update_icon()
|
||||
else
|
||||
if(busy)
|
||||
visible_message("<span class='notice'>\icon [src] flashes: insufficient materials: [getLackingMaterials(D)].</span>")
|
||||
busy = 0
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/RefreshParts()
|
||||
var/T = 0
|
||||
for(var/obj/item/weapon/reagent_containers/glass/G in component_parts)
|
||||
T += G.reagents.maximum_volume
|
||||
create_reagents(T)
|
||||
max_material_storage = 0
|
||||
for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts)
|
||||
max_material_storage += M.rating * 75000
|
||||
T = 0
|
||||
for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
|
||||
T += M.rating
|
||||
mat_efficiency = max(1 - (T - 1) / 4, 0.2)
|
||||
speed = T
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/update_icon()
|
||||
if(panel_open)
|
||||
icon_state = "circuit_imprinter_t"
|
||||
else if(busy)
|
||||
icon_state = "circuit_imprinter_ani"
|
||||
else
|
||||
icon_state = "circuit_imprinter"
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/proc/TotalMaterials()
|
||||
var/t = 0
|
||||
for(var/f in materials)
|
||||
t += materials[f]
|
||||
return t
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/dismantle()
|
||||
for(var/obj/I in component_parts)
|
||||
if(istype(I, /obj/item/weapon/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)
|
||||
new path(loc, round(materials[f] / SHEET_MATERIAL_AMOUNT))
|
||||
..()
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if(busy)
|
||||
to_chat(user, "<span class='notice'>\The [src] is busy. Please wait for completion of previous operation.</span>")
|
||||
return 1
|
||||
if(default_deconstruction_screwdriver(user, O))
|
||||
if(linked_console)
|
||||
linked_console.linked_imprinter = null
|
||||
linked_console = null
|
||||
return
|
||||
if(default_deconstruction_crowbar(user, O))
|
||||
return
|
||||
if(default_part_replacement(user, O))
|
||||
return
|
||||
if(istype(O, /obj/item/weapon/gripper/no_use/loader))
|
||||
return 0 //Sheet loaders weren't finishing attack(), this prevents the message "You can't stuff that gripper into this" without preventing the rest of the attack sequence from finishing
|
||||
if(panel_open)
|
||||
to_chat(user, "<span class='notice'>You can't load \the [src] while it's opened.</span>")
|
||||
return 1
|
||||
if(!linked_console)
|
||||
to_chat(user, "\The [src] must be linked to an R&D console first.")
|
||||
return 1
|
||||
if(O.is_open_container())
|
||||
return 0
|
||||
if(!istype(O, /obj/item/stack/material)) //Previously checked for specific material sheets, for some reason? Made the check on 133 redundant.
|
||||
to_chat(user, "<span class='notice'>You cannot insert this item into \the [src].</span>")
|
||||
return 1
|
||||
if(stat)
|
||||
return 1
|
||||
|
||||
if(TotalMaterials() + SHEET_MATERIAL_AMOUNT > max_material_storage)
|
||||
to_chat(user, "<span class='notice'>\The [src]'s material bin is full. Please remove material before adding more.</span>")
|
||||
return 1
|
||||
|
||||
var/obj/item/stack/material/S = O
|
||||
if(!(S.material.name in materials))
|
||||
to_chat(user, "<span class='warning'>The [src] doesn't accept [S.material]!</span>")
|
||||
return
|
||||
|
||||
busy = 1
|
||||
var/sname = "[S.name]"
|
||||
var/amnt = S.perunit
|
||||
var/max_res_amount = max_material_storage
|
||||
for(var/mat in materials)
|
||||
max_res_amount -= materials[mat]
|
||||
|
||||
if(materials[S.material.name] + amnt <= max_res_amount)
|
||||
if(S && S.get_amount() >= 1)
|
||||
var/count = 0
|
||||
add_overlay("fab-load-metal")
|
||||
spawn(10)
|
||||
cut_overlay("fab-load-metal")
|
||||
while(materials[S.material.name] + amnt <= max_res_amount && S.get_amount() >= 1)
|
||||
materials[S.material.name] += amnt
|
||||
S.use(1)
|
||||
count++
|
||||
to_chat(user, "<span class='filter_notice'>You insert [count] [sname] into the fabricator.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='filter_notice'>The fabricator cannot hold more [sname].</span>")
|
||||
busy = 0
|
||||
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/proc/addToQueue(var/datum/design/D)
|
||||
queue += D
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/proc/removeFromQueue(var/index)
|
||||
queue.Cut(index, index + 1)
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/proc/canBuild(var/datum/design/D)
|
||||
for(var/M in D.materials)
|
||||
if(materials[M] < (D.materials[M] * mat_efficiency))
|
||||
return 0
|
||||
for(var/C in D.chemicals)
|
||||
if(!reagents.has_reagent(C, D.chemicals[C] * mat_efficiency))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/proc/getLackingMaterials(var/datum/design/D)
|
||||
var/ret = ""
|
||||
for(var/M in D.materials)
|
||||
if(materials[M] < D.materials[M])
|
||||
if(ret != "")
|
||||
ret += ", "
|
||||
ret += "[D.materials[M] - materials[M]] [M]"
|
||||
for(var/C in D.chemicals)
|
||||
if(!reagents.has_reagent(C, D.chemicals[C]))
|
||||
if(ret != "")
|
||||
ret += ", "
|
||||
ret += C
|
||||
return ret
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/proc/build(var/datum/design/D)
|
||||
var/power = active_power_usage
|
||||
for(var/M in D.materials)
|
||||
power += round(D.materials[M] / 5)
|
||||
power = max(active_power_usage, power)
|
||||
use_power(power)
|
||||
for(var/M in D.materials)
|
||||
materials[M] = max(0, materials[M] - D.materials[M] * mat_efficiency)
|
||||
for(var/C in D.chemicals)
|
||||
reagents.remove_reagent(C, D.chemicals[C] * mat_efficiency)
|
||||
|
||||
if(D.build_path)
|
||||
var/obj/new_item = D.Fabricate(src, src)
|
||||
new_item.loc = 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
|
||||
/*///////////////Circuit Imprinter (By Darem)////////////////////////
|
||||
Used to print new circuit boards (for computers and similar systems) and AI modules. Each circuit board pattern are stored in
|
||||
a /datum/desgin on the linked R&D console. You can then print them out in a fasion similar to a regular lathe. However, instead of
|
||||
using metal and glass, it uses glass and reagents (usually sulphuric acid).
|
||||
*/
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter
|
||||
name = "Circuit Imprinter"
|
||||
icon_state = "circuit_imprinter"
|
||||
flags = OPENCONTAINER
|
||||
circuit = /obj/item/weapon/circuitboard/circuit_imprinter
|
||||
var/list/datum/design/queue = list()
|
||||
var/progress = 0
|
||||
|
||||
var/max_material_storage = 75000
|
||||
var/mat_efficiency = 1
|
||||
var/speed = 1
|
||||
|
||||
materials = list(MAT_STEEL = 0, MAT_GLASS = 0, MAT_PLASTEEL = 0, MAT_PLASTIC = 0, MAT_GRAPHITE = 0, MAT_GOLD = 0, MAT_SILVER = 0, MAT_OSMIUM = 0, MAT_LEAD = 0, MAT_PHORON = 0, MAT_URANIUM = 0, MAT_DIAMOND = 0, MAT_DURASTEEL = 0, MAT_VERDANTIUM = 0, MAT_MORPHIUM = 0, MAT_METALHYDROGEN = 0, MAT_SUPERMATTER = 0)
|
||||
|
||||
hidden_materials = list(MAT_PLASTEEL, MAT_DURASTEEL, MAT_GRAPHITE, MAT_VERDANTIUM, MAT_MORPHIUM, MAT_METALHYDROGEN, MAT_SUPERMATTER)
|
||||
|
||||
use_power = USE_POWER_IDLE
|
||||
idle_power_usage = 30
|
||||
active_power_usage = 2500
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/Initialize()
|
||||
. = ..()
|
||||
|
||||
spawn() // Go through all materials, and add them to the possible storage, but hide them unless we contain them.
|
||||
for(var/Name in name_to_material)
|
||||
if(Name in materials)
|
||||
continue
|
||||
|
||||
hidden_materials |= Name
|
||||
|
||||
materials[Name] = 0
|
||||
|
||||
default_apply_parts()
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/process()
|
||||
..()
|
||||
if(stat)
|
||||
update_icon()
|
||||
return
|
||||
if(queue.len == 0)
|
||||
busy = 0
|
||||
update_icon()
|
||||
return
|
||||
var/datum/design/D = queue[1]
|
||||
if(canBuild(D))
|
||||
busy = 1
|
||||
progress += speed
|
||||
if(progress >= D.time)
|
||||
build(D)
|
||||
progress = 0
|
||||
removeFromQueue(1)
|
||||
if(linked_console)
|
||||
linked_console.updateUsrDialog()
|
||||
update_icon()
|
||||
else
|
||||
if(busy)
|
||||
visible_message("<span class='notice'>\icon [src] flashes: insufficient materials: [getLackingMaterials(D)].</span>")
|
||||
busy = 0
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/RefreshParts()
|
||||
var/T = 0
|
||||
for(var/obj/item/weapon/reagent_containers/glass/G in component_parts)
|
||||
T += G.reagents.maximum_volume
|
||||
create_reagents(T)
|
||||
max_material_storage = 0
|
||||
for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts)
|
||||
max_material_storage += M.rating * 75000
|
||||
T = 0
|
||||
for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
|
||||
T += M.rating
|
||||
mat_efficiency = max(1 - (T - 1) / 4, 0.2)
|
||||
speed = T
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/update_icon()
|
||||
if(panel_open)
|
||||
icon_state = "circuit_imprinter_t"
|
||||
else if(busy)
|
||||
icon_state = "circuit_imprinter_ani"
|
||||
else
|
||||
icon_state = "circuit_imprinter"
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/proc/TotalMaterials()
|
||||
var/t = 0
|
||||
for(var/f in materials)
|
||||
t += materials[f]
|
||||
return t
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/dismantle()
|
||||
for(var/obj/I in component_parts)
|
||||
if(istype(I, /obj/item/weapon/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)
|
||||
new path(loc, round(materials[f] / SHEET_MATERIAL_AMOUNT))
|
||||
..()
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if(busy)
|
||||
to_chat(user, "<span class='notice'>\The [src] is busy. Please wait for completion of previous operation.</span>")
|
||||
return 1
|
||||
if(default_deconstruction_screwdriver(user, O))
|
||||
if(linked_console)
|
||||
linked_console.linked_imprinter = null
|
||||
linked_console = null
|
||||
return
|
||||
if(default_deconstruction_crowbar(user, O))
|
||||
return
|
||||
if(default_part_replacement(user, O))
|
||||
return
|
||||
if(istype(O, /obj/item/weapon/gripper/no_use/loader))
|
||||
return 0 //Sheet loaders weren't finishing attack(), this prevents the message "You can't stuff that gripper into this" without preventing the rest of the attack sequence from finishing
|
||||
if(panel_open)
|
||||
to_chat(user, "<span class='notice'>You can't load \the [src] while it's opened.</span>")
|
||||
return 1
|
||||
if(!linked_console)
|
||||
to_chat(user, "\The [src] must be linked to an R&D console first.")
|
||||
return 1
|
||||
if(O.is_open_container())
|
||||
return 0
|
||||
if(!istype(O, /obj/item/stack/material)) //Previously checked for specific material sheets, for some reason? Made the check on 133 redundant.
|
||||
to_chat(user, "<span class='notice'>You cannot insert this item into \the [src].</span>")
|
||||
return 1
|
||||
if(stat)
|
||||
return 1
|
||||
|
||||
if(TotalMaterials() + SHEET_MATERIAL_AMOUNT > max_material_storage)
|
||||
to_chat(user, "<span class='notice'>\The [src]'s material bin is full. Please remove material before adding more.</span>")
|
||||
return 1
|
||||
|
||||
var/obj/item/stack/material/S = O
|
||||
if(!(S.material.name in materials))
|
||||
to_chat(user, "<span class='warning'>The [src] doesn't accept [S.material]!</span>")
|
||||
return
|
||||
|
||||
busy = 1
|
||||
var/sname = "[S.name]"
|
||||
var/amnt = S.perunit
|
||||
var/max_res_amount = max_material_storage
|
||||
for(var/mat in materials)
|
||||
max_res_amount -= materials[mat]
|
||||
|
||||
if(materials[S.material.name] + amnt <= max_res_amount)
|
||||
if(S && S.get_amount() >= 1)
|
||||
var/count = 0
|
||||
add_overlay("fab-load-metal")
|
||||
spawn(10)
|
||||
cut_overlay("fab-load-metal")
|
||||
while(materials[S.material.name] + amnt <= max_res_amount && S.get_amount() >= 1)
|
||||
materials[S.material.name] += amnt
|
||||
S.use(1)
|
||||
count++
|
||||
to_chat(user, "<span class='filter_notice'>You insert [count] [sname] into the fabricator.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='filter_notice'>The fabricator cannot hold more [sname].</span>")
|
||||
busy = 0
|
||||
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/proc/addToQueue(var/datum/design/D)
|
||||
queue += D
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/proc/removeFromQueue(var/index)
|
||||
queue.Cut(index, index + 1)
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/proc/canBuild(var/datum/design/D)
|
||||
for(var/M in D.materials)
|
||||
if(materials[M] < (D.materials[M] * mat_efficiency))
|
||||
return 0
|
||||
for(var/C in D.chemicals)
|
||||
if(!reagents.has_reagent(C, D.chemicals[C] * mat_efficiency))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/proc/getLackingMaterials(var/datum/design/D)
|
||||
var/ret = ""
|
||||
for(var/M in D.materials)
|
||||
if(materials[M] < D.materials[M])
|
||||
if(ret != "")
|
||||
ret += ", "
|
||||
ret += "[D.materials[M] - materials[M]] [M]"
|
||||
for(var/C in D.chemicals)
|
||||
if(!reagents.has_reagent(C, D.chemicals[C]))
|
||||
if(ret != "")
|
||||
ret += ", "
|
||||
ret += C
|
||||
return ret
|
||||
|
||||
/obj/machinery/r_n_d/circuit_imprinter/proc/build(var/datum/design/D)
|
||||
var/power = active_power_usage
|
||||
for(var/M in D.materials)
|
||||
power += round(D.materials[M] / 5)
|
||||
power = max(active_power_usage, power)
|
||||
use_power(power)
|
||||
for(var/M in D.materials)
|
||||
materials[M] = max(0, materials[M] - D.materials[M] * mat_efficiency)
|
||||
for(var/C in D.chemicals)
|
||||
reagents.remove_reagent(C, D.chemicals[C] * mat_efficiency)
|
||||
|
||||
if(D.build_path)
|
||||
var/obj/new_item = D.Fabricate(src, src)
|
||||
new_item.loc = 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
|
||||
|
||||
@@ -1,87 +1,87 @@
|
||||
/***************************************************************
|
||||
** Design Datums **
|
||||
** All the data for building stuff and tracking reliability. **
|
||||
***************************************************************/
|
||||
/*
|
||||
For the materials datum, it assumes you need reagents unless specified otherwise. To designate a material that isn't a reagent,
|
||||
you use one of the material IDs below. These are NOT ids in the usual sense (they aren't defined in the object or part of a datum),
|
||||
they are simply references used as part of a "has materials?" type proc. They all start with a to denote that they aren't reagents.
|
||||
The currently supporting non-reagent materials:
|
||||
|
||||
Don't add new keyword/IDs if they are made from an existing one (such as rods which are made from metal). Only add raw materials.
|
||||
|
||||
Design Guidlines
|
||||
- When adding new designs, check rdreadme.dm to see what kind of things have already been made and where new stuff is needed.
|
||||
- A single sheet of anything is 2000 units of material. Materials besides metal/glass require help from other jobs (mining for
|
||||
other types of metals and chemistry for reagents).
|
||||
|
||||
*/
|
||||
//Note: More then one of these can be added to a design.
|
||||
|
||||
/datum/design //Datum for object designs, used in construction
|
||||
var/name = null //Name of the created object. If null it will be 'guessed' from build_path if possible.
|
||||
var/desc = null //Description of the created object. If null it will use group_desc and name where applicable.
|
||||
var/item_name = null //An item name before it is modified by various name-modifying procs
|
||||
var/id = "id" //ID of the created object for easy refernece. Alphanumeric, lower-case, no symbols.
|
||||
var/list/req_tech = list() //IDs of that techs the object originated from and the minimum level requirements.
|
||||
var/build_type = null //Flag as to what kind machine the design is built in. See defines.
|
||||
var/list/materials = list() //List of materials. Format: "id" = amount.
|
||||
var/list/chemicals = list() //List of chemicals.
|
||||
var/build_path = null //The path of the object that gets created.
|
||||
var/time = 10 //How many ticks it requires to build
|
||||
var/list/category = list() //Primarily used for Mech Fabricators, but can be used for anything.
|
||||
var/sort_string = "ZZZZZ" //Sorting order
|
||||
var/search_metadata // Optional string that interfaces can use as part of search filters. See- item/borg/upgrade/ai and the Exosuit Fabs.
|
||||
|
||||
/datum/design/New()
|
||||
..()
|
||||
if(!islist(category))
|
||||
log_runtime(EXCEPTION("Warning: Design [type] defined a non-list category. Please fix this."))
|
||||
category = list(category)
|
||||
item_name = name
|
||||
AssembleDesignInfo()
|
||||
|
||||
//These procs are used in subtypes for assigning names and descriptions dynamically
|
||||
/datum/design/proc/AssembleDesignInfo()
|
||||
AssembleDesignName()
|
||||
AssembleDesignDesc()
|
||||
return
|
||||
|
||||
/datum/design/proc/AssembleDesignName()
|
||||
if(!name && build_path) //Get name from build path if posible
|
||||
var/atom/movable/A = build_path
|
||||
name = initial(A.name)
|
||||
item_name = name
|
||||
return
|
||||
|
||||
/datum/design/proc/AssembleDesignDesc()
|
||||
if(!desc) //Try to make up a nice description if we don't have one
|
||||
desc = "Allows for the construction of \a [item_name]."
|
||||
return
|
||||
|
||||
//Returns a new instance of the item for this design
|
||||
//This is to allow additional initialization to be performed, including possibly additional contructor arguments.
|
||||
/datum/design/proc/Fabricate(var/newloc, var/fabricator)
|
||||
return new build_path(newloc)
|
||||
|
||||
/datum/design/item
|
||||
build_type = PROTOLATHE
|
||||
|
||||
//Make sure items don't get free power, or resources. Also make things be recycled with proper values.
|
||||
/datum/design/item/Fabricate()
|
||||
var/obj/item/I = ..()
|
||||
|
||||
if(LAZYLEN(materials))
|
||||
if(!LAZYLEN(I.matter))
|
||||
I.matter = list()
|
||||
else
|
||||
I.matter.Cut()
|
||||
|
||||
for(var/matname in materials)
|
||||
I.matter[matname] = materials[matname]
|
||||
|
||||
var/obj/item/weapon/cell/C = I.get_cell()
|
||||
if(C)
|
||||
C.charge = 0
|
||||
I.update_icon()
|
||||
/***************************************************************
|
||||
** Design Datums **
|
||||
** All the data for building stuff and tracking reliability. **
|
||||
***************************************************************/
|
||||
/*
|
||||
For the materials datum, it assumes you need reagents unless specified otherwise. To designate a material that isn't a reagent,
|
||||
you use one of the material IDs below. These are NOT ids in the usual sense (they aren't defined in the object or part of a datum),
|
||||
they are simply references used as part of a "has materials?" type proc. They all start with a to denote that they aren't reagents.
|
||||
The currently supporting non-reagent materials:
|
||||
|
||||
Don't add new keyword/IDs if they are made from an existing one (such as rods which are made from metal). Only add raw materials.
|
||||
|
||||
Design Guidlines
|
||||
- When adding new designs, check rdreadme.dm to see what kind of things have already been made and where new stuff is needed.
|
||||
- A single sheet of anything is 2000 units of material. Materials besides metal/glass require help from other jobs (mining for
|
||||
other types of metals and chemistry for reagents).
|
||||
|
||||
*/
|
||||
//Note: More then one of these can be added to a design.
|
||||
|
||||
/datum/design //Datum for object designs, used in construction
|
||||
var/name = null //Name of the created object. If null it will be 'guessed' from build_path if possible.
|
||||
var/desc = null //Description of the created object. If null it will use group_desc and name where applicable.
|
||||
var/item_name = null //An item name before it is modified by various name-modifying procs
|
||||
var/id = "id" //ID of the created object for easy refernece. Alphanumeric, lower-case, no symbols.
|
||||
var/list/req_tech = list() //IDs of that techs the object originated from and the minimum level requirements.
|
||||
var/build_type = null //Flag as to what kind machine the design is built in. See defines.
|
||||
var/list/materials = list() //List of materials. Format: "id" = amount.
|
||||
var/list/chemicals = list() //List of chemicals.
|
||||
var/build_path = null //The path of the object that gets created.
|
||||
var/time = 10 //How many ticks it requires to build
|
||||
var/list/category = list() //Primarily used for Mech Fabricators, but can be used for anything.
|
||||
var/sort_string = "ZZZZZ" //Sorting order
|
||||
var/search_metadata // Optional string that interfaces can use as part of search filters. See- item/borg/upgrade/ai and the Exosuit Fabs.
|
||||
|
||||
/datum/design/New()
|
||||
..()
|
||||
if(!islist(category))
|
||||
log_runtime(EXCEPTION("Warning: Design [type] defined a non-list category. Please fix this."))
|
||||
category = list(category)
|
||||
item_name = name
|
||||
AssembleDesignInfo()
|
||||
|
||||
//These procs are used in subtypes for assigning names and descriptions dynamically
|
||||
/datum/design/proc/AssembleDesignInfo()
|
||||
AssembleDesignName()
|
||||
AssembleDesignDesc()
|
||||
return
|
||||
|
||||
/datum/design/proc/AssembleDesignName()
|
||||
if(!name && build_path) //Get name from build path if posible
|
||||
var/atom/movable/A = build_path
|
||||
name = initial(A.name)
|
||||
item_name = name
|
||||
return
|
||||
|
||||
/datum/design/proc/AssembleDesignDesc()
|
||||
if(!desc) //Try to make up a nice description if we don't have one
|
||||
desc = "Allows for the construction of \a [item_name]."
|
||||
return
|
||||
|
||||
//Returns a new instance of the item for this design
|
||||
//This is to allow additional initialization to be performed, including possibly additional contructor arguments.
|
||||
/datum/design/proc/Fabricate(var/newloc, var/fabricator)
|
||||
return new build_path(newloc)
|
||||
|
||||
/datum/design/item
|
||||
build_type = PROTOLATHE
|
||||
|
||||
//Make sure items don't get free power, or resources. Also make things be recycled with proper values.
|
||||
/datum/design/item/Fabricate()
|
||||
var/obj/item/I = ..()
|
||||
|
||||
if(LAZYLEN(materials))
|
||||
if(!LAZYLEN(I.matter))
|
||||
I.matter = list()
|
||||
else
|
||||
I.matter.Cut()
|
||||
|
||||
for(var/matname in materials)
|
||||
I.matter[matname] = materials[matname]
|
||||
|
||||
var/obj/item/weapon/cell/C = I.get_cell()
|
||||
if(C)
|
||||
C.charge = 0
|
||||
I.update_icon()
|
||||
return I
|
||||
@@ -1,121 +1,121 @@
|
||||
/*
|
||||
Destructive Analyzer
|
||||
|
||||
It is used to destroy hand-held objects and advance technological research. Controls are in the linked R&D console.
|
||||
|
||||
Note: Must be placed within 3 tiles of the R&D Console
|
||||
*/
|
||||
|
||||
/obj/machinery/r_n_d/destructive_analyzer
|
||||
name = "destructive analyzer"
|
||||
icon_state = "d_analyzer"
|
||||
var/obj/item/weapon/loaded_item = null
|
||||
var/decon_mod = 0
|
||||
circuit = /obj/item/weapon/circuitboard/destructive_analyzer
|
||||
use_power = USE_POWER_IDLE
|
||||
idle_power_usage = 30
|
||||
active_power_usage = 2500
|
||||
var/rped_recycler_ready = TRUE
|
||||
|
||||
/obj/machinery/r_n_d/destructive_analyzer/Initialize()
|
||||
. = ..()
|
||||
default_apply_parts()
|
||||
|
||||
/obj/machinery/r_n_d/destructive_analyzer/RefreshParts()
|
||||
var/T = 0
|
||||
for(var/obj/item/weapon/stock_parts/S in component_parts)
|
||||
T += S.rating
|
||||
T *= 0.1
|
||||
decon_mod = clamp(T, 0, 1)
|
||||
|
||||
/obj/machinery/r_n_d/destructive_analyzer/update_icon()
|
||||
if(panel_open)
|
||||
icon_state = "d_analyzer_t"
|
||||
else if(loaded_item)
|
||||
icon_state = "d_analyzer_l"
|
||||
else
|
||||
icon_state = "d_analyzer"
|
||||
|
||||
/obj/machinery/r_n_d/destructive_analyzer/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if(busy)
|
||||
to_chat(user, "<span class='notice'>\The [src] is busy right now.</span>")
|
||||
return
|
||||
if(loaded_item)
|
||||
to_chat(user, "<span class='notice'>There is something already loaded into \the [src].</span>")
|
||||
return 1
|
||||
if(default_deconstruction_screwdriver(user, O))
|
||||
if(linked_console)
|
||||
linked_console.linked_destroy = null
|
||||
linked_console = null
|
||||
return
|
||||
if(default_deconstruction_crowbar(user, O))
|
||||
return
|
||||
if(default_part_replacement(user, O))
|
||||
return
|
||||
if(panel_open)
|
||||
to_chat(user, "<span class='notice'>You can't load \the [src] while it's opened.</span>")
|
||||
return 1
|
||||
if(!linked_console)
|
||||
to_chat(user, "<span class='notice'>\The [src] must be linked to an R&D console first.</span>")
|
||||
return
|
||||
if(!loaded_item)
|
||||
if(isrobot(user)) //Don't put your module items in there!
|
||||
return
|
||||
if(!O.origin_tech)
|
||||
to_chat(user, "<span class='notice'>This doesn't seem to have a tech origin.</span>")
|
||||
return
|
||||
if(O.origin_tech.len == 0)
|
||||
to_chat(user, "<span class='notice'>You cannot deconstruct this item.</span>")
|
||||
return
|
||||
busy = 1
|
||||
loaded_item = O
|
||||
user.drop_item()
|
||||
O.loc = src
|
||||
to_chat(user, "<span class='notice'>You add \the [O] to \the [src].</span>")
|
||||
flick("d_analyzer_la", src)
|
||||
spawn(10)
|
||||
update_icon()
|
||||
busy = 0
|
||||
return 1
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/destructive_analyzer/MouseDrop_T(atom/dropping, mob/living/user)
|
||||
if(istype(dropping, /obj/item/weapon/storage/part_replacer))
|
||||
var/obj/item/weapon/storage/part_replacer/replacer = dropping
|
||||
replacer.hide_from(user)
|
||||
if(!linked_console)
|
||||
to_chat(user, "<span class='notice'>\The [src] must be linked to an R&D console first.</span>")
|
||||
return 0
|
||||
if(!linked_console.linked_lathe)
|
||||
to_chat(user, "<span class='notice'>Link a protolathe to [src]'s R&D console first.</span>")
|
||||
return 0
|
||||
if(!rped_recycler_ready)
|
||||
to_chat(user, "<span class='notice'>\The [src]'s stock parts recycler isn't ready yet.</span>")
|
||||
return 0
|
||||
var/obj/machinery/r_n_d/protolathe/lathe_to_fill = linked_console.linked_lathe
|
||||
var/lowest_rating = INFINITY // We want the lowest-part tier rating in the RPED so we only recycle the lowest-tier parts.
|
||||
for(var/obj/item/B in replacer.contents)
|
||||
if(B.rped_rating() < lowest_rating)
|
||||
lowest_rating = B.rped_rating()
|
||||
if(lowest_rating == INFINITY)
|
||||
to_chat(user, "<span class='notice'>Mass part deconstruction attempt canceled - no valid parts for recycling detected.</span>")
|
||||
return 0
|
||||
for(var/obj/item/B in replacer.contents)
|
||||
if(B.rped_rating() > lowest_rating)
|
||||
continue
|
||||
if(lathe_to_fill && B.matter) // Sending salvaged materials to the lathe...
|
||||
for(var/t in B.matter)
|
||||
if(t in lathe_to_fill.materials)
|
||||
lathe_to_fill.materials[t] += B.matter[t] * src.decon_mod
|
||||
qdel(B)
|
||||
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
|
||||
rped_recycler_ready = FALSE
|
||||
addtimer(CALLBACK(src, PROC_REF(rped_ready)), 5 SECONDS)
|
||||
to_chat(user, "<span class='notice'>You deconstruct all the parts of rating [lowest_rating] in [replacer] with [src].</span>")
|
||||
return 1
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/r_n_d/destructive_analyzer/proc/rped_ready()
|
||||
rped_recycler_ready = TRUE
|
||||
playsound(get_turf(src), 'sound/machines/chime.ogg', 50, 1)
|
||||
/*
|
||||
Destructive Analyzer
|
||||
|
||||
It is used to destroy hand-held objects and advance technological research. Controls are in the linked R&D console.
|
||||
|
||||
Note: Must be placed within 3 tiles of the R&D Console
|
||||
*/
|
||||
|
||||
/obj/machinery/r_n_d/destructive_analyzer
|
||||
name = "destructive analyzer"
|
||||
icon_state = "d_analyzer"
|
||||
var/obj/item/weapon/loaded_item = null
|
||||
var/decon_mod = 0
|
||||
circuit = /obj/item/weapon/circuitboard/destructive_analyzer
|
||||
use_power = USE_POWER_IDLE
|
||||
idle_power_usage = 30
|
||||
active_power_usage = 2500
|
||||
var/rped_recycler_ready = TRUE
|
||||
|
||||
/obj/machinery/r_n_d/destructive_analyzer/Initialize()
|
||||
. = ..()
|
||||
default_apply_parts()
|
||||
|
||||
/obj/machinery/r_n_d/destructive_analyzer/RefreshParts()
|
||||
var/T = 0
|
||||
for(var/obj/item/weapon/stock_parts/S in component_parts)
|
||||
T += S.rating
|
||||
T *= 0.1
|
||||
decon_mod = clamp(T, 0, 1)
|
||||
|
||||
/obj/machinery/r_n_d/destructive_analyzer/update_icon()
|
||||
if(panel_open)
|
||||
icon_state = "d_analyzer_t"
|
||||
else if(loaded_item)
|
||||
icon_state = "d_analyzer_l"
|
||||
else
|
||||
icon_state = "d_analyzer"
|
||||
|
||||
/obj/machinery/r_n_d/destructive_analyzer/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if(busy)
|
||||
to_chat(user, "<span class='notice'>\The [src] is busy right now.</span>")
|
||||
return
|
||||
if(loaded_item)
|
||||
to_chat(user, "<span class='notice'>There is something already loaded into \the [src].</span>")
|
||||
return 1
|
||||
if(default_deconstruction_screwdriver(user, O))
|
||||
if(linked_console)
|
||||
linked_console.linked_destroy = null
|
||||
linked_console = null
|
||||
return
|
||||
if(default_deconstruction_crowbar(user, O))
|
||||
return
|
||||
if(default_part_replacement(user, O))
|
||||
return
|
||||
if(panel_open)
|
||||
to_chat(user, "<span class='notice'>You can't load \the [src] while it's opened.</span>")
|
||||
return 1
|
||||
if(!linked_console)
|
||||
to_chat(user, "<span class='notice'>\The [src] must be linked to an R&D console first.</span>")
|
||||
return
|
||||
if(!loaded_item)
|
||||
if(isrobot(user)) //Don't put your module items in there!
|
||||
return
|
||||
if(!O.origin_tech)
|
||||
to_chat(user, "<span class='notice'>This doesn't seem to have a tech origin.</span>")
|
||||
return
|
||||
if(O.origin_tech.len == 0)
|
||||
to_chat(user, "<span class='notice'>You cannot deconstruct this item.</span>")
|
||||
return
|
||||
busy = 1
|
||||
loaded_item = O
|
||||
user.drop_item()
|
||||
O.loc = src
|
||||
to_chat(user, "<span class='notice'>You add \the [O] to \the [src].</span>")
|
||||
flick("d_analyzer_la", src)
|
||||
spawn(10)
|
||||
update_icon()
|
||||
busy = 0
|
||||
return 1
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/destructive_analyzer/MouseDrop_T(atom/dropping, mob/living/user)
|
||||
if(istype(dropping, /obj/item/weapon/storage/part_replacer))
|
||||
var/obj/item/weapon/storage/part_replacer/replacer = dropping
|
||||
replacer.hide_from(user)
|
||||
if(!linked_console)
|
||||
to_chat(user, "<span class='notice'>\The [src] must be linked to an R&D console first.</span>")
|
||||
return 0
|
||||
if(!linked_console.linked_lathe)
|
||||
to_chat(user, "<span class='notice'>Link a protolathe to [src]'s R&D console first.</span>")
|
||||
return 0
|
||||
if(!rped_recycler_ready)
|
||||
to_chat(user, "<span class='notice'>\The [src]'s stock parts recycler isn't ready yet.</span>")
|
||||
return 0
|
||||
var/obj/machinery/r_n_d/protolathe/lathe_to_fill = linked_console.linked_lathe
|
||||
var/lowest_rating = INFINITY // We want the lowest-part tier rating in the RPED so we only recycle the lowest-tier parts.
|
||||
for(var/obj/item/B in replacer.contents)
|
||||
if(B.rped_rating() < lowest_rating)
|
||||
lowest_rating = B.rped_rating()
|
||||
if(lowest_rating == INFINITY)
|
||||
to_chat(user, "<span class='notice'>Mass part deconstruction attempt canceled - no valid parts for recycling detected.</span>")
|
||||
return 0
|
||||
for(var/obj/item/B in replacer.contents)
|
||||
if(B.rped_rating() > lowest_rating)
|
||||
continue
|
||||
if(lathe_to_fill && B.matter) // Sending salvaged materials to the lathe...
|
||||
for(var/t in B.matter)
|
||||
if(t in lathe_to_fill.materials)
|
||||
lathe_to_fill.materials[t] += B.matter[t] * src.decon_mod
|
||||
qdel(B)
|
||||
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
|
||||
rped_recycler_ready = FALSE
|
||||
addtimer(CALLBACK(src, PROC_REF(rped_ready)), 5 SECONDS)
|
||||
to_chat(user, "<span class='notice'>You deconstruct all the parts of rating [lowest_rating] in [replacer] with [src].</span>")
|
||||
return 1
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/r_n_d/destructive_analyzer/proc/rped_ready()
|
||||
rped_recycler_ready = TRUE
|
||||
playsound(get_turf(src), 'sound/machines/chime.ogg', 50, 1)
|
||||
|
||||
@@ -1,281 +1,281 @@
|
||||
/obj/machinery/r_n_d/protolathe
|
||||
name = "Protolathe"
|
||||
icon_state = "protolathe"
|
||||
flags = OPENCONTAINER
|
||||
circuit = /obj/item/weapon/circuitboard/protolathe
|
||||
use_power = USE_POWER_IDLE
|
||||
idle_power_usage = 30
|
||||
active_power_usage = 5000
|
||||
|
||||
var/max_material_storage = 100000
|
||||
|
||||
var/list/datum/design/queue = list()
|
||||
var/progress = 0
|
||||
|
||||
var/mat_efficiency = 1
|
||||
var/speed = 1
|
||||
var/list/LockedDesigns = list() //CHOMPADDITION: FOR VR mainly.
|
||||
//VOREStation Edit - Broke this into lines
|
||||
materials = list(
|
||||
MAT_STEEL = 0,
|
||||
MAT_GLASS = 0,
|
||||
MAT_PLASTEEL = 0,
|
||||
MAT_PLASTIC = 0,
|
||||
MAT_GRAPHITE = 0,
|
||||
MAT_GOLD = 0,
|
||||
MAT_SILVER = 0,
|
||||
MAT_OSMIUM = 0,
|
||||
MAT_LEAD = 0,
|
||||
MAT_PHORON = 0,
|
||||
MAT_URANIUM = 0,
|
||||
MAT_DIAMOND = 0,
|
||||
MAT_DURASTEEL = 0,
|
||||
MAT_VERDANTIUM = 0,
|
||||
MAT_MORPHIUM = 0,
|
||||
MAT_METALHYDROGEN = 0,
|
||||
MAT_SUPERMATTER = 0,
|
||||
MAT_TITANIUM = 0)
|
||||
|
||||
hidden_materials = list(MAT_PLASTEEL, MAT_DURASTEEL, MAT_GRAPHITE, MAT_VERDANTIUM, MAT_MORPHIUM, MAT_METALHYDROGEN, MAT_SUPERMATTER)
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/Initialize()
|
||||
. = ..()
|
||||
|
||||
// Go through all materials, and add them to the possible storage, but hide them unless we contain them.
|
||||
for(var/Name in name_to_material)
|
||||
if(Name in materials)
|
||||
continue
|
||||
|
||||
hidden_materials |= Name
|
||||
|
||||
materials[Name] = 0
|
||||
|
||||
default_apply_parts()
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/process()
|
||||
..()
|
||||
if(stat)
|
||||
update_icon()
|
||||
return
|
||||
if(queue.len == 0)
|
||||
busy = 0
|
||||
update_icon()
|
||||
return
|
||||
var/datum/design/D = queue[1]
|
||||
if(canBuild(D))
|
||||
busy = 1
|
||||
progress += speed
|
||||
if(progress >= D.time)
|
||||
build(D)
|
||||
progress = 0
|
||||
removeFromQueue(1)
|
||||
if(linked_console)
|
||||
linked_console.updateUsrDialog()
|
||||
flick("[initial(icon_state)]_finish", src)
|
||||
update_icon()
|
||||
else
|
||||
if(busy)
|
||||
visible_message("<span class='notice'>\icon [src] flashes: insufficient materials: [getLackingMaterials(D)].</span>")
|
||||
busy = 0
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/proc/TotalMaterials() //returns the total of all the stored materials. Makes code neater.
|
||||
var/t = 0
|
||||
for(var/f in materials)
|
||||
t += materials[f]
|
||||
return t
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/RefreshParts()
|
||||
var/T = 0
|
||||
for(var/obj/item/weapon/reagent_containers/glass/G in component_parts)
|
||||
T += G.reagents.maximum_volume
|
||||
create_reagents(T)
|
||||
max_material_storage = 0
|
||||
for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts)
|
||||
max_material_storage += M.rating * 75000
|
||||
T = 0
|
||||
for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
|
||||
T += M.rating
|
||||
mat_efficiency = max(1 - (T - 2) / 8, 0.2)
|
||||
speed = T / 2
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/dismantle()
|
||||
for(var/f in materials)
|
||||
eject_materials(f, -1)
|
||||
..()
|
||||
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/update_icon()
|
||||
cut_overlays()
|
||||
|
||||
icon_state = initial(icon_state)
|
||||
|
||||
if(panel_open)
|
||||
overlays.Add(image(icon, "[icon_state]_panel"))
|
||||
|
||||
if(stat & NOPOWER)
|
||||
return
|
||||
|
||||
if(busy)
|
||||
icon_state = "[icon_state]_work"
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if(busy)
|
||||
to_chat(user, "<span class='notice'>\The [src] is busy. Please wait for completion of previous operation.</span>")
|
||||
return 1
|
||||
if(!LAZYLEN(LockedDesigns) && default_deconstruction_screwdriver(user, O))//CHOMPADDITION Locked lathes are hard coded
|
||||
if(linked_console)
|
||||
linked_console.linked_lathe = null
|
||||
linked_console = null
|
||||
return
|
||||
if(default_deconstruction_crowbar(user, O))
|
||||
return
|
||||
if(default_part_replacement(user, O))
|
||||
return
|
||||
if(O.is_open_container())
|
||||
return 1
|
||||
if(istype(O, /obj/item/weapon/gripper/no_use/loader))
|
||||
return 0 //Sheet loaders weren't finishing attack(), this prevents the message "You can't stuff that gripper into this" without preventing the rest of the attack sequence from finishing
|
||||
if(panel_open)
|
||||
to_chat(user, "<span class='notice'>You can't load \the [src] while it's opened.</span>")
|
||||
return 1
|
||||
if(!linked_console)
|
||||
to_chat(user, "<span class='notice'>\The [src] must be linked to an R&D console first!</span>")
|
||||
return 1
|
||||
if(!istype(O, /obj/item/stack/material))
|
||||
to_chat(user, "<span class='notice'>You cannot insert this item into \the [src]!</span>")
|
||||
return 1
|
||||
if(stat)
|
||||
return 1
|
||||
|
||||
var/obj/item/stack/material/S = O
|
||||
if(!(S.material.name in materials))
|
||||
to_chat(user, "<span class='warning'>The [src] doesn't accept [S.material]!</span>")
|
||||
return
|
||||
|
||||
busy = 1
|
||||
var/sname = "[S.name]"
|
||||
var/amnt = S.perunit
|
||||
var/max_res_amount = max_material_storage
|
||||
for(var/mat in materials)
|
||||
max_res_amount -= materials[mat]
|
||||
|
||||
if(materials[S.material.name] + amnt <= max_res_amount)
|
||||
if(S && S.get_amount() >= 1)
|
||||
var/count = 0
|
||||
flick("[initial(icon_state)]_loading", src)
|
||||
while(materials[S.material.name] + amnt <= max_res_amount && S.get_amount() >= 1)
|
||||
materials[S.material.name] += amnt
|
||||
S.use(1)
|
||||
count++
|
||||
to_chat(user, "<span class='filter_notice'>You insert [count] [sname] into the fabricator.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='filter_notice'>The fabricator cannot hold more [sname].</span>")
|
||||
busy = 0
|
||||
|
||||
var/stacktype = S.type
|
||||
var/t = getMaterialName(stacktype)
|
||||
add_overlay("protolathe_[t]")
|
||||
spawn(10)
|
||||
cut_overlay("protolathe_[t]")
|
||||
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/proc/addToQueue(var/datum/design/D)
|
||||
queue += D
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/proc/removeFromQueue(var/index)
|
||||
queue.Cut(index, index + 1)
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/proc/canBuild(var/datum/design/D)
|
||||
//CHOMPADDITION: LOCKED designs
|
||||
for(var/datum/design/X in LockedDesigns)
|
||||
if(X == D)
|
||||
return 0
|
||||
//CHOMPADDITION: LOCKED designs
|
||||
for(var/M in D.materials)
|
||||
if(materials[M] < (D.materials[M] * mat_efficiency))
|
||||
return 0
|
||||
for(var/C in D.chemicals)
|
||||
if(!reagents.has_reagent(C, D.chemicals[C] * mat_efficiency))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/proc/getLackingMaterials(var/datum/design/D)
|
||||
var/ret = ""
|
||||
for(var/M in D.materials)
|
||||
if(materials[M] < D.materials[M])
|
||||
if(ret != "")
|
||||
ret += ", "
|
||||
ret += "[D.materials[M] - materials[M]] [M]"
|
||||
for(var/C in D.chemicals)
|
||||
if(!reagents.has_reagent(C, D.chemicals[C]))
|
||||
if(ret != "")
|
||||
ret += ", "
|
||||
ret += C
|
||||
return ret
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/proc/build(var/datum/design/D)
|
||||
var/power = active_power_usage
|
||||
for(var/M in D.materials)
|
||||
power += round(D.materials[M] / 5)
|
||||
power = max(active_power_usage, power)
|
||||
use_power(power)
|
||||
for(var/M in D.materials)
|
||||
materials[M] = max(0, materials[M] - D.materials[M] * mat_efficiency)
|
||||
for(var/C in D.chemicals)
|
||||
reagents.remove_reagent(C, D.chemicals[C] * mat_efficiency)
|
||||
|
||||
if(D.build_path)
|
||||
var/obj/new_item = D.Fabricate(src, src)
|
||||
new_item.loc = 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
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/proc/eject_materials(var/material, var/amount) // 0 amount = 0 means ejecting a full stack; -1 means eject everything
|
||||
var/recursive = amount == -1 ? TRUE : FALSE
|
||||
var/matstring = lowertext(material)
|
||||
|
||||
// 0 or null, nothing to eject
|
||||
if(!materials[matstring])
|
||||
return
|
||||
// Problem, fix problem and abort
|
||||
if(materials[matstring] < 0)
|
||||
warning("[src] tried to eject material '[material]', which it has 'materials[matstring]' of!")
|
||||
materials[matstring] = 0
|
||||
return
|
||||
|
||||
// Find the material datum for our material
|
||||
var/datum/material/M = get_material_by_name(matstring)
|
||||
if(!M)
|
||||
warning("[src] tried to eject material '[matstring]', which didn't match any known material datum!")
|
||||
return
|
||||
// Find what type of sheets it makes
|
||||
var/obj/item/stack/material/S = M.stack_type
|
||||
if(!S)
|
||||
warning("[src] tried to eject material '[matstring]', which didn't have a stack_type!")
|
||||
return
|
||||
|
||||
// If we were passed -1, then it's recursive ejection and we should eject all we can
|
||||
if(amount <= 0)
|
||||
amount = initial(S.max_amount)
|
||||
// Smaller of what we have left, or the desired amount (note the amount is in sheets, but the array stores perunit values)
|
||||
var/ejected = min(round(materials[matstring] / initial(S.perunit)), amount)
|
||||
|
||||
// Place a sheet
|
||||
S = M.place_sheet(get_turf(src), ejected)
|
||||
if(!istype(S))
|
||||
warning("[src] tried to eject material '[material]', which didn't generate a proper stack when asked!")
|
||||
return
|
||||
|
||||
// Reduce our amount stored
|
||||
materials[matstring] -= ejected * S.perunit
|
||||
|
||||
// Recurse if we have enough left for more sheets
|
||||
if(recursive && materials[matstring] >= S.perunit)
|
||||
eject_materials(matstring, -1)
|
||||
/obj/machinery/r_n_d/protolathe
|
||||
name = "Protolathe"
|
||||
icon_state = "protolathe"
|
||||
flags = OPENCONTAINER
|
||||
circuit = /obj/item/weapon/circuitboard/protolathe
|
||||
use_power = USE_POWER_IDLE
|
||||
idle_power_usage = 30
|
||||
active_power_usage = 5000
|
||||
|
||||
var/max_material_storage = 100000
|
||||
|
||||
var/list/datum/design/queue = list()
|
||||
var/progress = 0
|
||||
|
||||
var/mat_efficiency = 1
|
||||
var/speed = 1
|
||||
var/list/LockedDesigns = list() //CHOMPADDITION: FOR VR mainly.
|
||||
//VOREStation Edit - Broke this into lines
|
||||
materials = list(
|
||||
MAT_STEEL = 0,
|
||||
MAT_GLASS = 0,
|
||||
MAT_PLASTEEL = 0,
|
||||
MAT_PLASTIC = 0,
|
||||
MAT_GRAPHITE = 0,
|
||||
MAT_GOLD = 0,
|
||||
MAT_SILVER = 0,
|
||||
MAT_OSMIUM = 0,
|
||||
MAT_LEAD = 0,
|
||||
MAT_PHORON = 0,
|
||||
MAT_URANIUM = 0,
|
||||
MAT_DIAMOND = 0,
|
||||
MAT_DURASTEEL = 0,
|
||||
MAT_VERDANTIUM = 0,
|
||||
MAT_MORPHIUM = 0,
|
||||
MAT_METALHYDROGEN = 0,
|
||||
MAT_SUPERMATTER = 0,
|
||||
MAT_TITANIUM = 0)
|
||||
|
||||
hidden_materials = list(MAT_PLASTEEL, MAT_DURASTEEL, MAT_GRAPHITE, MAT_VERDANTIUM, MAT_MORPHIUM, MAT_METALHYDROGEN, MAT_SUPERMATTER)
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/Initialize()
|
||||
. = ..()
|
||||
|
||||
// Go through all materials, and add them to the possible storage, but hide them unless we contain them.
|
||||
for(var/Name in name_to_material)
|
||||
if(Name in materials)
|
||||
continue
|
||||
|
||||
hidden_materials |= Name
|
||||
|
||||
materials[Name] = 0
|
||||
|
||||
default_apply_parts()
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/process()
|
||||
..()
|
||||
if(stat)
|
||||
update_icon()
|
||||
return
|
||||
if(queue.len == 0)
|
||||
busy = 0
|
||||
update_icon()
|
||||
return
|
||||
var/datum/design/D = queue[1]
|
||||
if(canBuild(D))
|
||||
busy = 1
|
||||
progress += speed
|
||||
if(progress >= D.time)
|
||||
build(D)
|
||||
progress = 0
|
||||
removeFromQueue(1)
|
||||
if(linked_console)
|
||||
linked_console.updateUsrDialog()
|
||||
flick("[initial(icon_state)]_finish", src)
|
||||
update_icon()
|
||||
else
|
||||
if(busy)
|
||||
visible_message("<span class='notice'>\icon [src] flashes: insufficient materials: [getLackingMaterials(D)].</span>")
|
||||
busy = 0
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/proc/TotalMaterials() //returns the total of all the stored materials. Makes code neater.
|
||||
var/t = 0
|
||||
for(var/f in materials)
|
||||
t += materials[f]
|
||||
return t
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/RefreshParts()
|
||||
var/T = 0
|
||||
for(var/obj/item/weapon/reagent_containers/glass/G in component_parts)
|
||||
T += G.reagents.maximum_volume
|
||||
create_reagents(T)
|
||||
max_material_storage = 0
|
||||
for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts)
|
||||
max_material_storage += M.rating * 75000
|
||||
T = 0
|
||||
for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
|
||||
T += M.rating
|
||||
mat_efficiency = max(1 - (T - 2) / 8, 0.2)
|
||||
speed = T / 2
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/dismantle()
|
||||
for(var/f in materials)
|
||||
eject_materials(f, -1)
|
||||
..()
|
||||
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/update_icon()
|
||||
cut_overlays()
|
||||
|
||||
icon_state = initial(icon_state)
|
||||
|
||||
if(panel_open)
|
||||
overlays.Add(image(icon, "[icon_state]_panel"))
|
||||
|
||||
if(stat & NOPOWER)
|
||||
return
|
||||
|
||||
if(busy)
|
||||
icon_state = "[icon_state]_work"
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if(busy)
|
||||
to_chat(user, "<span class='notice'>\The [src] is busy. Please wait for completion of previous operation.</span>")
|
||||
return 1
|
||||
if(!LAZYLEN(LockedDesigns) && default_deconstruction_screwdriver(user, O))//CHOMPADDITION Locked lathes are hard coded
|
||||
if(linked_console)
|
||||
linked_console.linked_lathe = null
|
||||
linked_console = null
|
||||
return
|
||||
if(default_deconstruction_crowbar(user, O))
|
||||
return
|
||||
if(default_part_replacement(user, O))
|
||||
return
|
||||
if(O.is_open_container())
|
||||
return 1
|
||||
if(istype(O, /obj/item/weapon/gripper/no_use/loader))
|
||||
return 0 //Sheet loaders weren't finishing attack(), this prevents the message "You can't stuff that gripper into this" without preventing the rest of the attack sequence from finishing
|
||||
if(panel_open)
|
||||
to_chat(user, "<span class='notice'>You can't load \the [src] while it's opened.</span>")
|
||||
return 1
|
||||
if(!linked_console)
|
||||
to_chat(user, "<span class='notice'>\The [src] must be linked to an R&D console first!</span>")
|
||||
return 1
|
||||
if(!istype(O, /obj/item/stack/material))
|
||||
to_chat(user, "<span class='notice'>You cannot insert this item into \the [src]!</span>")
|
||||
return 1
|
||||
if(stat)
|
||||
return 1
|
||||
|
||||
var/obj/item/stack/material/S = O
|
||||
if(!(S.material.name in materials))
|
||||
to_chat(user, "<span class='warning'>The [src] doesn't accept [S.material]!</span>")
|
||||
return
|
||||
|
||||
busy = 1
|
||||
var/sname = "[S.name]"
|
||||
var/amnt = S.perunit
|
||||
var/max_res_amount = max_material_storage
|
||||
for(var/mat in materials)
|
||||
max_res_amount -= materials[mat]
|
||||
|
||||
if(materials[S.material.name] + amnt <= max_res_amount)
|
||||
if(S && S.get_amount() >= 1)
|
||||
var/count = 0
|
||||
flick("[initial(icon_state)]_loading", src)
|
||||
while(materials[S.material.name] + amnt <= max_res_amount && S.get_amount() >= 1)
|
||||
materials[S.material.name] += amnt
|
||||
S.use(1)
|
||||
count++
|
||||
to_chat(user, "<span class='filter_notice'>You insert [count] [sname] into the fabricator.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='filter_notice'>The fabricator cannot hold more [sname].</span>")
|
||||
busy = 0
|
||||
|
||||
var/stacktype = S.type
|
||||
var/t = getMaterialName(stacktype)
|
||||
add_overlay("protolathe_[t]")
|
||||
spawn(10)
|
||||
cut_overlay("protolathe_[t]")
|
||||
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/proc/addToQueue(var/datum/design/D)
|
||||
queue += D
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/proc/removeFromQueue(var/index)
|
||||
queue.Cut(index, index + 1)
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/proc/canBuild(var/datum/design/D)
|
||||
//CHOMPADDITION: LOCKED designs
|
||||
for(var/datum/design/X in LockedDesigns)
|
||||
if(X == D)
|
||||
return 0
|
||||
//CHOMPADDITION: LOCKED designs
|
||||
for(var/M in D.materials)
|
||||
if(materials[M] < (D.materials[M] * mat_efficiency))
|
||||
return 0
|
||||
for(var/C in D.chemicals)
|
||||
if(!reagents.has_reagent(C, D.chemicals[C] * mat_efficiency))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/proc/getLackingMaterials(var/datum/design/D)
|
||||
var/ret = ""
|
||||
for(var/M in D.materials)
|
||||
if(materials[M] < D.materials[M])
|
||||
if(ret != "")
|
||||
ret += ", "
|
||||
ret += "[D.materials[M] - materials[M]] [M]"
|
||||
for(var/C in D.chemicals)
|
||||
if(!reagents.has_reagent(C, D.chemicals[C]))
|
||||
if(ret != "")
|
||||
ret += ", "
|
||||
ret += C
|
||||
return ret
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/proc/build(var/datum/design/D)
|
||||
var/power = active_power_usage
|
||||
for(var/M in D.materials)
|
||||
power += round(D.materials[M] / 5)
|
||||
power = max(active_power_usage, power)
|
||||
use_power(power)
|
||||
for(var/M in D.materials)
|
||||
materials[M] = max(0, materials[M] - D.materials[M] * mat_efficiency)
|
||||
for(var/C in D.chemicals)
|
||||
reagents.remove_reagent(C, D.chemicals[C] * mat_efficiency)
|
||||
|
||||
if(D.build_path)
|
||||
var/obj/new_item = D.Fabricate(src, src)
|
||||
new_item.loc = 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
|
||||
|
||||
/obj/machinery/r_n_d/protolathe/proc/eject_materials(var/material, var/amount) // 0 amount = 0 means ejecting a full stack; -1 means eject everything
|
||||
var/recursive = amount == -1 ? TRUE : FALSE
|
||||
var/matstring = lowertext(material)
|
||||
|
||||
// 0 or null, nothing to eject
|
||||
if(!materials[matstring])
|
||||
return
|
||||
// Problem, fix problem and abort
|
||||
if(materials[matstring] < 0)
|
||||
warning("[src] tried to eject material '[material]', which it has 'materials[matstring]' of!")
|
||||
materials[matstring] = 0
|
||||
return
|
||||
|
||||
// Find the material datum for our material
|
||||
var/datum/material/M = get_material_by_name(matstring)
|
||||
if(!M)
|
||||
warning("[src] tried to eject material '[matstring]', which didn't match any known material datum!")
|
||||
return
|
||||
// Find what type of sheets it makes
|
||||
var/obj/item/stack/material/S = M.stack_type
|
||||
if(!S)
|
||||
warning("[src] tried to eject material '[matstring]', which didn't have a stack_type!")
|
||||
return
|
||||
|
||||
// If we were passed -1, then it's recursive ejection and we should eject all we can
|
||||
if(amount <= 0)
|
||||
amount = initial(S.max_amount)
|
||||
// Smaller of what we have left, or the desired amount (note the amount is in sheets, but the array stores perunit values)
|
||||
var/ejected = min(round(materials[matstring] / initial(S.perunit)), amount)
|
||||
|
||||
// Place a sheet
|
||||
S = M.place_sheet(get_turf(src), ejected)
|
||||
if(!istype(S))
|
||||
warning("[src] tried to eject material '[material]', which didn't generate a proper stack when asked!")
|
||||
return
|
||||
|
||||
// Reduce our amount stored
|
||||
materials[matstring] -= ejected * S.perunit
|
||||
|
||||
// Recurse if we have enough left for more sheets
|
||||
if(recursive && materials[matstring] >= S.perunit)
|
||||
eject_materials(matstring, -1)
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
/*
|
||||
Research and Development System. (Designed specifically for the /tg/station 13 (Space Station 13) open source project)
|
||||
|
||||
///////////////Overview///////////////////
|
||||
This system is a "tech tree" research and development system designed for SS13. It allows a "researcher" job (this document assumes
|
||||
the "scientist" job is given this role) the tools necessary to research new and better technologies. In general, the system works
|
||||
by breaking existing technology and using what you learn from to advance your knowledge of SCIENCE! As your knowledge progresses,
|
||||
you can build newer (and better?) devices (which you can also, eventually, deconstruct to advance your knowledge).
|
||||
|
||||
A brief overview is below. For more details, see the related files.
|
||||
|
||||
////////////Game Use/////////////
|
||||
The major research and development is performed using a combination of four machines:
|
||||
- R&D Console: A computer console that allows you to manipulate the other devices that are linked to it and view/manipulate the
|
||||
technologies you have researched so far.
|
||||
- Protolathe: Used to make new hand-held devices and parts for larger devices. All metals and reagents as raw materials.
|
||||
- Destructive Analyzer: You can put hand-held objects into it and it'll analyze them for technological advancements but it destroys
|
||||
them in the process. Destroyed items will send their raw materials to a linked Protolathe (if any)
|
||||
- Circuit Imprinter: Similar to the Protolathe, it allows for the construction of circuit boards. Uses glass and acid as the raw
|
||||
materials.
|
||||
|
||||
While researching you are dealing with two different types of information: Technology Paths and Device Designs. Technology Paths
|
||||
are the "Tech Trees" of the game. You start out with a number of them at the game start and they are improved by using the
|
||||
Destructive Analyzer. By themselves, they don't do a whole lot. However, they unlock Device Designs. This is the information used
|
||||
by the circuit imprinter and the protolathe to produce objects. It also tracks the current reliability of that particular design.
|
||||
|
||||
//EXISTING TECH
|
||||
Each tech path should have at LEAST one item at every level (levels 1 - 20). This is to allow for a more fluid progression of the
|
||||
researching. Existing tech (ie, anything you can find on the station or get from the quartermaster) shouldn't go higher then
|
||||
level 5 or 7. Everything past that should be stuff you research.
|
||||
|
||||
/*
|
||||
Research and Development System. (Designed specifically for the /tg/station 13 (Space Station 13) open source project)
|
||||
|
||||
///////////////Overview///////////////////
|
||||
This system is a "tech tree" research and development system designed for SS13. It allows a "researcher" job (this document assumes
|
||||
the "scientist" job is given this role) the tools necessary to research new and better technologies. In general, the system works
|
||||
by breaking existing technology and using what you learn from to advance your knowledge of SCIENCE! As your knowledge progresses,
|
||||
you can build newer (and better?) devices (which you can also, eventually, deconstruct to advance your knowledge).
|
||||
|
||||
A brief overview is below. For more details, see the related files.
|
||||
|
||||
////////////Game Use/////////////
|
||||
The major research and development is performed using a combination of four machines:
|
||||
- R&D Console: A computer console that allows you to manipulate the other devices that are linked to it and view/manipulate the
|
||||
technologies you have researched so far.
|
||||
- Protolathe: Used to make new hand-held devices and parts for larger devices. All metals and reagents as raw materials.
|
||||
- Destructive Analyzer: You can put hand-held objects into it and it'll analyze them for technological advancements but it destroys
|
||||
them in the process. Destroyed items will send their raw materials to a linked Protolathe (if any)
|
||||
- Circuit Imprinter: Similar to the Protolathe, it allows for the construction of circuit boards. Uses glass and acid as the raw
|
||||
materials.
|
||||
|
||||
While researching you are dealing with two different types of information: Technology Paths and Device Designs. Technology Paths
|
||||
are the "Tech Trees" of the game. You start out with a number of them at the game start and they are improved by using the
|
||||
Destructive Analyzer. By themselves, they don't do a whole lot. However, they unlock Device Designs. This is the information used
|
||||
by the circuit imprinter and the protolathe to produce objects. It also tracks the current reliability of that particular design.
|
||||
|
||||
//EXISTING TECH
|
||||
Each tech path should have at LEAST one item at every level (levels 1 - 20). This is to allow for a more fluid progression of the
|
||||
researching. Existing tech (ie, anything you can find on the station or get from the quartermaster) shouldn't go higher then
|
||||
level 5 or 7. Everything past that should be stuff you research.
|
||||
|
||||
*/
|
||||
@@ -1,185 +1,185 @@
|
||||
/*
|
||||
Research and Development (R&D) Console
|
||||
|
||||
This is the main work horse of the R&D system. It contains the menus/controls for the Destructive Analyzer, Protolathe, and Circuit
|
||||
imprinter. It also contains the /datum/research holder with all the known/possible technology paths and device designs.
|
||||
|
||||
Basic use: When it first is created, it will attempt to link up to related devices within 3 squares. It'll only link up if they
|
||||
aren't already linked to another console. Any consoles it cannot link up with (either because all of a certain type are already
|
||||
linked or there aren't any in range), you'll just not have access to that menu. In the settings menu, there are menu options that
|
||||
allow a player to attempt to re-sync with nearby consoles. You can also force it to disconnect from a specific console.
|
||||
|
||||
The imprinting and construction menus do NOT require toxins access to access but all the other menus do. However, if you leave it
|
||||
on a menu, nothing is to stop the person from using the options on that menu (although they won't be able to change to a different
|
||||
one). You can also lock the console on the settings menu if you're feeling paranoid and you don't want anyone messing with it who
|
||||
doesn't have toxins access.
|
||||
|
||||
When a R&D console is destroyed or even partially disassembled, you lose all research data on it. However, there are two ways around
|
||||
this dire fate:
|
||||
- The easiest way is to go to the settings menu and select "Sync Database with Network." That causes it to upload (but not download)
|
||||
it's data to every other device in the game. Each console has a "disconnect from network" option that'll will cause data base sync
|
||||
operations to skip that console. This is useful if you want to make a "public" R&D console or, for example, give the engineers
|
||||
a circuit imprinter with certain designs on it and don't want it accidentally updating. The downside of this method is that you have
|
||||
to have physical access to the other console to send data back. Note: An R&D console is on CentCom so if a random griffan happens to
|
||||
cause a ton of data to be lost, an admin can go send it back.
|
||||
- The second method is with Technology Disks and Design Disks. Each of these disks can hold a single technology or design datum in
|
||||
it's entirety. You can then take the disk to any R&D console and upload it's data to it. This method is a lot more secure (since it
|
||||
won't update every console in existence) but it's more of a hassle to do. Also, the disks can be stolen.
|
||||
*/
|
||||
|
||||
/obj/machinery/computer/rdconsole
|
||||
name = "R&D control console"
|
||||
desc = "Science, in a computer! Experiment results not guaranteed."
|
||||
icon_keyboard = "rd_key"
|
||||
icon_screen = "rdcomp"
|
||||
light_color = "#a97faa"
|
||||
circuit = /obj/item/weapon/circuitboard/rdconsole
|
||||
var/datum/research/files //Stores all the collected research data.
|
||||
var/obj/item/weapon/disk/tech_disk/t_disk = null //Stores the technology disk.
|
||||
var/obj/item/weapon/disk/design_disk/d_disk = null //Stores the design disk.
|
||||
|
||||
var/obj/machinery/r_n_d/destructive_analyzer/linked_destroy = null //Linked Destructive Analyzer
|
||||
var/obj/machinery/r_n_d/protolathe/linked_lathe = null //Linked Protolathe
|
||||
var/obj/machinery/r_n_d/circuit_imprinter/linked_imprinter = null //Linked Circuit Imprinter
|
||||
|
||||
var/id = 0 //ID of the computer (for server restrictions).
|
||||
var/sync = 1 //If sync = 0, it doesn't show up on Server Control Console
|
||||
|
||||
req_access = list(access_research) //Data and setting manipulation requires scientist access.
|
||||
|
||||
var/protofilter //String to filter protolathe designs by
|
||||
var/circuitfilter //String to filter circuit designs by
|
||||
|
||||
/obj/machinery/computer/rdconsole/proc/CallMaterialName(var/ID)
|
||||
var/return_name = ID
|
||||
switch(return_name)
|
||||
if("metal")
|
||||
return_name = "Metal"
|
||||
if("glass")
|
||||
return_name = "Glass"
|
||||
if("gold")
|
||||
return_name = "Gold"
|
||||
if("silver")
|
||||
return_name = "Silver"
|
||||
if("phoron")
|
||||
return_name = "Solid Phoron"
|
||||
if("uranium")
|
||||
return_name = "Uranium"
|
||||
if("diamond")
|
||||
return_name = "Diamond"
|
||||
return return_name
|
||||
|
||||
/obj/machinery/computer/rdconsole/proc/CallReagentName(var/ID)
|
||||
var/return_name = ID
|
||||
for(var/datum/reagent/R in SSchemistry.chemical_reagents)
|
||||
if(R.id == ID)
|
||||
return_name = R.name
|
||||
break
|
||||
return return_name
|
||||
|
||||
/obj/machinery/computer/rdconsole/proc/SyncRDevices() //Makes sure it is properly sync'ed up with the devices attached to it (if any).
|
||||
for(var/obj/machinery/r_n_d/D in range(3, src))
|
||||
if(D.linked_console != null || D.panel_open)
|
||||
continue
|
||||
if(istype(D, /obj/machinery/r_n_d/destructive_analyzer))
|
||||
if(linked_destroy == null)
|
||||
linked_destroy = D
|
||||
D.linked_console = src
|
||||
else if(istype(D, /obj/machinery/r_n_d/protolathe))
|
||||
if(linked_lathe == null)
|
||||
linked_lathe = D
|
||||
D.linked_console = src
|
||||
else if(istype(D, /obj/machinery/r_n_d/circuit_imprinter))
|
||||
if(linked_imprinter == null)
|
||||
linked_imprinter = D
|
||||
D.linked_console = src
|
||||
return
|
||||
|
||||
/obj/machinery/computer/rdconsole/proc/griefProtection() //Have it automatically push research to the CentCom server so wild griffins can't fuck up R&D's work
|
||||
for(var/obj/machinery/r_n_d/server/centcom/C in machines)
|
||||
for(var/datum/tech/T in files.known_tech)
|
||||
C.files.AddTech2Known(T)
|
||||
for(var/datum/design/D in files.known_designs)
|
||||
C.files.AddDesign2Known(D)
|
||||
C.files.RefreshResearch()
|
||||
|
||||
/obj/machinery/computer/rdconsole/New()
|
||||
..()
|
||||
files = new /datum/research(src) //Setup the research data holder.
|
||||
if(!id)
|
||||
for(var/obj/machinery/r_n_d/server/centcom/S in machines)
|
||||
S.update_connections()
|
||||
break
|
||||
|
||||
/obj/machinery/computer/rdconsole/Initialize()
|
||||
SyncRDevices()
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/computer/rdconsole/attackby(var/obj/item/weapon/D as obj, var/mob/user as mob)
|
||||
//Loading a disk into it.
|
||||
if(istype(D, /obj/item/weapon/disk))
|
||||
if(t_disk || d_disk)
|
||||
to_chat(user, "<span class='filter_notice'>A disk is already loaded into the machine.</span>")
|
||||
return
|
||||
|
||||
if(istype(D, /obj/item/weapon/disk/tech_disk))
|
||||
t_disk = D
|
||||
else if (istype(D, /obj/item/weapon/disk/design_disk))
|
||||
d_disk = D
|
||||
else
|
||||
to_chat(user, "<span class='notice'>Machine cannot accept disks in that format.</span>")
|
||||
return
|
||||
user.drop_item()
|
||||
D.loc = src
|
||||
to_chat(user, "<span class='notice'>You add \the [D] to the machine.</span>")
|
||||
else
|
||||
//The construction/deconstruction of the console code.
|
||||
..()
|
||||
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
/obj/machinery/computer/rdconsole/emp_act(var/remaining_charges, var/mob/user)
|
||||
if(!emagged)
|
||||
playsound(src, 'sound/effects/sparks4.ogg', 75, 1)
|
||||
emagged = 1
|
||||
to_chat(user, "<span class='notice'>You disable the security protocols.</span>")
|
||||
return 1
|
||||
|
||||
/obj/machinery/computer/rdconsole/proc/GetResearchLevelsInfo()
|
||||
var/list/dat = list()
|
||||
dat += "<UL>"
|
||||
for(var/datum/tech/T in files.known_tech)
|
||||
if(T.level < 1)
|
||||
continue
|
||||
dat += "<LI>"
|
||||
dat += "[T.name]"
|
||||
dat += "<UL>"
|
||||
dat += "<LI>Level: [T.level]"
|
||||
dat += "<LI>Summary: [T.desc]"
|
||||
dat += "</UL>"
|
||||
return dat.Join()
|
||||
|
||||
/obj/machinery/computer/rdconsole/proc/GetResearchListInfo()
|
||||
var/list/dat = list()
|
||||
dat += "<UL>"
|
||||
for(var/datum/design/D in files.known_designs)
|
||||
if(D.build_path)
|
||||
dat += "<LI><B>[D.name]</B>: [D.desc]"
|
||||
dat += "</UL>"
|
||||
return dat.Join()
|
||||
|
||||
/obj/machinery/computer/rdconsole/attack_hand(mob/user as mob)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
|
||||
tgui_interact(user) // TODO: remove the other UI
|
||||
|
||||
/obj/machinery/computer/rdconsole/robotics
|
||||
name = "Robotics R&D Console"
|
||||
id = 2
|
||||
req_access = list(access_robotics)
|
||||
|
||||
/obj/machinery/computer/rdconsole/core
|
||||
name = "Core R&D Console"
|
||||
id = 1
|
||||
/*
|
||||
Research and Development (R&D) Console
|
||||
|
||||
This is the main work horse of the R&D system. It contains the menus/controls for the Destructive Analyzer, Protolathe, and Circuit
|
||||
imprinter. It also contains the /datum/research holder with all the known/possible technology paths and device designs.
|
||||
|
||||
Basic use: When it first is created, it will attempt to link up to related devices within 3 squares. It'll only link up if they
|
||||
aren't already linked to another console. Any consoles it cannot link up with (either because all of a certain type are already
|
||||
linked or there aren't any in range), you'll just not have access to that menu. In the settings menu, there are menu options that
|
||||
allow a player to attempt to re-sync with nearby consoles. You can also force it to disconnect from a specific console.
|
||||
|
||||
The imprinting and construction menus do NOT require toxins access to access but all the other menus do. However, if you leave it
|
||||
on a menu, nothing is to stop the person from using the options on that menu (although they won't be able to change to a different
|
||||
one). You can also lock the console on the settings menu if you're feeling paranoid and you don't want anyone messing with it who
|
||||
doesn't have toxins access.
|
||||
|
||||
When a R&D console is destroyed or even partially disassembled, you lose all research data on it. However, there are two ways around
|
||||
this dire fate:
|
||||
- The easiest way is to go to the settings menu and select "Sync Database with Network." That causes it to upload (but not download)
|
||||
it's data to every other device in the game. Each console has a "disconnect from network" option that'll will cause data base sync
|
||||
operations to skip that console. This is useful if you want to make a "public" R&D console or, for example, give the engineers
|
||||
a circuit imprinter with certain designs on it and don't want it accidentally updating. The downside of this method is that you have
|
||||
to have physical access to the other console to send data back. Note: An R&D console is on CentCom so if a random griffan happens to
|
||||
cause a ton of data to be lost, an admin can go send it back.
|
||||
- The second method is with Technology Disks and Design Disks. Each of these disks can hold a single technology or design datum in
|
||||
it's entirety. You can then take the disk to any R&D console and upload it's data to it. This method is a lot more secure (since it
|
||||
won't update every console in existence) but it's more of a hassle to do. Also, the disks can be stolen.
|
||||
*/
|
||||
|
||||
/obj/machinery/computer/rdconsole
|
||||
name = "R&D control console"
|
||||
desc = "Science, in a computer! Experiment results not guaranteed."
|
||||
icon_keyboard = "rd_key"
|
||||
icon_screen = "rdcomp"
|
||||
light_color = "#a97faa"
|
||||
circuit = /obj/item/weapon/circuitboard/rdconsole
|
||||
var/datum/research/files //Stores all the collected research data.
|
||||
var/obj/item/weapon/disk/tech_disk/t_disk = null //Stores the technology disk.
|
||||
var/obj/item/weapon/disk/design_disk/d_disk = null //Stores the design disk.
|
||||
|
||||
var/obj/machinery/r_n_d/destructive_analyzer/linked_destroy = null //Linked Destructive Analyzer
|
||||
var/obj/machinery/r_n_d/protolathe/linked_lathe = null //Linked Protolathe
|
||||
var/obj/machinery/r_n_d/circuit_imprinter/linked_imprinter = null //Linked Circuit Imprinter
|
||||
|
||||
var/id = 0 //ID of the computer (for server restrictions).
|
||||
var/sync = 1 //If sync = 0, it doesn't show up on Server Control Console
|
||||
|
||||
req_access = list(access_research) //Data and setting manipulation requires scientist access.
|
||||
|
||||
var/protofilter //String to filter protolathe designs by
|
||||
var/circuitfilter //String to filter circuit designs by
|
||||
|
||||
/obj/machinery/computer/rdconsole/proc/CallMaterialName(var/ID)
|
||||
var/return_name = ID
|
||||
switch(return_name)
|
||||
if("metal")
|
||||
return_name = "Metal"
|
||||
if("glass")
|
||||
return_name = "Glass"
|
||||
if("gold")
|
||||
return_name = "Gold"
|
||||
if("silver")
|
||||
return_name = "Silver"
|
||||
if("phoron")
|
||||
return_name = "Solid Phoron"
|
||||
if("uranium")
|
||||
return_name = "Uranium"
|
||||
if("diamond")
|
||||
return_name = "Diamond"
|
||||
return return_name
|
||||
|
||||
/obj/machinery/computer/rdconsole/proc/CallReagentName(var/ID)
|
||||
var/return_name = ID
|
||||
for(var/datum/reagent/R in SSchemistry.chemical_reagents)
|
||||
if(R.id == ID)
|
||||
return_name = R.name
|
||||
break
|
||||
return return_name
|
||||
|
||||
/obj/machinery/computer/rdconsole/proc/SyncRDevices() //Makes sure it is properly sync'ed up with the devices attached to it (if any).
|
||||
for(var/obj/machinery/r_n_d/D in range(3, src))
|
||||
if(D.linked_console != null || D.panel_open)
|
||||
continue
|
||||
if(istype(D, /obj/machinery/r_n_d/destructive_analyzer))
|
||||
if(linked_destroy == null)
|
||||
linked_destroy = D
|
||||
D.linked_console = src
|
||||
else if(istype(D, /obj/machinery/r_n_d/protolathe))
|
||||
if(linked_lathe == null)
|
||||
linked_lathe = D
|
||||
D.linked_console = src
|
||||
else if(istype(D, /obj/machinery/r_n_d/circuit_imprinter))
|
||||
if(linked_imprinter == null)
|
||||
linked_imprinter = D
|
||||
D.linked_console = src
|
||||
return
|
||||
|
||||
/obj/machinery/computer/rdconsole/proc/griefProtection() //Have it automatically push research to the CentCom server so wild griffins can't fuck up R&D's work
|
||||
for(var/obj/machinery/r_n_d/server/centcom/C in machines)
|
||||
for(var/datum/tech/T in files.known_tech)
|
||||
C.files.AddTech2Known(T)
|
||||
for(var/datum/design/D in files.known_designs)
|
||||
C.files.AddDesign2Known(D)
|
||||
C.files.RefreshResearch()
|
||||
|
||||
/obj/machinery/computer/rdconsole/New()
|
||||
..()
|
||||
files = new /datum/research(src) //Setup the research data holder.
|
||||
if(!id)
|
||||
for(var/obj/machinery/r_n_d/server/centcom/S in machines)
|
||||
S.update_connections()
|
||||
break
|
||||
|
||||
/obj/machinery/computer/rdconsole/Initialize()
|
||||
SyncRDevices()
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/computer/rdconsole/attackby(var/obj/item/weapon/D as obj, var/mob/user as mob)
|
||||
//Loading a disk into it.
|
||||
if(istype(D, /obj/item/weapon/disk))
|
||||
if(t_disk || d_disk)
|
||||
to_chat(user, "<span class='filter_notice'>A disk is already loaded into the machine.</span>")
|
||||
return
|
||||
|
||||
if(istype(D, /obj/item/weapon/disk/tech_disk))
|
||||
t_disk = D
|
||||
else if (istype(D, /obj/item/weapon/disk/design_disk))
|
||||
d_disk = D
|
||||
else
|
||||
to_chat(user, "<span class='notice'>Machine cannot accept disks in that format.</span>")
|
||||
return
|
||||
user.drop_item()
|
||||
D.loc = src
|
||||
to_chat(user, "<span class='notice'>You add \the [D] to the machine.</span>")
|
||||
else
|
||||
//The construction/deconstruction of the console code.
|
||||
..()
|
||||
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
/obj/machinery/computer/rdconsole/emp_act(var/remaining_charges, var/mob/user)
|
||||
if(!emagged)
|
||||
playsound(src, 'sound/effects/sparks4.ogg', 75, 1)
|
||||
emagged = 1
|
||||
to_chat(user, "<span class='notice'>You disable the security protocols.</span>")
|
||||
return 1
|
||||
|
||||
/obj/machinery/computer/rdconsole/proc/GetResearchLevelsInfo()
|
||||
var/list/dat = list()
|
||||
dat += "<UL>"
|
||||
for(var/datum/tech/T in files.known_tech)
|
||||
if(T.level < 1)
|
||||
continue
|
||||
dat += "<LI>"
|
||||
dat += "[T.name]"
|
||||
dat += "<UL>"
|
||||
dat += "<LI>Level: [T.level]"
|
||||
dat += "<LI>Summary: [T.desc]"
|
||||
dat += "</UL>"
|
||||
return dat.Join()
|
||||
|
||||
/obj/machinery/computer/rdconsole/proc/GetResearchListInfo()
|
||||
var/list/dat = list()
|
||||
dat += "<UL>"
|
||||
for(var/datum/design/D in files.known_designs)
|
||||
if(D.build_path)
|
||||
dat += "<LI><B>[D.name]</B>: [D.desc]"
|
||||
dat += "</UL>"
|
||||
return dat.Join()
|
||||
|
||||
/obj/machinery/computer/rdconsole/attack_hand(mob/user as mob)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
|
||||
tgui_interact(user) // TODO: remove the other UI
|
||||
|
||||
/obj/machinery/computer/rdconsole/robotics
|
||||
name = "Robotics R&D Console"
|
||||
id = 2
|
||||
req_access = list(access_robotics)
|
||||
|
||||
/obj/machinery/computer/rdconsole/core
|
||||
name = "Core R&D Console"
|
||||
id = 1
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
|
||||
|
||||
//All devices that link into the R&D console fall into thise type for easy identification and some shared procs.
|
||||
|
||||
/obj/machinery/r_n_d
|
||||
name = "R&D Device"
|
||||
icon = 'icons/obj/machines/research.dmi'
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
use_power = USE_POWER_IDLE
|
||||
var/busy = 0
|
||||
var/obj/machinery/computer/rdconsole/linked_console
|
||||
|
||||
var/list/materials = list() // Materials this machine can accept.
|
||||
var/list/hidden_materials = list() // Materials this machine will not display, unless it contains them. Must be in the materials list as well.
|
||||
|
||||
/obj/machinery/r_n_d/attack_hand(mob/user as mob)
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/proc/getMaterialType(var/name)
|
||||
var/datum/material/M = get_material_by_name(name)
|
||||
if(M && M.stack_type)
|
||||
return M.stack_type
|
||||
return null
|
||||
|
||||
/obj/machinery/r_n_d/proc/getMaterialName(var/type)
|
||||
if(istype(type, /obj/item/stack/material))
|
||||
var/obj/item/stack/material/M = type
|
||||
return M.material.name
|
||||
return null
|
||||
|
||||
/obj/machinery/r_n_d/proc/eject(var/material, var/amount)
|
||||
if(!(material in materials))
|
||||
return
|
||||
var/obj/item/stack/material/sheetType = getMaterialType(material)
|
||||
var/perUnit = initial(sheetType.perunit)
|
||||
var/eject = round(materials[material] / perUnit)
|
||||
eject = amount == -1 ? eject : min(eject, amount)
|
||||
if(eject < 1)
|
||||
return
|
||||
new sheetType(loc, eject)
|
||||
materials[material] -= eject * perUnit
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
|
||||
|
||||
//All devices that link into the R&D console fall into thise type for easy identification and some shared procs.
|
||||
|
||||
/obj/machinery/r_n_d
|
||||
name = "R&D Device"
|
||||
icon = 'icons/obj/machines/research.dmi'
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
use_power = USE_POWER_IDLE
|
||||
var/busy = 0
|
||||
var/obj/machinery/computer/rdconsole/linked_console
|
||||
|
||||
var/list/materials = list() // Materials this machine can accept.
|
||||
var/list/hidden_materials = list() // Materials this machine will not display, unless it contains them. Must be in the materials list as well.
|
||||
|
||||
/obj/machinery/r_n_d/attack_hand(mob/user as mob)
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/proc/getMaterialType(var/name)
|
||||
var/datum/material/M = get_material_by_name(name)
|
||||
if(M && M.stack_type)
|
||||
return M.stack_type
|
||||
return null
|
||||
|
||||
/obj/machinery/r_n_d/proc/getMaterialName(var/type)
|
||||
if(istype(type, /obj/item/stack/material))
|
||||
var/obj/item/stack/material/M = type
|
||||
return M.material.name
|
||||
return null
|
||||
|
||||
/obj/machinery/r_n_d/proc/eject(var/material, var/amount)
|
||||
if(!(material in materials))
|
||||
return
|
||||
var/obj/item/stack/material/sheetType = getMaterialType(material)
|
||||
var/perUnit = initial(sheetType.perunit)
|
||||
var/eject = round(materials[material] / perUnit)
|
||||
eject = amount == -1 ? eject : min(eject, amount)
|
||||
if(eject < 1)
|
||||
return
|
||||
new sheetType(loc, eject)
|
||||
materials[material] -= eject * perUnit
|
||||
|
||||
@@ -1,227 +1,227 @@
|
||||
/*
|
||||
General Explination:
|
||||
The research datum is the "folder" where all the research information is stored in a R&D console. It's also a holder for all the
|
||||
various procs used to manipulate it. It has four variables and seven procs:
|
||||
|
||||
Variables:
|
||||
- possible_tech is a list of all the /datum/tech that can potentially be researched by the player. The RefreshResearch() proc
|
||||
(explained later) only goes through those when refreshing what you know. Generally, possible_tech contains ALL of the existing tech
|
||||
but it is possible to add tech to the game that DON'T start in it (example: Xeno tech). Generally speaking, you don't want to mess
|
||||
with these since they should be the default version of the datums. They're actually stored in a list rather then using typesof to
|
||||
refer to them since it makes it a bit easier to search through them for specific information.
|
||||
- know_tech is the companion list to possible_tech. It's the tech you can actually research and improve. Until it's added to this
|
||||
list, it can't be improved. All the tech in this list are visible to the player.
|
||||
- possible_designs is functionally identical to possbile_tech except it's for /datum/design.
|
||||
- known_designs is functionally identical to known_tech except it's for /datum/design
|
||||
|
||||
Procs:
|
||||
- TechHasReqs: Used by other procs (specifically RefreshResearch) to see whether all of a tech's requirements are currently in
|
||||
known_tech and at a high enough level.
|
||||
- DesignHasReqs: Same as TechHasReqs but for /datum/design and known_design.
|
||||
- AddTech2Known: Adds a /datum/tech to known_tech. It checks to see whether it already has that tech (if so, it just replaces it). If
|
||||
it doesn't have it, it adds it. Note: It does NOT check possible_tech at all. So if you want to add something strange to it (like
|
||||
a player made tech?) you can.
|
||||
- AddDesign2Known: Same as AddTech2Known except for /datum/design and known_designs.
|
||||
- RefreshResearch: This is the workhorse of the R&D system. It updates the /datum/research holder and adds any unlocked tech paths
|
||||
and designs you have reached the requirements for. It only checks through possible_tech and possible_designs, however, so it won't
|
||||
accidentally add "secret" tech to it.
|
||||
- UpdateTech is used as part of the actual researching process. It takes an ID and finds techs with that same ID in known_tech. When
|
||||
it finds it, it checks to see whether it can improve it at all. If the known_tech's level is less then or equal to
|
||||
the inputted level, it increases the known tech's level to the inputted level -1 or know tech's level +1 (whichever is higher).
|
||||
|
||||
The tech datums are the actual "tech trees" that you improve through researching. Each one has five variables:
|
||||
- Name: Pretty obvious. This is often viewable to the players.
|
||||
- Desc: Pretty obvious. Also player viewable.
|
||||
- ID: This is the unique ID of the tech that is used by the various procs to find and/or maniuplate it.
|
||||
- Level: This is the current level of the tech. All techs start at 1 and have a max of 20. Devices and some techs require a certain
|
||||
level in specific techs before you can produce them.
|
||||
- Req_tech: This is a list of the techs required to unlock this tech path. If left blank, it'll automatically be loaded into the
|
||||
research holder datum.
|
||||
|
||||
*/
|
||||
/***************************************************************
|
||||
** Master Types **
|
||||
** Includes all the helper procs and basic tech processing. **
|
||||
***************************************************************/
|
||||
GLOBAL_LIST_INIT(design_datums, list())
|
||||
|
||||
/datum/research //Holder for all the existing, archived, and known tech. Individual to console.
|
||||
var/list/known_tech = list() //List of locally known tech. Datum/tech go here.
|
||||
var/list/possible_designs = list() //List of all designs.
|
||||
var/list/known_designs = list() //List of available designs.
|
||||
|
||||
/datum/research/New() //Insert techs into possible_tech here. Known_tech automatically updated.
|
||||
if(!LAZYLEN(GLOB.design_datums))
|
||||
for(var/T in subtypesof(/datum/design))
|
||||
GLOB.design_datums += new T
|
||||
possible_designs = GLOB.design_datums
|
||||
|
||||
if(!LAZYLEN(known_tech))
|
||||
for(var/T in subtypesof(/datum/tech))
|
||||
known_tech += new T
|
||||
RefreshResearch()
|
||||
|
||||
/datum/research/techonly
|
||||
/datum/research/techonly/New()
|
||||
. = ..()
|
||||
possible_designs = list()
|
||||
known_designs = list()
|
||||
|
||||
/datum/research/techonly/RefreshResearch()
|
||||
. = ..()
|
||||
known_designs = list() // Just in case
|
||||
|
||||
//Checks to see if design has all the required pre-reqs.
|
||||
//Input: datum/design; Output: 0/1 (false/true)
|
||||
/datum/research/proc/DesignHasReqs(var/datum/design/D)
|
||||
if(!LAZYLEN(D.req_tech))
|
||||
return TRUE
|
||||
|
||||
var/list/k_tech = list()
|
||||
for(var/datum/tech/known in known_tech)
|
||||
k_tech[known.id] = known.level
|
||||
|
||||
for(var/req in D.req_tech)
|
||||
if(isnull(k_tech[req]) || k_tech[req] < D.req_tech[req])
|
||||
return 0
|
||||
|
||||
return TRUE
|
||||
|
||||
//Adds a tech to known_tech list. Checks to make sure there aren't duplicates and updates existing tech's levels if needed.
|
||||
//Input: datum/tech; Output: Null
|
||||
/datum/research/proc/AddTech2Known(var/datum/tech/T)
|
||||
for(var/datum/tech/known in known_tech)
|
||||
if(T.id == known.id)
|
||||
if(T.level > known.level)
|
||||
known.level = T.level
|
||||
return
|
||||
return
|
||||
|
||||
/datum/research/proc/AddDesign2Known(var/datum/design/D)
|
||||
LAZYDISTINCTADD(known_designs, D)
|
||||
|
||||
//Refreshes known_tech and known_designs list
|
||||
//Input/Output: n/a
|
||||
/datum/research/proc/RefreshResearch()
|
||||
for(var/datum/design/PD in possible_designs)
|
||||
if(DesignHasReqs(PD))
|
||||
AddDesign2Known(PD)
|
||||
for(var/datum/tech/T in known_tech)
|
||||
T.level = between(0, T.level, 20)
|
||||
return
|
||||
|
||||
//Refreshes the levels of a given tech.
|
||||
//Input: Tech's ID and Level; Output: null
|
||||
/datum/research/proc/UpdateTech(var/ID, var/level)
|
||||
for(var/datum/tech/KT in known_tech)
|
||||
if(KT.id == ID && KT.level <= level)
|
||||
KT.level = max(KT.level + 1, level - 1)
|
||||
return
|
||||
|
||||
// A simple helper proc to find the name of a tech with a given ID.
|
||||
/proc/CallTechName(var/ID)
|
||||
for(var/datum/tech/check_tech as anything in subtypesof(/datum/tech))
|
||||
if(initial(check_tech.id) == ID)
|
||||
return initial(check_tech.name)
|
||||
|
||||
/***************************************************************
|
||||
** Technology Datums **
|
||||
** Includes all the various technoliges and what they make. **
|
||||
***************************************************************/
|
||||
|
||||
/datum/tech //Datum of individual technologies.
|
||||
var/name = "name" //Name of the technology.
|
||||
var/desc = "description" //General description of what it does and what it makes.
|
||||
var/id = "id" //An easily referenced ID. Must be alphanumeric, lower-case, and no symbols.
|
||||
var/level = 1 //A simple number scale of the research level. Level 0 = Secret tech.
|
||||
|
||||
/datum/tech/materials
|
||||
name = "Materials Research"
|
||||
desc = "Development of new and improved materials."
|
||||
id = TECH_MATERIAL
|
||||
|
||||
/datum/tech/engineering
|
||||
name = "Engineering Research"
|
||||
desc = "Development of new and improved engineering parts."
|
||||
id = TECH_ENGINEERING
|
||||
|
||||
/datum/tech/phorontech
|
||||
name = "Phoron Research"
|
||||
desc = "Research into the mysterious substance colloqually known as 'phoron'."
|
||||
id = TECH_PHORON
|
||||
|
||||
/datum/tech/powerstorage
|
||||
name = "Power Manipulation Technology"
|
||||
desc = "The various technologies behind the storage and generation of electicity."
|
||||
id = TECH_POWER
|
||||
|
||||
/datum/tech/bluespace
|
||||
name = "'Blue-space' Research"
|
||||
desc = "Research into the sub-reality known as 'blue-space'"
|
||||
id = TECH_BLUESPACE
|
||||
|
||||
/datum/tech/biotech
|
||||
name = "Biological Technology"
|
||||
desc = "Research into the deeper mysteries of life and organic substances."
|
||||
id = TECH_BIO
|
||||
|
||||
/datum/tech/combat
|
||||
name = "Combat Systems Research"
|
||||
desc = "The development of offensive and defensive systems."
|
||||
id = TECH_COMBAT
|
||||
|
||||
/datum/tech/magnets
|
||||
name = "Electromagnetic Spectrum Research"
|
||||
desc = "Research into the electromagnetic spectrum. No clue how they actually work, though."
|
||||
id = TECH_MAGNET
|
||||
|
||||
/datum/tech/programming
|
||||
name = "Data Theory Research"
|
||||
desc = "The development of new computer and artificial intelligence and data storage systems."
|
||||
id = TECH_DATA
|
||||
|
||||
/datum/tech/syndicate
|
||||
name = "Transgressive Technologies Research"
|
||||
desc = "The study of technologies that sit on the very boundaries of legality and ethics."
|
||||
id = TECH_ILLEGAL
|
||||
level = 0
|
||||
|
||||
/datum/tech/arcane
|
||||
name = "Anomalous Research"
|
||||
desc = "Study of phenomena that disobey the fundamental laws of this universe."
|
||||
id = TECH_ARCANE
|
||||
level = 0
|
||||
|
||||
/datum/tech/precursor
|
||||
name = "Precursor Research"
|
||||
desc = "The applied study of Precursor Technology, for modern applications."
|
||||
id = TECH_PRECURSOR
|
||||
level = 0
|
||||
|
||||
/obj/item/weapon/disk/tech_disk
|
||||
name = "technology disk"
|
||||
desc = "A disk for storing technology data for further research."
|
||||
icon = 'icons/obj/discs_vr.dmi' //VOREStation Edit
|
||||
icon_state = "data-blue" //VOREStation Edit
|
||||
item_state = "card-id"
|
||||
randpixel = 5
|
||||
w_class = ITEMSIZE_SMALL
|
||||
matter = list(MAT_STEEL = 30, MAT_GLASS = 10)
|
||||
var/datum/tech/stored
|
||||
|
||||
/obj/item/weapon/disk/tech_disk/New()
|
||||
randpixel_xy()
|
||||
|
||||
/obj/item/weapon/disk/design_disk
|
||||
name = "component design disk"
|
||||
desc = "A disk for storing device design data for construction in lathes."
|
||||
icon = 'icons/obj/discs_vr.dmi' //VOREStation Edit
|
||||
icon_state = "data-purple" //VOREStation Edit
|
||||
item_state = "card-id"
|
||||
randpixel = 5
|
||||
w_class = ITEMSIZE_SMALL
|
||||
matter = list(MAT_STEEL = 30, MAT_GLASS = 10)
|
||||
var/datum/design/blueprint
|
||||
|
||||
/obj/item/weapon/disk/design_disk/New()
|
||||
randpixel_xy()
|
||||
/*
|
||||
General Explination:
|
||||
The research datum is the "folder" where all the research information is stored in a R&D console. It's also a holder for all the
|
||||
various procs used to manipulate it. It has four variables and seven procs:
|
||||
|
||||
Variables:
|
||||
- possible_tech is a list of all the /datum/tech that can potentially be researched by the player. The RefreshResearch() proc
|
||||
(explained later) only goes through those when refreshing what you know. Generally, possible_tech contains ALL of the existing tech
|
||||
but it is possible to add tech to the game that DON'T start in it (example: Xeno tech). Generally speaking, you don't want to mess
|
||||
with these since they should be the default version of the datums. They're actually stored in a list rather then using typesof to
|
||||
refer to them since it makes it a bit easier to search through them for specific information.
|
||||
- know_tech is the companion list to possible_tech. It's the tech you can actually research and improve. Until it's added to this
|
||||
list, it can't be improved. All the tech in this list are visible to the player.
|
||||
- possible_designs is functionally identical to possbile_tech except it's for /datum/design.
|
||||
- known_designs is functionally identical to known_tech except it's for /datum/design
|
||||
|
||||
Procs:
|
||||
- TechHasReqs: Used by other procs (specifically RefreshResearch) to see whether all of a tech's requirements are currently in
|
||||
known_tech and at a high enough level.
|
||||
- DesignHasReqs: Same as TechHasReqs but for /datum/design and known_design.
|
||||
- AddTech2Known: Adds a /datum/tech to known_tech. It checks to see whether it already has that tech (if so, it just replaces it). If
|
||||
it doesn't have it, it adds it. Note: It does NOT check possible_tech at all. So if you want to add something strange to it (like
|
||||
a player made tech?) you can.
|
||||
- AddDesign2Known: Same as AddTech2Known except for /datum/design and known_designs.
|
||||
- RefreshResearch: This is the workhorse of the R&D system. It updates the /datum/research holder and adds any unlocked tech paths
|
||||
and designs you have reached the requirements for. It only checks through possible_tech and possible_designs, however, so it won't
|
||||
accidentally add "secret" tech to it.
|
||||
- UpdateTech is used as part of the actual researching process. It takes an ID and finds techs with that same ID in known_tech. When
|
||||
it finds it, it checks to see whether it can improve it at all. If the known_tech's level is less then or equal to
|
||||
the inputted level, it increases the known tech's level to the inputted level -1 or know tech's level +1 (whichever is higher).
|
||||
|
||||
The tech datums are the actual "tech trees" that you improve through researching. Each one has five variables:
|
||||
- Name: Pretty obvious. This is often viewable to the players.
|
||||
- Desc: Pretty obvious. Also player viewable.
|
||||
- ID: This is the unique ID of the tech that is used by the various procs to find and/or maniuplate it.
|
||||
- Level: This is the current level of the tech. All techs start at 1 and have a max of 20. Devices and some techs require a certain
|
||||
level in specific techs before you can produce them.
|
||||
- Req_tech: This is a list of the techs required to unlock this tech path. If left blank, it'll automatically be loaded into the
|
||||
research holder datum.
|
||||
|
||||
*/
|
||||
/***************************************************************
|
||||
** Master Types **
|
||||
** Includes all the helper procs and basic tech processing. **
|
||||
***************************************************************/
|
||||
GLOBAL_LIST_INIT(design_datums, list())
|
||||
|
||||
/datum/research //Holder for all the existing, archived, and known tech. Individual to console.
|
||||
var/list/known_tech = list() //List of locally known tech. Datum/tech go here.
|
||||
var/list/possible_designs = list() //List of all designs.
|
||||
var/list/known_designs = list() //List of available designs.
|
||||
|
||||
/datum/research/New() //Insert techs into possible_tech here. Known_tech automatically updated.
|
||||
if(!LAZYLEN(GLOB.design_datums))
|
||||
for(var/T in subtypesof(/datum/design))
|
||||
GLOB.design_datums += new T
|
||||
possible_designs = GLOB.design_datums
|
||||
|
||||
if(!LAZYLEN(known_tech))
|
||||
for(var/T in subtypesof(/datum/tech))
|
||||
known_tech += new T
|
||||
RefreshResearch()
|
||||
|
||||
/datum/research/techonly
|
||||
/datum/research/techonly/New()
|
||||
. = ..()
|
||||
possible_designs = list()
|
||||
known_designs = list()
|
||||
|
||||
/datum/research/techonly/RefreshResearch()
|
||||
. = ..()
|
||||
known_designs = list() // Just in case
|
||||
|
||||
//Checks to see if design has all the required pre-reqs.
|
||||
//Input: datum/design; Output: 0/1 (false/true)
|
||||
/datum/research/proc/DesignHasReqs(var/datum/design/D)
|
||||
if(!LAZYLEN(D.req_tech))
|
||||
return TRUE
|
||||
|
||||
var/list/k_tech = list()
|
||||
for(var/datum/tech/known in known_tech)
|
||||
k_tech[known.id] = known.level
|
||||
|
||||
for(var/req in D.req_tech)
|
||||
if(isnull(k_tech[req]) || k_tech[req] < D.req_tech[req])
|
||||
return 0
|
||||
|
||||
return TRUE
|
||||
|
||||
//Adds a tech to known_tech list. Checks to make sure there aren't duplicates and updates existing tech's levels if needed.
|
||||
//Input: datum/tech; Output: Null
|
||||
/datum/research/proc/AddTech2Known(var/datum/tech/T)
|
||||
for(var/datum/tech/known in known_tech)
|
||||
if(T.id == known.id)
|
||||
if(T.level > known.level)
|
||||
known.level = T.level
|
||||
return
|
||||
return
|
||||
|
||||
/datum/research/proc/AddDesign2Known(var/datum/design/D)
|
||||
LAZYDISTINCTADD(known_designs, D)
|
||||
|
||||
//Refreshes known_tech and known_designs list
|
||||
//Input/Output: n/a
|
||||
/datum/research/proc/RefreshResearch()
|
||||
for(var/datum/design/PD in possible_designs)
|
||||
if(DesignHasReqs(PD))
|
||||
AddDesign2Known(PD)
|
||||
for(var/datum/tech/T in known_tech)
|
||||
T.level = between(0, T.level, 20)
|
||||
return
|
||||
|
||||
//Refreshes the levels of a given tech.
|
||||
//Input: Tech's ID and Level; Output: null
|
||||
/datum/research/proc/UpdateTech(var/ID, var/level)
|
||||
for(var/datum/tech/KT in known_tech)
|
||||
if(KT.id == ID && KT.level <= level)
|
||||
KT.level = max(KT.level + 1, level - 1)
|
||||
return
|
||||
|
||||
// A simple helper proc to find the name of a tech with a given ID.
|
||||
/proc/CallTechName(var/ID)
|
||||
for(var/datum/tech/check_tech as anything in subtypesof(/datum/tech))
|
||||
if(initial(check_tech.id) == ID)
|
||||
return initial(check_tech.name)
|
||||
|
||||
/***************************************************************
|
||||
** Technology Datums **
|
||||
** Includes all the various technoliges and what they make. **
|
||||
***************************************************************/
|
||||
|
||||
/datum/tech //Datum of individual technologies.
|
||||
var/name = "name" //Name of the technology.
|
||||
var/desc = "description" //General description of what it does and what it makes.
|
||||
var/id = "id" //An easily referenced ID. Must be alphanumeric, lower-case, and no symbols.
|
||||
var/level = 1 //A simple number scale of the research level. Level 0 = Secret tech.
|
||||
|
||||
/datum/tech/materials
|
||||
name = "Materials Research"
|
||||
desc = "Development of new and improved materials."
|
||||
id = TECH_MATERIAL
|
||||
|
||||
/datum/tech/engineering
|
||||
name = "Engineering Research"
|
||||
desc = "Development of new and improved engineering parts."
|
||||
id = TECH_ENGINEERING
|
||||
|
||||
/datum/tech/phorontech
|
||||
name = "Phoron Research"
|
||||
desc = "Research into the mysterious substance colloqually known as 'phoron'."
|
||||
id = TECH_PHORON
|
||||
|
||||
/datum/tech/powerstorage
|
||||
name = "Power Manipulation Technology"
|
||||
desc = "The various technologies behind the storage and generation of electicity."
|
||||
id = TECH_POWER
|
||||
|
||||
/datum/tech/bluespace
|
||||
name = "'Blue-space' Research"
|
||||
desc = "Research into the sub-reality known as 'blue-space'"
|
||||
id = TECH_BLUESPACE
|
||||
|
||||
/datum/tech/biotech
|
||||
name = "Biological Technology"
|
||||
desc = "Research into the deeper mysteries of life and organic substances."
|
||||
id = TECH_BIO
|
||||
|
||||
/datum/tech/combat
|
||||
name = "Combat Systems Research"
|
||||
desc = "The development of offensive and defensive systems."
|
||||
id = TECH_COMBAT
|
||||
|
||||
/datum/tech/magnets
|
||||
name = "Electromagnetic Spectrum Research"
|
||||
desc = "Research into the electromagnetic spectrum. No clue how they actually work, though."
|
||||
id = TECH_MAGNET
|
||||
|
||||
/datum/tech/programming
|
||||
name = "Data Theory Research"
|
||||
desc = "The development of new computer and artificial intelligence and data storage systems."
|
||||
id = TECH_DATA
|
||||
|
||||
/datum/tech/syndicate
|
||||
name = "Transgressive Technologies Research"
|
||||
desc = "The study of technologies that sit on the very boundaries of legality and ethics."
|
||||
id = TECH_ILLEGAL
|
||||
level = 0
|
||||
|
||||
/datum/tech/arcane
|
||||
name = "Anomalous Research"
|
||||
desc = "Study of phenomena that disobey the fundamental laws of this universe."
|
||||
id = TECH_ARCANE
|
||||
level = 0
|
||||
|
||||
/datum/tech/precursor
|
||||
name = "Precursor Research"
|
||||
desc = "The applied study of Precursor Technology, for modern applications."
|
||||
id = TECH_PRECURSOR
|
||||
level = 0
|
||||
|
||||
/obj/item/weapon/disk/tech_disk
|
||||
name = "technology disk"
|
||||
desc = "A disk for storing technology data for further research."
|
||||
icon = 'icons/obj/discs_vr.dmi' //VOREStation Edit
|
||||
icon_state = "data-blue" //VOREStation Edit
|
||||
item_state = "card-id"
|
||||
randpixel = 5
|
||||
w_class = ITEMSIZE_SMALL
|
||||
matter = list(MAT_STEEL = 30, MAT_GLASS = 10)
|
||||
var/datum/tech/stored
|
||||
|
||||
/obj/item/weapon/disk/tech_disk/New()
|
||||
randpixel_xy()
|
||||
|
||||
/obj/item/weapon/disk/design_disk
|
||||
name = "component design disk"
|
||||
desc = "A disk for storing device design data for construction in lathes."
|
||||
icon = 'icons/obj/discs_vr.dmi' //VOREStation Edit
|
||||
icon_state = "data-purple" //VOREStation Edit
|
||||
item_state = "card-id"
|
||||
randpixel = 5
|
||||
w_class = ITEMSIZE_SMALL
|
||||
matter = list(MAT_STEEL = 30, MAT_GLASS = 10)
|
||||
var/datum/design/blueprint
|
||||
|
||||
/obj/item/weapon/disk/design_disk/New()
|
||||
randpixel_xy()
|
||||
|
||||
@@ -1,312 +1,312 @@
|
||||
/obj/machinery/r_n_d/server
|
||||
name = "R&D Server"
|
||||
icon = 'icons/obj/machines/research_vr.dmi' //VOREStation Edit - New Icon
|
||||
icon_state = "server"
|
||||
var/datum/research/files
|
||||
var/health = 100
|
||||
var/list/id_with_upload = list() //List of R&D consoles with upload to server access.
|
||||
var/list/id_with_download = list() //List of R&D consoles with download from server access.
|
||||
var/id_with_upload_string = "" //String versions for easy editing in map editor.
|
||||
var/id_with_download_string = ""
|
||||
var/server_id = 0
|
||||
var/produces_heat = 1
|
||||
idle_power_usage = 800
|
||||
var/delay = 10
|
||||
req_access = list(access_rd) //Only the R&D can change server settings.
|
||||
circuit = /obj/item/weapon/circuitboard/rdserver
|
||||
|
||||
/obj/machinery/r_n_d/server/Initialize()
|
||||
. = ..()
|
||||
default_apply_parts()
|
||||
|
||||
/obj/machinery/r_n_d/server/Destroy()
|
||||
griefProtection()
|
||||
..()
|
||||
|
||||
/obj/machinery/r_n_d/server/RefreshParts()
|
||||
var/tot_rating = 0
|
||||
for(var/obj/item/weapon/stock_parts/SP in src)
|
||||
tot_rating += SP.rating
|
||||
update_idle_power_usage(initial(idle_power_usage) / max(1, tot_rating))
|
||||
|
||||
/obj/machinery/r_n_d/server/Initialize()
|
||||
. = ..()
|
||||
if(!files)
|
||||
files = new /datum/research(src)
|
||||
var/list/temp_list
|
||||
if(!id_with_upload.len)
|
||||
temp_list = list()
|
||||
temp_list = splittext(id_with_upload_string, ";")
|
||||
for(var/N in temp_list)
|
||||
id_with_upload += text2num(N)
|
||||
if(!id_with_download.len)
|
||||
temp_list = list()
|
||||
temp_list = splittext(id_with_download_string, ";")
|
||||
for(var/N in temp_list)
|
||||
id_with_download += text2num(N)
|
||||
|
||||
/obj/machinery/r_n_d/server/process()
|
||||
var/datum/gas_mixture/environment = loc.return_air()
|
||||
switch(environment.temperature)
|
||||
if(0 to T0C)
|
||||
health = min(100, health + 1)
|
||||
if(T0C to (T20C + 20))
|
||||
health = between(0, health, 100)
|
||||
if((T20C + 20) to (T0C + 70))
|
||||
health = max(0, health - 1)
|
||||
if(health <= 0)
|
||||
griefProtection() //I dont like putting this in process() but it's the best I can do without re-writing a chunk of rd servers.
|
||||
files.known_designs = list()
|
||||
for(var/datum/tech/T in files.known_tech)
|
||||
if(prob(1))
|
||||
T.level--
|
||||
files.RefreshResearch()
|
||||
if(delay)
|
||||
delay--
|
||||
else
|
||||
produce_heat()
|
||||
delay = initial(delay)
|
||||
|
||||
/obj/machinery/r_n_d/server/emp_act(severity)
|
||||
griefProtection()
|
||||
..()
|
||||
|
||||
/obj/machinery/r_n_d/server/ex_act(severity)
|
||||
griefProtection()
|
||||
..()
|
||||
|
||||
//Backup files to CentCom to help admins recover data after greifer attacks
|
||||
/obj/machinery/r_n_d/server/proc/griefProtection()
|
||||
for(var/obj/machinery/r_n_d/server/centcom/C in machines)
|
||||
for(var/datum/tech/T in files.known_tech)
|
||||
C.files.AddTech2Known(T)
|
||||
for(var/datum/design/D in files.known_designs)
|
||||
C.files.AddDesign2Known(D)
|
||||
C.files.RefreshResearch()
|
||||
|
||||
/obj/machinery/r_n_d/server/proc/produce_heat()
|
||||
if(!produces_heat)
|
||||
return
|
||||
|
||||
if(!use_power)
|
||||
return
|
||||
|
||||
if(!(stat & (NOPOWER|BROKEN))) //Blatently stolen from telecoms
|
||||
var/turf/simulated/L = loc
|
||||
if(istype(L))
|
||||
var/datum/gas_mixture/env = L.return_air()
|
||||
|
||||
var/transfer_moles = 0.25 * env.total_moles
|
||||
|
||||
var/datum/gas_mixture/removed = env.remove(transfer_moles)
|
||||
|
||||
if(removed)
|
||||
var/heat_produced = idle_power_usage //obviously can't produce more heat than the machine draws from it's power source
|
||||
|
||||
removed.add_thermal_energy(heat_produced)
|
||||
|
||||
env.merge(removed)
|
||||
|
||||
/obj/machinery/r_n_d/server/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if(default_deconstruction_screwdriver(user, O))
|
||||
return
|
||||
if(default_deconstruction_crowbar(user, O))
|
||||
return
|
||||
if(default_part_replacement(user, O))
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/server/centcom
|
||||
name = "Central R&D Database"
|
||||
server_id = -1
|
||||
|
||||
/obj/machinery/r_n_d/server/centcom/proc/update_connections()
|
||||
var/list/no_id_servers = list()
|
||||
var/list/server_ids = list()
|
||||
for(var/obj/machinery/r_n_d/server/S in machines)
|
||||
switch(S.server_id)
|
||||
if(-1)
|
||||
continue
|
||||
if(0)
|
||||
no_id_servers += S
|
||||
else
|
||||
server_ids += S.server_id
|
||||
|
||||
for(var/obj/machinery/r_n_d/server/S in no_id_servers)
|
||||
var/num = 1
|
||||
while(!S.server_id)
|
||||
if(num in server_ids)
|
||||
num++
|
||||
else
|
||||
S.server_id = num
|
||||
server_ids += num
|
||||
no_id_servers -= S
|
||||
|
||||
/obj/machinery/r_n_d/server/centcom/process()
|
||||
return PROCESS_KILL //don't need process()
|
||||
|
||||
/obj/machinery/computer/rdservercontrol
|
||||
name = "R&D Server Controller"
|
||||
desc = "Manage the research designs and servers. Can also modify upload/download permissions to R&D consoles."
|
||||
icon_keyboard = "rd_key"
|
||||
icon_screen = "rdcomp"
|
||||
light_color = "#a97faa"
|
||||
circuit = /obj/item/weapon/circuitboard/rdservercontrol
|
||||
var/screen = 0
|
||||
var/obj/machinery/r_n_d/server/temp_server
|
||||
var/list/servers = list()
|
||||
var/list/consoles = list()
|
||||
var/badmin = 0
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/tgui_status(mob/user)
|
||||
. = ..()
|
||||
if(!allowed(user) && !emagged)
|
||||
. = min(., STATUS_UPDATE)
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "ResearchServerController", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = ..()
|
||||
|
||||
data["badmin"] = badmin
|
||||
|
||||
var/list/server_list = list()
|
||||
data["servers"] = server_list
|
||||
for(var/obj/machinery/r_n_d/server/S in machines)
|
||||
if(istype(S, /obj/machinery/r_n_d/server/centcom) && !badmin)
|
||||
continue
|
||||
var/list/tech = list()
|
||||
var/list/designs = list()
|
||||
var/list/server_data = list(
|
||||
"name" = S.name,
|
||||
"ref" = REF(S),
|
||||
"id" = S.server_id,
|
||||
"id_with_upload" = S.id_with_upload,
|
||||
"id_with_download" = S.id_with_download,
|
||||
"tech" = tech,
|
||||
"designs" = designs,
|
||||
)
|
||||
for(var/datum/tech/T in S.files.known_tech)
|
||||
tech.Add(list(list(
|
||||
"name" = T.name,
|
||||
"id" = T.id,
|
||||
)))
|
||||
for(var/datum/design/D in S.files.known_designs)
|
||||
designs.Add(list(list(
|
||||
"name" = D.name,
|
||||
"id" = D.id,
|
||||
)))
|
||||
server_list.Add(list(server_data))
|
||||
|
||||
var/list/console_list = list()
|
||||
data["consoles"] = console_list
|
||||
for(var/obj/machinery/computer/rdconsole/C in machines)
|
||||
if(!C.sync)
|
||||
continue
|
||||
console_list.Add(list(list(
|
||||
"name" = C.name,
|
||||
"ref" = REF(C),
|
||||
"loc" = get_area(C),
|
||||
"id" = C.id,
|
||||
)))
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
add_fingerprint(usr)
|
||||
switch(action)
|
||||
if("toggle_upload", "toggle_download")
|
||||
var/obj/machinery/r_n_d/server/S = locate(params["server"])
|
||||
if(!istype(S))
|
||||
return
|
||||
if(istype(S, /obj/machinery/r_n_d/server/centcom) && !badmin)
|
||||
return
|
||||
var/obj/machinery/computer/rdconsole/C = locate(params["console"])
|
||||
if(!istype(C) || !C.sync)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("toggle_upload")
|
||||
if(C.id in S.id_with_upload)
|
||||
S.id_with_upload -= C.id
|
||||
else
|
||||
S.id_with_upload += C.id
|
||||
if("toggle_download")
|
||||
if(C.id in S.id_with_download)
|
||||
S.id_with_download -= C.id
|
||||
else
|
||||
S.id_with_download += C.id
|
||||
return TRUE
|
||||
|
||||
if("reset_tech")
|
||||
var/obj/machinery/r_n_d/server/target = locate(params["server"])
|
||||
if(!istype(target))
|
||||
return FALSE
|
||||
var/choice = tgui_alert(usr, "Technology Data Rest", "Are you sure you want to reset this technology to its default data? Data lost cannot be recovered.", list("Continue", "Cancel"))
|
||||
if(choice == "Continue")
|
||||
for(var/datum/tech/T in target.files.known_tech)
|
||||
if(T.id == params["tech"])
|
||||
T.level = 1
|
||||
break
|
||||
target.files.RefreshResearch()
|
||||
return TRUE
|
||||
|
||||
if("reset_design")
|
||||
var/obj/machinery/r_n_d/server/target = locate(params["server"])
|
||||
if(!istype(target))
|
||||
return FALSE
|
||||
var/choice = tgui_alert(usr, "Design Data Deletion", "Are you sure you want to delete this design? If you still have the prerequisites for the design, it'll reset to its base reliability. Data lost cannot be recovered.", list("Continue", "Cancel"))
|
||||
if(choice == "Continue")
|
||||
for(var/datum/design/D in target.files.known_designs)
|
||||
if(D.id == params["design"])
|
||||
target.files.known_designs -= D
|
||||
break
|
||||
target.files.RefreshResearch()
|
||||
return TRUE
|
||||
|
||||
if("transfer_data")
|
||||
if(!badmin)
|
||||
// no href exploits, you've been r e p o r t e d
|
||||
log_admin("Warning: [key_name(usr)] attempted to transfer R&D data from [params["server"]] to [params["target"]] via href exploit with [src] [COORD(src)]")
|
||||
message_admins("Warning: [ADMIN_FULLMONTY(usr)] attempted to transfer R&D data from [params["server"]] to [params["target"]] via href exploit with [src] [ADMIN_COORDJMP(src)]")
|
||||
return FALSE
|
||||
var/obj/machinery/r_n_d/server/from = locate(params["server"])
|
||||
if(!istype(from))
|
||||
return
|
||||
var/obj/machinery/r_n_d/server/target = locate(params["target"])
|
||||
if(!istype(target))
|
||||
return
|
||||
target.files.known_designs |= from.files.known_designs
|
||||
target.files.known_tech |= from.files.known_tech
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/attack_hand(mob/user as mob)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/emag_act(var/remaining_charges, var/mob/user)
|
||||
if(!emagged)
|
||||
playsound(src, 'sound/effects/sparks4.ogg', 75, 1)
|
||||
emagged = 1
|
||||
to_chat(user, "<span class='notice'>You you disable the security protocols.</span>")
|
||||
SStgui.update_uis(src)
|
||||
return 1
|
||||
|
||||
/obj/machinery/r_n_d/server/robotics
|
||||
name = "Robotics R&D Server"
|
||||
id_with_upload_string = "1;2"
|
||||
id_with_download_string = "1;2"
|
||||
server_id = 2
|
||||
|
||||
/obj/machinery/r_n_d/server/core
|
||||
name = "Core R&D Server"
|
||||
id_with_upload_string = "1"
|
||||
id_with_download_string = "1"
|
||||
/obj/machinery/r_n_d/server
|
||||
name = "R&D Server"
|
||||
icon = 'icons/obj/machines/research_vr.dmi' //VOREStation Edit - New Icon
|
||||
icon_state = "server"
|
||||
var/datum/research/files
|
||||
var/health = 100
|
||||
var/list/id_with_upload = list() //List of R&D consoles with upload to server access.
|
||||
var/list/id_with_download = list() //List of R&D consoles with download from server access.
|
||||
var/id_with_upload_string = "" //String versions for easy editing in map editor.
|
||||
var/id_with_download_string = ""
|
||||
var/server_id = 0
|
||||
var/produces_heat = 1
|
||||
idle_power_usage = 800
|
||||
var/delay = 10
|
||||
req_access = list(access_rd) //Only the R&D can change server settings.
|
||||
circuit = /obj/item/weapon/circuitboard/rdserver
|
||||
|
||||
/obj/machinery/r_n_d/server/Initialize()
|
||||
. = ..()
|
||||
default_apply_parts()
|
||||
|
||||
/obj/machinery/r_n_d/server/Destroy()
|
||||
griefProtection()
|
||||
..()
|
||||
|
||||
/obj/machinery/r_n_d/server/RefreshParts()
|
||||
var/tot_rating = 0
|
||||
for(var/obj/item/weapon/stock_parts/SP in src)
|
||||
tot_rating += SP.rating
|
||||
update_idle_power_usage(initial(idle_power_usage) / max(1, tot_rating))
|
||||
|
||||
/obj/machinery/r_n_d/server/Initialize()
|
||||
. = ..()
|
||||
if(!files)
|
||||
files = new /datum/research(src)
|
||||
var/list/temp_list
|
||||
if(!id_with_upload.len)
|
||||
temp_list = list()
|
||||
temp_list = splittext(id_with_upload_string, ";")
|
||||
for(var/N in temp_list)
|
||||
id_with_upload += text2num(N)
|
||||
if(!id_with_download.len)
|
||||
temp_list = list()
|
||||
temp_list = splittext(id_with_download_string, ";")
|
||||
for(var/N in temp_list)
|
||||
id_with_download += text2num(N)
|
||||
|
||||
/obj/machinery/r_n_d/server/process()
|
||||
var/datum/gas_mixture/environment = loc.return_air()
|
||||
switch(environment.temperature)
|
||||
if(0 to T0C)
|
||||
health = min(100, health + 1)
|
||||
if(T0C to (T20C + 20))
|
||||
health = between(0, health, 100)
|
||||
if((T20C + 20) to (T0C + 70))
|
||||
health = max(0, health - 1)
|
||||
if(health <= 0)
|
||||
griefProtection() //I dont like putting this in process() but it's the best I can do without re-writing a chunk of rd servers.
|
||||
files.known_designs = list()
|
||||
for(var/datum/tech/T in files.known_tech)
|
||||
if(prob(1))
|
||||
T.level--
|
||||
files.RefreshResearch()
|
||||
if(delay)
|
||||
delay--
|
||||
else
|
||||
produce_heat()
|
||||
delay = initial(delay)
|
||||
|
||||
/obj/machinery/r_n_d/server/emp_act(severity)
|
||||
griefProtection()
|
||||
..()
|
||||
|
||||
/obj/machinery/r_n_d/server/ex_act(severity)
|
||||
griefProtection()
|
||||
..()
|
||||
|
||||
//Backup files to CentCom to help admins recover data after greifer attacks
|
||||
/obj/machinery/r_n_d/server/proc/griefProtection()
|
||||
for(var/obj/machinery/r_n_d/server/centcom/C in machines)
|
||||
for(var/datum/tech/T in files.known_tech)
|
||||
C.files.AddTech2Known(T)
|
||||
for(var/datum/design/D in files.known_designs)
|
||||
C.files.AddDesign2Known(D)
|
||||
C.files.RefreshResearch()
|
||||
|
||||
/obj/machinery/r_n_d/server/proc/produce_heat()
|
||||
if(!produces_heat)
|
||||
return
|
||||
|
||||
if(!use_power)
|
||||
return
|
||||
|
||||
if(!(stat & (NOPOWER|BROKEN))) //Blatently stolen from telecoms
|
||||
var/turf/simulated/L = loc
|
||||
if(istype(L))
|
||||
var/datum/gas_mixture/env = L.return_air()
|
||||
|
||||
var/transfer_moles = 0.25 * env.total_moles
|
||||
|
||||
var/datum/gas_mixture/removed = env.remove(transfer_moles)
|
||||
|
||||
if(removed)
|
||||
var/heat_produced = idle_power_usage //obviously can't produce more heat than the machine draws from it's power source
|
||||
|
||||
removed.add_thermal_energy(heat_produced)
|
||||
|
||||
env.merge(removed)
|
||||
|
||||
/obj/machinery/r_n_d/server/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
if(default_deconstruction_screwdriver(user, O))
|
||||
return
|
||||
if(default_deconstruction_crowbar(user, O))
|
||||
return
|
||||
if(default_part_replacement(user, O))
|
||||
return
|
||||
|
||||
/obj/machinery/r_n_d/server/centcom
|
||||
name = "Central R&D Database"
|
||||
server_id = -1
|
||||
|
||||
/obj/machinery/r_n_d/server/centcom/proc/update_connections()
|
||||
var/list/no_id_servers = list()
|
||||
var/list/server_ids = list()
|
||||
for(var/obj/machinery/r_n_d/server/S in machines)
|
||||
switch(S.server_id)
|
||||
if(-1)
|
||||
continue
|
||||
if(0)
|
||||
no_id_servers += S
|
||||
else
|
||||
server_ids += S.server_id
|
||||
|
||||
for(var/obj/machinery/r_n_d/server/S in no_id_servers)
|
||||
var/num = 1
|
||||
while(!S.server_id)
|
||||
if(num in server_ids)
|
||||
num++
|
||||
else
|
||||
S.server_id = num
|
||||
server_ids += num
|
||||
no_id_servers -= S
|
||||
|
||||
/obj/machinery/r_n_d/server/centcom/process()
|
||||
return PROCESS_KILL //don't need process()
|
||||
|
||||
/obj/machinery/computer/rdservercontrol
|
||||
name = "R&D Server Controller"
|
||||
desc = "Manage the research designs and servers. Can also modify upload/download permissions to R&D consoles."
|
||||
icon_keyboard = "rd_key"
|
||||
icon_screen = "rdcomp"
|
||||
light_color = "#a97faa"
|
||||
circuit = /obj/item/weapon/circuitboard/rdservercontrol
|
||||
var/screen = 0
|
||||
var/obj/machinery/r_n_d/server/temp_server
|
||||
var/list/servers = list()
|
||||
var/list/consoles = list()
|
||||
var/badmin = 0
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/tgui_status(mob/user)
|
||||
. = ..()
|
||||
if(!allowed(user) && !emagged)
|
||||
. = min(., STATUS_UPDATE)
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "ResearchServerController", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = ..()
|
||||
|
||||
data["badmin"] = badmin
|
||||
|
||||
var/list/server_list = list()
|
||||
data["servers"] = server_list
|
||||
for(var/obj/machinery/r_n_d/server/S in machines)
|
||||
if(istype(S, /obj/machinery/r_n_d/server/centcom) && !badmin)
|
||||
continue
|
||||
var/list/tech = list()
|
||||
var/list/designs = list()
|
||||
var/list/server_data = list(
|
||||
"name" = S.name,
|
||||
"ref" = REF(S),
|
||||
"id" = S.server_id,
|
||||
"id_with_upload" = S.id_with_upload,
|
||||
"id_with_download" = S.id_with_download,
|
||||
"tech" = tech,
|
||||
"designs" = designs,
|
||||
)
|
||||
for(var/datum/tech/T in S.files.known_tech)
|
||||
tech.Add(list(list(
|
||||
"name" = T.name,
|
||||
"id" = T.id,
|
||||
)))
|
||||
for(var/datum/design/D in S.files.known_designs)
|
||||
designs.Add(list(list(
|
||||
"name" = D.name,
|
||||
"id" = D.id,
|
||||
)))
|
||||
server_list.Add(list(server_data))
|
||||
|
||||
var/list/console_list = list()
|
||||
data["consoles"] = console_list
|
||||
for(var/obj/machinery/computer/rdconsole/C in machines)
|
||||
if(!C.sync)
|
||||
continue
|
||||
console_list.Add(list(list(
|
||||
"name" = C.name,
|
||||
"ref" = REF(C),
|
||||
"loc" = get_area(C),
|
||||
"id" = C.id,
|
||||
)))
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
add_fingerprint(usr)
|
||||
switch(action)
|
||||
if("toggle_upload", "toggle_download")
|
||||
var/obj/machinery/r_n_d/server/S = locate(params["server"])
|
||||
if(!istype(S))
|
||||
return
|
||||
if(istype(S, /obj/machinery/r_n_d/server/centcom) && !badmin)
|
||||
return
|
||||
var/obj/machinery/computer/rdconsole/C = locate(params["console"])
|
||||
if(!istype(C) || !C.sync)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("toggle_upload")
|
||||
if(C.id in S.id_with_upload)
|
||||
S.id_with_upload -= C.id
|
||||
else
|
||||
S.id_with_upload += C.id
|
||||
if("toggle_download")
|
||||
if(C.id in S.id_with_download)
|
||||
S.id_with_download -= C.id
|
||||
else
|
||||
S.id_with_download += C.id
|
||||
return TRUE
|
||||
|
||||
if("reset_tech")
|
||||
var/obj/machinery/r_n_d/server/target = locate(params["server"])
|
||||
if(!istype(target))
|
||||
return FALSE
|
||||
var/choice = tgui_alert(usr, "Technology Data Rest", "Are you sure you want to reset this technology to its default data? Data lost cannot be recovered.", list("Continue", "Cancel"))
|
||||
if(choice == "Continue")
|
||||
for(var/datum/tech/T in target.files.known_tech)
|
||||
if(T.id == params["tech"])
|
||||
T.level = 1
|
||||
break
|
||||
target.files.RefreshResearch()
|
||||
return TRUE
|
||||
|
||||
if("reset_design")
|
||||
var/obj/machinery/r_n_d/server/target = locate(params["server"])
|
||||
if(!istype(target))
|
||||
return FALSE
|
||||
var/choice = tgui_alert(usr, "Design Data Deletion", "Are you sure you want to delete this design? If you still have the prerequisites for the design, it'll reset to its base reliability. Data lost cannot be recovered.", list("Continue", "Cancel"))
|
||||
if(choice == "Continue")
|
||||
for(var/datum/design/D in target.files.known_designs)
|
||||
if(D.id == params["design"])
|
||||
target.files.known_designs -= D
|
||||
break
|
||||
target.files.RefreshResearch()
|
||||
return TRUE
|
||||
|
||||
if("transfer_data")
|
||||
if(!badmin)
|
||||
// no href exploits, you've been r e p o r t e d
|
||||
log_admin("Warning: [key_name(usr)] attempted to transfer R&D data from [params["server"]] to [params["target"]] via href exploit with [src] [COORD(src)]")
|
||||
message_admins("Warning: [ADMIN_FULLMONTY(usr)] attempted to transfer R&D data from [params["server"]] to [params["target"]] via href exploit with [src] [ADMIN_COORDJMP(src)]")
|
||||
return FALSE
|
||||
var/obj/machinery/r_n_d/server/from = locate(params["server"])
|
||||
if(!istype(from))
|
||||
return
|
||||
var/obj/machinery/r_n_d/server/target = locate(params["target"])
|
||||
if(!istype(target))
|
||||
return
|
||||
target.files.known_designs |= from.files.known_designs
|
||||
target.files.known_tech |= from.files.known_tech
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/attack_hand(mob/user as mob)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/emag_act(var/remaining_charges, var/mob/user)
|
||||
if(!emagged)
|
||||
playsound(src, 'sound/effects/sparks4.ogg', 75, 1)
|
||||
emagged = 1
|
||||
to_chat(user, "<span class='notice'>You you disable the security protocols.</span>")
|
||||
SStgui.update_uis(src)
|
||||
return 1
|
||||
|
||||
/obj/machinery/r_n_d/server/robotics
|
||||
name = "Robotics R&D Server"
|
||||
id_with_upload_string = "1;2"
|
||||
id_with_download_string = "1;2"
|
||||
server_id = 2
|
||||
|
||||
/obj/machinery/r_n_d/server/core
|
||||
name = "Core R&D Server"
|
||||
id_with_upload_string = "1"
|
||||
id_with_download_string = "1"
|
||||
server_id = 1
|
||||
Reference in New Issue
Block a user