Author Topic: Crafting with Cauldrons and Forges etc  (Read 894 times)

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
Crafting with Cauldrons and Forges etc
« on: June 20, 2012, 01:50:02 pm »


               Im planning on adding a Crafting system into my PW - To compliment the Gathering / Mining system that I already have.


I just wanted to run down some of the principles I was gonna impliment, if something similar exists already, by all means, let me know.



1.  Player is able to summon a Cauldron or Forge table to them via use of magic
2. The Cauldron or Forge has an inventory.
3. The Cauldron / Forge will have an onDisturbed event, that should fire each time an item is added or taken away.
4. Each Recipie will be a combination of up to 10 reagents.
5. When a new creation is being made, it starts a counter at 1.
6. When the first item is added, it does a select query from the database, to find out if there are any recipies that begin with that item. (eg  - select where reagent_1 = resref/tag
7. When a successful select is done, this locks the system onto that recipie, and means it will be expecting the next re-agents in the proper order, to be the ones that match that recipie.
8. Any reagent not part of the recipie will break the chain.
9. When the final reagent/step has been fulfilled, script X fires or Item ResRef Y is created on the cauldron or forge.

This is to be data-driven.
Allowing a script to be fired, or for a specified item to be generated.
Reagents are consumed afterwards.



Example

1. Summon the Cauldron
2. Put in some rose petals. - No Effect  (No Recipies start with Rose Petals)
3. Put in some Virgins Blood - Shiny visual indicates successful step, increments the counter +1, to select step 2 in the database.
4. Put in some rose petals - Another shiney effect indicates that second step succeeded.
5. Put in a Large Bone - Poof!!   Recipie complete
                              Either creates an item, or Executes a Script (if one specified)
6. Consume all reagents in the cauldron.


Im torn between the methodology above
or
Put all the items into the cauldron at once,
Then trigger it somehow to get each item, and then somehow find the row in the database that contains all of those items as reagents.

Im not sure how to do the second approach.
eg
For instance,
If the database structure is

ID /   RECIPIE_ID /  RECIPIE_NAME / REAGENT_1 / REAGENT_2 / REAGENT_3  etc


Im thinking I would need to do a

Select ID from Recipies where REAGENT_1 = 'reagent1s-tag'  or REAGENT_1 = 'reagent2s-tag'  or REAGENT_1 = 'reagent3s-tag'
 
Then I could loop through each potential match, and verify if that row contains all the provided reagents.

Im just wondering if anyone has a more efficient way of doing the second approach.

Note - I would much rather use a Crafting system I developed myself.
As I find them easier to maintain than backwards engineering someone elses.



Any assistance with the Select queries etc would be greatful.

My main requirement is

1. Have multiple items in the container
2. Select the appropriate row in the database that contains all of those items.

The main problem is, coping with ordering of items etc,
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Crafting with Cauldrons and Forges etc
« Reply #1 on: June 24, 2012, 10:40:42 pm »


               Questions: 

How many  different regents are there in the game?

How long can a DB identifier name be in the NWNx DB?



Based on the Idea of adding one item to the crafting placeable at a time,  Using the OnDistrubed event.

You could give each one of your regents a either a one or two letter code and build the identifier from what has already been added to the DB.   Looking the identifier up in the DB  would give the information on how to proceed from that point.   

since I do not know much about the nwnx DB.  Here is the Idea using the standard DB and 2 digit ID codes for the regents.    


With the example you gave (Virgins Blood, rose petals, Large Bone    ) above the DB would have three entries for the recipe all of them strings. 

BV = "continue"   // DB entry for new add of Virgins Blood
BVPR = "continus" // Entry for Virgins Blood with new add of rose petals,  
BVPRbL = " (Create | RunScript)  ResRef "

simplest way for me to explain it is with halh worked out code.  Here it is:

 
string GetRegentID(string sTag)
 {
    // Many options on how to get the ID.
    // Anything from look up in DB,
    // having them pre loaded into locals on the placable,
    // having them encoded onto the regent in one fasion or another,
    // To just a big long If.. else if.. statment.
    //
    //
    // if the if.. else if.. statment is used, I would also cache the items used
    // onto the item used so that the code only has to be found via if statment one time.
    // Example here is the with the If.. else if.. Methoid with cashing.

    string sRegentCode = GetLocalString( OBJECT_SELF,"RID"+sTag);

    // regent code not yet looked up.
    if  ( sRegentCode == "")
    {
        // Default for this item not being a regent.
        sRegentCode= "None";


        // b = bone
        //     L= Large
        //     M = Medium
        //     S = Small
        // B = blood
        //     V = Virgins
        //     D = Dragons
        // P = petals
        //     R = Rose

        if (sTag=="Virgins_Blood")     sRegentCode = "BV";
        else if (sTag=="Dragons_Blood")sRegentCode = "BD";
        else if (sTag=="Large_Bone") sRegentCode = "bL";
        else if (sTag=="Medium_Bone") sRegentCode = "bM";
        else if (sTag=="Small_Bone") sRegentCode = "bS";
        else if (sTag=="rose_petals") sRegentCode = "PR";

       // Set the code on the placeable so it does not have to be looked u again.
       SetLocalString( OBJECT_SELF,"RID"+sTag,sRegentCode );
    }
     return sRegentCode;
 }


string GetMixtureAction( string sMixture)
{
  // once again cache already looked up mixtures on the caldron.
  string sMixAction = GetLocalString(OBJECT_SELF,"Mix_"+sMixture);
  if (sMixAction== "")
  {
     sMixAction = GetCampaignString("rescipes",sMixture);
     if (sMixAction== "") sMixAction = "Action Invalid";
     SetLocalString(OBJECT_SELF,"Mix_"+sMixture,sMixAction);
  }
  return sMixAction;
}


void main()
{
  object oRegent = GetInventoryDisturbItem();
  int nEvent = GetInventoryDisturbType();

  switch ( nEvent )
  {
    case INVENTORY_DISTURB_TYPE_REMOVED:
     // code to break the crafting process.
     // until all items are removed.
     // Or however you want to handle it.
    break;

    case INVENTORY_DISTURB_TYPE_ADDED:
    {
       // get stored string from privous additions.
      string sCurrentMix = GetLocalString(OBJECT_SELF,"CurrentMix");

      // Get the regent Id
      string sRegentID =  GetRegentID( GetTag(oRegent));
      // Check to see if it is valid.
      if (sRegentID == "None")
      {
         // code to abort the process
         return;
      }

      // Add the ID to you current Mix and store it.
      sCurrentMix += sRegentID;
      SetLocalString(OBJECT_SELF,"CurrentMix",sCurrentMix);


      // get the action for current mix.
     string sMixAction = GetMixtureAction(sCurrentMix);

     // Handle the action.
     // you may want to make a function for this as it gets more complex.
 
    if (sMixAction ==  "Action Invalid")
     {
        // Run Abort code
     }
     else if (sMixAction == "continue")
     {
        // code to play default correct componet add effect.
     }
     else if ( TestStringAgainstPattern("**Create**",sMixAction ))
     {
       // Code to speerate out resref of item to create.
       // destroy items and reset vars.
     }
     else if ( TestStringAgainstPattern("**RunScript**",sMixAction))
     {
        // Code to seperate out resref of script and clear vars.
     }
     else if ( TestStringAgainstPattern("**effect**",sMixAction))
     {
       // Code to parse for spescial effect to play at this point.
     }
    }
    break;
  }
 
}   


               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
Crafting with Cauldrons and Forges etc
« Reply #2 on: June 24, 2012, 11:41:48 pm »


               

How many different regents are there in the game?

How long can a DB identifier name be in the NWNx DB?


Im treating any item in game, as a potential reagent. The recipie list is on-going.
For time being, I am using the ID Column in  the mysql database, as the recipie id, and the way of selecting it, is based on the tag of the first recipie reagent added to the cauldron.

(When recipies, spells, or rituals are added, they go into my online spell book - here
http://nwn.azmodan.net/magic/
)


I guess I kinda opted for a more complex solution for my system.

I have made it possible for players to summon cauldrons to themselves - via the verbal ritual system I made.

They basically speak the phrase
'Gond, Lord of Crafting'
'Mystra, Diety of Magic'
'Bless me'
'As I work'

then some nice visuals, and a cauldron appears.
(A Red Circle 5ft in radius appears around the cauldron - if the player steps out of it, the cauldron vanishes)

Using the onDisturbed event of the cauldron, I have done the following.

Split the disturbed event into 3

1. Items Added
2. Items Removed
3. Items Stolen

When an Item is added- it checks to see if it is currently working on a recipie already.
If not - it then scans the database via sql query, for any recipie that begins with the reagent that was just entered - it queries on the tag of the item
(since tags are things that are now changeable via nwnx - its a fair enough way to do things, since I can make rituals to do special things to the tags - to transform items into other items that can be used in other recipies etc)
If it finds a recipie that begins with that reagent, it locks the cauldron into that recipie.

Subsequent reagents added, will increment the 'step' variable, which will tell the cauldron to query the 'step2' reagent for that recipie - if it matches the reagent that was entered = Good - nice visual, and progresses the step variable again.

When the Step variable is equal to the amount of populated steps/reagents required for the recipie, it considers the recipie complete.

I also have it set up in such a way that I can specify whether an item is to be created in the cauldron, as the product of the recipie, or whether a specific script should run.

Which allows me to make recipies that do fantastical effects, and not just create items.

On Removed/On Steal side of disturbed event, causes the recipie to reset, and tells the player to start from scratch.

The only downside to my system, is that only one recipie, can have a specific reagent as its step 1.
eg

If I had 2 recipies

One required Virgins Blood + Fairy Dust = Level Up or something
One requires Virgins Blood + Dragon Blood = Invulnerability for 2 minutes

I would need to be creative with how I put them in the database.
eg- Virgins Blood + Fairy Dust
Dragon Blood + Virgins Blood

or - If I wanted, I could make the product of one of the recipies, be a reagent in the second recipie.

Its a complex system sure, but I can live with it.
Recipies are added basically via phpmyadmin (mysql database)
Good combo with resman - never need to reboot.
               
               

               


                     Modifié par Baaleos, 24 juin 2012 - 10:51 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Crafting with Cauldrons and Forges etc
« Reply #3 on: June 25, 2012, 12:22:47 am »


               Yea, The system I posted has some of the same draw backs. First componets can be the same, but you would not be able to have one recipe be a part of another.

eg. If DragonsBlood, fairyDust and rosePetal created something. you could not use DragonsBlood, fairyDust, rosePetal and largeBone to crea tsomething else in that order  since the other craft would be created/executed as soon as the rose petal was added. again the same componets could be used if the order of the first three was changed.

I was not really looking for you to use the system I gave above. i just gave it so you could derive Ideas from it.

The only benifit I see above what you already have is the ability to use the same starting componet and the ability to change effects in the middle of the craft also. The step the craft is in, would be determined by the length of the Current Mix Id given. So there is really no need for a step number. It would also allow for you to have mutations of the crafting objects if that was your goal. Since every time a componet is added it checks for an action to take from the DB, It is  open ended for you, to set it up to do anything you want on any given step.

The caching of the items on the object was also keeping in mind that it was a summonsed caldron. I dout I would want to do the same with a caldron that could sit in the game for days. The caching is just there to speed up the case when a PC is making the same Item Over and over again.

Note: To add Recipies to my system you would also want to write a system to add then to the DB. It would be a pain to enter each recipie step one at a time.

I tried to keep everything you stated in your original post in mind. If you like it use it, If not disreguard.
               
               

               


                     Modifié par Lightfoot8, 24 juin 2012 - 11:26 .
                     
                  


            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
Crafting with Cauldrons and Forges etc
« Reply #4 on: June 25, 2012, 12:48:31 am »


               yeah - I already do a little bit of cache-ing

When recipie data is retrieved, it checks for the info on the module to begin with, if it returns nothing, then it requests it from the database, and then stores as a local int/string on the module.
Just to eliminate subsequent requests for the same information, although - the mysql query is still required for the actual reagent/recipie selection.
Its just details such as the script/product and amount of steps that gets cached.