Author Topic: An NPC or placeable to exchange one type of item for another.  (Read 964 times)

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
An NPC or placeable to exchange one type of item for another.
« Reply #15 on: September 02, 2011, 06:34:19 am »


               Yep indeed. I am testing this right now. First thing I am noticing is if you don't have two of the first type of shard it wont let you proceed to any of the higher level shard's dialog options for exchange. Not sure if that is what you were getting at Lighfoot8 but that's the first problem I am encountering. I am also not sure if it is a problem with the script or my convo setup, but that's where I am at with it.

Edit: It does indeed work if you have 2 of the first shard types, however it only is working for that first shard type. Even if I have 2 of the first and 2 of the second it only give me the option to exchange the 1st shard types. Again I am not sure if this is due to the script or my conversation set up, I will keep testing.
               
               

               


                     Modifié par Lazarus Magni, 02 septembre 2011 - 05:37 .
                     
                  


            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
An NPC or placeable to exchange one type of item for another.
« Reply #16 on: September 02, 2011, 06:54:31 am »


               Edit 2:
Well I changed the conversation format, and it seems to work for all shard types now, however for some reason there seems to be some strange anomolies. Sometimes when it exchanges any of the 5 higher shard types, it doesn't actually destroy the original 2 lower ones (it does do this however for the lowest 2 shard types), but only destroys one of them. Other times even if I have 2 of the higher shard types, if I don't have at least 2 of the lowest I can't exchange (in it's semi-functional sense.)
               
               

               


                     Modifié par Lazarus Magni, 02 septembre 2011 - 05:55 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
An NPC or placeable to exchange one type of item for another.
« Reply #17 on: September 02, 2011, 07:02:44 am »


               yep that was one of the errors.    look at your DestroyNumItems function.  what happen if  nStackSize < nToDestroy but not equal to 1
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
An NPC or placeable to exchange one type of item for another.
« Reply #18 on: September 02, 2011, 07:19:20 am »


               Ok, scratch the bulk of my previous edits, it turns out I had the wrong tag/resrefs for at least one of the scripts. So long story short this does seem to work, but you're correct Light, for some reason it is only destroying 1 shard (not 2) for any of the exchangable shard types. I am not sure how to fix this, and if you have noticed any other errors I have not in testing I would welcome the input.
               
               

               


                     Modifié par Lazarus Magni, 02 septembre 2011 - 07:20 .
                     
                  


            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
An NPC or placeable to exchange one type of item for another.
« Reply #19 on: September 02, 2011, 08:38:03 am »


               Ok... LMAo, I duno what is up? But when I tested locally the above was happening. Now that I am testing live on the mod it seems to be a-ok. So yeah... iduno, but it's beautifull, and thank you both. If you all see some more refinement that it needs I welcome it, but yeah, this is a good first (if not final) step. Thank you so much!
               
               

               
            

Legacy__Guile

  • Hero Member
  • *****
  • Posts: 1308
  • Karma: +0/-0
An NPC or placeable to exchange one type of item for another.
« Reply #20 on: September 03, 2011, 02:20:58 am »


               I have a question for you Lightfoot8...

Is declaring the Prototypes before defining them in an Include really necessary or does it provided a benefit to do so?
(Just curious, as this is a more advanced subject I never really asked about.)
               
               

               


                     Modifié par _Guile, 03 septembre 2011 - 01:25 .
                     
                  


            

Legacy__Guile

  • Hero Member
  • *****
  • Posts: 1308
  • Karma: +0/-0
An NPC or placeable to exchange one type of item for another.
« Reply #21 on: September 03, 2011, 02:21:59 am »


               I believe I found the errors he was referring to, I believe they were in the include script

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//  item_conv_inc

//  This is an include script, it's saved under the name (item_conv_inc)
//  This script has 2 Custom Fucntions which...
//  a) Return How many of a particular item the PC Has (GetItemCount)
//  'B)' Destroys X of a given item by tagname, (can reduce Item StackSize)

//////////////////////////////////////////////////////////////////////////////
//Declare All Prototypes
int GetIemCount(object oPC, string sTag);
void DestroyNumItems(object oTarget, string sTag, int nToDestroy);

////////////////////////////////////////////////////////////////////////////
//Prototypes Defined

//Define Prototype
int GetIemCount(object oPC, string sTag)
{
  int i = 0;
  string sIT;
  int nStackSize;

  object oItem = GetFirstItemInInventory(oPC);
    //Continue till there are 0 left to destroy...
    while (GetIsObjectValid(oItem))
    {

      sIT = GetTag(oItem);

      if (sIT == sTag)
      {
        nStackSize = GetItemStackSize(oItem);

        i += nStackSize;
      }

        oItem = GetNextItemInInventory(oPC);
    }

  //Tell the script how many "shards" they have (included all stacked count)
  return i;
}

//Define Prototype
void DestroyNumItems(object oTarget, string sTag, int nToDestroy)
{
    float fDelay;
    int nStackSize;
    int nAdj;
    string sIT; // Item Tagname
    object oItem = GetFirstItemInInventory(oTarget);
    //Continue till there are 0 left to destroy...
    while (GetIsObjectValid(oItem) && nToDestroy >= 1)
    {

            sIT = GetTag(oItem);
            nStackSize = GetItemStackSize(oItem);

            //If they have 2 Shards & This is indeed a Shard (item)
            if (sIT == sTag) //Obviously they have at least 1 stack size
            {
                fDelay += 0.03;
                if(nStackSize >= nToDestroy)
                {
                 nAdj = nStackSize - nToDestroy;
                 SetItemStackSize(oItem, nAdj);
                 nToDestroy = 0; //(no more needed now!)
                 //Stop here!
                 break;
                }

                //Otherwise if the stack size is only 1, kill this item
                // also decrement the # we are to destroy by 1
                else if(nStackSize == 1)
                {
                 DestroyObject(oItem, fDelay);
                 nToDestroy -= 1; // Decrement the total
                }
                //There is no else
            }

        oItem = GetNextItemInInventory(oTarget);
    }
}
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
An NPC or placeable to exchange one type of item for another.
« Reply #22 on: September 03, 2011, 04:50:17 am »


               first script.
  Looks good. but you can safly remove the include for nw_io_plot it is just not used or needed.

second script.

Line:  #include nw_I0_plot. 
this is only used for a wrapper around a standerd function.  I would just get ride of the include and use the standard function.  The function being TakeGold. Not an error just a prefferance.  

Line:  object oItem = GetItemPossessedBy(oPC, sItemTagName);
oItem is not used anywhere in the script just get ride of this line.

Line:    object oTarget = oPC;
oTarget is only used in one place in the script.  It would be better to just use oPC the creating a whole new var for oTarget.  however since the only place it is used is in an assigncommand, for a function that does not need to be assigned,  just get rid of the line and the assignedcammand lower down in the script..

Line;  DestroyNumItems(oPC, sItemTagName, nRequired);
This function is flawed. leave it as is. the function will need to be fixed in the include however.(script3)

Line: AssignCommand(oTarget, TakeGold(nGoldRequired, oPC, TRUE));
This is where the unneeded assignedcommand and wrapper function are, changing the line to :
TakeGoldFromCreature(nGoldRequired, oPC, TRUE);
allows us to get rid of the two lines mentioned above.

Line: DelayCommand(0.5,ExportSingleCharacter(oPC));
Now this is an interresting one.  First I do not see anyreason to export the character without also updating the DB if you are also storing shard information in the DB.   Doing so just risks getting the DB and character out os sink in the event of a server crash.   but that is not the real problem here.   This export of the PC at a 0.5 delay risks saving the character in a state out of sink with itsself.    The DestroyNumItems function above destroys stacks of items at an incremental delay of 0.3 seconds.  So if it ever destroys more then one stack on the PC, they will be saved at a time when there inventory is out of sink.  I would suggest just removing the line.

Line: CreateItemOnObject(sItemResRef, oPC, nGivenTotal);
Here the problem is that CreateItemOnObject can only create one stack. If   nGivenTotal is ever greater then the Max Stack Size for the item, It will simply not give the PC the number of item requested. To fix this you need to check if the Max stack size is greater then the number of items you where trying to create.  If it was not create some more.    

Here is the second script with the fixes in it.   

//-----------------------------------------------
// Script Name = ?????

//Required Includes DONT TOUCH
#include "item_conv_inc"

void main()
{
   // ***SETTINGS***

    //Set this to the # of the Item they must have
    int nRequired = 2;

    //Set this to 0 if they DO NOT require gold
    int nGoldRequired = 100000; //Amount of gold they need

    //Set the tagname of the item they must have to get the item given
    string sItemTagName = "tagname";

    string sName = "Name of Item Goes Here";

    //Set this to the resref of the item they will recieve (if qualified)
    //this is NOT the tagname!
    string sItemResRef = "resref";

    //Set this to the # of the item you wish to give
    //(If the item given is stackable it will be stacked!)
    int nGivenTotal = 1; //Default = 1; (Give only one by default)



/////////////////////////////////////////////////////////////////
//WARNING: Don't Alter Anything below!!!
/////////////////////////////////////////////////////////////////

    object oPC = GetPCSpeaker();
    int nStackSize;
    int nCount = GetIemCount(oPC, sItemTagName);

   //This part will prevent exploits (like dropping gold to prevent losing it etc)
   if(nCount < nRequired)
   {
     FloatingTextStringOnCreature("You must have " +
     IntToString(nRequired) + sName +"!", oPC, FALSE);
     return;
   }
   if(GetGold(oPC) < nGoldRequired)
   {
     FloatingTextStringOnCreature("You don't have " +
     IntToString(nGoldRequired) + " gold on you!", oPC, FALSE);
     return;
   }

   //Obviously we are continuing if they have enough shards..

   //Take 2 of them from the PC
   DestroyNumItems(oPC, sItemTagName, nRequired);

   //take gold
   TakeGoldFromCreature(nGoldRequired, oPC, TRUE);

   //Give the PC X of the item to be given
   object oItem;
   int nMaxStack;
   do
   {
     oItem = CreateItemOnObject(sItemResRef, oPC,nGivenTotal);
     // if nMaxStack is 0 we need to get is value.
     if(!nMaxStack) nMaxStack = StringToInt(Get2DAString("baseitems","Stacking",GetBaseItemType(oItem)));     nGivenTotal-= nMaxStack;
     // if nGiveTotal is postive we still need to give some items.
    }while (nGivenTotal>0);
 

//End main script
}

    

This just leaves the include file to fix.  ( and no Guile your fix did not take care of the problem. 
Ok the DestroyNumItems as it is currently written with the fix.   is finding the item with the correct tag  and checking to see if the stack size is equal to or greater then then number to destroy if it is it decreasses the stack size by the number to destroy and breaking the loop.    First problem with this Idea is that you can not set a  stack size to 0 or below. if you try to it just defaults to 1.  So if the PC only had a stack of two on him and you are trying to destroy two items.  It would try to set the stack size to 0 and only succeed in setting it to 1, Declair that both items where destroyed and break the loop.       Now lets assume that you are trying to destroy 3 items and the PC has split the stack of the  4 shards  he has into two stacks of two.   when the inventory search comes to the first stack of two and compairs the stack size it is not greater or equal to the number to destroy so it will skip right past that section.  the stack size is also not equal to one, so it will skip right past that section also and continue on searching for the next item doing nothing to this stack.   When it finds the secong stack It will do the same nothing.  So no Items will be destroyed.  

Here is the fix for your include script.

//-------------------------------------------------------------------------------------------------
//  Include Script Name =   item_conv_inc      (Save it Under THIS Name!)

//  This is an include script, it's saved under the name (item_conv_inc)
//  This script has 2 Custom Fucntions which...
//  a) Return How many of a particular item the PC Has (GetItemCount)
//  'B)' Destroys X of a given item by tagname, (can reduce Item StackSize)

//////////////////////////////////////////////////////////////////////////////
//Declare All Prototypes
int GetIemCount(object oPC, string sTag);
void DestroyNumItems(object oTarget, string sTag, int nToDestroy = 2);

////////////////////////////////////////////////////////////////////////////
//Prototypes Defined

//Define Prototype
int GetIemCount(object oPC, string sTag)
{
  int i = 0;
  string sIT;
  int nStackSize;

  object oItem = GetFirstItemInInventory(oPC);
    //Continue till there are 0 left to destroy...
    while (GetIsObjectValid(oItem))
    {

      sIT = GetTag(oItem);

      if (sIT == sTag)
      {
        nStackSize = GetItemStackSize(oItem);

        i += nStackSize;
      }

        oItem = GetNextItemInInventory(oPC);
    }

  //Tell the script how many "shards" they have (included all stacked count)
  return i;
}

//Define Prototype
void DestroyNumItems(object oTarget, string sTag, int nToDestroy = 2)
{
    float fDelay;
    int nStackSize;
    int nAdj;
    string sIT; // Item Tagname
    object oItem = GetFirstItemInInventory(oTarget);
    //Continue till there are 0 left to destroy...
    while (GetIsObjectValid(oItem) && nToDestroy >= 1)
    {

            sIT = GetTag(oItem);
            nStackSize = GetItemStackSize(oItem);

            //If they have 2 Shards & This is indeed a Shard (item)
            if (sIT == sTag) //Obviously they have at least 1 stack size
            {
                fDelay += 0.03;
                if(nStackSize <= nToDestroy)
                {
                  DestroyObject(oItem, fDelay);
                  nToDestroy -= nStackSize;
                  if(!nToDestroy) break;
                }
                else
                {
                  SetItemStackSize(oItem,nStackSize - nToDestroy);
                  break;
                }
            }
        oItem = GetNextItemInInventory(oTarget);
    }
}


               
               

               


                     Modifié par Lightfoot8, 03 septembre 2011 - 11:24 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
An NPC or placeable to exchange one type of item for another.
« Reply #23 on: September 03, 2011, 04:58:52 am »


               

_Guile wrote...

I have a question for you Lightfoot8...

Is declaring the Prototypes before defining them in an Include really necessary or does it provided a benefit to do so?
(Just curious, as this is a more advanced subject I never really asked about.)


This thread may help:  http://social.biowar...7813274#7813274
               
               

               
            

Legacy__Guile

  • Hero Member
  • *****
  • Posts: 1308
  • Karma: +0/-0
An NPC or placeable to exchange one type of item for another.
« Reply #24 on: September 03, 2011, 02:46:19 pm »


               Thanks Lightfoot, added the recommended changes to the original scripts
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
An NPC or placeable to exchange one type of item for another.
« Reply #25 on: September 03, 2011, 07:11:13 pm »


               Thank you guys for the further refinement of this. As I mentioned the previous version does seem to be working, the only bugs I found were when testing locally it was not destroying 2 shards for all the types of exchanges, but it was however doing this correctly live on the server for some reason. The only other things is it was not showing 2 shards being destroyed in the log (perhaps because are in a stack), however if you watch your inventory it does in fact destroy 2.

I am not a scripter though, so perhaps you 2 can see potential problems that are not apparent to me, so I will give this update a try. Thank again you two!
Laz

Edit: I just read the rest of Lighfoot8's post, and yep I see the problems. I will certainly give these edits a try.
               
               

               


                     Modifié par Lazarus Magni, 03 septembre 2011 - 06:26 .
                     
                  


            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
An NPC or placeable to exchange one type of item for another.
« Reply #26 on: September 03, 2011, 07:22:37 pm »


               
Quote
Lightfoot8 wrote...


Line: DelayCommand(0.5,ExportSingleCharacter(oPC));
Now this is an interresting one.  First I do not see anyreason to export the character without also updating the DB if you are also storing shard information in the DB.   Doing so just risks getting the DB and character out os sink in the event of a server crash.   but that is not the real problem here.   This export of the PC at a 0.5 delay risks saving the character in a state out of sink with itsself.    The DestroyNumItems function above destroys stacks of items at an incremental delay of 0.3 seconds.  So if it ever destroys more then one stack on the PC, they will be saved at a time when there inventory is out of sink.  I would suggest just removing the line.

[/quote]

Oh by the way, just in case you were interested. I believe this was a relic of the initial script attempt I had posted, which was basically just a hack job of our shard to QP conversion script. The shards are not stored in the DB, but the QP are. Guilie prolly just assumed I had a reason for having that in there originally, but really I was just trying to modify an existing script that had a similar function (quite unsucessfully I might add.)
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
An NPC or placeable to exchange one type of item for another.
« Reply #27 on: September 03, 2011, 11:18:00 pm »


               Umm well, this update didn't exactly work. When I go to do one exchange, it starts converting every single shard I have into the type I was exchanging to.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
An NPC or placeable to exchange one type of item for another.
« Reply #28 on: September 04, 2011, 12:04:38 am »


               arrrg.   well as soon as I get rid of all the orange gems tha I just created on my character,  ill figure out what I did wrong.
               
               

               
            

Legacy_ffbj

  • Hero Member
  • *****
  • Posts: 1097
  • Karma: +0/-0
An NPC or placeable to exchange one type of item for another.
« Reply #29 on: September 04, 2011, 12:23:38 am »


               I usually put the restrictions for number of items in the sc.  Like this:

int GetNumItems(object oTarget,string sItem)
{
int nNumItems = 0;
object oItem = GetFirstItemInInventory(oTarget);
while (GetIsObjectValid(oItem) == TRUE)
{
if (GetTag(oItem) == sItem)
{
nNumItems = nNumItems + GetNumStackedItems(oItem);
}
oItem = GetNextItemInInventory(oTarget);
}
return nNumItems;
}
 

int StartingConditional()
{
object oPC = GetPCSpeaker();

if (!(GetNumItems(oPC, "TagOfItem") >= 3)) return FALSE;

return TRUE;
}
 So the sc would check for 3 or more of the specified item.

Then in the action taken simply:

#include "nw_i0_plot"

//Put this on action taken in the conversation editor

void main()
{
object oPC = GetPCSpeaker();
object oItem;
oItem = GetItemPossessedBy(oPC, "TagOfItem ");
TakeNumItems(oPC, "TagOfItem", 3);

if (GetIsObjectValid(oItem))
   DestroyObject(oItem);

CreateItemOnObject("resrefoitemcreated", oPC);
}

Don't know if that's helpful in this particular case.
               
               

               


                     Modifié par ffbj, 03 septembre 2011 - 11:34 .