• 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!

Cargo Capacity Problem on Small Ships

So we have now found out that this bug is the very same as the notorious "midnight bug" and I think we should come up with a proper solution for this one. This solution should include:
1) Prevention of cargo space over-up (probably by simply making it so you can't load more than you can)
2) Making sure that all ships can carry at least the cargo they need to (as bought by auto-buy)
 
How about adding some code like this in ships_init.c that will be run for each and every ship when it is being initialized?<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->        for(i=0;i<GOODS_QUANTITY;i++)
        {
            int minCap = 0;
            if(i == GOOD_WHEAT && FOOD_ON)
            {
                minCap = sti(minCap) + 1+makeint(makefloat(refShip.MaxCrew) * FOOD_PER_CREW * WHEAT_DAYS);
            }
            if(i == GOOD_RUM && FOOD_ON)
            {
                minCap = sti(minCap) + 1+makeint(makefloat(refShip.MaxCrew) * FOOD_PER_CREW * RUM_DAYS);
            }
            if(i == GOOD_GUNPOWDER && CANNONPOWDER_MOD && refShip.CannonsQuantity > 0)
            {
                ref rCannon; makeref(rCannon,Cannon[refShip.Cannon]);
                int needPwdr = 0;
                float averageQty = 0.0;
                if (USE_REAL_CANNONS)     { averageQty = makefloat(makeint(refShip.CannonsQuantity) * BALLS_PER + makeint(refShip.CannonsQuantity) * GRAPE_PER) + makeint(refShip.CannonsQuantity) * CHAIN_PER))/3; }
                else                     { averageQty = makefloat(makeint(refShip.CannonsQuantity) * BALLS_PER + makeint(refShip.CannonsQuantity) * GRAPE_PER) + makeint(refShip.CannonsQuantity) * CHAIN_PER) + makeint(refShip.CannonsQuantity) * BOMBS_PER))/4; }
                float canCharge = makefloat(averageQty/makefloat(refShip.CannonsQuantity));
                if(CheckAttribute(rCannon,"gunpowder")) needPwdr = sti(rCannon.gunpowder);
                minCap = sti(minCap) + makeint(refShip.CannonsQuantity) * needPwdr * canCharge) + (makefloat(refShip.MaxCrew) * 3));
            }
            if(i == GOOD_BALLS)
            {
                minCap = sti(minCap) + makeint(refShip.CannonsQuantity) * BALLS_PER);
            }
            if(i == GOOD_GRAPES)
            {
                minCap = sti(minCap) + makeint(refShip.CannonsQuantity) * GRAPE_PER);
            }
            if(i == GOOD_KNIPPELS)
            {
                minCap = sti(minCap) + makeint(refShip.CannonsQuantity) * CHAIN_PER);
            }
            if(i == GOOD_BOMBS && USE_REAL_CANNONS)
            {
                minCap = sti(minCap) + makeint(refShip.CannonsQuantity) * BOMBS_PER);
            }
            if(i == GOOD_SAILCLOTH)
            {
                minCap = sti(minCap) + makeint(refShip.HP) * SAIL_PER);
            }
            if(i == GOOD_PLANKS)
            {
                minCap = sti(minCap) + makeint(refShip.HP) * PLANKS_PER);
            }
        }
        if(minCap > refShip.Capacity) refShip.Capacity = minCap;<!--c2--></div><!--ec2-->
I haven't tested this yet. But the idea is that if auto-buy would buy more by default than the capacity of the ship, then the capacity of the ship should be the amount required by auto-buy. That could ensure that no ship can ever be overloaded by auto-buy, because every ship could hold the cargo required by auto-buy. This would also ensure that the capacity is set to a reasonable amount for all ships, even if somebody set refShip.Capacity = 0.
 
<!--quoteo(post=222987:date=Nov 24 2007, 10:33 AM:name=Pieter Boelen)--><div class='quotetop'>QUOTE(Pieter Boelen @ Nov 24 2007, 10:33 AM) [snapback]222987[/snapback]</div><div class='quotemain'><!--quotec-->How about adding some code like this in ships_init.c that will be run for each and every ship when it is being initialized?

I haven't tested this yet. But the idea is that if auto-buy would buy more by default than the capacity of the ship, then the capacity of the ship should be the amount required by auto-buy. That could ensure that no ship can ever be overloaded by auto-buy, because every ship could hold the cargo required by auto-buy. This would also ensure that the capacity is set to a reasonable amount for all ships, even if somebody set refShip.Capacity = 0.<!--QuoteEnd--></div><!--QuoteEEnd-->

If that's the way you want to do it, that should work. The real fix for refShip.Capacity = 0 is to make people set their ship stats properly.

It should be possible to have a ship that had very little cargo room. This means you'd have to give up something. Instead of sailing out with a year's supply of provisions, ammo and repair materials, cut the amount back to reasonable numbers. You may end up with a ship that had room for a couple of weeks provisions, some ammo, and little else.

Anyway, didn't we fix the over cargo bugs a long time ago? <img src="style_emoticons/<#EMO_DIR#>/biggrin.gif" style="vertical-align:middle" emoid=":D" border="0" alt="biggrin.gif" />

Hook
 
Apparently we didn't, because it's plaguing us still. On some ships it is possible to get the cargo over-up problem just by performing an auto-buy. So if the ship simply cannot hold that amount, there is two options: 1) make sure the ship CAN hold that amount or 2) make sure the auto-buy doesn't buy more than the ship can hold. Option 2 might be getting pretty complicated, so I thought to try option 1. Originally the capacities were set properly, but it seems that with the introduction of new goods (gunpowder?) that now the ships need more capacity than they were given. So we could increase the capacities of all the ships, which would be a lot of work and would not ensure that this problem doesn't occur again, or we can try what I propose. I'm not sure if my code would actually work though. I came up with it in five minutes and didn't check it one bit. <img src="style_emoticons/<#EMO_DIR#>/unsure.gif" style="vertical-align:middle" emoid=":?" border="0" alt="unsure.gif" />

Another problem that was reported was that a scripted trading quest (Vigila Mendez I think it was) caused a cargo over-up.
 
I doubt it as well. Might be a possibility though. <img src="style_emoticons/<#EMO_DIR#>/dunno.gif" style="vertical-align:middle" emoid=":shrug" border="0" alt="dunno.gif" />
 
yeah, to quote myself, you can expect anything with these mods. meanwhile, good to see hookey again. <img src="style_emoticons/<#EMO_DIR#>/smile2.gif" style="vertical-align:middle" emoid=":))" border="0" alt="smile2.gif" />
 
<!--quoteo(post=223021:date=Nov 24 2007, 01:25 PM:name=Pieter Boelen)--><div class='quotetop'>QUOTE(Pieter Boelen @ Nov 24 2007, 01:25 PM) [snapback]223021[/snapback]</div><div class='quotemain'><!--quotec-->2) make sure the auto-buy doesn't buy more than the ship can hold. Option 2 might be getting pretty complicated...<!--QuoteEnd--></div><!--QuoteEEnd-->

There's probably no really good way to solve this problem. But as long as all ships have reasonable cargo limits, numbers of guns and crew, etc, and as long as people don't try setting the default autobuy loads too high, it should work.

Two ways to solve it that I can think of off the top of my head:

1) Calculate the amount room the full autobuy would use, then if it's more than you can hold, cut everything back by the percentage over. For example, if you need to buy 30 days food, but can only hold half the cargo you need, cut the food back to 15 days. Do the same with all the different autobuy cargo goods.

2) Start buying cargo in the order specified above (food, ammo, repairs) until you run out of room. You may not get all the repair goods you need in a case like this, and in extreme cases you won't get a full load of ammo.

For generated enemy ships, either way should work, assuming they use the autobuy code.

If I remember right, the last thing you want to do during any kind of a trade mission is to use autobuy. If a scripted trade mission requires more room than you have, either dump some cargo starting with repair goods, then ammo until you have enough room, or tell the player they need X amount of cargo space and they need to free up some before continuing.

Hook
 
Thanks a lot. Seems this is getting a bit too complicated for me though. I'm not as brilliant with the code as most of our programmers are. I think I should ask Pirate_KK or Maximus to have a look at this. <img src="style_emoticons/<#EMO_DIR#>/unsure.gif" style="vertical-align:middle" emoid=":?" border="0" alt="unsure.gif" />
 
i think it should be 20 days. it takes approx. 18 days to go from the furthest end of the archipelago to the other using the worldmap.
 
For that you can just set WHEAT_DAYS and RUM_DAYS to 20. Wouldn't really solve our problem though. <img src="style_emoticons/<#EMO_DIR#>/unsure.gif" style="vertical-align:middle" emoid=":?" border="0" alt="unsure.gif" />
 
As long as ships all have reasonable parameters, and as long as the autobuy settings are within reasonable limits, this problem should never come up. If someone wants to edit his ship to sail out with 5000 crew, he'll have to turn off food.

Another solution is to disable autobuy for any ship that doesn't have enough cargo room for the standard autobuy load and let the player buy stuff manually.

If it were me, I'd be fixing the ships. There's still a large "resource management" component to the game. At least there was last time I played. <img src="style_emoticons/<#EMO_DIR#>/smile.gif" style="vertical-align:middle" emoid=":)" border="0" alt="smile.gif" />

Hook
 
Then we'd need to figure out which ships have the problem and figure out better capacity values for them. Right? Wouldn't my above code proposition do that automatically? <img src="style_emoticons/<#EMO_DIR#>/unsure.gif" style="vertical-align:middle" emoid=":?" border="0" alt="unsure.gif" />
 
I've rewritten the GiveShip2Character code again and it finally seems to give normal cargo values after the supply and doesn't give a cargo over-up problem anymore. However, a problem does occur on such ships as the Gunboat that simply cannot hold all the supplies auto-buy is set to buy. It will then fill up the entire hold and skip all cargo that cannot be loaded. Unfortunately the game prioritizes ammunition over rations and rum. This results in the Gunboat never getting any rum when performing an auto-buy. Can anybody try that in their game? Just get a Gunboat, perform and auto-buy and see if you get any rum. Preferrably someone who is playing one of the more recent Build 14 Alpha versions.

This is the code I have now:<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->void GiveShip2Character(ref char, string shiptype, string shipname, int nat, bool hirecrew, bool getsupplies)
{
    char.ship.type = shiptype;
    char.ship.name = shipname;
    aref arship; makearef(arship, char.ship); DeleteAttribute(arship,"stats");
    SetRandomStatsToShip(arship, GetCharacterShipType(char), nat);
    ResetCannons(char);
    DeleteAttribute(&char,"ship.masts");
    ProcessSailRepair(&char,100.0);
    ProcessHullRepair(&char, 100.0);
    if(hirecrew || sti(GetCrewQuantity(&char)) > sti(GetMaxCrewQuantity(&char)))
    {
        SetCrewQuantity(&char, GetMaxCrewQuantity(&char));
    }
    if(getsupplies || sti(GetCargoLoad(&char)) > sti(GetCargoMaxSpace(&char)))
    {
        EmptyShip(char) // First remove all goods from the ship
        SupplyShip(char) // Then add them again
    }
}

void EmptyShip(ref char)
{
    int i;
    for(i=0;i<GOODS_QUANTITY;i++)
    {
        RemoveCharacterGoods(char,i,GetCargoGoods(char,i));
    //    string goodsName = Goods.name;
    //    char.Ship.Cargo.Goods.(goodsName) = 0;
    }
}

void SupplyShip(ref char)
{
    int i;
    for(i=0;i<GOODS_QUANTITY;i++)
    {
        int getQty = 0;
        if(i == GOOD_WHEAT && FOOD_ON)
        {
            getQty = 1+makeint(makefloat(GetCrewQuantity(&char)) * FOOD_PER_CREW * WHEAT_DAYS);
        }
        if(i == GOOD_RUM && FOOD_ON)
        {
            getQty = 1+makeint(makefloat(GetCrewQuantity(&char)) * FOOD_PER_CREW * RUM_DAYS);
        }
        if(i == GOOD_GUNPOWDER && CANNONPOWDER_MOD && GetMaxCannonQuantity(&char) > 0)
        {
            ref rCannon; makeref(rCannon,Cannon[GetCaracterShipCannonsType(&char)]);
            int needPwdr = 0;
            float averageQty = 0.0;
            if (USE_REAL_CANNONS)     { averageQty = makefloat(GetCargoGoods(&char,GOOD_BALLS) + GetCargoGoods(&char,GOOD_GRAPES) + GetCargoGoods(&char,GOOD_KNIPPELS))/3; }
            else                     { averageQty = makefloat(GetCargoGoods(&char,GOOD_BALLS) + GetCargoGoods(&char,GOOD_GRAPES) + GetCargoGoods(&char,GOOD_KNIPPELS) + GetCargoGoods(&char,GOOD_BOMBS))/4; }
            float canCharge = makefloat(averageQty/makefloat(GetMaxCannonQuantity(&char)));
            if(CheckAttribute(rCannon,"gunpowder")) needPwdr = sti(rCannon.gunpowder);
            getQty = makeint((makefloat(GetMaxCannonQuantity(&char)) * needPwdr * canCharge) + (makefloat(GetCrewQuantity(&char)) * 3));
        }
        if(i == GOOD_BALLS)
        {
            getQty = makeint(makefloat(GetMaxCannonQuantity(&char)) * BALLS_PER);
        }
        if(i == GOOD_GRAPES)
        {
            getQty = makeint(makefloat(GetMaxCannonQuantity(&char)) * GRAPE_PER);
        }
        if(i == GOOD_KNIPPELS)
        {
            getQty = makeint(makefloat(GetMaxCannonQuantity(&char)) * CHAIN_PER);
        }
        if(i == GOOD_BOMBS && USE_REAL_CANNONS)
        {
            getQty = makeint(makefloat(GetMaxCannonQuantity(&char)) * BOMBS_PER);
        }
        if(i == GOOD_SAILCLOTH)
        {
            getQty = makeint(makefloat(GetCharacterShipHP(&char)) * SAIL_PER);
        }
        if(i == GOOD_PLANKS)
        {
            getQty = makeint(makefloat(GetCharacterShipHP(&char)) * PLANKS_PER);
        }
        AddCharacterGoods(char, i, getQty); // Hopefully this will prevent cargo over-ups now
    }
}<!--c2--></div><!--ec2-->
 
So I wrote this function to calculate the required cargo space for a ship when performing an auto-buy:<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->int GetSupplyWeight(ref Ship)
{
    int i;
    int weight = 0;
    for(i=0;i<GOODS_QUANTITY;i++)
    {
        int getQty = 0;
        if(i == GOOD_WHEAT && FOOD_ON)
        {
            getQty = 1+makeint(makefloat(Ship.MaxCrew) * FOOD_PER_CREW * WHEAT_DAYS);
        }
        if(i == GOOD_RUM && FOOD_ON)
        {
            getQty = 1+makeint(makefloat(Ship.MaxCrew) * FOOD_PER_CREW * RUM_DAYS);
        }
        if(i == GOOD_GUNPOWDER && CANNONPOWDER_MOD && Ship.CannonsQuantity > 0)
        {
            ref rCannon; makeref(rCannon,Cannon[Ship.Cannon]);
            int needPwdr = 0;
            float averageQty = 0.0;
            if (USE_REAL_CANNONS)     { averageQty = makefloat(sti(Ship.CannonsQuantity) * BALLS_PER + sti(Ship.CannonsQuantity) * GRAPE_PER + sti(Ship.CannonsQuantity) * CHAIN_PER)/3; }
            else                     { averageQty = makefloat(sti(Ship.CannonsQuantity) * BALLS_PER + sti(Ship.CannonsQuantity) * GRAPE_PER + sti(Ship.CannonsQuantity) * CHAIN_PER + sti(Ship.CannonsQuantity) * BOMBS_PER)/4; }
            float canCharge = makefloat(averageQty/makefloat(Ship.CannonsQuantity));
            if(CheckAttribute(rCannon,"gunpowder")) needPwdr = sti(rCannon.gunpowder);
            getQty = makeint((makefloat(Ship.CannonsQuantity) * needPwdr * canCharge) + (makefloat(Ship.MaxCrew) * 3));
        }
        if(i == GOOD_BALLS)
        {
            getQty = makeint(makefloat(Ship.CannonsQuantity) * BALLS_PER);
        }
        if(i == GOOD_GRAPES)
        {
            getQty = makeint(makefloat(Ship.CannonsQuantity) * GRAPE_PER);
        }
        if(i == GOOD_KNIPPELS)
        {
            getQty = makeint(makefloat(Ship.CannonsQuantity) * CHAIN_PER);
        }
        if(i == GOOD_BOMBS && USE_REAL_CANNONS)
        {
            getQty = makeint(makefloat(Ship.CannonsQuantity) * BOMBS_PER);
        }
        if(i == GOOD_SAILCLOTH)
        {
            getQty = makeint(makefloat(Ship.HP) * SAIL_PER);
        }
        if(i == GOOD_PLANKS)
        {
            getQty = makeint(makefloat(Ship.HP) * PLANKS_PER);
        }
        weight = weight + GetGoodWeightByType(i,getQty);
    }
    return weight;
}<!--c2--></div><!--ec2-->
I then want it use in ships_init.c as such:<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->if(GetSupplyWeight(refShip)>sti(refShip.Capacity)) refShip.Capacity = GetSupplyWeight(refShip);<!--c2--></div><!--ec2-->
The idea is that this would ensure that all ships would be able to carry the cargo they would need to perform a proper auto-buy. However, this doesn't work for me, because this function requires the goods and cannons to already be initialized. So I added the ordinary intialization code above my check as such:<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->        if (LoadSegment("STORE\initGoods.c")) // PB: Need the goods first
        {
            InitGoods();
            UnloadSegment("STORE\initGoods.c");
        }
        if(LoadSegment("cannons\cannons_init.c")) // PB: And the cannons too
        {
            InitCannons();
            UnloadSegment("cannons\cannons_init.c");
        }<!--c2--></div><!--ec2-->
Now I'm getting "undeclared identifier" errors on InitGoods() and InitCannons(). <img src="style_emoticons/<#EMO_DIR#>/boom.gif" style="vertical-align:middle" emoid=":boom" border="0" alt="boom.gif" />

I am thinking I am going to abandon all this and just make sure that food and rum is supplied before the cannonballs so that you get the most important supplies first. GRRR! <img src="style_emoticons/<#EMO_DIR#>/modding.gif" style="vertical-align:middle" emoid=":modding" border="0" alt="modding.gif" />
 
So, now for a SIMPLE solution instead. <img src="style_emoticons/<#EMO_DIR#>/icon_mrgreen1.gif" style="vertical-align:middle" emoid=":cheeky" border="0" alt="icon_mrgreen1.gif" />

<!--sizeo:3--><span style="font-size:12pt;line-height:100%"><!--/sizeo--><i><b>QUESTION TO ALL:</b></i><!--sizec--></span><!--/sizec-->
Would you mind to have wheat and rum be the first goods in the goods lists in the game?

I think it would be a good idea to make food and rum be the first things bought by auto-buy, but it's using the order from goods.h:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->#define GOOD_BALLS        0
#define GOOD_GRAPES        1
#define GOOD_KNIPPELS        2
#define GOOD_BOMBS        3

#define GOOD_GUNPOWDER    4
#define GOOD_SAILCLOTH        5
#define GOOD_PLANKS        6
#define GOOD_WHEAT        7
#define GOOD_RUM        8<!--c2--></div><!--ec2-->
Simplest solution would be to set wheat and rum as goods #0 and #1.
 
<!--quoteo(post=232245:date=Jan 5 2008, 02:26 PM:name=Pieter Boelen)--><div class='quotetop'>QUOTE(Pieter Boelen @ Jan 5 2008, 02:26 PM) [snapback]232245[/snapback]</div><div class='quotemain'><!--quotec-->So, now for a SIMPLE solution instead. <img src="style_emoticons/<#EMO_DIR#>/icon_mrgreen1.gif" style="vertical-align:middle" emoid=":cheeky" border="0" alt="icon_mrgreen1.gif" />

<!--sizeo:3--><span style="font-size:12pt;line-height:100%"><!--/sizeo--><i><b>QUESTION TO ALL:</b></i><!--sizec--></span><!--/sizec-->
Would you mind to have wheat and rum be the first goods in the goods lists in the game?

I think it would be a good idea to make food and rum be the first things bought by auto-buy, but it's using the order from goods.h:
[codeSimplest solution would be to set wheat and rum as goods #0 and #1.<!--QuoteEnd--></div><!--QuoteEEnd-->

You mean like this?<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->#define GOOD_WHEAT        0
#define GOOD_RUM            1

#define GOOD_BALLS            2
#define GOOD_GRAPES        3
#define GOOD_KNIPPELS        4
#define GOOD_BOMBS        5
#define GOOD_GUNPOWDER        6

#define GOOD_SAILCLOTH        7
#define GOOD_PLANKS        8<!--c2--></div><!--ec2-->
 
<!--quoteo(post=232245:date=Jan 5 2008, 08:26 PM:name=Pieter Boelen)--><div class='quotetop'>QUOTE(Pieter Boelen @ Jan 5 2008, 08:26 PM) [snapback]232245[/snapback]</div><div class='quotemain'><!--quotec-->Simplest solution would be to set wheat and rum as goods #0 and #1.<!--QuoteEnd--></div><!--QuoteEEnd-->
I think that starting from loading of food and rum is more logical - people would prefer to take care for their needs in the first place, and aren't so desperate to feed the cannons instead of them for any cost...

pirate_kk
 
Back
Top