Game Development Community

Alchemy System - in theory

by Infinitum3D · in Torque Game Engine · 01/28/2007 (12:39 am) · 11 replies

I'm creating an alchemy system and I'd like your comments, thoughts, and opinions.

I plan on using Tim Newell's Inventory Popup Tutorial as a base.

www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=1842

I'd like for characters to be able to create potions usings herbal ingredients and alchemy equipment.

I have a Mortar_and_Pestle.dts

Since Tim's system has four spaces for items, I'll be using Aloe, Blackberry, Chamomile, and Dandelion. Alphabetical for simplicity.

I have aloe.dts, etc.

Should I create a new alchemy.cs or just add the new datablocks to the inventory.cs that I already have.

I'll also need alchemyGUI.cs to hold the GUI stuff.

I want characters to be able to combine items, like Aloe and Blackberry to "create Restore Health potion". Is there an easy way to script this?

Does anyone have a system already in play? Am I going about this right, or is there a better way?

Thanks for your help!

Tony

ps. Thanks Tim for a great tutorial!

#1
01/28/2007 (2:30 am)
I would probably make a alchemy.cc and add it to the source code for the engine, but a alchemy.cs would work too. Either way you want it to be seperate from inventory.cs. That way it will be easier to debug and modify later.

There are a lot of things you can do with an alchemy system. I have been toying with the idea of making one myself, but I have been busy working on a quests/objectives system.
The big thing would be to make it as generic as possible. And come up with a formula for figuring out what is made with the ingredients.

Ex:
Give the datablocks for the Aloe, Blackberry, Chamomile, and Dandelion a effect property.
Make the effect property be of them all be restore health (oblivion anyone!?! lol).
Then when they are combined use a generic formula that looks at the effect property of each alchemy item to create the potion.

You could do pretty much anything with it if you get creative enough.
#2
01/29/2007 (4:39 am)
If I were a programmer I could make alchemy.cc but I'm just learning Torque.

Quote:And come up with a formula for figuring out what is made with the ingredients.

Any tips on how this could by done? Does Torque support if - then functions? Or could someone point me to an example?

I have the datablocks written to make the herbs collectable, like inventory items. I just don't know how to code the mixing part.

Thanks.

Tony
#3
01/29/2007 (5:09 am)
Torque supports if - then, if-then-else-if-then ..., and a few other branching structures.

Ex: Checking two items and turning them into a health potion
Torque Script:
if (%item.effect $= %item2.effect){
   'Decrease amount in inventory of item and item2 
   //Add New Item
   if (%item.effect $= "Restore Health"){
        //Add Health Potion
        <insert code here to add item to inventory>        
   } 
}

This is a simplistic example, but I think it shows my point. You can easily expand upon this like so.

Torque Script:
if (%item.effect $= %item2.effect){
   'Decrease amount in inventory of item and item2 
   //Add New Item
   if (%item.effect $= "Restore Health"){
        //Add Health Potion
        <insert code here to add item to inventory>        
   }else{
      if{%item.effect $= "Fire Damage"){
         //Add Fire Potion
       <insert code here to add item to inventory>  
      }else{ 
         <cycle continues with if()>
      }
   }
}

Depending on how many items you want to make you might want to go with switch statements instead. To make it easier to read then nested ifs.

Also check THIS to get some more examples of other branching structures.
#4
01/30/2007 (4:57 am)
Thanks!

I was considering Arrays, but simce I'm not a very good programmer, I'd need help. In the past, using VisualBasic, I wrote a CaseSelect: function which is similar to an array.

ex. If Case0 then "X",
If Case1 then "Y",
If Case2 then "Z"

I'll keep looking into it. Any other advice?

Thanks.

Tony
#5
01/30/2007 (6:26 am)
EDIT: Rewrote the post.

Hi Tony,

When I saw you mention cases, I remembered that I had used them before my programmer friend created a more robust solution for our collision system. It has a pretty good depth of checking for results and options based on the input. There are actually more parameters passed by the engine's onCollision callback than I used, as I just didn't need them.

I think that the general structure of this approach could work for your alchemy solution at least temporarily. Depending on the depth of your system though, this could become a very messy bit of script.

So, my thinking would be that the function is called when the user presses a 'Combine' button and you could pass whatever you like. I.e. each herb and it's number, how many unique herbs, what type of mortar and pestle, the skill level, etc. I'm assuming that the inventory system you're building from allows you to check what's in it and pass that information along to this function.

Potentially, if you have the player specify what they're trying to make, the case could take that string and then step through a standardized evaluation of the attempt. In that instance, since each case in this function would follow a similar format and you would only need to modify the format to reflect things like required skill level, ingredients, and equipment which I would think might make it easier and faster to manage the system.

//-----------------------------------------------------------------------------
// Game Collisions.
//-----------------------------------------------------------------------------
function t2dSceneObject::onCollision( %srcObj, %dstObj, %srcRef, %dstRef, %time, %normal, %contactCount, %contacts )
{

    // Handle Source Object.
    switch$( %srcObj.tag )
    {
        // Player Hit something.
        case "player":
            // Enemy Fire?
            if ( %dstObj.tag $= "enemyfire" )
                {
                %dstObj.safeDelete();
                $playerCurrentHitPoints--;
                createSparkExplosion( %srcObj );
                createHealthDown1( %srcObj );
                // Any hit points left?
                if ($playerCurrentHitPoints <= 0)
                    {
                    // No, so kill player.
                    killPlayer();
                    
                    // Schedule new Player.
                    schedule( 3000, 0, "ResetPlayer");
                    }
                }
            
            else if ( %dstObj.tag $= "eTurretShip" )
                {
                $playerCurrentHitPoints--;
                createHealthDown1( %srcObj );
                // Any hit points left?
                    if ($playerCurrentHitPoints <= 0)
                    {
                    // No, so kill player.
                    killPlayer();
                    // Schedule new Player.
                    schedule( 3000, 0, "ResetPlayer");
                    }
                %dstObj.hitpoints--;
                createTurretShipDamage( %dstObj );
                createSparkExplosion( %srcObj );
                    if (%dstObj.hitpoints <= 0)
                    {
                        // Create Explosion.
                        create10ptsExplosion( %dstObj );
                        // Destroy Enemy Ship.          
                        %dstObj.safeDelete();
                        // Add Player Score.
                        addPlayerScore( 10 );
                    }
                }
				
        // Player Fire.
        case "laserfire":
			if ( %dstObj.tag $= "armor" )
                {
                    %srcObj.safeDelete();
                    createSparkExplosion( %srcObj );
                    %dstObj.safeDelete();
                }
        
        // Space station       
	case "eSpaceStation":
        	if ( %dstObj.tag $= "eTurretShip" ) // don't hurt the ships being launched
                return;
					
        // Enemy Fire.
        case "enemyfire":
            // Delete (unless hit by player fire).
            if ( %dstObj.tag $= "playerfire" || %dstObj.tag $= "seekermissile"  )
                return;
            if ( %dstObj.tag !$= "playerfire" )
            {
                %srcObj.safeDelete();
                // Create Explosion.
                createSparkExplosion( %srcObj );
            }
            if ( %dstObj.tag $= "smallerAsteroid" )
            {
                %srcObj.safeDelete();
                // Create Explosion.
                createAsteroidCrash( %dstObj );
                %dstObj.safeDelete();
            }
    }

}
#6
01/30/2007 (7:06 am)
Bumped due to massive edit of the previous post.
#7
02/02/2007 (2:42 pm)
Thanks Don. I've been reading up on switches since they apparently work the same way as CaseSelect in VB.

When I get time, I'll try to write some switch scripts for my Alchemy engine. I'm sure I'll need more help, so I'll be posting more questions soon.

Tony
#8
02/02/2007 (4:36 pm)
I'd be tempted to do the combinations with a more data-driven approach and not so much if-else action.

something like this:
$gCombinations["mortar", "aloe"       ] = "healing";
$gCombinations["mortar", "oregano"    ] = "groundHerbs";
$gCombinations["tomato", "groundHerbs"] = "pizzaSauce";
$gCombinations["tallow", "string"     ] = "candle";


function getCombination(%ingredientA, %ingredientB)
{
   %try = $gCombinations[%ingredientA, %ingredientB];
   if (%try !$= "")
      return %try;

   %try = $gCombinations[%ingredientB, %ingredientA];
   if (%try !$= "")
      return %try;
   
   return "";
}

edit - i prefer the data-driven approach for a few reasons. 1) it's easier to understand what's going on. 2) once you've got it working you'll make way fewer mistakes when making new combinations. 3) much, much less code. 4) it's possibly slightly faster 5) a total non-programmer can easily come along and modify the combination rules.

Quote:I was considering Arrays, but simce I'm not a very good programmer, I'd need help
if you're going to do any significant development in torqueScript, you'd probably be best off becoming familiar w/ arrays. I think "the game programmer's guide to torque" probably covers them.
#9
02/03/2007 (11:27 pm)
This is very good. But I've got to stop trying to script things at 2:27 a.m. (yawn)

Tony
#10
02/04/2007 (12:28 am)
Figured I'd share our "recipe" system.

I used to be a bit of a math geek and our system is based on a subset of numbers that solve Euclid's Algorithm (with an addition or two): 2, 3, 5, 11, 13, 17, 19, 23, 29, 33, 37, 41, 57, and 73.

Each number is assigned to one of our material components. The thing that is special about these numbers is that there are an extremely limited number of combinations where if you add them together it gives the same result. If it does give the same result, it is considered a different route of creating the same item: 13 + 11 + 17 = 41... so those 3 items would be the same as using one "41" item.

Example:
Component A = 17
Component B = 29
Component C = 3
Component D = 19

A + C = 20 = Health Potion
B + D + C = 51 = Stamina Potion
A + B + C = 49 = Extra Long Jump Potion

A system such as this allows for expansion of both material components and effects in a very simple manner.
#11
02/05/2007 (9:30 am)
Huh, interesting, bryce!