I need help with setting up an array...

Post » Fri Jan 22, 2010 4:46 am

I love playing with eat/sleep mods because of the day/night cycle they enforce upon the game, and how through their penalty systems you can really feel like you're pushing yourself if you are in the depths of a dungeon with 30 hours of no sleep and 18 hours since your last meal. What I hate about having to eat is the pathetic selection of foodstuffs. I mean, you can only eat so many heads of lettuce and wheels of cheese before you wonder to yourself, "Self, why can't you cook some of that rat meat you've been lugging around for weeks?" Some mods let you "cook", but they're menu-driven and because of that they're limited in scope. Witness Coleen's Oblivion Farmer's Market: you can roast venison, or boar, but not crab of rat. Not to mention it knows nothing about ingredients from other mods.

So I'm working on a food crafting engine that will be have an open-ended raw-ingredient-to-finished-product system. Inspired by the Cobl dinner plate system, I plan to have a set of levelled lists which contain the "raw ingredients" that one can cook with: raw meats, veggies, grains, etc. Using this system I can have a mod that's filtered into the bashed patch (similar to Cobl Filter Late MERGE ONLY.esp or the Item Interchange system) that allows me (or anyone else) to add items from other mods to these lists for players to cook with, and only the mods the player has loaded will matter. Using the raw ingredients from any number of mods is easy this way. I haven't yet figured out how to/if I can let the player make items from other mods (ie, how to craft rat-on-a-stick from Better Cities.esm). This part may not be possible...

I will allow up to 4 ingredients per cooking recipe (for simplicity more than anything), and I'm building the system to allow "specific" and "generic" ingredients. For example, to make "roast venison" you'd need to use venison as the specific (and only) ingredient. To make fruit salad, you could use any three fruits as generic ingredients. To make a fruit pie, you'd need flour (specifically) and any fruit (generically). When the player's selected their raw ingredients, the script will check the ingredients against its known recipes and ask, for example, "Are you trying to make broiled crab meat?" If it doesn't find a matching recipe it'll ask the user to name the product (or cancel, of course). I'll also have different cooking tools (ie, frying pan, pie plate, soup pot) so you could get different results using the same ingredients with a different cooking method - baked potato on the baking sheet, mashed potatoes in the pot.

I'm ruminating on a system to let the user name the cooked product, determine what type of food it is (for the Cobl food lists), and choose an icon/model for the product. It'll probably be OBSE text entry, messagebox, and a container full of icons to choose from, respectively. Oh, another thing is that I'm hoping to be able to store recipes using the names of the raw ingredients (as opposed to thier formIDs) so that if you have multiple mods that add "wolf meat" you can use anything named "wolf meat" to make your wolfburgers.

I figure the only way to create "new food" on the fly is to have a default ebible ingredient object and clone it, assigning a new name, icon/model, ingredient effects, weight, etc.

So far so good. I've got my lists, a test merge mod pulling items from alive waters and MMM, and I'm able to let the player select things to cook and determine what they've selected and whether each is specific or generic.

Now what I'm having trouble with is figuring out how to set up an array to keep track of it all. What I imagine I'll need is something like:
  • product number (is this needed in an array? can I just iterate through the whole array and search by one of the keys?)
  • name of the product/recipe (string)
  • name of each of the 1 to 4 ingredients used, and if each is specific or generic (string? sub array? this is where I'm confoosed! This is how I'd like to match player-selected ingredients to known recipes... is this possible?)
  • food type (numeric? probably easiest, since it'll need to be parsed to load into the cobl lists http://obse.silverlock.org/obse_command_doc.html#Leveled_List)

The other pertinent stuff will be part of the cloned item (weight, ingredient effects, appearance, price, etc).

What I'm hoping is that someone can take me by the hand and help me understand arrays and how best to make use of them for this project. Examples are good! :)

Thanks!
User avatar
sarah simon-rogaume
 
Posts: 3383
Joined: Thu Mar 15, 2007 4:41 am

Post » Thu Jan 21, 2010 2:52 pm

I've had very good results using what I call "array-objects", meaning creating an array model to represent each and every 'object' I handle in the mod. This concept helps A LOT while coding.

In your case, at first glance, I see two "objects": ingredients and recipes
Obs: I like using stringmaps (for code readability), although I guess arrays would be more efficient.

You would need 4 arrays:
array_var asIngredientarray_var asRecipearray_var asIngredients  ;  a list of all ingredientsarray_var asRecipes    ;  a list of all recipeslet asIngredients := ar_construct stringmaplet asRecipes := ar_construct stringmap


An Ingredient array might be like this:
;=== Initialization ===let asIngredient := ar_construct stringmaplet asIngredient["Name"]:= "Apple"let asIngredient["refObje"]:= applelet asIngredient ["] :=  some other attribute you may need along the way;=== Add to the list ===let asIngredients["Apple"] := asIngredient


A recipe array might be like this:
;=== Initialization ===let asRecipe := ar_construct stringmaplet asRecipe["sName"]:= "Apple Pie"let asRecipe["refFood"]:= MyApplePieClonedFormlet asRecipe["arIngredients"]:= ar_construct arraylet asRecipe["arIngredients"][0] := asIngredients["Apple"]let asRecipe["arIngredients"][1] := asIngredients["Flour"];=== Add to the list ===let asRecipes["Apple Pie"] := asRecipe

User avatar
Chris Johnston
 
Posts: 3392
Joined: Fri Jul 07, 2006 12:40 pm

Post » Fri Jan 22, 2010 2:37 am

I've had very good results using what I call "array-objects", meaning creating an array model to represent each and every 'object' I handle in the mod. This concept helps A LOT while coding.

In your case, at first glance, I see two "objects": ingredients and recipes
Obs: I like using stringmaps (for code readability), although I guess arrays would be more efficient.

A recipe array might be like this:
;=== Initialization ===let asRecipe := ar_construct stringmaplet asRecipe["sName"]:= "Apple Pie"let asRecipe["refFood"]:= MyApplePieClonedFormlet asRecipe["arIngredients"]:= ar_construct arraylet asRecipe["arIngredients"][0] := asIngredients["Apple"]let asRecipe["arIngredients"][1] := asIngredients["Flour"];=== Add to the list ===let asRecipes["Apple Pie"] := asRecipe



Thanks, that's pretty helpful, and actually makes sense. :)

But I still have more questions... How would I go about walking through the asRecipies array sequentially? Would that be the ar_First and ar_Next commands? How do I pull all the relevant data out of the array when I want it? Would it be something like
let asTemp := asRecipies[$MyStringVar]let sTempName := asTemp["sName"]let refTempFood := asTemp["refFood"]etc...


I guess the biggest problem I have with arrays is getting the syntax down pat...
User avatar
A Lo RIkIton'ton
 
Posts: 3404
Joined: Tue Aug 21, 2007 7:22 pm

Post » Thu Jan 21, 2010 3:31 pm

The best method to walk arrays is the ForEach + Loop functions.

Supposing you have an array of ingredient names and want to find the recipe, you could write a User Function to do it.

Something like:

scn zzRecipeFromIngredientsarray_var arIngredientsarray_var asRecipearray_var asEntryBegin Function {arIngredients} ;= Supposing:;=== The Recipe list asRecipes is defined in the quest MyQuest;=== The Ingredient list asIngredients is in the quest MyQuest ;=== arIngredients = a list of the (up to) 4 available ingredients. ;===       Each entry pointing to an ingredient in the MyQuest.asIngredients	SetFunctionValue 0 	foreach asEntry <- MyQuest.asRecipes		let asRecipe := asEntry[value]			;=== Check if the available ingredients match the recipe's required ingredients === 		if eval call zzMatchArrays arIngredients  asRecipe["arIngredients"] 			SetFunctionValue asRecipe 			break		endif	loopend


The zzMatchArrays function could be something like this:
scn zzMatchArrays array_var ar1array_var ar2array_var asEntry1array_var asEntry2short iMatchCountBegin Function {ar1 ar2} 	SetFunctionValue 0 	;=== Supposing no duplicated entries in the arrays === 	foreach asEntry1 <- ar1 		foreach asEntry2 <- ar2			if eval asEntry1[value] == asEntry2[value]				let 	iMatchCount += 1				break			endif		loop	loop	if iMatchCount == ar_size ar2		SetFunctionValue 1	endifend


This array matching thing may be too heavy on CPU if the lists are big. If this is the case, you may need some additional, auxiliary arrays to speed up the process, but this should be a concern later down the road.
User avatar
James Wilson
 
Posts: 3457
Joined: Mon Nov 12, 2007 12:51 pm

Post » Fri Jan 22, 2010 12:50 am

Late with the reply, but thanks again for your help. I think I have arrays sorted out in my head now and my mod's proceeding nicely.

I also stumbled upon your http://cs.elderscrolls.com/constwiki/index.php/ArrayDeepDump - very nice! :bowdown:
User avatar
+++CAZZY
 
Posts: 3403
Joined: Wed Sep 13, 2006 1:04 pm


Return to IV - Oblivion