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

Included in Build Ship Encounter Chances Correction

One thing we could do to try and help with this is required is to loosen up the criteria after, say, the 50th loop.
For example, allow for type "war" if "trade" isn't working. Or increasing the max class/decreasing the min class by 1.

Note that the types of encounters are set up in PROGRAM\Encounters\Encounters_init.c, which is also what is used (I think) for the information in the Sail Ho interface.
That code looks... interesting. And is probably where things are sourced from in the first place. At least on the worldmap and probably during DirectSail too.
The Coast Raiders might be different. I'm not at all familiar with exactly what it does though. :confused:
 
With that example of a 'Trade' ship with max/min class 3... does the game define 'Trade' as being refShip.Type.Trade = true AND refShip.Type.War = false?
If that's the case... there are NO Tier 3 trade vessels in the game. There are some 'balanced' vessels like the Amsterdam in that Tier, though.
From what I understand from the code, ANY ship with refShip.Trade = true is considered a 'Trade' ship by the selection code. It only excludes ships that are 'War' only.
The whole idea of a "balanced" ship was something that one of our modders came up with a few years ago when he was rebalancing all the ships in the game.
There was no such thing in the original game. :shrug

That encounter was a Dutch one though. But since I was playing in the Napoleonic period, the Amsterdam has a chance of 0.0, so there would be no ship available at all.
The log failed to mention any of that because I hadn't set up the logging quite correctly yet when I did that. As I later found out and rectified.
Perhaps I should put a note of what Period you're in for those messages too. You would know which storyline you're in, but that is not obvious when posted on the forum. :facepalm
Edit: Use attached instead for the period addition.
 

Attachments

  • Ships.zip
    7.5 KB · Views: 97
It sounds as though we should take a closer look at Encounters_init.c, then. If we can modify that to get some more reasonable encounters, we might be able to reduce the amount of recurring loops.
At first glance, though, the code looks pretty odd, as you say.

EDIT: Including the period in the logs would be highly useful. That explains why no Tier 3 trade ship was found in the Napoleonic era, because none exist (I think).
 
New sample of what it looks like:
Code:
Force_GetShipType: Maxclass = 3, Minclass = 8, Per = Napoleonic, Nat = Spain, Type = trade, Loop = 0, Ship ID = Shnyava1
Force_GetShipType: Maxclass = 3, Minclass = 8, Per = Napoleonic, Nat = Spain, Type = trade, Loop = 0, Ship ID = Tartane1
Force_GetShipType: Maxclass = 2, Minclass = 8, Per = Napoleonic, Nat = Spain, Type = war, Loop = 0, Ship ID = SP_Essex
Force_GetShipType: Maxclass = 2, Minclass = 8, Per = Napoleonic, Nat = Spain, Type = war, Loop = 0, Ship ID = Galeoth2
Force_GetShipType: Maxclass = 3, Minclass = 8, Per = Napoleonic, Nat = Spain, Type = trade, Loop = 0, Ship ID = Lugger4
Force_GetShipType: Maxclass = 3, Minclass = 8, Per = Napoleonic, Nat = Spain, Type = trade, Loop = 0, Ship ID = Yacht1
Is there any other information you need?

Also, I might have been posting at the same time as you with some of my stuff above and on the previous page. You might want to check you've seen it all.
REALLY time for bed now though, so I'll leave you in some peace and quiet for a change! :razz

EDIT: Including the period in the logs would be highly useful. That explains why no Tier 3 trade ship was found in the Napoleonic era, because none exist (I think).
Already done. See above. :doff
 
I've seen all your posts, yes. But at this time of night, it's not all going in, and I'm too tired to write extensive replies. :ko
 
I've seen all your posts, yes. But at this time of night, it's not all going in, and I'm too tired to write extensive replies. :ko
Fair enough. Just making sure. :wp

That last ships.zip gives an instacrash............
Really? Attached works for me. Should be the same as the one posted above.
Anything in the log files relating to this? :shock
 

Attachments

  • Ships.zip
    7.5 KB · Views: 89
Not anymore. I reinstalled beta 3 WIP1(2) so I could continue playing. It was some sort of compile error. I will try this again.

EDIT: This time it works.
 
Note that the types of encounters are set up in PROGRAM\Encounters\Encounters_init.c, which is also what is used (I think) for the information in the Sail Ho interface.
That code looks... interesting. And is probably where things are sourced from in the first place. At least on the worldmap and probably during DirectSail too.
The Coast Raiders might be different. I'm not at all familiar with exactly what it does though. :confused:
I've been looking into the encounter code in Encounters_init.c, and trying to figure out what sections like these actually mean:
Code:
        makeref(rEnc, EncountersTypes[ENCOUNTER_TYPE_MERCHANT0]);    // 3 + 0
        n++; rEnc.Skip = false;
        rEnc.Type = ENCOUNTER_TRADE;
        rEnc.MinRank = 1;
        Enc_AddShips(rEnc, "Trade", 1, 3);
        Enc_ExcludeNation(rEnc, PIRATE);
 
        Enc_AddClasses(rEnc, 1, 5, 6, 0, 0);
        Enc_AddClasses(rEnc, 2, 5, 6, 0, 0);
        Enc_AddClasses(rEnc, 3, 4, 6, 0, 0);
        Enc_AddClasses(rEnc, 4, 4, 6, 0, 0);
        Enc_AddClasses(rEnc, 5, 3, 6, 0, 0);
        Enc_AddClasses(rEnc, 6, 3, 6, 0, 0);
        Enc_AddClasses(rEnc, 7, 3, 6, 0, 0);
        Enc_AddClasses(rEnc, 8, 3, 5, 0, 0);
        Enc_AddClasses(rEnc, 9, 3, 5, 0, 0);
        Enc_AddClasses(rEnc, 10,3, 5, 0, 0);
        Enc_AddClasses(rEnc, -1,4, 6, 0, 0); // NK for shipcap off
You might know most of this already, but just in case, here's what I think I've managed to figure out, based on the patterns in the code:
  • The five numbers in the Enc_AddClasses lines follow this format: Encounter Rank, Trade Maxclass, Trade Minclass, War Maxclass, War Minclass.
  • rEnc.MinRank corresponds to the Encounter Rank in the first Enc_AddClasses line.
  • Each Enc_AddShips line determines the type of ship, the min number and max number of those ships to generate.
While this theory seems to hold water, one thing that bugs me is that I can't find any cases in the file where the game tries to find a Trade ship with both a min and max class of 3, like the example we mentioned above. :facepalm
 
Trying to find all instances where Force_GetShipType is being called. This post contains the LESS important ones. See the next post for the crucial one.

Coastal Guard Ships used for Process Late Loan in PROGRAM\Dialog_func.c:
Code:
void SelectCoastalGuardShip(ref rCharacter)
{
[...]
    int minclass = 8 - makeint((irank - Rand(3))/2) ;
    int maxclass = 8 - makeint((irank + Rand(3))/2) ;
    if(maxclass < 8 - makeint(makeint(PChar.rank) * 2 / 3)) maxclass = 8 - makeint(makeint(PChar.rank) * 2 / 3);
    if(minclass < 8 - makeint(makeint(PChar.rank) * 2 / 3)) minclass = 8 - makeint(makeint(PChar.rank) * 2 / 3);
    if(maxclass < MAXCOASTGUARDCLASS) maxclass = MAXCOASTGUARDCLASS;
    if(minclass < MAXCOASTGUARDCLASS) minclass = MAXCOASTGUARDCLASS;
    if(minclass > 7) minclass = 7;
    if(maxclass > 7) maxclass = 7;
    rCharacter.Ship.idx = Force_GetShipType(maxclass, minclass, "War", sti(rCharacter.nation)); // PS

Governor Ship Hunting and Treasure Quest Pirates in PROGRAM\QUESTS\quests_common.c:
Code:
void GeneratePirateQuest(ref gov, bool GovernorQuest) // KK
{
[...]
    int minclass = 8 - makeint((irank - Rand(3))/2) ;
    int maxclass = 8 - makeint((irank + Rand(3))/2) ;
    if(maxclass < 8 - makeint(makeint(PChar.rank) * 2 / 3)) maxclass = 8 - makeint(makeint(PChar.rank) * 2 / 3);
    if(minclass < 8 - makeint(makeint(PChar.rank) * 2 / 3)) minclass = 8 - makeint(makeint(PChar.rank) * 2 / 3);
    if(iNation == PIRATE && maxclass < MAXPIRATECLASS) maxclass = MAXPIRATECLASS; // KK
    if(iNation == PIRATE && minclass < MAXPIRATECLASS) minclass = MAXPIRATECLASS; // KK
    if(minclass > 7) minclass = 7;
    if(maxclass > 7) maxclass = 7;
    //Log_SetStringToLog("Minclass " + minclass + "; Max " + maxclass);
    if (sti(rFantom.nation) >= NATIONS_QUANTITY) rFantom.nation = PIRATE; // KB- Fix Governor Pirate Quest bug // KK
    iShipType = Force_GetShipType(maxclass, minclass, "War", sti(rFantom.nation)); // PS

Escort Ship Quest in PROGRAM\QUESTS\quests_common.c:
Code:
void GenerateConvoyQuest()
{
[...]
    irank = 8 - irank/2;
    if(irank < MAXMERCHANTCLASS) irank = MAXMERCHANTCLASS;
    if(irank > 5) irank = 5;
    iShipType = Force_GetShipType(irank, irank+1, "trade", -1);

Safeguard against CTDs from invalid ship types in PROGRAM\SEA_AI\AIShip.c:
Code:
void Ship_Add2Sea(int iCharacterIndex, bool bFromCoast, string sFantomType)
{
[...]
    int iShipType = GetCharacterShipType(rCharacter); // PS
    if (iShipType < 0 || iShipType >= SHIP_TYPES_QUANTITY_WITH_FORT)
    {
        Trace("Character.id = " + rCharacter.id + ", have invalid ship type = " + iShipType + ", and try load to sea");
        //return; // NK 04-09-12 fix so you never crash on bad ship type. -->
        if(!LAi_IsDead(rCharacter))
        {
            if(sti(rCharacter.nation) == PIRATE) rCharacter.fantomtype = "pirate"; //SCREWFACE : PIRATE is a nation - type is "pirate";
            string ftype = "war"; if(CheckAttribute(rCharacter,"fantomtype")) ftype = rCharacter.fantomtype;
            rCharacter.ship.type = GetShipID(Force_GetShipType(GetCharacterShipClass(GetMainCharacter()) - 1, GetCharacterShipClass(GetMainCharacter()) +1, ftype, sti(rCharacter.nation)));

Coast Raider Ships in PROGRAM\SEA_AI\sea.c:
Code:
void SetCoastTraffic(string islandstr)
{
[...]
                // PRS3 new get ship call
                int minclass = MIN_CLASS;
                //scale minclass between 7 and CR_MAX_MINCLASS based on PChar level
                if(GetLevel(&Pchar) < (MIN_CLASS-CR_MAX_MINCLASS)*CR_MINCLASS_PERLEVEL) minclass = (MIN_CLASS - makeint(makefloat(GetLevel(&Pchar)) / CR_MINCLASS_PERLEVEL));
                int maxclass = MAX_CLASS;

                switch(sFantomType)
                {
                    case "pirate": maxclass = CR_MAXPIRATECLASS; break;
                    case "trade": maxclass = MAXMERCHANTCLASS; break;
                    case "war": if(crnation == sti(CurIsland.smuggling_nation)) { maxclass = MAXCOASTGUARDCLASS; } break;
                }
                // cap if GetShipCap()
                if(GetShipCap() && maxclass < GetCharacterShipClass(Pchar) - CR_CLASS_ABOVE_PCHAR) maxclass = GetCharacterShipClass(Pchar) - CR_CLASS_ABOVE_PCHAR;
                if(GetShipCap() && maxclass < (MIN_CLASS+1)-GetLevel(Pchar) - CR_CLASS_ABOVE_PCHAR) maxclass = (MIN_CLASS+1) - GetLevel(Pchar) - CR_CLASS_ABOVE_PCHAR;
                if(maxclass < MAX_CLASS) maxclass = MAX_CLASS;
                //trstr += " Maxclass " + maxclass + ", minclass " + minclass;
                crship = Force_GetShipType(maxclass, minclass, sFantomType, crnation);
 
Continuing from above, this is where the REALLY important stuff is.

WorldMap and DirectSail Encounters in PROGRAM\SEA_AI\AIFantom.c:
Code:
int Fantom_GenerateEncounter(string sGroupName, int iEType, int iNation) // NK // KK
{
[...]
    iNumMerchantShips = MakeInt(aMerchant.ShipsMin) + rand(MakeInt(aMerchant.ShipsMax) - MakeInt(aMerchant.ShipsMin));
    iNumWarShips = MakeInt(aWar.ShipsMin) + rand(MakeInt(aWar.ShipsMax) - MakeInt(aWar.ShipsMin));
 
    int iRank = sti(rCharacter.Rank);
    if(GetShipCap()) { { if((8-GetCharacterShipClass(rCharacter)) * 2 < iRank) iRank = (8-GetCharacterShipClass(rCharacter)) * 2; } } // NK
    Encounter_GetClassesFromRank(iEType, iRank, &iMerchantClassMin, &iMerchantClassMax, &iWarClassMin, &iWarClassMax);
[...]
    for (i=0; i<iNumMerchantShips; i++)
    {
        if(iNumShips + i >= MAX_SHIPS_ON_SEA) return i; // NK bugfix
        iShipType = Force_GetShipType(iMerchantClassMax, iMerchantClassMin, "Trade", iNation); // NK change to type trade, fixed to swap min,max 04-09-13. Change to Force
        if (iShipType == INVALID_SHIP_TYPE) continue;
        //Trace("Merchant ship class = " + ShipsTypes[iShipType].Class + ", name = " + ShipsTypes[iShipType].Name);
        Fantom_AddFantomCharacter(sGroupName, iShipType, "trade", iEType, iNation);
    }
 
    for (i=0; i<iNumWarShips; i++)
    {
        if(iNumShips + iNumMerchantShips + i >= MAX_SHIPS_ON_SEA) return iNumMerchantShips + i; // NK bugfix
        iShipType = Force_GetShipType(iWarClassMax, iWarClassMin, "War", iNation); // NK fixed to swap min,max 04-09-13 Change to Force
}
For DirectSail:
int enctype = makeint(rand(6) );

For Worldmap:
Generated in PROGRAM\Encounters\Encounters_map.c
Code looks complicated; don't feel like analysing it right now! :whipa
 
Perhaps it will suffice to just know WHICH encounter is being generated by the code to be able to analyse this further if required.
Extract attached to PROGRAM\SEA_AI . This gives an additional compile.log entry like so:
Code:
Fantom_GenerateEncounter: type = Pirate, # Mer = 0, Mer MAX = 4, Mer MIN = 6, # War = 1, War MAX = 4, War MIN = 5
Force_GetShipType: Maxclass = 4, Minclass = 5, Per = Napoleonic, Nat = Pirate, Type = War, Loop = 0, Ship ID = PiratBrig50
We can compare that to Encounters_init.c:
Code:
        makeref(rEnc, EncountersTypes[ENCOUNTER_TYPE_PIRATE]);    // 0 + 2
        n++; rEnc.Skip = false;
        Enc_AddShips(rEnc, "War", 1, 2);
        rEnc.MinRank = 1;
        rEnc.MaxRank = 6;
        rEnc.Type = ENCOUNTER_WAR;

        Enc_AddClasses(rEnc, 1, 0, 0, 6, 6);
        Enc_AddClasses(rEnc, 2, 0, 0, 6, 6);
        Enc_AddClasses(rEnc, 3, 0, 0, 5, 6);
        Enc_AddClasses(rEnc, 4, 0, 0, 5, 6);
        Enc_AddClasses(rEnc, 5, 0, 0, 4, 6);
        Enc_AddClasses(rEnc, -1,4, 6, maxpirate3_1, 5); // NK for shipcap off
If I read this correctly, it means:
Enc_AddShips = Between 1 and 2 ships of type War
MinRank = Minimum rank the player must have before this type of encounter will occur (?) - Would only apply when the rank-based Ship Cap is ON (we like to have this OFF)
MaxRank = Maximum rank the player must have before this type of encounter will occur (?) - Would only apply when the rank-based Ship Cap is ON (we like to have this OFF)

Enc_AddClasses = The min and max class per rank
First number = Player level. -1 is in use when the rank-based Ship Cap is OFF, so that is the line that is used by default.
Second and third number: Min and Max rank of Merchants
Fourth and fifth number: Min and Max rank of Warships

So in my example, I was getting a warship between "max_pirate3_1" and 5, which turned out to be between classes 4 and 5.
By default, max_pirate3_1 is set to "3", but because MAXPIRATECLASS is 4 in InternalSettings.h, that is where the class 4 and 5 comes from.
Is that making any sense yet? Do you think you can work with this? Or do you need something more to figure this out?
 

Attachments

  • AIFantom.zip
    8.4 KB · Views: 77
It makes sense, but it's still confusing, if you get what I mean.
I still don't understand where the game is getting some of these encounters from, such as the min/max class 3 Trade encounter that I keep seeing in my Compile log. :facepalm

One thing I DO know is that we need to reduce the frequency of pirate encounters with Maxclass 4, so we don't see PiratCorvette, CrimsonBlood and PiratFrigateSup too often.
But all these bloody numbers are doing my head in. :modding
 
Is this what you are talking about?
 

Attachments

  • force ship-1.jpg
    force ship-1.jpg
    162.2 KB · Views: 67
  • compile.log
    101.2 KB · Views: 75
  • error.log
    132 bytes · Views: 83
I still don't understand where the game is getting some of these encounters from, such as the min/max class 3 Trade encounter that I keep seeing in my Compile log. :facepalm
That is what my AIFantom.c change is for: That will tell us what kind of encounter the game requested and will hopefully point us in the direction of that class 3 trade ship.
Hylie, please get that file I posted here: http://www.piratesahoy.net/threads/ship-encounter-chances-correction.17815/page-11#post-453157
If it happens again, we'll have more data to go on. :doff

One thing I DO know is that we need to reduce the frequency of pirate encounters with Maxclass 4, so we don't see PiratCorvette, CrimsonBlood and PiratFrigateSup too often.
Indeed. This is the reason why the Crimson Blood is encountered so frequently right here:
Code:
Force_GetShipType: Maxclass = 4, Minclass = 4, Per = Colonial Powers, Nat = Pirate, Type = War, Loop = 29, Ship ID = CrimsonBlood
Game was clearly having a lot of trouble finding a ship at all and returned the Crimson Blood in the end.

But all these bloody numbers are doing my head in. :modding
Welcome to MY world! And no, I don't like it either. :pirate41:
 
That is what my AIFantom.c change is for: That will tell us what kind of encounter the game requested and will hopefully point us in the direction of that class 3 trade ship.

Ah, I see what you mean now. Must've been too tired last night. :oops:
I've installed the new Beta 3 files and will get back to testing soon.
 
In which year was "HMS" added to British naval ship names? Or at least which time period?

Edit: According to Wikipedia, only in the Napoleonic time period (17989).
I'm adjusting the code so that this prefix will only be used in the last time period now, instead of ALL of them.
Should be more accurate, no? :cheeky
 
In which year was "HMS" added to British naval ship names? Or at least which time period?

Wikipedia lists the first use of HMS as 1789, and HBMS before that. Somehow I find that hard to believe, having seen many ships referred to as HMS before that time.
In game terms, I'd say it should first come into use in Period 2, which is closest to when the navy apparently became the 'Royal Navy' under Charles II in 1660.
Think of ships like Mary Rose from the 16th century, which didn't use HMS.

EDIT: On an unrelated note, it seems the Excel Web App as been updated, so you can now sort and filter the columns in any of the spreadsheets in my SkyDrive folder, just as you would in the normal version of Excel. :dance
 
Wikipedia lists the first use of HMS as 1789, and HBMS before that. Somehow I find that hard to believe, having seen many ships referred to as HMS before that time.
In game terms, I'd say it should first come into use in Period 2, which is closest to when the navy apparently became the 'Royal Navy' under Charles II in 1660.
Think of ships like Mary Rose from the 16th century, which didn't use HMS.
Thanks! Golden Age of Piracy and more recent it is then. :doff

EDIT: On an unrelated note, it seems the Excel Web App as been updated, so you can now sort and filter the columns in any of the spreadsheets in my SkyDrive folder, just as you would in the normal version of Excel. :dance
I've been happily using those filters when I was looking up pirate ships today.

BTW: Perhaps you can add a link to it in the opening post or something? I always have to search quite a bit when I want it. :facepalm
 
Back
Top