Aller au contenu

Photo

An NPC or placeable to exchange one type of item for another.


  • Veuillez vous connecter pour répondre
35 réponses à ce sujet

#1
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
I am looking to set up some sort of an NPC or a placeable (like a workbench) that can exchange one type of gem (or shard as the case may be) for another at a cost (say 2 of the original for 1 of the new), and I was wondering if there already is such a system I could just plug the appropiate tags into that someone could point me to? And if not if anyone would be willing to help me make one? I imagine it would need to preform some sort of check to see if the PC has the item(s), and then be able to take it and give the other.
Thank you,
Laz

Modifié par Lazarus Magni, 01 septembre 2011 - 11:59 .


#2
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
Well if there is no prefab version of this, this is what I have so far:
// Checks if a player has 2 Red Shards

#include "nw_i0_plot"
int StartingConditional()
{
    object oPC = GetPCSpeaker();
    //Checks if the PC has 2 Red Shards
    if ( HasItem (oPC, "laz_redqpshard") && HasItem(oPC, "laz_redqpshard") ) return TRUE;
    return FALSE;
}

This compiles, but I am not sure if it will check twice the same red shard.

I also have been working on this for the exchange:

// Script that exchanges 2 Red Shards into an Orange one  for 100k gp
//  This function was created by  AgedAlchemist on the Bioware forums
//  Link: http://nwn.bioware.c...723351&forum=47
//  Searches oTarget's inventory for items tagged sTag, and destroys nToDestroy of them.
//  It does not search for items equipped by Creatures.
void DestroyNumItems(object oTarget, string sTag, int nToDestroy = 2);
void DestroyNumItems(object oTarget, string sTag, int nToDestroy = 2)
{
    float fDelay;
    int nStackSize;
    object oItem = GetFirstItemInInventory(oTarget);
    while (GetIsObjectValid(oItem) && nToDestroy > 1)
    {
        if(GetTag(oItem) == sTag)
        {
            nStackSize = GetItemStackSize(oItem);
            if (nStackSize <= nToDestroy)
            {
                fDelay += 0.03;
                nToDestroy -= nStackSize;
                DestroyObject(oItem, fDelay);
            }
            else
            {
                SetItemStackSize(oItem, nStackSize - nToDestroy);
                nToDestroy = 0;
            }
        }
        oItem = GetNextItemInInventory(oTarget);
    }
}
#include "nw_i0_plot"
#include "tal_qp_include"
void main()
{
    object oPC = GetPCSpeaker();
    object oMerchant = GetLastSpeaker();
    //Checks if the PC 2 Red shards.
    if ( HasItem(oPC, "laz_redqpshard") && HasItem(oPC, "laz_redqpshard") && GetGold(oPC) > 100000)
    {
        //Remove 2 Red shards
        int nStackSize;
        int nQPs;
        object oShardStack;
        string sStackTag;
        oShardStack = GetItemPossessedBy(oPC, "laz_redqpshard");
        sStackTag = GetTag(oShardStack);
        DestroyNumItems(oPC, sStackTag);
        oShardStack = GetItemPossessedBy(oPC, "laz_redqpshard");
        sStackTag = GetTag(oShardStack);
        DestroyNumItems(oPC, sStackTag);
        //Exports character
        DelayCommand(0.5,ExportSingleCharacter(oPC));
        //Give QP and take gold
        TakeGold(100000, oPC);
        ActionGiveItem("laz_orangeqpshrd", oPC);
    }
    else AssignCommand(oMerchant, ActionSpeakString("You don't have 100,000 gold."));
}
This however does not compile, and I get this error message:
laz_shardexchang.nss(66): ERROR: DECLARATION DOES NOT MATCH PARAMETERS

Any help would be appreciated.

#3
_Guile

_Guile
  • Members
  • 685 messages
//========================================
//Script 1:

#include "nw_i0_plot"
#include "tal_qp_include"

//This will tell us how many shards they have on them right now
int GetItemCount(object oPC, string sTag);

void main()
{
    object oPC = GetPCSpeaker();
    object oMerchant = OBJECT_SELF;
    string sStackTag = "laz_redqpshard";
    object oShardStack = GetItemPossessedBy(oPC, sStackTag);
    int nStackSize;
    int nShards = GetItemCount(oPC, sStackTag);

    int nQPs;
    object oTarget = oPC;

    if(GetGold(oPC)<100000)
    {
     AssignCommand(oMerchant, ActionSpeakString("You don't have 100,000 gold."));
     return;
    }
    //If they don't have enough (2 or more)...
    if(nShards < 2)
    {
     AssignCommand(oMerchant, ActionSpeakString("You need at least 2 shards."));
     return;
    }

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

        //Take 2 of them from the PC  (You must set how many you wish to take here!)
        DestroyNumItems(oPC, sStackTag, 2);

        //Give QP and take gold
        AssignCommand(oTarget, TakeGold(100000, oPC, TRUE));

        //Exports character
        DelayCommand(0.5,ExportSingleCharacter(oPC));

        //Give the PC 1 of these items (NOTE: This is the RESREF name not tagname!)
        CreateItemOnObject("laz_orangeqpshrd", oPC, 1);

//End main script
}

//Prototype Defined
int GetItemCount(object oPC, string sTag)
{
  int iCount = 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);

        iCount += nStackSize;
      }

        oItem = GetNextItemInInventory(oPC);
    }

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

//=================================================
//Script 2:

// Script Name:  tal_qp_include

// Script that exchanges 2 Red Shards into an Orange one  for 100k gp
//  This function was created by  AgedAlchemist on the Bioware forums
//  Link: http://nwn.bioware.c...723351&forum=47
//  Searches oTarget's inventory for items tagged sTag, and destroys nToDestroy of them.
//  It does not search for items equipped by Creatures.

void DestroyNumItems(object oTarget, string sTag, int nToDestroy);

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;
                }

                //Take 2 shards from the PC
                if(nStackSize == 1)
                {
                 DestroyObject(oItem, fDelay);
                 nToDestroy -= 1;
                }

            }

        oItem = GetNextItemInInventory(oTarget);
    }
}

//=======================================
//Script 3:

#include "nw_i0_plot"

//This will tell us how many shards they have on them right now
int GetItemCount(object oPC, string sTag);

int StartingConditional()
{
    object oPC = GetPCSpeaker();
    //Checks if the PC has 2 Red Shards
    string sStackTag = "laz_redqpshard";
    int nShards = GetShardNum(oPC, sStackTag);

    if (nShards >=2 )
    { return TRUE; }
    else
    { return FALSE; }
}


//Prototype Defined
int GetItemCount(object oPC, string sTag)
{
  int iCount = 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);

        iCount += nStackSize;
      }

        oItem = GetNextItemInInventory(oPC);
    }

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

//---------------------------------

Those should work for you, compiled them, though I didn't test them, pretty sure they are good..

Modifié par _Guile, 02 septembre 2011 - 02:15 .


#4
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
Thank you Guile! I will give these a try. I am just a lil confused though about why there are 3? Are 1 and 2, just alternate versions of the same thing?

Modifié par Lazarus Magni, 02 septembre 2011 - 01:56 .


#5
_Guile

_Guile
  • Members
  • 685 messages
Did a triple check, those are the final editions, should be all good.

Script 1 is the main script that actually does the taking of the shards & gold,
             This script goes in the ActionTaken event of a conversation line that will take the Shards & Gold
Script 2 is an Include to Script 1 (hence the #include "scriptname" part found in script 1)
Script 3 is a starting conditional for the line (in red by NPC) that will show if the PC is allowed to trade in for the item desired.

If the PC fails to meet the requirements, the PC will see the next line in the conversation instead..(Again the red NPC Conversation line, not the PC's conversation lines)

If you use the PC's line as the Starting conditional then the option will not appear (to trade shards & gold for item) until they do meet the requirements.   However if you use the Starting Conditional under the NPC, the next line should inform the PC why they are not qualified to get the desired item, and should tell them what they need.

Technically you could merge Script 2 with script one, placing the delclared prototype below GetItemCount();
and placing the actual defined prototype below void main() { }  (and below GetItemCount() still)
If I was to redo these scripts it would be with constants settings to allow the user to use these scripts for other conversations etc...  (let me have a crack that and I'll post that in the last post I made)

    //Note this is really not needed because we are working from a conversation!
    //The starting conditional script will prevent the PC from getting this far!
    /*
     if(GetGold(oPC)< nGoldRequired)
     {
      AssignCommand(oMerchant, ActionSpeakString("You don't have 100,000 gold."));
      return;
     }
     //If they don't have enough (2 or more)...
     if(nShards < nRequired)
     {
      AssignCommand(oMerchant, ActionSpeakString("You need at least 2 shards."));
      return;
     }
    */

Hope that helps more..

Modifié par _Guile, 02 septembre 2011 - 02:32 .


#6
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
@Guile. GetLastSpeaker(); is for use in OnConversation event scripts, not conversation scripts. If the conversation is always started via the OnConversation event there is no porblem using it in the conversation scripts. however since not all conversations are started by the OnConversation Event using it in a conversation script is a bad practice.

@Lazarous: No Getting the item possed by the PC twice will not check to see if the PC has two of the items.

_Guiles scripts look like they will work, as long as the shards are stackable and they are in the same stack. Of cource you will want to change his check in the second script for the stack size from if(nStackSize < 2) to if(nStackSize <= 2)

and also change in the first script the line object oMerchant = GetLastSpeaker(); to object oMerchant = OBJECT_SELF;

So let me try and get a better Idea of what you are wanting. I am guesing that you have a gem monitary system. With each gem have a montary value. If this is true I just do not get the 1000K + 2 red gems = one Orange gem. Can you clarify your system a little better for me?

#7
_Guile

_Guile
  • Members
  • 685 messages
Thanks for catching that, turned oMerchant to OBJECT_SELF (from a conversation)

Those should work, unless I missed something else..

Modifié par _Guile, 02 septembre 2011 - 02:12 .


#8
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
Thank you Guile, that does clarify things, and thank you both for the input.

Most likely it would be as I believe Guile was guessing an on conversation event script. Just a simple conversation saying do you want to convert 2 reds into an orange, and than an action taken event on the yes choice, or something to that effect.

Light, I kinda figured I was way off, which is why I am glad to get some help here. To clarify, no there is basically the standard GP based economy on Av3 with the exception of things called Quest Points (QPs) which can be gained from DM events, or forged (so to speak, it's actually credited to the PC account in the DB) from things called QP shards which drop from bosses. There are 7 types of shards, and on collecting all seven (plus 1 mil gold) you can convert them into a QP. QP are used to buy special items and DM services. This would just allow players to convert 1 shard type into another which I have heard alot of players ask for since some are quite difficult to obtain (especially for newer players.)

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


#9
_Guile

_Guile
  • Members
  • 685 messages
Did you want to check for the 100,000 Gold in the Starting Conditional too?

#10
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
I honestly don't really know what a starting conditional is.
*looks sheepish*
But I can intuit that it is a condition that must be met before the script is run? If so, yes that would prolly be good.

#11
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages

    //Note this is really not needed because we are working from a conversation!
    //The starting conditional script will prevent the PC from getting this far!
    /*
     if(GetGold(oPC)< nGoldRequired)
     {
      AssignCommand(oMerchant, ActionSpeakString("You don't have 100,000 gold."));
      return;
     }
     //If they don't have enough (2 or more)...
     if(nShards < nRequired)
     {
      AssignCommand(oMerchant, ActionSpeakString("You need at least 2 shards."));
      return;
     }
    */
 


Really it is needed.   It stops the PC's from cheating the conversation.  ie.  starting the conversation, having the line displayed,  Dumping there gold and shards on the ground and then selecting the conversation line to get the new shard for nothing.   

#12
_Guile

_Guile
  • Members
  • 685 messages
A starting conditional is a script that goes in the paceholder (white box) of a line... in the TextAppearsWhen Tab, so if you click a line and look down to the right, you will see you are usually on the TextAppearsWhen Tab, in that white box, select edit, and paste script 1 there... save it under a name...


For the sake of saving you some time & frustrations, as you may need this script for other shards colors, etc... I made a more versatile version for you, which you could always use scripts 1 & 2 (Just save it under a new name FIRST, and then make alterations to the settings to configure it to a different item). Script 3 however would never change (the include)...

EDITED: Fixed as Lightfoot8 Prescribed below, thanks Lightfoot8
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Script 1 (This goes in the TextAppearWhen Tab for the line you wish to check to see if the PC has enough of the required items &/or Gold ) This line will NOT show if they are NOT qualified!
(This should be the NPC's line in red, as an option, and it should be above line #2 that the NPC speaks)

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

//Required Include (Don't remove)
#include "item_conv_inc"

int StartingConditional()
{
     // ***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";

/////////////////////////////////////////////////////////////////
//WARNING: Don't touch anything below!
/////////////////////////////////////////////////////////////////
   
     object oPC = GetPCSpeaker();

    // Custom Function that returns the # of a particular item
    // (included stack counts) that the PC has on them
    int nCount = GetIemCount(oPC, sItemTagName);

    if (nCount >= nRequired && GetGold(oPC) >= nGoldRequired)
    { return TRUE; }
    else
    { return FALSE; }

}

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Script 2: This goes on the line where the PC will select the option to actually trade in the required items &/or gold to get the item, it will actually end the conversation and they should recieve the item if they are indeed qualified, otherwise they will get a message instead!

//-----------------------------------------------
//-----------------------------------------------
// 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) Get2DAString("baseitems","Stacking",GetBaseItemType(oItem));

     nGivenTotal-= nMaxStack;
     // if nGiveTotal is postive we still need to give some items.
    }while (nGivenTotal>0);
 

//End main script
}

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Script 3: This script should just be pasted into the script editor, and saved...  (DO NOT ALTER IT!)
               This script is only used by Script 1 & 2, it's only for saving space in Script 1 & 2

//-------------------------------------------------------------------------------------------------
//  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);

////////////////////////////////////////////////////////////////////////////
//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)
                {
                  DestroyObject(oItem, fDelay);
                  nToDestroy -= nStackSize;
                  if(!nToDestroy) break;
                }
                else
                {
                  SetItemStackSize(oItem,nStackSize - nToDestroy);
                  break;
                }
            }
        oItem = GetNextItemInInventory(oTarget);
    }
}

Modifié par _Guile, 05 septembre 2011 - 03:21 .


#13
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
Thank you Guile, that helps alot, and was very clear. I will try these ASAP.

#14
_Guile

_Guile
  • Members
  • 685 messages

Lazarus Magni wrote...

Thank you Guile, that helps alot, and was very clear. I will try these ASAP.


Your very welcome, I aim to please, always.. :D

Lightfoot8 wrote...

Really it is needed.   It stops the PC's from cheating the conversation.  ie.  starting the conversation, having the line displayed,  Dumping there gold and shards on the ground and then selecting the conversation line to get the new shard for nothing.   


Technically they really aren't, if you were smart, you would put the
starting conditional on the line of the NPC where the NPC tells the PC, "There
you go" (giving them the item), & on that same line you would give
them the stuff with the 2nd script...  If they didn't qualify to see the
line that gives them the item, then they would read the next line which
would explain to them that they still need X to get the item... 
(But that's just my 2 cents, so I'm not really wrong, technically.)

Though you are correct in a sense, they are needed to prevent exploiting if you aren't using a 2nd check, so I corrected it in my second version, thank you for your comments though.

Modifié par _Guile, 02 septembre 2011 - 03:26 .


#15
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
There are a few problems in _Guile's scripts. I don't have time to give the fixes right now, I will try to get them tomorow evening after work, I someone else or Guile does not fix them first.

#16
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
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 .


#17
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
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 .


#18
Lightfoot8

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

#19
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
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 .


#20
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
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!

#21
_Guile

_Guile
  • Members
  • 685 messages
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 .


#22
_Guile

_Guile
  • Members
  • 685 messages
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);
    }
}

#23
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
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 .


#24
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages

_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

#25
_Guile

_Guile
  • Members
  • 685 messages
Thanks Lightfoot, added the recommended changes to the original scripts