Moar whitespace normalization [MDB IGNORE] (#7750)

Co-authored-by: Raeschen <rycoop29@gmail.com>
This commit is contained in:
Drathek
2024-02-16 01:54:47 -08:00
committed by GitHub
parent eecf6bbff9
commit 3995338290
1177 changed files with 550902 additions and 550902 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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.
*/

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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