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

Fixed No salary screen when skip past paydate

jsv

Freebooter
Storm Modder
My current game (in beta 4 from 29 Nov) was started on December 2nd and I've used 2-12-1700 as in-game starting date as well. Now it's mid-January in the game and nobody yet has asked for salary. My officers say I owe ~8000 to the crew (which seems off, as my crew's monthly salary is only about 2000, but that's a different issue). All I've done in the game was some trading, little smuggling, and running away from pirates. No piracy, no signing articles, no crimes against humanity. No worldmap either, it's an Ironman/Swashbuckler game.

I've checked the value of the LastPayMonth attribute, it is 1 so the game does think I've already paid in January. That's confusing, as the only place where LastPayMonth could have been updated seems to be here (DoDailyUpdates in calendar.c):

Code:
if(!CheckAttribute(PChar,"LastPayMonth"))    PChar.LastPayMonth = GetDataMonth(); // PB: NOT at the beginning of the game
// KK -->
        if(!LAi_IsFightMode(PChar)) //Don't show while in a battle
        {
            if( sti(PChar.LastPayMonth) != GetDataMonth() )
            {
                //if( GetDataDay() >= 7 && !sti(PChar.articles) ) //Can be triggered every day of the month in case you had a large cargo shift or something like that.
                //{
                if(!sti(PChar.articles)) //Check for articles -Levis
                {
                    PChar.LastPayMonth = GetDataMonth();
                    LaunchSalaryScreen();
                }
                //}
            }
        }
I don't really get how LastPayMonth ended up being set to 1 without me seeing that Salary Screen. There are ways, of course, like LastPayMonth being stipped somewhere before the check or CalcSquadronPayment returning zero to LaunchSalaryScreen, but they do not seem very likely. Unfortunately I do not have saves from in-game December.

For now I've called LaunchSalaryScreen from the console... let's see what will happen in February.
 
There was an issue before where the screen asking for payment DID open but for some reason would be automatically closed right after and you'd hardly get to see it at all.
When that happened, you indeed wouldn't pay, but the crew would remember you owe them the money and ask for it next time again.
And Morale would drop because you skipped paying.

I think you can check if that is the case from the value of PayOwed somewhere.
 
That's probably what had happened, although I haven't noticed any morale drop... I'll monitor all this salary thing closely for a while. :)
 
Well, it's February in the game and there are definitely some problems. Here is what I've discovered so far.

  • Transition from 31 Jan to 1 Feb at sea: no salary dialog, because at this point GetDataMonth() still returns 1 even if it's 00:10 already.
  • After that, still at sea, transition from 1 Feb to 2 Feb. I finally asked to pay the salary.
  • But the above was during testing. In the actual game I was unloading cargo from 29 Jan for 5 days. After closing the store dialog, there is a loooooong delay while DoDailyUpdates is called 5 times. There is a call to LaunchSalaryScreen() from the fourth of them, but no actual salary dialog is shown. No further attempts this month, as LastPayMonth is already updated.
 
Last edited:
I wonder why the salarayscreen actually closes...
can you find anything in DoDailyUpdates which makes the screen close?
 
Not at first glance. It doesn't do much itself, just calls a bunch of other functions. An obvious recent addition there is your UpdateAllIslandSmuggling, but I do not see why it should close anything...
 
Additional observation: when spending a payday (paynight?) in a tavern, the salary screen actually appears on the screen, but it's immediately closed and you get transferred to your room before you have a chance to pay.
In comparison, when skipping paydate by unloading cargo in a shop, the salary screen never becomes visible (although the function does get called).
If the salary screen gets called while travelling on the worldmap, it works as it should.
 
If the salary screen gets called while travelling on the worldmap, it works as it should.

On the World Map is the only place I have ever seen the Salary screen - never had it at any other time as far as I can remember in Build 14.

:cheers
 
Not even 3D Sailing Mode? Thought it did work there.

Thanks for the extra details, gents! :doff
 
On the World Map is the only place I have ever seen the Salary screen - never had it at any other time as far as I can remember in Build 14.
It also works OK when spending night at sea. I don't remember if it works from the time skipping dialog, but it certainly works if you simply accelerate time and wait till daily update.
And it better to be the night from 1st to 2nd of the month, or chances are the screen was already skipped and won't activate for the rest of the month.

All in all, currently it's rather hard to pay the crew. Unless you're a voodoo practitioner, console summoner or a black magician of some other kind. :)
 
Would you consider this problem to be worse than it used to be?
I know it used to occasionally not trigger and I figure it has been like this for years.
 
I think it was better a couple of years ago. But I also thought the wounded were healed properly back then... and now we know they never were. :)
In any case, in beta 14 it's broken almost completely, especially on Ironman.
I've only seen a working salary screen in my debugging sessions. When I play as I would normally, it hasn't yet triggered even once.
I strongly suspect the morale drop from skipped payment doesn't work either. At least I do not see any morale drop after not paying the crew for a couple of months.
 
I'm looking at the code for skipping salary, and I do not really understand why it is structured the way it is...

The salary.c file starts with a declaration of a couple initialized variables:

Code:
int nPaymentQ;
int nMoraleDecreaseQ;

They get initialized in CalculateInfoData like this:
Code:
// NK -->
    nPaymentQ = CalcSquadronPayment(mchref);
    int nLeadership = GetShipSkill(mchref,SKILL_LEADERSHIP);

    nMoraleDecreaseQ = 30-nLeaderShip;
    if( CheckCharacterPerk(mchref,"IronWill") ) nMoraleDecreaseQ /= 2;

Now, nPaymentQ is shown at the interface screen and is also used when performing the actual payment, so it makes sense for it to be kept in a global var and precalculated.
But nMoraleDecreaseQ is only used in SkipSailorPayment:

Code:
void SkipSailorPayment()
{
    ref mchref = GetMainCharacter();
    int morale = 45;
//MAXIMUS: for new Mutiny -->
    int debt = GetPaymentSum(mchref);
    mchref.crewdebt = sti(mchref.crewdebt) + debt;
//MAXIMUS: for new Mutiny <--
    if( CheckAttribute(mchref,"Ship.Crew.Morale") ) morale = sti(mchref.Ship.Crew.Morale);

    // PB: Repeat Payment Skipping Penalty -->
    if(!CheckAttribute(mchref, "repeat_salary_payment")) mchref.repeat_salary_payment = 0;
    else
    {
        if(sti(mchref.repeat_salary_payment) > 0) mchref.repeat_salary_payment  = 0;
    }
    mchref.repeat_salary_payment        = sti(mchref.repeat_salary_payment) - 1;

    nMoraleDecreaseQ = abs(sti(mchref.repeat_salary_payment)) * nMoraleDecreaseQ;
    // PB: Repeat Payment Skipping Penalty <--

    morale -= nMoraleDecreaseQ;
    if(morale<0)    morale = 0;

    //mchref.CrewPayment = nPaymentQ; //JA 28Nov06 Not required as money owed to crew now stored elsewhere

    int cn, i;
    for(i=1; i<4; i++)
    {
        cn = GetCompanionIndex(mchref,i);
        if(cn>=0)
        {
            // PB: Use Companion Skills and Reputation for Morale -->
            morale = 45;
            if( CheckAttribute(cn,"Ship.Crew.Morale") ) morale = sti(cn.Ship.Crew.Morale);
            morale -= nMoraleDecreaseQ;
            if(morale<0)    morale = 0;
            Characters[cn].Ship.Crew.Morale = morale;
            // PB: Use Companion Skills and Reputation for Morale <--
        }
    }

    if(sti(mchref.Ship.Crew.Morale) <= 10)    KAM_Mutiny();//MAXIMUS: new "Mutiny"
}
Unless I'm missing something, it could be just as well calculated directly here, without going through all the hops.

That aside, the code looks like it should work, so the reason I do not see morale decrease is probably because SkipSailorPayment does not get called when salary is skipped like this.
 
Returning to the original problem, do we have any other dialog that is called by daily update and is working correctly?
 
Unless I'm missing something, it could be just as well calculated directly here, without going through all the hops.
Maybe it used to be needed, but isn't anymore? You could to change it so it isn't a global one and see what happens.

That aside, the code looks like it should work, so the reason I do not see morale decrease is probably because SkipSailorPayment does not get called when salary is skipped like this.
You can check that by sticking some TraceAndLog lines in the various functions and see what ends up being written to compile.log when it skips.

Returning to the original problem, do we have any other dialog that is called by daily update and is working correctly?
The only one that I think MAY be working is the "Mutiny Screen".
 
The only one that I think MAY be working is the "Mutiny Screen".
Can't check right now, whether it really working, but unlike salary, mutiny uses delayed execution like this:
Code:
void KAM_Mutiny()
{
//MAXIMUS: new "Mutiny" -->
    if (GetCrewQuantity(GetMainCharacter()) > 0) {
        Log_SetStringToLog(XI_ConvertString("MUTINY") + "!");
        if (bSeaActive && IsEntity(&worldMap))
            LaunchMutinyScreen();
        else
            PostEvent("StartMutiny", 2500, "1", 0);
    }
//MAXIMUS: new "Mutiny" <--
}
 
Can't check right now, whether it really working, but unlike salary, mutiny uses delayed execution like this:
Might make a difference indeed....
Should be relatively easy to add to the salary code as well, right?
 
Relatively... Still it's worth checking first if the mutiny really activates in stores/taverns. I'll try it in the evening.
 
OK, the experiment was a complete success. I've made mutiny activation in daily update unconditional, and lo and behold: it works everywhere! It activates in taverns, it activates when loading cargo, it activates when unloading cargo, it activates when skipping time on the board... every bloody night I have a damn mutiny. :pirates


If I have time tomorrow, I'll add an event, its handler and whatever else is needed to salary.c... Although I can't promise it will be in time for the planned release. These weeks before the New Year are somewhat unpredictable. :)
 
PROGRAM\calendar.c looks to be where the screen is meant to be triggered:
Code:
void DoDailyUpdates(string mask)
{
   if(mask == "all")
   {
//--------------------------
     // LDH copied from worldmap_events.c to pay crew salary - 05Jan09
     // Note:  This only runs if we're sailing. Can we get it to work overnight in tavern?
     //if (bSeaActive)     // LDH added 07Jan09  //Can also be triggered on land - Levis
     //{
     ref PChar = GetMainCharacter();
     if(!CheckAttribute(PChar,"articles"))     PChar.articles = 0;
     if(!CheckAttribute(PChar,"LastPayMonth"))   PChar.LastPayMonth = GetDataMonth(); // PB: NOT at the beginning of the game
// KK -->
     if(!LAi_IsFightMode(PChar)) //Don't show while in a battle
     {
       if( sti(PChar.LastPayMonth) != GetDataMonth() )
       {
         //if( GetDataDay() >= 7 && !sti(PChar.articles) ) //Can be triggered every day of the month in case you had a large cargo shift or something like that.
         //{
         if(!sti(PChar.articles)) //Check for articles -Levis
         {
           PChar.LastPayMonth = GetDataMonth();
           LaunchSalaryScreen();
         }
         //}
       }
     }
// <-- KK
     //}

And this from PROGRAM\INTERFACE\interface.c is what gets executed at that time:
Code:
void LaunchSalaryScreen()
{
   if (CalcSquadronPayment(GetMainCharacter()) == 0) return;   // LDH don't bother if crew pay is zero 04Mar09
   if(procInterfacePrepare(INTERFACE_SALARY))
   {
     nPrevInterface = -1;
     CurrentInterface = INTERFACE_SALARY;
     InitInterface(Interfaces[CurrentInterface].IniFile);
   }
}

An alternate solution might be to move the "PChar.LastPayMonth = GetDataMonth();" line INTO the Salary Interface.
If that is added to ExecuteSailorPayment() and SkipSailorPayment(),
then the salary screen should keep appearing EVERY day until the player actively presses the either the "pay" or "skip" buttons.
Right?

Maybe both solutions can be implemented so that they both form fail-safes for each other?
 
Back
Top