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

Low Priority Small crew can never consume last rum and food

Tingyun

Corsair
Storm Modder
I have 1 food, 1 rum, and in testing the permanency of maltese HP boost, I let three months run by at sea. My crew of 3 reported every single day that they had the same amount of days left (33 of food, 66 of rum), and never ran out even after 3 months.

I imagine this might be an issue when a crew is small enough it doesn't consume a unit in a single day? Not sure how high priority this is, but wanted to report it.
 
do you have a savegame where this is the case?
 
Sure! My maltese abuse saved game is perfect for this: Balancing needed: Maltese crypt, 1000 player HP and a couple of hundred thousand gold per hour | PiratesAhoy!

Load it up, it is saved right after I spent three months just accelerating time on the world map to make sure the HP boost is permanent. The entire time, I was getting messages saying 33 days left food, 66 days left rum, every day, for 3 months. ;)

You can also immediatlly step back onto the ship, go to the world map, and accelerate time, and you'll see the same.

3 crew, 1 food, 1 rum.

I tested on world map mostly, but I think the same also happened direct sail, as I let s few days pass there.
 
Does the F2> Ship> Crew interface tell you the total rum consumption per day?
This is probably a very low number indeed, smaller than zero.

It should also tell you how many more days you've still got left.
 
F2> Ship> Crew interface doesn't tell me amount per day, but it does give me how long it lasts.

Food is 33 days, rum is 66 days.

I also get a message saying that much is left, whenever any day passes (so on the world map, with accelerated time, I will be spammed with messages saying 33 days of food left, 66 days of rum, covering the left upper part of the screen)
 
Relevant file is PROGRAM\WorldMap\DailyCrewUpdate.c, look for "Food & Rum system".
 
Found it, but rather confused by it. ;) Also, it seems to repeat twice?

//JA 1Dec06 reworked Food & Rum system -->
//food
int foodQ = GetSquadronGoods(pchar, GOOD_WHEAT);
float foodRatio[4];
int ft[4];
ft[0]=0; ft[1] = 0; ft[2]=0; ft[3]=0;
float foodused = 0;
if(CheckFood) foodused = makefloat(crewQ) * FOOD_PER_CREW;
float foodusedtemp = 0.0;
if(CheckAttribute(pchar,"Crewstatus.foodused"))
{ //Add leftover food requirement from yesterday.
if(CheckFood) { foodusedtemp = foodusedtemp + stf(pchar.Crewstatus.foodused); }
pchar.Crewstatus.foodused = 0.0;
}
int foodrations = 1; //this is a divisor
if(CheckAttribute(pchar,"Crewstatus.foodrations")) foodrations = sti(pchar.Crewstatus.foodrations);
int food_daysleft = 999;

float rationedFoodConsumption;
if(foodused==0) rationedFoodConsumption = 1; // avoid divide by zero
else
{
rationedFoodConsumption = foodused / makefloat(foodrations);
//Add by levis for cooking perk:
if(CheckCharacterPerk(pchar, "Cooking")) rationedFoodConsumption = rationedFoodConsumption*0.9;
}
if(CheckFood) food_daysleft = makeint((makefloat(foodQ) - foodusedtemp) / rationedFoodConsumption);

if(CheckFood) { if((makefloat(foodQ) - foodusedtemp) / rationedFoodConsumption < 1) { food_daysleft = 0; } }

int daysnofood = 0;
if(CheckFood) { if(CheckAttribute(pchar, "Crewstatus.daysnofood")) { daysnofood = sti(pchar.Crewstatus.daysnofood); } }

if(food_daysleft < 8 && food_daysleft > 0 && LogsToggle >= LOG_NORMAL) Log_SetStringToLog(TranslateString("","Captain, we have only") + " " + food_daysleft + " " + TranslateString("","days worth of food left!"));
// KK if(food_daysleft == 0 && LogsToggle > LOG_QUIET) Log_SetStringToLog(TranslateString("","Captain, we're out of food!"));

//fill foodratio so we can track what ship had what food later.
int iMostFoodShip = 0; //JA find the ship with the most food on it for handling special low food case later
if(CheckFood && foodQ) // NK 04-09-09 divbyzero error fix
{
float iHighestFoodRatio = 0; //JA Need this to handle special case.
for(i=0; i<COMPANION_MAX; i++)
{
cn = GetCompanionIndex(pchar,i);
if(cn!=-1) { // KK --> // PB: Included GetRemovable(GetCharacter(cn))
foodRatio = makefloat(GetCargoGoods(&Characters[cn],GOOD_WHEAT)) / makefloat(foodQ);
if(foodRatio > iHighestFoodRatio)
{
iHighestFoodRatio = foodRatio;
iMostFoodShip = i;
}
}// <-- KK
}
}

//rum
int rumQ = GetSquadronGoods(pchar, GOOD_RUM);
float rumRatio[4];
int rt[4];
rt[0]=0; rt[1] = 0; rt[2]=0; rt[3]=0;
float rumused = 0;
if(CheckFood) rumused = makefloat(crewQ) * FOOD_PER_CREW;
float rumusedtemp = 0.0;
if(CheckAttribute(pchar,"Crewstatus.rumused")) //Handle left over rum fraction used from yesterday.
{
if(CheckFood) { rumusedtemp = rumusedtemp + stf(pchar.Crewstatus.rumused); }
pchar.Crewstatus.rumused = 0.0;
}
int rumrations = 2; //this is a divisor
if(CheckAttribute(pchar,"Crewstatus.rumrations")) rumrations = sti(pchar.Crewstatus.rumrations);
int rum_daysleft = 999;

float rationedRumConsumption;
if(rumused==0) rationedRumConsumption = 1;
else rationedRumConsumption = rumused / makefloat(rumrations);
if(CheckFood) rum_daysleft = makeint((makefloat(rumQ) - rumusedtemp) / rationedRumConsumption);

// --> Swindler 05-10-10: fix for divide by zero error
if (rumused > 0 && (makefloat(rumQ) - rumusedtemp) / rationedRumConsumption < 1) { rum_daysleft = 0; }
// Swindler <--

if(rum_daysleft < 8 && rum_daysleft > 0 && LogsToggle >= LOG_NORMAL) Log_SetStringToLog(TranslateString("","Captain, we have only") + " " + rum_daysleft + " " + TranslateString("","days worth of rum left!"));
// KK if(rum_daysleft == 0 && LogsToggle > LOG_QUIET) Log_SetStringToLog(TranslateString("","Captain, we're out of rum!"));

int rum2chance = RUM_BASECH + ((skillLead/2 + skillLuck/2) * (PerkIron + 0.5));

//fill rumratio so we can track what ship had what rum later.
int iMostRumShip = 0; //JA find the ship with the most rum on it for handling special low rum case later
if(CheckFood && rumQ) // NK 04-09-09 divbyzero error fix
{
float iHighestRumRatio = 0; //JA Need this to handle special case.
for(i=0; i<COMPANION_MAX; i++)
{
cn = GetCompanionIndex(pchar,i);
if(cn!=-1) { // KK --> // PB: Included GetRemovable(GetCharacter(cn))
rumRatio = makefloat(GetCargoGoods(&Characters[cn],GOOD_RUM)) / makefloat(rumQ);
if(rumRatio > iHighestRumRatio)
{
iHighestRumRatio = rumRatio;
iMostRumShip = i;
}
} // <-- KK
}
}


//check food and deal with it.
if(CheckFood)
{
foodusedtemp = foodusedtemp + rationedFoodConsumption; //Get total food to be eaten today

//Handle fractional food requiements.
//ignore small leftover food fractions
if (round(foodusedtemp) - foodusedtemp <= 0.05 && round(foodusedtemp) - foodusedtemp >= -0.05) {
foodusedtemp = round(foodusedtemp);
}
else //add extra food fraction to next day's food, and round down todays food.
{
pchar.Crewstatus.foodused = foodusedtemp - makefloat(makeint(foodusedtemp));
foodusedtemp = makeint(foodusedtemp);
}
//Remove eaten food from total quantity

foodQ = foodQ - foodusedtemp;

if(foodQ <= 0)
{
foodQ = 0;
pchar.Crewstatus.foodused = 0.0;
}

//divide remaining food back into ships
for(i=0; i<COMPANION_MAX; i++)
{
cn = GetCompanionIndex(pchar,i);
if(cn!=-1) ft = makeint(makefloat(foodQ)*foodRatio);
}
if(ft[0]+ft[1]+ft[2]+ft[3] == 0 && foodQ > 0) //handle special case of trying to divide 1 or two food between a few ships
{
ft[iMostFoodShip] = 1; //put last remaining food on this ship;
}

// PB: Start at a different number each time to evenly distribute consumption
if (CheckAttribute(pchar, "Crewstatus.foodlastship"))
{
j = sti(pchar.Crewstatus.foodlastship) + 1;
if (j >= 4) j = 0;
}
else
{
j = 0;
}
pchar.Crewstatus.foodlastship = j;

//if food doesn't divide evenly:
while(ft[0]+ft[1]+ft[2]+ft[3] != foodQ)
{
for(i=0; i<4; i++)
{
j = i + sti(pchar.Crewstatus.foodlastship);
if (j >= 4) j -= 4;
if (ft[j] > 0) //Ship had food
{
if(ft[0]+ft[1]+ft[2]+ft[3] > foodQ) //too much food allocated, so remove some
{
ft[j]--;
}
if(ft[0]+ft[1]+ft[2]+ft[3] < foodQ) //not enough food allocated, so add some
{
ft[j]++;
}
}
}
}
//JA <-- 1Dec06 reworked Food & Rum system

for(i=0; i<COMPANION_MAX; i++)
{
cn = GetCompanionIndex(pchar,i);
if(cn!=-1) SetCharacterGoods(&Characters[cn],GOOD_WHEAT, ft);
}
if(LogsToggle > LOG_QUIET)
{
if (foodQ <= 0)
Log_SetStringToLog(TranslateString("","Captain, we're out of food!"));
else
Log_SetStringToLog(TranslateString("","Food Qty") + ": " + makeint(foodQ) + ", " + TranslateString("","good for") + " " + food_daysleft + " " + XI_ConvertString("days."));
}
if(foodQ <= 0)
{
daysnofood++;
moralescale = moralescale * (FOOD0_SCALE/(pow(daysnofood,1.25)/2));
float tempdie = 1 - ((pow(daysnofood,1.5) + frand(pow(daysnofood,1.5)))/4.0 * FOOD_CREWDIEOFF * (1.0-(FRAND(skillLuck)/30.0)));
if(tempdie < 0) tempdie = 0.0;
if(GetCrewQuantity(pchar) <= makeint(makefloat(GetMaxCrewQuantity(pchar)) / 4.0)) KAM_Mutiny(); //MAXIMUS: new "Mutiny"
// KK -->
for (i = 1; i < COMPANION_MAX; i++)
{
cn = GetCompanionIndex(pchar, i);
if (cn < 0) continue;
chref = GetCharacter(cn);
if (IsMutineer(chref) == false && GetCrewQuantity(chref) <= makeint(makefloat(GetMaxCrewQuantity(chref)) / 4.0)) {
SetMutineer(chref, true);
bCompanionMutiny = true;
}
}
// <-- KK
//Log_SetStringToLog("Dieratio: " + tempdie);
//Log_SetStringToLog("No food! Scale down to " + moralescale);
string tempded = GetSquadronCrewQuantity(pchar) - SetSquadronCrewQuantityRatio(pchar, tempdie);
if(LogsToggle > LOG_QUIET)
{
if(tempded < 1) Log_SetStringToLog(TranslateString("","Captain, we're out of crew!"));
else Log_SetStringToLog("" + tempded + " " + TranslateString("","crew have died from starvation."));
}
}
else
{
daysnofood = 0;
if(foodrations == 2)
{
moralescale = moralescale * FOOD2_SCALE;
//Log_SetStringToLog("Scale down to " + moralescale);
}
}
}
pchar.Crewstatus.foodrations = foodrations;
pchar.Crewstatus.daysnofood = daysnofood;

//JA 1Dec06 reworked Food & Rum system -->
//check rum and deal with it.
if(CheckFood)
{
rumusedtemp = rumusedtemp + rationedRumConsumption; //JA: total rum used today and rest of yesterday

//Handle fractional rum requiements.
//ignore small leftover rum fractions
if(round(rumusedtemp) - rumusedtemp <= 0.05 && round(rumusedtemp) - rumusedtemp >= -0.05) rumusedtemp = round(rumusedtemp);
else //add extra rum fraction to next day's rum, and round down todays rum.
{
pchar.Crewstatus.rumused = rumusedtemp - makefloat(makeint(rumusedtemp));
rumusedtemp = makeint(rumusedtemp);
}
//Remove eaten rum from total quantity
rumQ = rumQ - rumusedtemp;

if(rumQ <= 0)
{
rumQ = 0;
pchar.Crewstatus.rumused = 0.0
}

//divide remaining rum back into ships
for(i=0; i<COMPANION_MAX; i++)
{
cn = GetCompanionIndex(pchar,i);
if(cn!=-1) rt = makeint(makefloat(rumQ)*rumRatio);
}

if(rt[0]+rt[1]+rt[2]+rt[3] == 0 && rumQ > 0) //handle special case of trying to divide 1 or two rum between a few ships
{
rt[iMostRumShip] = 1; //put last remaining rum on this ship;
}

// PB: Start at a different number each time to evenly distribute consumption
if (CheckAttribute(pchar, "Crewstatus.rumlastship"))
{
j = sti(pchar.Crewstatus.rumlastship) + 1;
if (j >= 4) j = 0;
}
else
{
j = 0;
}
pchar.Crewstatus.rumlastship = j;

//if rum doesn't divide evenly:
while(rt[0]+rt[1]+rt[2]+rt[3] != rumQ)
{
for(i=0; i<4; i++)
{
j = i + sti(pchar.Crewstatus.rumlastship);
if (j >= 4) j -= 4;
if (rt[j] > 0) //ship had rum
{
if(rt[0]+rt[1]+rt[2]+rt[3] > rumQ) //too much rum so remove one
{
rt[j]--;
}
if(rt[0]+rt[1]+rt[2]+rt[3] < rumQ) //not enough rum so add one
{
rt[j]++;
}
}
}
}
SetCharacterGoods(pchar, GOOD_RUM, rt[0]);
for(i=1; i<COMPANION_MAX; i++)
{
cn = GetCompanionIndex(pchar,i);
if(cn!=-1) SetCharacterGoods(&Characters[cn],GOOD_RUM, rt);
}

//JA <-- 1Dec06 reworked Food & Rum system

if(LogsToggle > LOG_QUIET)
{
if(rumQ <= 0) Log_SetStringToLog(TranslateString("","Captain, we're out of rum!"));
else Log_SetStringToLog(TranslateString("","Rum Qty") + ": " + makeint(rumQ) + ", " + TranslateString("","good for") + " " + rum_daysleft + " " + XI_ConvertString("days."));
}

if(rumQ <= 0)
{
moralescale = moralescale * RUM0_SCALE;
//Log_SetStringToLog("No rum! Scale down to " + moralescale);
}
else
{
if(rumrations == 1)
{
if(!rand(rum2chance))
{
Log_SetStringToLog(TranslateString("","Drunken brawl breaks out, morale plummets!")); // NK 05-03-19 added detail
moralech = moralech - RUMDEC * (2-moralemod); // PB: Corrected to prevent morale INCREASING when this happens
ResetTimeToNormal(); // PB: Slow down game to normal speed so you can deal with the situation
}
else
{
moralescale = moralescale * RUM_SCALE;
}
}
else
{
moralescale = moralescale * RUM2_SCALE;
}
}
}
 
Minor update:

Testing in game with 35 crew shows fractional values are correctly handled at that level (ie, each day the "days left" would go down properly by 1, even if the amount of goods stayed the same, and then after a couple of days the amoint of goods would go down).

So it only messes up for extremely low values of crew, and even a low but still reasonabke amount of crew works fine.
 
I wonder if the number becomes so low that it goes below the minimum fraction that a float can handle.
 
If that is the case, maybe it is not worth tracking down--I can't imagine many people are going to be sailing around with 3 crew. I was only doing so myself because I was specifically running quick tests for other bugs and needed time to pass.
 
Maybe we can do an if (consumption < 0.0001) consumption = 0.0001; or something like that?
 
Back
Top