• New Horizons on Maelstrom
    Maelstrom New Horizons


    Visit our website www.piratehorizons.com to quickly find download links for the newest versions of our New Horizons mods Beyond New Horizons and Maelstrom New Horizons!

Confirmed Bug Item traders having to much or to few goods and money

Just posting this here for referance.
This function is called from the dialog files when the item trading is asked for.
Code:
void GiveItemToTrader(ref ch)
{
    //trace("Gauging: NEXTDAY_start giveitem. Char " + ch.id + ", qual " + ch.itemtrade.quality);
    // unneeded ref pchar = GetMainCharacter();
    int chridx = sti(ch.index);
    if(chridx == GetMainCharacterIndex()) // 05-05-03 bugfix
    {
        trace("GIVING ItemTrade TO PCHAR! ERROR!");
        DeleteAttribute(GetMainCharacter(),"itemtrade");
        DeleteAttribute(&ShipLookupTable,"itemtraders."+Characters[GetMainCharacterIndex()].id);
        return;
    }
    ch = GetCharacter(chridx); // just to be sure

    //DeleteAttribute(ch, "items");
    bool givenew = false;
    string iDay, iMonth;
    iDay = environment.date.day;
    iMonth = environment.date.month;
    string lastspeak_date = iDay + " " + iMonth;
    //int iRDTSC;
    if(!CheckAttribute(ch, "items"))
    {
        givenew = true; // note a trader may have a sword/gun, thus meaning that this check will give true even when we haven't assigned items yet. So:
        trace("IT ch " + ch.id + " has no items tree");
    }
    else
    {
        if(CheckAttribute(ch, "quest.item_date")) // if we have this
        {
            if(ch.quest.item_date == "0") { givenew = true; } // if it's not set to a date, means we haven't assigned items.
        }
        else // we may not have item_date yet. If so, check quest.meeting
        {
            if(!CheckAttribute(ch,"quest.meeting") || ch.quest.meeting == "0") // we check this
            {
                givenew = true;
            }
            ch.quest.item_date = "0"; // assign something to item_date.
        }
    }
    if (!CheckAttribute(ch, "itemtrade.itemlist")) givenew = true;    // LDH 16Mar09
    //trace("Gauging: NEXTDAY_did checks");
    if(givenew) // do we decide to fill the trader or just update.
    {
        //trace("Gauging: NEXTDAY_givenew!!!");
        //trace("IT starting from scratch");
        if(!CheckAttribute(ch,"itemtrade.done")) // start from scratch
        {
            IT_AssignTypesToTrader(&ch); // will not do anything if types already assigned.
            SetTraderItemStats(&ch, IT_RECALC_ALL);
        }
        else
        {
            SetTraderItemStats(&ch, IT_RECALC_QL_TN);  // 05-04-17
        }
        GiveNewItemsToTrader(&ch);

        ch.quest.item_date = lastspeak_date;
    }
    else // i.e. we just do an update.
    {
        //trace("Gauging: NEXTDAY_decide to update");
        if(ch.quest.item_date != lastspeak_date)
        {
            int i, curqty, moneych;
            i = sti(ch.itemtrade.quality);
            if(i < IT_QUAL_MAX && CheckAttribute(ch, "itemtrade.numtimes") && sti(ch.itemtrade.numtimes) > i * 10) // quality update.
            {
                //trace("Gauging: NEXTDAY_increase quality start");
                ch.itemtrade.numtimes = 0;
                ch.itemtrade.quality = sti(ch.itemtrade.quality) + 1;
                SetTraderItemStats(&ch, IT_RECALC_QL_TN);
                moneych = sti(ch.money);
                // we need to update base money

                // new:
                aref itmtree1, itmtree2, itmtemp;

                ch.olditems = "";
                makearef(itmtemp, ch.olditems);         // create temp holder pointer
                makearef(itmtree1, ch.items);             // create pointer to items
                CopyAttributes(&itmtemp, &itmtree1);     // make backup // TIH '&' fix Aug28'06
                DeleteAttribute(ch, "items");             // clear for givenew

                GiveNewItemsToTrader(&ch);                 // give new

                DeleteAttribute(ch, "items");             // clear for return old
                ch.items = "";                             // clean items
                makearef(itmtree2, ch.items);            // create pointer to items
                CopyAttributes(&itmtree2, &itmtemp);     // copy old back // TIH '&' fix Aug28'06
                DeleteAttribute(ch, "olditems");        // clear old out

                /* old:
                aref itmtree, itmtemp;
                ch.olditems = ""; makearef(itmtemp, ch.olditems); makearef(itmtree, ch.items); // create old items tree
                CopyAttributes(itmtemp, itmtree); // and make backup
                DeleteAttribute(ch, "items"); // clear for givenew
                GiveNewItemsToTrader(&ch); // give new
                //off for now, we do a regular update for the new items.
                //makearef(itmtree, ch.items); ch.newitems = ""; makearef(itmtemp, ch.newitems); //make new items tree
                //CopyAttributes(itmtemp, itmtree); // make backup of new items
                DeleteAttribute(ch, "items");
                ch.items = ""; // clean items
                makearef(itmtemp, ch.olditems);
                CopyAttributes(itmtree, itmtemp); // copy old back
                DeleteAttribute(ch, "olditems");
                */

                ch.money = moneych; // restore old money.
                // *** maybe we add model changing code here, to visually show quality.
                //trace("Gauging: NEXTDAY_increase qual end");
                trace("IT "+ ch.id +" raised to level "+ ch.itemtrade.quality);
            }

            string id;
            ref itm;
            ch.itemtrade.update = true; // set up update

            aref itms; makearef(itms, ch.items);
            //list all items before update.
            //trace("Gauging: NEXTDAY_bef list all items first");
            for(i = 0; i < GetAttributesNum(itms); i++)
            {
                id = GetAttributeName(GetAttributeN(itms, i));
                ch.itemtrade.update.(id) = true;
            }
            //iRDTSC = RDTSC_B();
            //trace("Gauging: NEXTDAY_now actually givenewitems");
            GiveNewItemsToTrader(&ch);
            //trace("Gauging: NEXTDAY_finished givenewitems");
            moneych = 0;
            bool replace;
            makearef(itms, ch.itemtrade.update);
            for(i = 0; i < GetAttributesNum(itms); i++) // find items that haven't been dealt with yet. That means they are in the buyonly list (either via quality or skipsell).
            {
                id = GetAttributeName(GetAttributeN(itms, i));
                if (GetItemIndex(id) < 0) continue;        // LDH fix for bad items
                makeref(itm, Items[GetItemIndex(id)]);
                curqty = sti(GetAttributeValue(GetAttributeN(itms, i)));
                TakeNItems(&ch, id, -curqty);
                replace = CheckAttribute(itm, "replacewith");
                TakeNItems(&ch, id, -curqty);
                if(replace) // if possible, replace item.
                {
                    while(replace)
                    {
                        id = itm.replacewith;
                        makeref(itm, Items[GetItemIndex(id)]);
                        if(sti(itm.skipsell)) // if still can't sell
                        {
                            if(CheckAttribute(itm, "replacewith")) continue; // continue with replacing
                            else { replace = false; TakeNItems(&ch, id, curqty); break; } // else stop here and get money.
                        }
                        else { break; } // stop here if item not skipsell.
                    }
                }
                if(!replace) moneych += curqty * GetItemPriceTrader(&ch, id); // otherwise ditch item and get the money back.
            }
            DeleteAttribute(ch, "itemtrade.update");
            //trace("Gauging: NEXTDAY_done it.update list");
            AddMoneyToCharacter(&ch, moneych);
            // now do money vs. town, base.
            moneych = makeint(stf(ch.itemtrade.basemoney) * GetTownItemPrice(GetTownFromID(GetTownIDFromLocID(ch.location)), ""));
            moneych = makeint((moneych - GetCharacterMoney(&ch)) * IT_UPD_MONEYCHANGER);
            AddMoneyToCharacter(&ch, moneych);

            ch.quest.item_date = lastspeak_date;
        }
    }
    //trace("====================================================");
    //trace("Setup Item Trader: "+ch.id);
    //DumpAttributes(ch);
    //trace("====================================================");
    //trace("Gauging: NEXTDAY_done giveitem");

    if (ENABLE_AMMOMOD)        // LDH skip ammo if mod disabled
    {
        //JRH -->
        if(CheckCharacterItem(ch, "gunpowder") > 0) TakeNItems(ch,"gunpowder", -100);
        if(CheckCharacterItem(ch, "pistolbullets") > 0)    TakeNItems(ch,"pistolbullets", -100);
        if(CheckCharacterItem(ch, "pistolgrapes") > 0)    TakeNItems(ch,"pistolgrapes", -100);
        if(CheckCharacterItem(ch, "musketbullets") > 0)    TakeNItems(ch,"musketbullets", -100);
        if(CheckCharacterItem(ch, "powderflask") > 0) TakeNItems(ch,"powderflask", -100);
        if(CheckCharacterItem(ch, "ammopouch") > 0)    TakeNItems(ch,"ammopouch", -100);

        ref pchar = GetMainCharacter();
        int ra;
        int ra1;
        int ra2;
        int ra4;
        int ra8;
        int ra16;
        float ff;

        if(CheckAttribute(pchar, "rank"))
        {
            ra = stf(pchar.rank);
            if(ra > 16)
            {
                ra = 16;
            }
        }

        ff = 1.0;            //change here only
        ra1 = ff*ra;
        ra2 = round(0.5*ra1);
        ra4 = round(0.25*ra1);
        ra8 = round(0.125*ra1);
        ra16 = round(0.0625*ra1);

        if(ch.itemtrade.tradetype == IT_TYPE_STALL || ch.itemtrade.tradetype == IT_TYPE_GENERAL || ch.itemtrade.tradetype == IT_TYPE_STORE)
        {
            TakeNItems(ch,"gunpowder", ra2 + rand(ra2) );
            TakeNItems(ch,"pistolbullets", ra2 + rand(ra2) );
            TakeNItems(ch,"pistolgrapes", ra2 + rand(ra2) );
            TakeNItems(ch,"musketbullets", ra4 + rand(ra4) );

            if(rand(100)<20) TakeNItems(ch,"powderflask", 1);
            if(rand(100)<20) TakeNItems(ch,"ammopouch", 1 );    //test available from start JRH
        }
       
        if(sti(GetStorylineVar(FindCurrentStoryline(), "BUG_PUZZLES")) > 0)
        {
            TakeNItems(ch,"spyglass1", -100);
            TakeNItems(ch,"spyglass2", -100);
            TakeNItems(ch,"spyglass3", -100);
            TakeNItems(ch,"spyglass4", -100);
            TakeNItems(ch,"compass1", -100);
            TakeNItems(ch,"compass2", -100);
            TakeNItems(ch,"compass3", -100);
            TakeNItems(ch,"sextant", -100);
            TakeNItems(ch,"Minerscrow", -100);
            TakeNItems(ch,"Minerspick", -100);
            TakeNItems(ch,"Minersspade", -100);   
            TakeNItems(ch,"gunpowder", -100);
            TakeNItems(ch,"pistolbullets", -100);
            TakeNItems(ch,"musketbullets", -100);               
            TakeNItems(ch,"pistolgrapes", -100);
        }
        //JRH <--
    }
}
 
First few problems I spot:
Code:
if(!CheckAttribute(ch, "items"))
    {
        givenew = true; // note a trader may have a sword/gun, thus meaning that this check will give true even when we haven't assigned items yet. So:
        trace("IT ch " + ch.id + " has no items tree");
    }
    else
    {
This will never be true, it will always go into the else case.
Code:
if (!CheckAttribute(ch, "itemtrade.itemlist")) givenew = true;    // LDH 16Mar09
There seems to be an itemlist and itemslist, and both are used on different places, but from what I see they should be the same, so I'm afraid there is a typo somewhere which prevents this from working properly and updating an itemtraders items way to often.
 
Isn't 'ch.items' the stuff the character personally has, while 'ch.itemtrade.itemlist' is the stuff for sale?
 
I'm not 100% sure. To really figure it out someone has to add a lot of debug code and see what is exactly happening.
 
It has been like this forever. Currently it affects the Buccaneer Camp on Hispaniola as one can only buy/sell cargo there.
 
It has been like this forever. Currently it affects the Buccaneer Camp on Hispaniola as one can only buy/sell cargo there.
:( :( :(

I think all towns should have a "port" though, which in the came of the Camp should be the closest shore.
So if you drop anchor at that shore, maybe they do have items there...?
 
How is the port associated with the store?

I'll need to check - or perhaps someone can confirm - whether you can land at Nevis Pirate Settlement port (whose ID is "QC_port") and then buy items from the Pirate Settlement store. Possibly the "townsack" line? "QC_Port" has one:
Code:
Locations[n].townsack = "Quebradas Costillas";
But Boca de Hubon, alias "Hispaniola_shore_02", has no such line.
 
How is the port associated with the store?
It is associated with the town, so I think it is in towns_init.c (or maybe islands_init.c).

I have some faint memory of doing something with that to get the "Ship Escort Quests" to work also for those small, secret smuggling/pirate villages.
 
Hmm... In "InitTowns.c", for "Quebradas Costillas" (in the context of towns, that's Pirate Settlement):
Code:
   ctown.boarding.l1 = "QC_port";
   ctown.boarding.l2 = "QC_town_exit";
   ctown.boarding.l3 = "QC_town";
And for "Buccaneers Camp":
Code:
   ctown.boarding.l1 = "Hispaniola_shore_02";
   ctown.boarding.l2 = "Buccaneers_Camp";
I've no idea of the mechanism, but it looks as though where the port doesn't lead straight to the town, those "ctown.boarding" lines show the route you take to get there. If so, the list for "Buccaneers Camp" is incomplete, because there are two jungle locations between Boca de Hubon and Buccaneers Camp. So I'll need to see what happens if I change the lines for "Buccaneers Camp" to this:
Code:
   ctown.boarding.l1 = "Hispaniola_shore_02";
   ctown.boarding.l2 = "Hispaniola_Jungle_02";
   ctown.boarding.l3 = "Hispaniola_Jungle_03";
   ctown.boarding.l4 = "Buccaneers_Camp";
Incidentally, this probably also explains why traders aren't properly set up if you enter a town from the beach. The town's "ctown.boarding" lines will list the town's main port.
 
Those lines are only for the Town Capture progression. I think there is something else to define the port that goes with a town.
 
Back
Top