mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-09 16:14:13 +00:00
184 lines
7.3 KiB
Plaintext
184 lines
7.3 KiB
Plaintext
/* * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* /datum/recipe by rastaf0 13 apr 2011 *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* This is powerful and flexible recipe system.
|
|
* It exists not only for food.
|
|
* supports both reagents and objects as prerequisites.
|
|
* In order to use this system you have to define a deriative from /datum/recipe
|
|
* * reagents are reagents. Acid, milc, booze, etc.
|
|
* * items are objects. Fruits, tools, circuit boards.
|
|
* * result is type to create as new object
|
|
* * time is optional parameter, you shall use in in your machine,
|
|
default /datum/recipe/ procs does not rely on this parameter.
|
|
*
|
|
* Functions you need:
|
|
* /datum/recipe/proc/make(var/obj/container as obj)
|
|
* Creates result inside container,
|
|
* deletes prerequisite reagents,
|
|
* transfers reagents from prerequisite objects,
|
|
* deletes all prerequisite objects (even not needed for recipe at the moment).
|
|
*
|
|
* /proc/select_recipe(list/datum/recipe/avaiable_recipes, obj/obj as obj, exact = 1)
|
|
* Wonderful function that select suitable recipe for you.
|
|
* obj is a machine (or magik hat) with prerequisites,
|
|
* exact = 0 forces algorithm to ignore superfluous stuff.
|
|
*
|
|
* Functions you do not need to call directly but could:
|
|
* /datum/recipe/proc/check_reagents(var/datum/reagents/avail_reagents)
|
|
* //1 = precisely, 0 = insufficiently, -1 = superfluous
|
|
*
|
|
* /datum/recipe/proc/check_items(var/obj/container as obj)
|
|
* //1 = precisely, 0=insufficiently, -1 = superfluous
|
|
*
|
|
* */
|
|
/datum/recipe
|
|
|
|
var/list/reagents //List of reagents needed and their amount, reagents = list(BERRYJUICE = 5)
|
|
var/list/reagents_forbidden //List of reagents that will not be transfered to the cooked item if found. reagents_forbidden = list(TOXIN, WATER)
|
|
var/list/items //List of items needed, items = list(/obj/item/tool/crowbar, /obj/item/weapon/welder)
|
|
var/result //Result of a complete recipe. result = /obj/item/weapon/reagent_containers/food/snacks/donut/normal
|
|
var/time = 10 SECONDS //Length of time it takes to complete the recipe. In 10ths of a second
|
|
|
|
/*
|
|
check_reagents function
|
|
Looks for reagents in the reagent container passed to it, and if this matches what we require.
|
|
|
|
args:
|
|
/datum/reagents: avail_reagents: The reagent container we are checking
|
|
|
|
return:
|
|
0/FALSE: Unable to find all reagents we require
|
|
1/TRUE: Able to find enough reagents to satisfy requirements
|
|
-1: Found what we require, but there is more reagents than just what we need
|
|
*/
|
|
/datum/recipe/proc/check_reagents(var/datum/reagents/avail_reagents)
|
|
. = 1
|
|
for(var/r_r in reagents)
|
|
if(islist(r_r)) //The reagents required is a list, so could be satisfied by one or another reagent (SACIDS can be satisfied by sulphuric acid, or formic acid)
|
|
var/list/L = r_r
|
|
var/found = FALSE
|
|
for(var/I in L)
|
|
var/reagent_amount = avail_reagents.get_reagent_amount(I)
|
|
if(abs(reagent_amount - reagents[r_r])<0.1)
|
|
found = TRUE
|
|
if(reagent_amount > reagents[r_r])
|
|
. = -1
|
|
break
|
|
if(!found)
|
|
return 0
|
|
else
|
|
var/reagent_amount = avail_reagents.get_reagent_amount(r_r)
|
|
if(abs(reagent_amount - reagents[r_r])<0.1)
|
|
if(reagent_amount > reagents[r_r])
|
|
. = -1
|
|
else
|
|
return 0
|
|
|
|
if((reagents ? reagents.len : 0) < avail_reagents.reagent_list.len)
|
|
return -1
|
|
return .
|
|
|
|
/*
|
|
check_items function
|
|
Checks if the container passed, contains the objects required to satisfy the recipes requirements.
|
|
args:
|
|
obj: container: What container we will be checking.
|
|
|
|
return:
|
|
1/TRUE: Able to find enough objects to satisfy requirements
|
|
0/FALSE: Unable to find enough objects to satisfy requirements
|
|
-1: Found enough objects to satisfy requirements, and more.
|
|
|
|
*/
|
|
/datum/recipe/proc/check_items(var/obj/container as obj)
|
|
if(!items) //If there's no items in our recipe
|
|
if(locate(/obj/) in container) //but we find something, at the least.
|
|
return -1
|
|
else
|
|
return 1 //Technically, we've satisfied the requirements, as the requirements are null
|
|
. = 1
|
|
var/list/checklist = items.Copy()
|
|
for(var/obj/O in container) //Let's loop through all the objects in our recipe machine
|
|
var/found = 0 //If what we found is part of the recipe
|
|
for(var/type in checklist)
|
|
if(istype(O, type)) //Is that what we are looking for
|
|
checklist -= type //Good, strike it out of our checklist
|
|
found = TRUE
|
|
break //Break that loop, continue downwards
|
|
if(!found) //We found something that's not part of our recipe
|
|
. = -1
|
|
if(checklist.len) //Are there still items on our recipe checklist ?
|
|
return 0 //Something is missing, abort
|
|
return .
|
|
|
|
/*
|
|
make_food function
|
|
Final function in the chain of successes. This makes the resulting object, and handles transferring reagents from its assumed component parts to the product.
|
|
args:
|
|
obj:container: What the object is being made within (Microwave, oven, etc.)
|
|
|
|
return:
|
|
obj: Resulting object.
|
|
*/
|
|
/datum/recipe/proc/make_food(var/obj/container)
|
|
var/obj/result_obj = new result(container)
|
|
for(var/obj/O in (container.contents - result_obj))
|
|
if(O.reagents)
|
|
//Should we have forbidden reagents, purge them first.
|
|
for(var/r_r in reagents_forbidden)
|
|
if(islist(r_r))
|
|
var/list/L = r_r
|
|
for(var/I in L)
|
|
O.reagents.del_reagent(I)
|
|
O.reagents.del_reagent(r_r)
|
|
//Transfer any reagents found in the object, to the resulting object
|
|
O.reagents.trans_to(result_obj, O.reagents.total_volume)
|
|
qdel(O)
|
|
container.reagents.clear_reagents() //Clear all the reagents we haven't transfered, for instance if we need to cook in water
|
|
score["meals"]++
|
|
return result_obj
|
|
|
|
|
|
/*
|
|
Select_recipe function
|
|
Loop through all recipes that we are passed, return the ones we can work with
|
|
Args:
|
|
available recipes: Potential recipes we will check against
|
|
recipe_source: The object to check for the reagents and items within (A microwave, oven, etc.)
|
|
exact: Should what we find in the obj be exactly what we're looking for (TRUE) or not (FALSE)
|
|
|
|
return:
|
|
Recipe that works with what we have.
|
|
*/
|
|
/proc/select_recipe(var/list/datum/recipe/available_recipes, var/obj/recipe_source, var/exact = TRUE)
|
|
if(!exact)
|
|
exact = -1 //Change it to -1 for simplicity, too much or not enough is the same problem now
|
|
var/list/possible_recipes = list()
|
|
|
|
for(var/datum/recipe/recipe in available_recipes)
|
|
if(recipe.check_reagents(recipe_source.reagents) == exact && recipe.check_items(recipe_source) == exact)
|
|
possible_recipes += recipe
|
|
//If there is no possible recipes, return a fail
|
|
if(possible_recipes.len == 0)
|
|
return null
|
|
//If only one possible recipe, return only it
|
|
else if(possible_recipes.len == 1)
|
|
return possible_recipes[1]
|
|
//Else, we return the best fitting recipe.
|
|
else
|
|
var/reagents_count = 0
|
|
var/items_count = 0
|
|
. = possible_recipes[1] //We'll estimate the first recipe we found is the correct one until we start looping, to avoid returning nothing
|
|
|
|
//Loop through all those recipes we found to be matching, return the last one that we find to be usable.
|
|
for(var/datum/recipe/recipe in possible_recipes)
|
|
var/items_number = (recipe.items) ? (recipe.items.len) : 0
|
|
var/reagents_number = (recipe.reagents) ? (recipe.reagents.len) : 0
|
|
|
|
//If there's more items or as much items and more reagents than the previous recipe
|
|
if(items_number > items_count || (items_number == items_count && reagents_number > reagents_count))
|
|
reagents_count = reagents_number
|
|
items_count = items_number
|
|
. = recipe
|
|
return .
|