Author Topic: Any scripting method for transferring all inventory items to a remote container?  (Read 498 times)

Legacy_Furnaceden

  • Newbie
  • *
  • Posts: 6
  • Karma: +0/-0


               Hello,

I am new to this forum and I apologize if this topic has been addressed already, but I performed a reasonably diligent search and could not find anything.

Is there a way to transfer all of the player-character's inventory to a container in another area? For example, if I wanted to create a module with a segment where the player is taken prisoner and all belongings confiscated, and the character has to escape and make it back to a point without the aid of those belongings. Of course, the prisoner's confiscated stuff would be safely and "conveniently" locked away in a container by the guards (nobody wants to lose all their precious enchanted stuff for good, after all).

Is there a script or method to accomplish this? Even, say, a way of turning the current character-state into a "corpse-container" elsewhere -- form of an armoire, maybe -- and regenerating a duplicate with all personal stats but without items? That would be a horribly convoluted method but I'm just spit-balling here.
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0


                I have a function for doing that which I call MoveInventory.

I beleive others have pointed out problems with how I implemented this, but I haven't encountered anything. I hope some of those that know what they are doing chime in and explain how to improve my function.

While it owuld be best to go to pastebin to see my function (see link above), I am also posting it here:

int MoveInventory(object oSource, object oTarget)
{
   object oItem, oCopy; int nCount;

   // move gold
   if(GetObjectType(oSource)==OBJECT_TYPE_CREATURE)
   {
       int nGold   = GetGold(oSource);
       if(nGold)
       {
           AssignCommand(oTarget, TakeGoldFromCreature(nGold, oSource));
           ++nCount;
       }
   }

   // copy containers
   oItem    = GetFirstItemInInventory(oSource);
   while(GetIsObjectValid(oItem))
   {
       if(GetHasInventory(oItem)&&!GetLocalInt(oItem,"COPIED"))
       {
           nCount++;
           // create a copy of the container
           oCopy   = CreateItemOnObject(GetResRef(oItem), oTarget, 1, GetTag(oItem));
           SetLocalInt(oItem, "COPIED", TRUE); // mark the original as copied
           SetName(oCopy, GetName(oItem));
           SetDescription(oCopy, GetDescription(oItem));
           SetIdentified(oCopy, GetIdentified(oItem));
           // copy contents of container
           nCount  +=  MoveInventory(oItem, oCopy);
           DestroyObject(oItem, 0.1);
       }

       oItem   = GetNextItemInInventory(oSource);
   }
   // copy items
   oItem    = GetFirstItemInInventory(oSource);
   while(GetIsObjectValid(oItem))
   {
       if(!GetHasInventory(oItem)&&!GetLocalInt(oItem,"COPIED"))
       {
           nCount++;
           CopyItem(oItem, oTarget, TRUE);
           SetLocalInt(oItem, "COPIED", TRUE);
           DestroyObject(oItem, 0.1);
       }

       oItem   = GetNextItemInInventory(oSource);
   }

   return nCount;
}
               
               

               


                     Modifié par henesua, 21 février 2014 - 01:04 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0


               Here's how your script works:
Inventory items are arranged in order from last disturbed to first disturbed with the contents of containers immediately following the container item.

So you would first transfer all gold,
Then you would copy container 1.
Then you would check container 1 for gold.
Then you would check container 1 for containers.
Then you would copy the inventory of container 1 to its new container.
You would then be at the end of the inventory of container 1 so the next object for examining containers is just after container 1 and its contents, so you would then proceed to container 2.
Repeat container 1 loop for the remaining containers.
Next you copy all items not in a container.

Inefficient but it works.  One thing that would save a lot of script time is not to check containers for containers.
               
               

               
            

Legacy_Proleric

  • Hero Member
  • *****
  • Posts: 1750
  • Karma: +0/-0


               A few issues:

  • Removing equipped items (if we're in jail, having a sword might be frowned on).



  • Removing the creature skin will break the 1.69 horse system



  • Containers have a stack limit of 50,000 gold

Here's my script. There's an option to remove the clothing/armour, too, in case you want to equip a prison uniform or whatever.

I've never bothered much with containers, so I'm not sure whether special processing is required for them. EDIT : It is - see next post for fix.
               
               

               


                     Modifié par Proleric1, 21 février 2014 - 03:11 .
                     
                  


            

Legacy_Proleric

  • Hero Member
  • *****
  • Posts: 1750
  • Karma: +0/-0


               I've added a line to my script which handles container items with contents.

I find that container items cannot contain gold or nested containers, so the result is simple, but comprehensive, I think.
               
               

               


                     Modifié par Proleric1, 21 février 2014 - 03:08 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0


               Proleric1, your script doesn't accomplish one thing that henesua's script accomplishes, that is keeping the inventory contents in the same container.  I am not sure why you are bringing up point 2 (removal of creature skin) as henesua doesn't do an inventory removal in his function.  Due to the fact that the function calls itself, I think henesua would do an inventory strip outside this function if it were called for.
               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0


               

WhiZard wrote...

Inefficient but it works. One thing that would save a lot of script time is not to check containers for containers.


Its not that inefficient in the grand scheme of things. Containers don't have containers so that always fails,and the recursion stops. A few extra instructions maybe, but a bit of elegance. Assuming the variables used in the iterators are on the object being iterated you could remove the recursion and add another loop there to copy over all the items in each container inline. You still need to mark them.

(Edit again: Nevermind - I didn't notice the two loops. That could be made into one without much trouble I think...)

Plus, I expect stripping all the PC gear is not that common.

One thing that Hen's does is keep the contents of PC containers in the container. This seems like a nice feature.

(Edit : What Whizard said..)

@Proleric: Agree with most of what yours does, stripping equipped things etc. But your fixed version empties all the containers that get moved. Also you could just stop the inventory loop before the carmor slot. Then you don't need to hardcode the resref of the skin, which is configurable (at least in Krit's updated skin code).

One issue with the containers part of Henesua's is variables on the container. I have a bunch of auto sorting containers PCs can use which have settings on them. Need code in there to copy that state over to the newly created container.

Good discussion - made me see a few issues with what I have currently, which I'm off to fix...
               
               

               


                     Modifié par meaglyn, 21 février 2014 - 04:52 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0


               I have cleaned up Henesua's script to work more efficiently (although it no longer factors in gold).  Gold and equipped item sweeps can be done on the side.

int MoveInventory(object oSource, object oTarget)
{
// This function can cause problems if misused
if(oTarget == oSource)  return -1;
int nCount, nCount2; object oCopy, oBlank;
object oItem = GetFirstItemInInventory(oSource);
while(GetIsObjectValid(oItem))
   {
   nCount++;
   oCopy = CreateItemOnObject(GetResRef(oItem), oTarget, 1, GetTag(oItem));
  SetName(oCopy, GetName(oItem));
  SetDescription(oCopy, GetDescription(oItem));
  SetIdentified(oCopy, GetIdentified(oItem));
  if(GetHasInventory(oItem))
    {
    nCount2 = MoveInventory(oItem, oCopy);
    nCount += nCount2;
    while(nCount2--) oBlank = GetNextItemInInventory(oSource);
    }
  DestroyObject(oItem);
  oItem = GetNextItemInInventory(oSource);
  }
return nCount;
}
               
               

               


                     Modifié par WhiZard, 21 février 2014 - 05:05 .
                     
                  


            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0


               Hhm, you're doing it all with CreateItemOnObject.  That means no variables... I think you may have gone one step too far in the name of efficiency '<img'>

I like the oBlank usage instead of marking the items, although it does rely on implementation details of the lower levels. I may borrow that ...
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0


               

meaglyn wrote...

Hhm, you're doing it all with CreateItemOnObject.  That means no variables... I think you may have gone one step too far in the name of efficiency '<img'>


Ironically, CopyItem (with or without variables) would also be far more efficient than Create. '<img'>

Funky
               
               

               
            

Legacy_Proleric

  • Hero Member
  • *****
  • Posts: 1750
  • Karma: +0/-0


               

WhiZard wrote...

Proleric1, your script doesn't accomplish one thing that henesua's script accomplishes, that is keeping the inventory contents in the same container.

Interesting. Have you tested this? My finding is that containers can't be nested, nor can they contain gold, but perhaps I've missed something.

WhiZard wrote...
I am not sure why you are bringing up point 2 (removal of creature skin) as henesua doesn't do an inventory removal in his function. ...

The most important difference between Henesua's script and mine is that I remove equipped items, which is normally a requirement for jail scenarios etc. That implies the additional requirement to retain the horse skin.

Incidentally, I'm using CopyItem, which is faster and preserves variables, as FunkySwerve says.

meaglyn wrote...

@Proleric: ...you could just stop the inventory loop before the carmor slot. Then you don't need to hardcode the resref of the skin, which is configurable (at least in Krit's updated skin code).

True, the literal is just sloppy. Since the engine isn't going to change now, I guess we could use the "inside information" that the creature slot has a higher number than the others, though purists might argue with that, too.

meaglyn wrote...
One issue with the containers part of Henesua's is variables on the container.

Yes, I wondered if anyone ever did that.

Good discussion.
               
               

               


                     Modifié par Proleric1, 21 février 2014 - 06:24 .
                     
                  


            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0


               

Proleric1 wrote...

True, the literal is just sloppy. Since the engine isn't going to change now, I guess we could use the "inside information" that the creature slot has a higher number than the others, though purists might argue with that, too.


I put this just inside my for loop:

if (i == INVENTORY_SLOT_CARMOUR)
                        continue;

Then I'm not relying on the relative numerical values at all.
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0


               I forget why i did not copy objects with inventory. That said I appreciate all the comments, folks. When I have time I'll take a look at this function again.

I hope the OP is getting what they need. If not, speak up.
               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0


               

henesua wrote...
I forget why i did not copy objects with inventory.


I think it just doesn't work, at least if there is anything in it.
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0


               

FunkySwerve wrote...

meaglyn wrote...

Hhm, you're doing it all with CreateItemOnObject.  That means no variables... I think you may have gone one step too far in the name of efficiency '<img'>


Ironically, CopyItem (with or without variables) would also be far more efficient than Create. '<img'>

Funky


Easy enough to adjust for...


int MoveInventory(object oSource, object oTarget)
{
// This function can cause problems if misused
if(oTarget == oSource)  return -1;
int nCount, nCount2; object oCopy, oBlank;
object oItem = GetFirstItemInInventory(oSource);
while(GetIsObjectValid(oItem))
   {
   nCount++;
   if(GetHasInventory(oItem))
     {
     oCopy = CreateItemOnObject(GetResRef(oItem), oTarget, 1, GetTag(oItem));
     SetName(oCopy, GetName(oItem));
     SetDescription(oCopy, GetDescription(oItem));
     SetIdentified(oCopy, GetIdentified(oItem));
     nCount2 = MoveInventory(oItem, oCopy);
     nCount += nCount2;
     while(nCount2--) oBlank = GetNextItemInInventory(oSource);
     }
  else CopyItem(oItem, oTarget, TRUE);
  DestroyObject(oItem);
  oItem = GetNextItemInInventory(oSource);
  }
return nCount;
}