mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-20 22:54:46 +00:00
* TGUI Destructive Analyzer (#79572) ## About The Pull Request I made this to help me move more towards my goals [laid out here](https://hackmd.io/XLt5MoRvRxuhFbwtk4VAUA) which currently doesn't have much interest. This makes the Destructive Analyzer use a little neat TGUI menu instead of its old HTML one. I also touch a lot of science stuff and a little experimentor stuff, so let me explain a bit: Old iterations of Science had different items that you can use to boost nodes through deconstruction. This has been removed, and its only feature is the auto-unlocking of nodes (that is; making them visible to the R&D console). I thought that instead of keeping this deprecated code around, I would rework it a little to make it clear what we actually use it for (unhiding nodes). All vars and procs that mentioned this have been renamed or reworked to make more sense now. Experimentor stuff shares a lot with the destructive analyzer, so I had to mess with that a bit to keep its decayed corpse of deprecated code, functional. I also added context tips to the destructive analyzer, and added the ability to AltClick to remove the inserted item. Removing items now also plays a little sound because it was kinda lame. Also, balloon alerts. ## Why It's Good For The Game Moves a shitty machine to TGUI so it is slightly less shitty, now it's more direct and compact with more player-feedback. Helps me with a personal project and yea ### Video demonstration I show off connecting the machine to R&D Servers, but I haven't changed the behavior of that and the roundstart analyzers are connected to servers by default. https://github.com/tgstation/tgstation/assets/53777086/65295600-4fae-42d1-9bae-eccefe337a2b ## Changelog 🆑 refactor: Destructive Analyzers now have a TGUI menu. /🆑 * TGUI Destructive Analyzer * Modular --------- Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com>
307 lines
12 KiB
Plaintext
307 lines
12 KiB
Plaintext
/// Scientific paper datum for retrieval and re-reading. A lot of the variables are there for fluff & flavor.
|
|
/datum/scientific_paper
|
|
/// The title of our paper.
|
|
var/title
|
|
/// The principal author of our paper.
|
|
var/author
|
|
/// Whether this paper is co-authored or not.
|
|
var/et_alia = FALSE
|
|
/// Abstract.
|
|
var/abstract
|
|
/// The coop and funding gains from the paper.
|
|
var/list/gains
|
|
/// Experiment typepath.
|
|
var/datum/experiment/ordnance/experiment_path
|
|
/// The main "score" of a particular experiment.
|
|
var/tracked_variable
|
|
/**
|
|
* Derived from tracked_variable. Used for indexing and to reduce duplicates.
|
|
* Only one paper can be published in each tier for each experiment.
|
|
*/
|
|
var/tier
|
|
/// The selected sponsor for our paper. Pathtype form.
|
|
var/datum/scientific_partner/partner_path
|
|
|
|
/datum/scientific_paper/New()
|
|
. = ..()
|
|
set_amount()
|
|
|
|
/**
|
|
* Calculate the gains of an experiment.
|
|
* Gain calculation follows a sigmoid curve.
|
|
* f(x) = L / (1+e^(-k(x-xo)))
|
|
* L is the upper limit. This should be the gain variable * 2.
|
|
* k is the steepness.
|
|
* x0 is the midpoint.
|
|
* x is our tracked variable.
|
|
* Returns the expected value of that tier.
|
|
*/
|
|
/datum/scientific_paper/proc/calculate_gains(calculated_tier)
|
|
if(!experiment_path || !tracked_variable)
|
|
return FALSE
|
|
|
|
var/datum/experiment/ordnance/initialized_experiment = locate(experiment_path) in SSresearch.ordnance_experiments
|
|
var/gain = initialized_experiment.gain[calculated_tier]
|
|
var/target_amount = initialized_experiment.target_amount[calculated_tier]
|
|
/// Steepness is calculated so that f(x=0) is always 1.
|
|
var/steepness = log(gain*2 - 1) / target_amount
|
|
var/calculated_gain = gain*2 / (1+NUM_E**(-steepness*(tracked_variable-target_amount)))
|
|
return calculated_gain
|
|
|
|
/// Determine which tier can we publish at. Lower limit for an allowed tier is 10% of gain. Empty list if none are allowed.
|
|
/datum/scientific_paper/proc/calculate_tier()
|
|
var/list/allowed_tiers = list()
|
|
if(!experiment_path || !tracked_variable)
|
|
return allowed_tiers
|
|
var/datum/experiment/ordnance/initialized_experiment = locate(experiment_path) in SSresearch.ordnance_experiments
|
|
for (var/each_tier in 1 to min(length(initialized_experiment.target_amount), length(initialized_experiment.gain)))
|
|
var/calculated_gain = calculate_gains(each_tier)
|
|
if(calculated_gain > 0.1 * initialized_experiment.gain[each_tier])
|
|
allowed_tiers += each_tier
|
|
return allowed_tiers
|
|
|
|
/**
|
|
* Experiment -> Tier -> Gains
|
|
* Experiment -> Partners -> Gains
|
|
* Changing anything in the chain means those following it should be recounted.
|
|
*/
|
|
|
|
/**
|
|
* Used when assigning an experiment to a specific paper.
|
|
* Failing to provide a proper path, a tracked variable, or a correct data should null every non-fluff data.
|
|
* Implement this in the children procs.
|
|
*/
|
|
/datum/scientific_paper/proc/set_experiment(ex_path = null, variable = null, data = null)
|
|
return
|
|
|
|
/// Sets a tier for us. Nulls the tier when called without args. Re-counts the amount.
|
|
/datum/scientific_paper/proc/set_tier(assigned_tier = null)
|
|
tier = null
|
|
if(assigned_tier && (assigned_tier in calculate_tier()))
|
|
tier = assigned_tier
|
|
set_amount()
|
|
|
|
/** Sets a specific partner for our paper. Partners give money and boost points.
|
|
* Partners exist separately from experiments and wont need to be reset every time something changes.
|
|
*/
|
|
/datum/scientific_paper/proc/set_partner(new_partner = null)
|
|
partner_path = null
|
|
if(ispath(new_partner, /datum/scientific_partner))
|
|
var/datum/scientific_partner/partner = locate(new_partner) in SSresearch.scientific_partners
|
|
if(experiment_path in partner.accepted_experiments)
|
|
partner_path = new_partner
|
|
set_amount()
|
|
|
|
/** Does the counting for gains.
|
|
* Call this whenever experiments/tier/partners are changed.
|
|
* Handled automatically, calling this proc externally shouldn't be necessary.
|
|
* Also doubles as an initialization for the gains list.
|
|
*/
|
|
/datum/scientific_paper/proc/set_amount()
|
|
gains = list(SCIPAPER_COOPERATION_INDEX = 0, SCIPAPER_FUNDING_INDEX = 0)
|
|
if(!tier || !experiment_path || !tracked_variable)
|
|
return FALSE
|
|
var/gain = calculate_gains(tier)
|
|
for (var/gain_type in 1 to gains.len)
|
|
gains[gain_type] = gain
|
|
if(!partner_path)
|
|
continue
|
|
var/datum/scientific_partner/partner = locate(partner_path) in SSresearch.scientific_partners
|
|
gains[gain_type] *= partner.multipliers[gain_type]
|
|
|
|
/** Fully check if our paper have all the required variables, and prevent duplicate papers being published in the same tier.
|
|
* Things to check: tier, gain, and partner here. ex_path and record datums in subtypes.
|
|
*/
|
|
/datum/scientific_paper/proc/allowed_to_publish(datum/techweb/techweb_to_check)
|
|
if(!tier || !gains || !partner_path || (0 in gains))
|
|
return FALSE
|
|
return !techweb_to_check.published_papers[experiment_path][tier]
|
|
|
|
/datum/scientific_paper/proc/publish_paper(datum/techweb/techweb_to_publish)
|
|
autofill()
|
|
techweb_to_publish.published_papers[experiment_path][tier] = src
|
|
techweb_to_publish.scientific_cooperation[partner_path] += gains[SCIPAPER_COOPERATION_INDEX]
|
|
if(istype(techweb_to_publish, /datum/techweb/science))
|
|
var/datum/bank_account/dept_budget = SSeconomy.get_dep_account(ACCOUNT_SCI)
|
|
if(dept_budget)
|
|
dept_budget.adjust_money(gains[SCIPAPER_FUNDING_INDEX] * SCIPAPER_GAIN_TO_MONEY)
|
|
|
|
/**
|
|
* Clones into a new paper type.
|
|
* Important (non-fluff) variables will be carried over and should be cleaned with set_experiment by whoever is calling this.
|
|
*
|
|
* clone_into your own typepath will be like a normal clone.
|
|
*
|
|
* If you want to subtype this, do it in a way that doesn't mess with the type change.
|
|
*/
|
|
/datum/scientific_paper/proc/clone_into(typepath)
|
|
var/datum/scientific_paper/new_paper = new typepath
|
|
new_paper.title = title
|
|
new_paper.author = author
|
|
new_paper.et_alia = et_alia
|
|
new_paper.abstract = abstract
|
|
new_paper.gains = gains
|
|
new_paper.experiment_path = experiment_path
|
|
new_paper.tracked_variable = tracked_variable
|
|
new_paper.tier = tier
|
|
new_paper.partner_path = partner_path
|
|
return new_paper
|
|
|
|
/// Returns the formatted, readable gist of our paper in a list.
|
|
/datum/scientific_paper/proc/return_gist()
|
|
var/list/gist = list()
|
|
var/list/transcripted_gains = list(SCIPAPER_COOPERATION_INDEX, SCIPAPER_FUNDING_INDEX)
|
|
for (var/index in 1 to transcripted_gains.len)
|
|
if (!gains)
|
|
transcripted_gains[index] = "None"
|
|
continue
|
|
switch (round(gains[index]))
|
|
if(-INFINITY to 0)
|
|
transcripted_gains[index] = "None"
|
|
if(1 to 24)
|
|
transcripted_gains[index] = "Little"
|
|
if(25 to 49)
|
|
transcripted_gains[index] = "Moderate"
|
|
if(50 to 99)
|
|
transcripted_gains[index] = "Significant"
|
|
if(100 to INFINITY)
|
|
transcripted_gains[index] = "Huge"
|
|
else
|
|
transcripted_gains[index] = "Undefined"
|
|
gist["gains"] = transcripted_gains
|
|
gist["title"] = title
|
|
gist["author"] = author
|
|
gist["etAlia"] = et_alia
|
|
gist["abstract"] = abstract
|
|
gist["experimentName"] = initial(experiment_path?.name)
|
|
gist["tier"] = tier
|
|
gist["partner"] = initial(partner_path?.name)
|
|
return gist
|
|
|
|
/datum/scientific_paper/proc/autofill()
|
|
if(!title)
|
|
title = "On [initial(experiment_path.name)] - [tier]"
|
|
if(!author)
|
|
author = "Unknown"
|
|
et_alia = FALSE
|
|
if(!abstract)
|
|
abstract = "Published on [station_time_timestamp()]"
|
|
|
|
/datum/scientific_paper/explosive
|
|
/**
|
|
* Used to check explosive experiments that needs to be unique.
|
|
* References a tachyon record where applicable.
|
|
*/
|
|
var/datum/data/tachyon_record/explosion_record
|
|
|
|
/// Check if our explosion has already been published and whether the experiment path is correct or not.
|
|
/datum/scientific_paper/explosive/allowed_to_publish(datum/techweb/techweb_to_check)
|
|
if(!ispath(experiment_path, /datum/experiment/ordnance/explosive))
|
|
return FALSE
|
|
if(!istype(explosion_record))
|
|
return FALSE
|
|
var/list/published_papers = techweb_to_check.published_papers
|
|
for(var/experiment_path in published_papers)
|
|
for(var/datum/scientific_paper/explosive/papers in published_papers[experiment_path])
|
|
var/datum/data/tachyon_record/record_to_check = papers.explosion_record
|
|
if(explosion_record.explosion_identifier == record_to_check.explosion_identifier)
|
|
return FALSE
|
|
return ..()
|
|
|
|
/datum/scientific_paper/explosive/set_experiment(ex_path = null, variable = null, data = null)
|
|
if(!ispath(ex_path, /datum/experiment/ordnance/explosive) || !variable || !istype(data, /datum/data/tachyon_record))
|
|
experiment_path = null
|
|
tracked_variable = null
|
|
explosion_record = null
|
|
else
|
|
experiment_path = ex_path
|
|
tracked_variable = variable
|
|
explosion_record = data
|
|
|
|
set_tier()
|
|
set_partner()
|
|
|
|
/datum/scientific_paper/explosive/clone_into(typepath)
|
|
if(typepath != type)
|
|
return ..()
|
|
|
|
var/datum/scientific_paper/explosive/new_paper = ..(typepath)
|
|
new_paper.explosion_record = explosion_record
|
|
return new_paper
|
|
|
|
/datum/scientific_paper/gaseous
|
|
var/datum/data/compressor_record/compressor_record
|
|
|
|
/**
|
|
* Check if our record datum is a duplicate or no.
|
|
* No index number is necessary because compressor records cant be replicated.
|
|
* Also checks the experiment path.
|
|
*/
|
|
/datum/scientific_paper/gaseous/allowed_to_publish(datum/techweb/techweb_to_check)
|
|
if(!ispath(experiment_path, /datum/experiment/ordnance/gaseous))
|
|
return FALSE
|
|
if(!istype(compressor_record))
|
|
return FALSE
|
|
var/list/published_papers = techweb_to_check.published_papers
|
|
for(var/experiment_path in published_papers)
|
|
for(var/datum/scientific_paper/gaseous/papers in published_papers[experiment_path])
|
|
if(compressor_record == papers.compressor_record)
|
|
return FALSE
|
|
. = ..()
|
|
|
|
/datum/scientific_paper/gaseous/set_experiment(ex_path = null, variable = null, data = null)
|
|
var/invalid = FALSE
|
|
|
|
invalid = invalid || !ispath(ex_path, /datum/experiment/ordnance/gaseous)
|
|
invalid = invalid || !variable
|
|
invalid = invalid || !istype(data, /datum/data/compressor_record)
|
|
|
|
if(invalid)
|
|
experiment_path = null
|
|
tracked_variable = null
|
|
compressor_record = null
|
|
else
|
|
experiment_path = ex_path
|
|
tracked_variable = variable
|
|
compressor_record = data
|
|
|
|
set_tier()
|
|
set_partner()
|
|
|
|
/datum/scientific_paper/gaseous/clone_into(typepath)
|
|
if(typepath != type)
|
|
return ..()
|
|
|
|
var/datum/scientific_paper/gaseous/new_paper = ..(typepath)
|
|
new_paper.compressor_record = compressor_record
|
|
return new_paper
|
|
|
|
/// Various informations on companies/scientific programs/journals etc that the players can sign on to.
|
|
/datum/scientific_partner
|
|
/// Name of the partner, shown in the Science program's UI.
|
|
var/name
|
|
/// Brief explanation of the associated program. Can be used for lore.
|
|
var/flufftext
|
|
/// Cash and renown multiplier for allying with this partner.
|
|
var/list/multipliers = list(SCIPAPER_COOPERATION_INDEX = 1, SCIPAPER_FUNDING_INDEX = 1)
|
|
/// List of ordnance experiments that our partner is willing to accept. If this list is not filled it means the partner will accept everything.
|
|
var/list/accepted_experiments = list()
|
|
/// Associative list of which technology the partner might be able to boost and by how much.
|
|
var/list/boostable_nodes = list()
|
|
|
|
/datum/scientific_partner/proc/purchase_boost(datum/techweb/purchasing_techweb, datum/techweb_node/node)
|
|
if(!allowed_to_boost(purchasing_techweb, node.id))
|
|
return FALSE
|
|
purchasing_techweb.boost_techweb_node(node, list(TECHWEB_POINT_TYPE_GENERIC = boostable_nodes[node.id]))
|
|
purchasing_techweb.scientific_cooperation[type] -= boostable_nodes[node.id] * SCIENTIFIC_COOPERATION_PURCHASE_MULTIPLIER
|
|
return TRUE
|
|
|
|
/datum/scientific_partner/proc/allowed_to_boost(datum/techweb/purchasing_techweb, node_id)
|
|
if(purchasing_techweb.scientific_cooperation[type] < (boostable_nodes[node_id] * SCIENTIFIC_COOPERATION_PURCHASE_MULTIPLIER)) // Too expensive
|
|
return FALSE
|
|
if(!(node_id in purchasing_techweb.get_available_nodes())) // Not currently available
|
|
return FALSE
|
|
if((TECHWEB_POINT_TYPE_GENERIC in purchasing_techweb.boosted_nodes[node_id]) && (purchasing_techweb.boosted_nodes[node_id][TECHWEB_POINT_TYPE_GENERIC] >= boostable_nodes[node_id])) // Already bought or we have a bigger discount
|
|
return FALSE
|
|
return TRUE
|