Aller au contenu

Photo

ga_take_item takes too many items when it's a stack


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

#1
ColorsFade

ColorsFade
  • Members
  • 1 270 messages
I am using ga_take_item to take two gems from the PC. These items are stackable, so it's very likely the PC has more than the required 2 for the quest. During my initial tests of this conversation node I never had more than two of the gems. However, in playtesting through the mod, I ended up with five. When this conversation node fires, the NPC takes all five when they are supposed to only take two of them. 

Does anyone know why this happens or how to fix it? 

#2
kamal_

kamal_
  • Members
  • 5 254 messages
First, do you want to take or destroy? Taking moves them to the npc's inventory (where they can be stolen or gotten by killing the npc).

#3
ColorsFade

ColorsFade
  • Members
  • 1 270 messages
Well, either would work. Destroying might be better. I take it that it matters?

#4
Dann-J

Dann-J
  • Members
  • 3 161 messages
Destroying stacked items has always been an issue using the default GA_ script. Someone re-wrote the script to fix it and posted it on a forum somewhere (how's that for specific?), and I've been using the modified version ever since.

I'll see if I can dig it up somewhere. I'm at work at the moment, but I've always got a USB stick on me with my in-progress modules backed up. Often I can copy a script straight from the MOD file using UltraEdit (which quite helpfully converts the binary info into plain text).

#5
Dann-J

Dann-J
  • Members
  • 3 161 messages
Here it is. I have no idea who originally wrote it though:

// ga_destroy_item2
/*
This takes an item from a player
sItemTag = This is the string name of the item's tag
nQuantity = The number of items to destroy. -1 is all of the Player's items of that tag.
*/

#include "nw_i0_plot"

void DestroyItems(object oTarget,string sItem,int nNumItems)
{
int nCount = 0;
object oItem = GetFirstItemInInventory(oTarget);

while (GetIsObjectValid(oItem) == TRUE && nCount < nNumItems)
{
if (GetTag(oItem) == sItem)
{
int nRemainingToDestroy = nNumItems - nCount;
int nStackSize = GetItemStackSize(oItem);

if(nStackSize <= nRemainingToDestroy)
{
DestroyObject(oItem,0.1f);
nCount += nStackSize;
}
else
{
int nNewStackSize = nStackSize - nRemainingToDestroy;
SetItemStackSize(oItem, nNewStackSize);
break;
}
}
oItem = GetNextItemInInventory(oTarget);
}
return;
}

void main(string sItemTag,int nQuantity)
{

int nTotalItem;
object oPC = GetPCSpeaker();
object oItem; // Items in inventory

if ( nQuantity < 0 ) // Destroy all instances of the item
{
nTotalItem = GetNumItems( oPC,sItemTag );
DestroyItems( oPC,sItemTag,nTotalItem );
}
else
{
DestroyItems( oPC,sItemTag,nQuantity );
}

}

#6
kamal_

kamal_
  • Members
  • 5 254 messages

ColorsFade wrote...

Well, either would work. Destroying might be better. I take it that it matters?

If you take an item and reward the player during the take action (give them gold, xp or whatever), then the player can loop the reward via pickpocketing the item and turning it in repeatedly. This was a bug source in Path of Evil that I hadn't considered until people reported doing it.

Alternately, the Uber Sword of Ultra Doom +5 that you gave the player temporarily for a specific quest, and then take the sword from them when they turn in the quest for reward, is still pickpocketable for the player to get the item again for general use outside the specific quest. While it's possibly realistic they could steal the sword back, you probably don't want that to be a possibility.

So now I destroy items I intend the player to no longer be able to get.

#7
andysks

andysks
  • Members
  • 1 651 messages

kamal_ wrote...


This was a bug source in Path of Evil that I hadn't considered until people reported doing it.



Even in elder scrolls these bugs exist. I remember in oblivion I could turn the quest for the vampirism treatment over and over agian to get the gold.
I guess none can ever predict all these.
But it's good to know that it happens with the ga_take_item. Does it happen if the item is even non pickpocketable?

#8
Tchos

Tchos
  • Members
  • 5 063 messages
Another approach, which is what I use most of the time, is that acquiring the item(s) advances the journal, and it's a journal check that handles the turn-in, not the possession of the item(s). And then, after the player comes to the questgiver for a reward, I destroy all copies of the item(s) in the world, whether the player is carrying them or not.

I have plans to use the global unacquire event to decrement the journal stage if the player drops or sells the item, to avoid the incongruity of the questgiver happily giving the reward to a player that dropped the item. But even without doing that, it avoids the infinite turn-in problem.

#9
Dann-J

Dann-J
  • Members
  • 3 161 messages
There's also the problem of conversations that check the entire party for the presence of an item (to make a conversation node available), but which only remove that item from the current speaker. If the current speaker doesn't have the item in their inventory, you get the reward and get to keep the item. The players can't continually get the reward over and over if you make the conversation node once-only, but they still get to keep the item.

Even if the speaker who initates the conversation actually has the item, in a 'party chat' conversation there's no guarantee they'll still be the speaker for the node it gets taken from.

I created my own GA_ script that removes a specified number of items from the party, regardless of how many each party member has. It loops through each inventory, removing as many of the items as it finds if the number is less than the specified number to take, then searches the next party member's inventory for the remainder until the right number of items has been taken. So if you want to take 10 items from the party, and they're split across several party members (one has 3, another has 2, another has 12, etc), the script takes three from the first inventory, 2 from the next, and only five from the next.

You can see the script in all its elegant beauty here.

Modifié par DannJ, 03 décembre 2013 - 04:17 .


#10
Tchos

Tchos
  • Members
  • 5 063 messages
That script sounds ideal. Does it also work if one of the PCs has more than one stack, both of which are fewer than the required number, and the rest are on other PCs? Say, the quest requires 10 items, and PC 1 had 6, but split into 2 stacks of 3, and PC 2 had 4 more.

Also, have you ever found any trouble caused by a PC having the quest items in an inventory slot with several empty slots in front of it? It seems like some methods stop when they reach a gap like that.

#11
Morbane

Morbane
  • Members
  • 1 883 messages

Tchos wrote...

That script sounds ideal. Does it also work if one of the PCs has more than one stack, both of which are fewer than the required number, and the rest are on other PCs? Say, the quest requires 10 items, and PC 1 had 6, but split into 2 stacks of 3, and PC 2 had 4 more.

Also, have you ever found any trouble caused by a PC having the quest items in an inventory slot with several empty slots in front of it? It seems like some methods stop when they reach a gap like that.


without reading the script - i would have to say yes since the script loops through the entire inventory - such loops do not stop at the mentioned item until the entire inventory has been looped through. loopy huh :P

#12
Dann-J

Dann-J
  • Members
  • 3 161 messages

Tchos wrote...

That script sounds ideal. Does it also work if one of the PCs has more than one stack, both of which are fewer than the required number, and the rest are on other PCs? Say, the quest requires 10 items, and PC 1 had 6, but split into 2 stacks of 3, and PC 2 had 4 more.

Also, have you ever found any trouble caused by a PC having the quest items in an inventory slot with several empty slots in front of it? It seems like some methods stop when they reach a gap like that.


I've tested it under all sorts of conditions, including multiple stacks in one inventory, multiple stacks across multiple inventories, etc. It keeps going until it's found and destroyed the correct amount.

What you see in in the inventory interface isn't how the script sees things. The first/next loop isn't checking inventory slots, but rather inventory items. Whether the first item it encounters is in the 1st or 128th inventory slot doesn't matter - it's still the 'first' inventory item (or second, third, etc).

You need to make sure the conversation node checks you've got at least the minimum amount before making that node available. The script doesn't care if you've got less than the required amount - it just takes everything you've got.

There's no check for equipped slots either. If the items you're returning are equippable, then you'd have to have another function that loops through each party member's equipment slots and unequips the items if they match your specified tags. Loopier and loopier (to misquote Alice).

#13
Tchos

Tchos
  • Members
  • 5 063 messages
Good to know.

So, for the check, have you found the default gc_ scripts to be good enough in determining that the party has enough of the item?

#14
Dann-J

Dann-J
  • Members
  • 3 161 messages
Once of the standard GC_ scripts has an option to check the entire party (GC_Check_Item?).

#15
ColorsFade

ColorsFade
  • Members
  • 1 270 messages
DannJ, just wanted to say thanks: the script you provided here worked like a charm. Appreciate it!