Merge pull request #8667 from Ghommie/Ghommie-cit61

Ports the system for randomized semi-persistent chem reactions.
This commit is contained in:
kevinz000
2019-06-23 06:54:43 -07:00
committed by GitHub
11 changed files with 364 additions and 55 deletions

View File

@@ -21,7 +21,9 @@
if(GLOB.chemical_reactions_list)
return
var/paths = subtypesof(/datum/chemical_reaction)
//Randomized need to go last since they need to check against conflicts with normal recipes
var/paths = subtypesof(/datum/chemical_reaction) - typesof(/datum/chemical_reaction/randomized) + subtypesof(/datum/chemical_reaction/randomized)
GLOB.chemical_reactions_list = list()
for(var/path in paths)
@@ -29,6 +31,9 @@
var/datum/chemical_reaction/D = new path()
var/list/reaction_ids = list()
if(!D.id)
continue
if(D.required_reagents && D.required_reagents.len)
for(var/reaction in D.required_reagents)
reaction_ids += reaction

View File

@@ -32,6 +32,8 @@
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "quality_drink", /datum/mood_event/quality_verygood)
if (DRINK_FANTASTIC)
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "quality_drink", /datum/mood_event/quality_fantastic)
if (FOOD_AMAZING)
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "quality_food", /datum/mood_event/amazingtaste)
return ..()
/datum/reagent/consumable/nutriment
@@ -711,3 +713,14 @@
nutriment_factor = 5 * REAGENTS_METABOLISM
color = "#eef442" // rgb: 238, 244, 66
taste_description = "mournful honking"
/datum/reagent/consumable/secretsauce
name = "secret sauce"
id = "secret_sauce"
description = "What could it be."
nutriment_factor = 2 * REAGENTS_METABOLISM
color = "#792300"
taste_description = "indescribable"
quality = FOOD_AMAZING
taste_mult = 100
can_synth = FALSE

View File

@@ -0,0 +1,212 @@
GLOBAL_LIST_INIT(food_reagents, build_reagents_to_food()) //reagentid = related food types
/proc/build_reagents_to_food()
. = list()
for (var/type in subtypesof(/obj/item/reagent_containers/food))
var/obj/item/reagent_containers/food/item = new type()
for(var/r in item.list_reagents)
if (!.[r])
.[r] = list()
.[r] += type
qdel(item)
//dang plant snowflake
for (var/type in subtypesof(/obj/item/seeds))
var/obj/item/seeds/item = new type()
for(var/r in item.reagents_add)
if (!.[r])
.[r] = list()
.[r] += type
qdel(item)
#define RNGCHEM_INPUT "input"
#define RNGCHEM_CATALYSTS "catalysts"
#define RNGCHEM_OUTPUT "output"
/datum/chemical_reaction/randomized
name = "semi randomized reaction"
var/persistent = FALSE
var/persistence_period = 7 //Will reset every x days
var/created //creation timestamp
var/randomize_container = FALSE
var/list/possible_containers = list()
var/randomize_req_temperature = TRUE
var/min_temp = 1
var/max_temp = 600
var/randomize_inputs = TRUE
var/min_input_reagent_amount = 1
var/max_input_reagent_amount = 10
var/min_input_reagents = 2
var/max_input_reagents = 5
var/list/possible_reagents = list()
var/min_catalysts = 0
var/max_catalysts = 2
var/list/possible_catalysts = list()
var/randomize_results = FALSE
var/min_output_reagent_amount = 1
var/max_output_reagent_amount = 5
var/min_result_reagents = 1
var/max_result_reagents = 1
var/list/possible_results = list()
/datum/chemical_reaction/randomized/proc/GenerateRecipe()
created = world.time
if(randomize_container)
required_container = pick(possible_containers)
if(randomize_req_temperature)
required_temp = rand(min_temp,max_temp)
is_cold_recipe = pick(TRUE,FALSE)
if(randomize_results)
results = list()
var/list/remaining_possible_results = GetPossibleReagents(RNGCHEM_OUTPUT)
var/out_reagent_count = min(rand(min_result_reagents,max_result_reagents),remaining_possible_results.len)
for(var/i in 1 to out_reagent_count)
var/r_id = pick_n_take(remaining_possible_results)
results[r_id] = rand(min_output_reagent_amount,max_output_reagent_amount)
if(randomize_inputs)
var/list/remaining_possible_reagents = GetPossibleReagents(RNGCHEM_INPUT)
var/list/remaining_possible_catalysts = GetPossibleReagents(RNGCHEM_CATALYSTS)
//We're going to assume we're not doing any weird partial reactions for now.
for(var/reagent_type in results)
remaining_possible_catalysts -= reagent_type
remaining_possible_reagents -= reagent_type
var/in_reagent_count = min(rand(min_input_reagents,max_input_reagents),remaining_possible_reagents.len)
if(in_reagent_count <= 0)
return FALSE
required_reagents = list()
for(var/i in 1 to in_reagent_count)
var/r_id = pick_n_take(remaining_possible_reagents)
required_reagents[r_id] = rand(min_input_reagent_amount,max_input_reagent_amount)
remaining_possible_catalysts -= r_id //Can't have same reagents both as catalyst and reagent. Or can we ?
required_catalysts = list()
var/in_catalyst_count = min(rand(min_catalysts,max_catalysts),remaining_possible_catalysts.len)
for(var/i in 1 to in_catalyst_count)
var/r_id = pick_n_take(remaining_possible_catalysts)
required_catalysts[r_id] = rand(min_input_reagent_amount,max_input_reagent_amount)
return TRUE
/datum/chemical_reaction/randomized/proc/GetPossibleReagents(kind)
switch(kind)
if(RNGCHEM_INPUT)
return possible_reagents.Copy()
if(RNGCHEM_CATALYSTS)
return possible_catalysts.Copy()
if(RNGCHEM_OUTPUT)
return possible_results.Copy()
/datum/chemical_reaction/randomized/proc/HasConflicts()
for(var/x in required_reagents)
for(var/datum/chemical_reaction/R in GLOB.chemical_reactions_list[x])
if(chem_recipes_do_conflict(R,src))
return TRUE
return FALSE
/datum/chemical_reaction/randomized/proc/unwrap_reagent_list(list/textreagents)
. = list()
for(var/R in textreagents)
var/pathR = text2path(R)
if(!pathR)
return null
.[pathR] = textreagents[R]
/datum/chemical_reaction/randomized/proc/LoadOldRecipe(recipe_data)
created = text2num(recipe_data["timestamp"])
var/req_reag = unwrap_reagent_list(recipe_data["required_reagents"])
if(!req_reag)
return FALSE
required_reagents = req_reag
var/req_catalysts = unwrap_reagent_list(recipe_data["required_catalysts"])
if(!req_catalysts)
return FALSE
required_catalysts = req_catalysts
required_temp = recipe_data["required_temp"]
is_cold_recipe = recipe_data["is_cold_recipe"]
var/temp_results = unwrap_reagent_list(recipe_data["results"])
if(!temp_results)
return FALSE
results = temp_results
var/containerpath = text2path(recipe_data["required_container"])
if(!containerpath)
return FALSE
required_container = containerpath
return TRUE
/datum/chemical_reaction/randomized/secret_sauce
name = "secret sauce creation"
id = "secretsauce"
persistent = TRUE
persistence_period = 7 //Reset every week
randomize_container = TRUE
possible_containers = list(/obj/item/reagent_containers/glass/bucket) //easy way to ensure no common conflicts
randomize_req_temperature = TRUE
results = list("secret_sauce" =1)
/datum/chemical_reaction/randomized/secret_sauce/GetPossibleReagents(kind)
switch(kind)
if(RNGCHEM_INPUT,RNGCHEM_CATALYSTS)
var/food_reagent_ids = list()
for(var/key in GLOB.food_reagents)
food_reagent_ids += key
return food_reagent_ids
return ..()
/obj/item/paper/secretrecipe
name = "old recipe"
var/recipe_id = "secretsauce"
/obj/item/paper/secretrecipe/examine(mob/user) //Extra secret
if(isobserver(user))
return
. = ..()
/obj/item/paper/secretrecipe/Initialize()
. = ..()
if(SSpersistence.initialized)
UpdateInfo()
else
SSticker.OnRoundstart(CALLBACK(src,.proc/UpdateInfo))
/obj/item/paper/secretrecipe/proc/UpdateInfo()
var/datum/chemical_reaction/recipe = get_chemical_reaction(recipe_id)
if(!recipe)
info = "This recipe is illegible."
var/list/dat = list("<ul>")
for(var/rid in recipe.required_reagents)
var/datum/reagent/R = GLOB.chemical_reagents_list[rid]
dat += "<li>[recipe.required_reagents[rid]]u of [R.name]</li>"
dat += "</ul>"
if(recipe.required_catalysts.len)
dat += "With following present: <ul>"
for(var/rid in recipe.required_catalysts)
var/datum/reagent/R = GLOB.chemical_reagents_list[rid]
dat += "<li>[recipe.required_catalysts[rid]]u of [R.name]</li>"
dat += "</ul>"
dat += "Mix slowly"
if(recipe.required_container)
var/obj/item/I = recipe.required_container
dat += " in [initial(I.name)]"
if(recipe.required_temp != 0)
if(recipe.is_cold_recipe)
dat += " below [recipe.required_temp] degrees"
else
dat += " above [recipe.required_temp] degrees"
dat += "."
info = dat.Join("")
update_icon()

View File

@@ -11,57 +11,5 @@
for(var/i2 in (i+1) to reactions.len)
var/datum/chemical_reaction/r1 = reactions[i]
var/datum/chemical_reaction/r2 = reactions[i2]
if(recipes_do_conflict(r1, r2))
if(chem_recipes_do_conflict(r1, r2))
Fail("Chemical recipe conflict between [r1.type] and [r2.type]")
/datum/unit_test/reagent_recipe_collisions/proc/recipes_do_conflict(datum/chemical_reaction/r1, datum/chemical_reaction/r2)
//do the non-list tests first, because they are cheaper
if(r1.required_container != r2.required_container)
return FALSE
if(r1.is_cold_recipe == r2.is_cold_recipe)
if(r1.required_temp != r2.required_temp)
//one reaction requires a more extreme temperature than the other, so there is no conflict
return FALSE
else
var/datum/chemical_reaction/cold_one = r1.is_cold_recipe ? r1 : r2
var/datum/chemical_reaction/warm_one = r1.is_cold_recipe ? r2 : r1
if(cold_one.required_temp < warm_one.required_temp)
//the range of temperatures does not overlap, so there is no conflict
return FALSE
//find the reactions with the shorter and longer required_reagents list
var/datum/chemical_reaction/long_req
var/datum/chemical_reaction/short_req
if(r1.required_reagents.len > r2.required_reagents.len)
long_req = r1
short_req = r2
else if(r1.required_reagents.len < r2.required_reagents.len)
long_req = r2
short_req = r1
else
//if they are the same length, sort instead by the length of the catalyst list
//this is important if the required_reagents lists are the same
if(r1.required_catalysts.len > r2.required_catalysts.len)
long_req = r1
short_req = r2
else
long_req = r2
short_req = r1
//check if the shorter reaction list is a subset of the longer one
var/list/overlap = r1.required_reagents & r2.required_reagents
if(overlap.len != short_req.required_reagents.len)
//there is at least one reagent in the short list that is not in the long list, so there is no conflict
return FALSE
//check to see if the shorter reaction's catalyst list is also a subset of the longer reaction's catalyst list
//if the longer reaction's catalyst list is a subset of the shorter ones, that is fine
//if the reaction lists are the same, the short reaction will have the shorter required_catalysts list, so it will register as a conflict
var/list/short_minus_long_catalysts = short_req.required_catalysts - long_req.required_catalysts
if(short_minus_long_catalysts.len)
//there is at least one unique catalyst for the short reaction, so there is no conflict
return FALSE
//if we got this far, the longer reaction will be impossible to create if the shorter one is earlier in GLOB.chemical_reactions_list, and will require the reagents to be added in a particular order otherwise
return TRUE