Skip to content

Save Merch Store for PW?

Is there a way to save items sold on merchants so they will be there after a server restart?

I'm trying to make Vendors sell items that have been picked up by players. The modules OnAcquire script just adds the item to a merchant store. This works fine, but once I restart the server, it's wiped.

Comments

  • ForSeriousForSerious Member Posts: 446
    I have not worked directly with merchant inventories, but I have my whole loot system setup to be from a database. It should be similar.
    Can you be a little more specific?
    Like: do you want the sate of the merchant inventory to be saved, or just any items sold to it to be restored over a reset?
  • BuddywarriorBuddywarrior Member Posts: 62
    The state of the merchant inventory would be ideal. The process should look something like this.

    1: 'Player A' picks up an item with a value over 2k.
    2: Module adds it to the merchant inventory.
    3: 'Player B' can see the item being sold by the merchant.
    4: On Server reset, the inventory state of merchant remains unchanged.
    5: Buddywarrior is gitty with excitement.
  • ForSeriousForSerious Member Posts: 446
    edited October 2021
    'Player A' picks it up from where?
    And, does the merchant already have items to sell? (A little harder because you need to make a way to populate the database that does not create duplicates every time the server resets.)
    Are item blueprint references fine, or are there modified items that will be picked up?
  • BuddywarriorBuddywarrior Member Posts: 62
    It's called from the OnAcquireItem of the module, then using a CreateItemOnObject("resref", Trader) to add it to the Merch, and only if they don't already have it.

    Merch will start with nothing.

    resrefs are fine, I'm getting that info as it's being called.


  • ForSeriousForSerious Member Posts: 446
    edited October 2021
    Last questions: Should the items be infinitely available once in the store?
    Are there more than one locations where players can access this store?
  • BuddywarriorBuddywarrior Member Posts: 62
    One in and One out. And currently one Merch in one Area.
  • ForSeriousForSerious Member Posts: 446
    One in and One out.
    I'm a little surprised by this. If you have three players: one gets the item when they find it. One can buy it. And the other is out of luck.

    Am I missing something? Would you rather do it when the player sells the item to the store?
  • BuddywarriorBuddywarrior Member Posts: 62
    Yep, that's the way I'm going. I don't believe locally stored variables stick around on objects in game after a server restart. Will I have to look at a database solution?
  • ForSeriousForSerious Member Posts: 446
    Yeah. I'm almost done writing up a starting point. I just need to clean the deleting script up, and probably test everything. There's a lot of little details that I might have missed.
  • BuddywarriorBuddywarrior Member Posts: 62
    Holy cow chips! That's amazing ForSerious.
  • ForSeriousForSerious Member Posts: 446
    edited October 2021
    It was a fun little challenge! Didn't want to resist.
    It's not perfect. Here's what I have:
    OnClientEnter: Block items already in inventory from being added.
    object oVault = GetModule();
        // sName must be some unique identifier to oPC entering.
        // You can use something like CDkey + full name.
        DelayCommand(3.0, SetLocalInt(oVault, sName, TRUE));
    
    OnAcquireItem: The main magic.
    void main()
    {
        string sRef;
        object oPossessor = GetModuleItemAcquiredBy();
        string sName = GetTag(oPossessor);
        object oVault = GetModule();
        // Without this when the player enters, it will start to add all their items into the store.
        int iIsLoaded = GetLocalInt(oVault, sName);
        if(!iIsLoaded)
        {
            return;
        }
        // This is a way to make a working arroy in a database. This stores the length of the array.
        int iIndex = GetCampaignInt("isbase", "INDEX_ITEM_STORE");
        object oItem = GetModuleItemAcquired();
        if(GetGoldPieceValue(oItem) >= 2000)
        {
            // Don't add the item to the store if it came from the store. Delete it.
            if(GetTag(GetModuleItemAcquiredFrom()) == "EmptyStore")
            {
                sRef = GetResRef(oItem);
                iIndex = GetLocalInt(oItem, "index");
                // Erase the entry in the DB to be cleaned up later.
                if(sRef != "" && sRef != " ")
                {
                    SetCampaignString("isbase", IntToString(iIndex), " ");
                }
            }
            else
            {
                object oStore = GetObjectByTag("EmptyStore");
                // Check the store for the item just picked up.
                if(!GetIsObjectValid(GetItemPossessedBy(oStore, GetTag(oItem))))
                {
                    CreateItemOnObject(GetResRef(oItem), oStore);
                    // Create object needs a resref, so get that for storing in the database.
                    sRef = GetResRef(oItem);
                    if(sRef != "" && sRef != " ")
                    {
                        // Save the ref at the end of the array.
                        // You can only have one of these per database because it's using numbers as pointers to the items in the database.
                        // You can, however, have as many databases as you want.
                        SetCampaignString("isbase", IntToString(iIndex), sRef);
                        // Mark that the array is longer.
                        iIndex++;
                        SetCampaignInt("isbase", "INDEX_ITEM_STORE", iIndex);
                    }
                }
            }
        }
    }
    
    OnModuleLoad: Load all items into the store
    void main()
    {
        string sRef;
        object oCreated;
        int i;
        object oStore = GetObjectByTag("EmptyStore");
        int iIndex = GetCampaignInt("isbase", "INDEX_ITEM_STORE");
        for(i = 0; i < iIndex; i++)
        {
            sRef = GetCampaignString("isbase", IntToString(i));
            if(sRef != "" && sRef != " ")
            {
                oCreated = CreateItemOnObject(sRef, oStore);
                // Mark what item needs to be removed from the DB when bought.
                SetLocalInt(oCreated, "index", i);
                SetIdentified(oCreated, TRUE);
                SetInfiniteFlag(oCreated, FALSE);
            }
        }
    }
    
    OnStoreClose: Refresh the database so that it doesn't have a bunch of blank entries.
    void main()
    {
        int iMax = GetCampaignInt("isbase", "INDEX_ITEM_STORE");
        int iIndex = 0;
        string sRef;
        int i;
        for(i = 0; i < iMax; i++)
        {
            sRef = GetCampaignString("isbase", IntToString(i));
            if(sRef != "" && sRef != " ")
            {
                SetCampaignString("isbase", IntToString(iIndex), sRef);
                iIndex++;
            }
        }
        int j;
        for(j = iIndex; j <= iMax; j++)
        {
            SetCampaignString("isbase", IntToString(j), " ");
        }
        SetCampaignInt("isbase", "INDEX_ITEM_STORE", iIndex);
    }
    

    It's a little more complicated than I thought it would be. Please ask if you need anything explained. I kind of started to, then stopped when it got super long.
    Be sure to change all the names of things like tags and the database if you wish.

    There is one issue I don't know how to account for right now: If a player drops an item and picks it back up, it will add it to the store. I could make it so that it won't if they pick it up off the floor, but not if they put it in a chest and take it back out.
  • BuddywarriorBuddywarrior Member Posts: 62
    I'll have to try it on a different computer. My work one keeps asking me to enter a Player Name and the server keeps refusing it. But I'm excited to try it. It looks pretty straight forward to me. I'll keep you posted.
Sign In or Register to comment.