mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2025-12-21 15:42:35 +00:00
* Mitigates research recycling exploits by minimizing what can be recycled * Moves the research design check into a new unit test * Adds unit test for stack material recipes costs and fixes these costs * Instead of changing recipes the resulting materials are worth less * Crap fix
288 lines
11 KiB
Plaintext
288 lines
11 KiB
Plaintext
/*
|
|
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.
|
|
- 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 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 15. 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 design lists
|
|
var/global/list/designs = null
|
|
var/global/list/designs_protolathe_categories = list()
|
|
var/global/list/designs_imprinter_categories = 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/known_designs = list() //List of available designs.
|
|
|
|
var/standard_start_level // The level non-antag techs are set at
|
|
var/antag_start_level // ditto but antag
|
|
var/load_tech = TRUE // Whether we should gather the techs
|
|
var/load_designs = TRUE // ditto but designs
|
|
|
|
/datum/research/New() //Insert techs into possible_tech here. Known_tech automatically updated.
|
|
if(load_tech)
|
|
for(var/tech_path in subtypesof(/datum/tech))
|
|
var/datum/tech/T = new tech_path(src)
|
|
known_tech[T.id] = T
|
|
if(!T.antag_tech)
|
|
if(standard_start_level)
|
|
T.level = standard_start_level
|
|
else
|
|
if(antag_start_level)
|
|
T.level = antag_start_level
|
|
if(load_designs && isnull(designs))
|
|
InitializeDesigns()
|
|
RefreshResearch()
|
|
|
|
/datum/research/techonly
|
|
load_designs = FALSE
|
|
|
|
/datum/research/hightech
|
|
standard_start_level = 3
|
|
|
|
/datum/research/proc/InitializeDesigns()
|
|
designs = list()
|
|
for(var/T in subtypesof(/datum/design))
|
|
var/datum/design/D = new T
|
|
designs[D.type] = D
|
|
if(D.build_type & PROTOLATHE)
|
|
designs_protolathe_categories |= D.p_category
|
|
if(D.build_type & IMPRINTER)
|
|
designs_imprinter_categories |= D.p_category
|
|
|
|
//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(!D.req_tech.len)
|
|
return TRUE
|
|
|
|
for(var/req in D.req_tech)
|
|
var/datum/tech/T = known_tech[req]
|
|
if(isnull(T))
|
|
return FALSE
|
|
if(T.level < D.req_tech[req])
|
|
return FALSE
|
|
|
|
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)
|
|
if(isnull(T))
|
|
return
|
|
var/datum/tech/known = known_tech[T.id]
|
|
var/will_update_progress = FALSE
|
|
if(T.level > known.level)
|
|
known.level = T.level
|
|
known.next_level_threshold = T.next_level_threshold
|
|
known.next_level_progress = 0
|
|
will_update_progress = TRUE
|
|
else if (T.level == known.level && T.next_level_progress > known.next_level_progress)
|
|
will_update_progress = TRUE
|
|
|
|
if(will_update_progress)
|
|
known.next_level_progress = T.next_level_progress
|
|
|
|
/datum/research/proc/AddDesign2Known(var/datum/design/D)
|
|
known_designs[D.type] = D
|
|
|
|
//Refreshes known_tech and known_designs list
|
|
//Input/Output: n/a
|
|
/datum/research/proc/RefreshResearch()
|
|
known_designs.Cut() // this is to refresh the ordering of the designs, the alternative is an expensive insertion or sorting proc
|
|
if(load_designs)
|
|
for(var/path in designs)
|
|
var/datum/design/PD = designs[path]
|
|
if(DesignHasReqs(PD))
|
|
AddDesign2Known(PD)
|
|
for(var/id in known_tech)
|
|
var/datum/tech/T = known_tech[id]
|
|
T.level = between(0, T.level, MAX_TECH_LEVEL)
|
|
T.next_level_threshold = get_level_value(T.level)
|
|
|
|
/datum/research/proc/get_level_value(var/level)
|
|
return 5 ** level
|
|
|
|
//Refreshes the levels of a given tech.
|
|
//Input: Tech's ID and Level; Output: null
|
|
/datum/research/proc/UpdateTech(var/ID, var/update_level)
|
|
var/datum/tech/KT = known_tech[ID]
|
|
var/progress = get_level_value(update_level)
|
|
while(progress > 0)
|
|
if(KT.level >= MAX_TECH_LEVEL)
|
|
break
|
|
if(KT.next_level_progress + progress >= KT.next_level_threshold)
|
|
progress -= KT.next_level_threshold - KT.next_level_progress
|
|
KT.level++
|
|
KT.level = clamp(KT.level, 0, MAX_TECH_LEVEL)
|
|
KT.next_level_threshold = get_level_value(KT.level)
|
|
continue
|
|
KT.next_level_progress += progress
|
|
break
|
|
|
|
// A simple helper proc to find the name of a tech with a given ID.
|
|
/proc/CallTechName(var/ID)
|
|
for(var/T in subtypesof(/datum/tech))
|
|
var/datum/tech/check_tech = T
|
|
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/antag_tech
|
|
var/level = 1 //A simple number scale of the research level. Level 0 = Secret tech.
|
|
var/next_level_progress = 0 // The research progress until the next level is reached, makes things more gradual
|
|
var/next_level_threshold = 10 // The next threshold that must be reached before it ticks to the next level
|
|
|
|
/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 = "Esoteric Technologies Research"
|
|
desc = "The study of bleeding-edge, experimental and often restricted technologies."
|
|
id = TECH_ILLEGAL
|
|
antag_tech = TRUE
|
|
level = 0
|
|
|
|
/datum/tech/arcane
|
|
name = "Arcane Research"
|
|
desc = "Research into the occult and arcane field for use in practical science"
|
|
id = TECH_ARCANE
|
|
antag_tech = TRUE
|
|
level = 0
|
|
|
|
/obj/item/disk/tech_disk
|
|
name = "technology disk"
|
|
desc = "A disk for storing technology data for further research."
|
|
icon = 'icons/obj/cloning.dmi'
|
|
icon_state = "datadisk2"
|
|
item_state = "card-id"
|
|
w_class = ITEMSIZE_SMALL
|
|
matter = list(DEFAULT_WALL_MATERIAL = 30, MATERIAL_GLASS = 10)
|
|
var/datum/tech/stored
|
|
|
|
/obj/item/disk/tech_disk/Initialize(mapload)
|
|
. = ..()
|
|
pixel_x = rand(-5, 5)
|
|
pixel_y = rand(-5, 5)
|
|
|
|
/obj/item/disk/tech_disk/examine(mob/user, distance)
|
|
. = ..()
|
|
if(distance <= 1)
|
|
if(stored)
|
|
to_chat(user, FONT_SMALL("It is storing the following tech:"))
|
|
to_chat(user, FONT_SMALL(" - [stored.name]: Level - [stored.level] | Progress - [stored.next_level_progress]/[stored.next_level_threshold]"))
|
|
else
|
|
to_chat(user, FONT_SMALL("It doesn't have any tech stored."))
|
|
|
|
/obj/item/disk/design_disk
|
|
name = "component design disk"
|
|
desc = "A disk for storing device design data for construction in lathes."
|
|
icon = 'icons/obj/cloning.dmi'
|
|
icon_state = "datadisk2"
|
|
item_state = "card-id"
|
|
w_class = ITEMSIZE_SMALL
|
|
matter = list(DEFAULT_WALL_MATERIAL = 30, MATERIAL_GLASS = 10)
|
|
var/datum/design/blueprint
|
|
|
|
/obj/item/disk/design_disk/Initialize(mapload)
|
|
. = ..()
|
|
pixel_x = rand(-5, 5)
|
|
pixel_y = rand(-5, 5)
|
|
|
|
/obj/item/disk/design_disk/examine(mob/user, distance)
|
|
. = ..()
|
|
if(distance <= 1)
|
|
if(blueprint)
|
|
to_chat(user, FONT_SMALL("It is storing the following design:"))
|
|
to_chat(user, FONT_SMALL(" - [blueprint.name]"))
|
|
else
|
|
to_chat(user, FONT_SMALL("It doesn't have any blueprint stored."))
|