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

Unconfirmed Bug False flag recognition

Grey Roger

Sea Dog
Staff member
Administrator
Storm Modder
Fals flag recognition doesn't work. The reason is this line in "Screwface_functions.c", function 'CheckForMainCharacterfalseflag':
Code:
if (GetAttribute(chr, "skipFalseFlag"))        return false;
As far as I can tell, attribute "skipFalseFlag" is only assigned to Mergildo Hurtado, the captain of the Montanez in "Strange Things Going On in the Caribbean" (and the "Hoist The Colours" variant, "Sao Feng's Lost His Bodyguards"). But if 'GetAttribute' can't find the given attribute on the given character, it returns "-1" (string, not integer). So 'if (GetAttribute(chr, "skipFalseFlag"))' will always pass and 'CheckForMainCharacterfalseflag' will always quit before it gets to any serious checking.

That's easily enough fixed - use 'CheckAttribute' instead of 'GetAttribute'. And then false flag recognition works too well. Sailing out of San Juan under a false flag, trying to get past the fort, my chance of recognition should be around 40% based on fame, "sneak" skill and range. But that's checked every few seconds, which means I'm recognised shortly after setting sail. I tried putting some 'traceandlog' statements into the function, as well as commenting out the bit which does the actual recognising, so that I could see my chances of recognition at all points as I sailed past the fort, plus how many checks were made between leaving port and leaving visual range, and the fort made about 50 attempts. (That, of course, is depending on my speed. If the wind had been near storm level, I'd have been away sooner and checked less often. If the wind had been near calm, it would have been the opposite.)

Perhaps divide recognition chance by 50 so that your actual chance of being recognised at some point during the encounter is about what it should be?
 
Fals flag recognition doesn't work.
Oh yikes; that's BAD!!
Completely takes away the whole risk and excitement of it all. :facepalm

And indeed, there's zero point using 'GetAttribute' there. The value of it doesn't matter at all.
Really should've been 'Check' all along.

But that's checked every few seconds
I always did wonder what effect that'd have...

Perhaps divide recognition chance by 50 so that your actual chance of being recognised at some point during the encounter is about what it should be?
Makes sense to me.
Can always be fine-tuned more later if need be,
Though chances are, nobody will ever be fully happy with any setting.
Doubt most people would like having their fake flag caught.
But it IS supposed to happen; and be a serious problem.


I always had an idea tying in with this too.
Right now, "Fame" doesn't affect gameplay a whole ton; except that "higher" means "more likely to be recognized".
What if "reputation" is made a factor in the fame equation?
So you could actually deliberately lower your fame by moving back towards neutral.

Likewise, what if your reputation would ALWAYS be slowly returning back to neutral if you don't do anything?
So you'd have to keep working on keeping your reputation?

Then if your fame is high enough (caused either by very high OR very low reputation),
it starts affecting the surrender chances of enemy ships.
In other words: you gain easy sea battles at the expense of being unable to fool people into believing your false flags.
 
I always did wonder what effect that'd have...
Pretty obvious. If you even have a 10% base chance of recognition and you're being checked several times per minute, you will be spotted sooner or later. Probably sooner, especially if there are other ships nearby - if one of them starts firing, you have the choice of firing back under your false flag and being labelled an evil pirate, raising a hostile flag and having everyone fire at you, or just accepting fire until you're out of range. (Realistically, what's San Juan fort supposed to do if one ship under Spanish flag starts firing at another and the fort hasn't recognised either of them as false flags?)

Makes sense to me.
Can always be fine-tuned more later if need be,
Though chances are, nobody will ever be fully happy with any setting.
Doubt most people would like having their fake flag caught.
But it IS supposed to happen; and be a serious problem.
Tying into this is the bug whereby, if you moor at a beach and walk into town, nobody has items for sale and street traders don't have any money with which to buy your items either. I've a vague memory of putting a 'townsack' line into one of the beach location definitions and the traders then working properly; I'll try that again and if it works, I'll need to do it to all beach locations. Because if street traders can be made to work properly then there's a simple way to avoid being recognised by the fort, which is don't sail into town!

In any case, I'll try replacing "GetAttribute" with "CheckAttribute", divide the recognition chance by 50, and see how long I live. Maybe try dividing by other numbers.

I always had an idea tying in with this too.
Right now, "Fame" doesn't affect gameplay a whole ton; except that "higher" means "more likely to be recognized".
What if "reputation" is made a factor in the fame equation?
So you could actually deliberately lower your fame by moving back towards neutral.
Reputation is whether you're known to be good, evil or neutral. Fame is how many people know that. So I'd keep them separate. You could be famous for sinking lots of ships and being promoted, or for other reasons which have nothing to do with your reputation.

Likewise, what if your reputation would ALWAYS be slowly returning back to neutral if you don't do anything?
So you'd have to keep working on keeping your reputation?

Then if your fame is high enough (caused either by very high OR very low reputation),
it starts affecting the surrender chances of enemy ships.
In other words: you gain easy sea battles at the expense of being unable to fool people into believing your false flags.
More precisely, reputation could affect surrender chances, but only if the enemy passes a fame check on you. You might have a reputation for being a really nice guy but it won't affect the chances of the enemy captain surrendering if he's never heard of you.

Surrender chances could change depending on reputation (subject to a fame check). Extreme niceness means the enemy is less likely to surrender on sea but more likely to surrender after boarding - he knows you're not going to execute him so he may as well have a go, then surrender when it becomes clear he can't win. Extreme nastiness means the exact opposite - he's more likely to surrender on sea in the hope that you'll spare him if he doesn't annoy you, and less likely to surrender after boarding because he reckons he's doomed anyway.

Whether I, or anyone else, will ever implement any of this is another matter! I have other things to worry about at the moment, e.g. trying to get false flag recognition working at a reasonable level. xD
 
Pretty obvious. If you even have a 10% base chance of recognition and you're being checked several times per minute, you will be spotted sooner or later.
Figures, yes.

Realistically, what's San Juan fort supposed to do if one ship under Spanish flag starts firing at another and the fort hasn't recognised either of them as false flags?
Good question.

In reality, I suppose they'd throw up some signaling flags to confirm who's legit...

Tying into this is the bug whereby, if you moor at a beach and walk into town, nobody has items for sale and street traders don't have any money with which to buy your items either. I've a vague memory of putting a 'townsack' line into one of the beach location definitions and the traders then working properly
Indeed I think that was some sort of oversight of whoever overhauled the item trading system.
Unfortunate, really...

Reputation is whether you're known to be good, evil or neutral. Fame is how many people know that. So I'd keep them separate. You could be famous for sinking lots of ships and being promoted, or for other reasons which have nothing to do with your reputation.
I mean...
How can you be famous for being "neutral"?
Surely having a polarized reputation should help?
Especially if it's difficult to keep it there?

Surrender chances could change depending on reputation (subject to a fame check). Extreme niceness means the enemy is less likely to surrender on sea but more likely to surrender after boarding - he knows you're not going to execute him so he may as well have a go, then surrender when it becomes clear he can't win. Extreme nastiness means the exact opposite - he's more likely to surrender on sea in the hope that you'll spare him if he doesn't annoy you, and less likely to surrender after boarding because he reckons he's doomed anyway.
Was just about to ask about "the Blackbeard effect", e.g. being SO scary that people DON'T fight.
But actually, that second half of your explanation sounds pretty perfect for that. :onya

Whether I, or anyone else, will ever implement any of this is another matter! I have other things to worry about at the moment, e.g. trying to get false flag recognition working at a reasonable level. xD
Truth.
Maybe a thought for another game in the future.
 
Good question.

In reality, I suppose they'd throw up some signaling flags to confirm who's legit...
Which means perhaps the "Master of Disguise" perk should perhaps have a level requirement and then be made more effective. -10% to base chance of recognition meant nothing during my tests. The "Master of Disguise" knows some useful tricks such as which signalling flags to raise.

I mean...
How can you be famous for being "neutral"?
Surely having a polarized reputation should help?
Especially if it's difficult to keep it there?
You're not famous for being neutral, you're famous for other things. Michiel de Ruyter isn't famous for being an all-round nice guy, he's famous for the Medway raid. Saving the son of a Spanish admiral might boost your reputation, but what's going to boost your fame is looting San Juan and then getting a couple of promotions for it.
 
Which means perhaps the "Master of Disguise" perk should perhaps have a level requirement and then be made more effective. -10% to base chance of recognition meant nothing during my tests. The "Master of Disguise" knows some useful tricks such as which signalling flags to raise.
Always nice when perks have a notable impact on gameplay.
Just a percentage here or there always struck me as quite dull...
 
Next problem: they might recognise you but they don't do anything about it.

I sailed out of San Juan port, right between two Spanish patrol ships in the hope that being at close range would allow them to recognise me. It did. I've put some 'trace' commands into "Screwface_functions.c", function 'CheckForMainCharacterfalseflag', to show the detection calculations at various stages, and there's already a 'trace' to show if someone recognises you. One of the patrol ships did indeed recognise me, after which both of them continued to remember me as hostile - if one ship of a group recognises you, it alerts the rest of its group, so they all get the "recognized" attribute. Neither of them started firing and neither of them showed red on my compass. (Yes, it is the enhanced compass which shows enemies as red.)
 
Neither of them started firing and neither of them showed red on my compass. (Yes, it is the enhanced compass which shows enemies as red.)
Related stuff from PROGRAM\BATTLE_INTERFACE\BattleInterface.c:
Code:
    if (CheckRelations)
    {
        CheckAllShips("forts", true); // PB: Set initial relations for ships
        CheckAllShips("ships", true); // PB: Set initial relations for forts

        UpdateRelations();
    }

And PROGRAM\BATTLE_INTERFACE\LogInterface.c:
Code:
                    // PB: Check False Flags
                    bool Recognized = false;
                    Recognized = Recognized || CheckAllShips("forts", false);
                    Recognized = Recognized || CheckAllShips("ships", false);
                    if (Recognized)
                    {
                        if(iRealismMode<2) 
                            LogIt(TranslateString("", "We are recognized, captain!"));
                        RefreshBattleInterface(true);
                    }

That 'UpdateRelations();' should be doing the trick:
Code:
void UpdateRelations()
{
    if (bSeaActive)
    {
        SendMessage(&AISea, "l", AI_MESSAGE_UPDATE_RELATIONS);
    }
}
Is that getting called at all?
 
Further tests showed that enemy ships sometimes truly become hostile, turn red on the compass and start firing; and sometimes they don't. I've no idea why. But if 'UpdateRelations' is what makes them hostile then there's an easy solution, which is to add a call to it in function 'SetGroupHostile' in "Screwface_functions.c". That seems to be working so far...

Next problem: how to scale the recognition factor. There are two extremes of player. One uses the worldmap to arrive at the island, uses Sail-To to teleport to the port, then docks at once; and on leaving port, goes straight to worldmap. This one will almost never be detected unless the chance is fairly high, or unless there's a storm or some random enemy ships near the port when he's trying to dock. The other type of player direct-sails everywhere and if the detection rate is scaled up to catch the worldmap/sail-to type then this one will be detected every time, especially if the wind is low or blowing the wrong way when he's trying to leave port.
 
Further tests showed that enemy ships sometimes truly become hostile, turn red on the compass and start firing; and sometimes they don't. I've no idea why. But if 'UpdateRelations' is what makes them hostile then there's an easy solution, which is to add a call to it in function 'SetGroupHostile' in "Screwface_functions.c". That seems to be working so far...
That does still suggest a flaw in the current system.
CheckForMainCharacterfalseflag is only ever called by CheckAllShips; and that is the function that calls 'SetGroupHostile'.
CheckAllShips is also the function that then triggers 'RefreshBattleInterface(true)' from LogInterface.
And 'RefreshBattleInterface(true)' is in turn again what calls 'UpdateRelations()' in the first place.

So how can it be possible that 'SetGroupHostile' DOES get called, but 'UpdateRelations()' apparently doesn't take effect?
When the one leads logically directly to the other (albeit through a few separate steps that trigger each other, one after the other).

It is true that SetGroupHostile can also be called by Ship_FireAction instead.
But that has its own separate 'RefreshBattleInterface(true);' to go with it.
So that shouldn't be the issue either.

My suggestion would be to put some trace statements in there to check if 'UpdateRelations()' is indeed being called properly.
And, if not, where does the chain break?

Next problem: how to scale the recognition factor. There are two extremes of player. One uses the worldmap to arrive at the island, uses Sail-To to teleport to the port, then docks at once; and on leaving port, goes straight to worldmap. This one will almost never be detected unless the chance is fairly high, or unless there's a storm or some random enemy ships near the port when he's trying to dock. The other type of player direct-sails everywhere and if the detection rate is scaled up to catch the worldmap/sail-to type then this one will be detected every time, especially if the wind is low or blowing the wrong way when he's trying to leave port.
I indeed saw a Let's Play of someone who literally kept going back to the worldmap, just to find the port entrance.
Which struck me as complete madness; because that's what bloody 3D Sailing Mode is for!
He didn't spot the town rrrright next to the fort and then got completely lost.
Which is bizarre, because very close to the fort is indeed exactly where the town was.
After all, what else would a fort be fort; if not to protect a town??? o_O

One thing I wonder: might there eventually be a way to automatically trigger a reload to 3D Sailing Mode at a certain distance from an island.
It just doesn't make sense to me to be worldmap-ing until literally right next to your final destination.
Worldmap is for longer-distance navigation...

I don't think it's worth keeping worldmap-obsessed players in mind for the balancing.
Those players don't quite play the game "like it's meant to" anyway.

Though perhaps one though:
Have a SUBSTANTIALLY HIGHER false chance recognition value once after reloading into the scene; and then have that chance reduce with time to a low base level.
That way, if you DirectSail to another island, you get that HIGH CHANCE at a large distance, which means it'll not be such a big issue.
While if you WorldMap instead, it'll happen right next to the fort, which is MUCH more dangerous.
 
That does still suggest a flaw in the current system.
CheckForMainCharacterfalseflag is only ever called by CheckAllShips; and that is the function that calls 'SetGroupHostile'.
CheckAllShips is also the function that then triggers 'RefreshBattleInterface(true)' from LogInterface.
And 'RefreshBattleInterface(true)' is in turn again what calls 'UpdateRelations()' in the first place.
Not so. It is true that 'CheckForMainCharacterFalseFlag' is called by 'CheckAllShips'. But 'CheckAllShips' does not call 'RefreshBattleInterface' - in fact, 'RefreshBattleInterface' is not mentioned anywhere in "Screwface_functions.c".

So how can it be possible that 'SetGroupHostile' DOES get called, but 'UpdateRelations()' apparently doesn't take effect?
When the one leads logically directly to the other (albeit through a few separate steps that trigger each other, one after the other).
Possibly because 'SetGroupHostile' is called directly by 'CheckForMainCharacterfalseflag' if the randomised check against the chance of detection triggers.

It is true that SetGroupHostile can also be called by Ship_FireAction instead.
But that has its own separate 'RefreshBattleInterface(true);' to go with it.
So that shouldn't be the issue either.
It's also not a factor in any of these tests because I haven't been firing at anyone, so the only firing that happens is if a ship or fort detects my false flag and does turn properly hostile. (At which point I still don't fire, partly because I don't want to raise my true flag and provoke more hostility, but mainly because in that case this test has concluded successfully so I reload my savegame in San Juan port and try again.)

I indeed saw a Let's Play of someone who literally kept going back to the worldmap, just to find the port entrance.
Which struck me as complete madness; because that's what bloody 3D Sailing Mode is for!
He didn't spot the town rrrright next to the fort and then got completely lost.
Which is bizarre, because very close to the fort is indeed exactly where the town was.
After all, what else would a fort be fort; if not to protect a town??? o_O
Santiago's fort is on a point of land. If you sail to the wrong side of that port, you end up at Playa de Sierra Maestra, which is also within range of the fort ("Ardent" makes significant use of this). And if that player was using an old game in which Playa de Sierra Maestra wasn't accessible outside the "Bartolomeu" storyline, he could quite easily fail to find Santiago.

For that matter, San Juan's fort is on a point guarding the entrance to the town and can easily be seen from the other side of that point. And then there's Cartagena fort, which is some way out of town, half way up a long peninsula. For some reason you can't get to Cartagena by worldmap, it always drops you some way out of town even if you have sailed right to the town on the map. So I can easily imagine a player running into that fort, not spotting the town, and trying to use worldmap to get closer to shore, which doesn't work.

One thing I wonder: might there eventually be a way to automatically trigger a reload to 3D Sailing Mode at a certain distance from an island.
It just doesn't make sense to me to be worldmap-ing until literally right next to your final destination.
Worldmap is for longer-distance navigation...

I don't think it's worth keeping worldmap-obsessed players in mind for the balancing.
Those players don't quite play the game "like it's meant to" anyway.
As Barbossa might say, "Ah, we has us a problem there!" For one thing, I am one of those "worldmap-obsessed players" - if I'm playing a main story plus two or three sidequests together, especially if one of them is time-limited, I'm not inclined to switch to 3D sailing a long way out of town and take my chances with a low wind, or a wind pointing the wrong way, in conjunction with 1 hour days! For another, quoting from the new long comment near the end of "globals.c", "you are a pirate; and you are FREE!" :p The game gives the player various options - who's to say which one is the way the game is meant to be played? (The original game didn't have Direct Sail, so it could be argued that using worldmap to get near the destination and then Sail-To to finish the trip is the way it's meant to be played!)

Though perhaps one though:
Have a SUBSTANTIALLY HIGHER false chance recognition value once after reloading into the scene; and then have that chance reduce with time to a low base level.
That way, if you DirectSail to another island, you get that HIGH CHANCE at a large distance, which means it'll not be such a big issue.
While if you WorldMap instead, it'll happen right next to the fort, which is MUCH more dangerous.
I'm not sure if I can have a value which reduces with time. But it might be possible to set the chance higher at the first check and then drop it to the normal lower setting from then on.
 
Not so. It is true that 'CheckForMainCharacterFalseFlag' is called by 'CheckAllShips'. But 'CheckAllShips' does not call 'RefreshBattleInterface' - in fact, 'RefreshBattleInterface' is not mentioned anywhere in "Screwface_functions.c".
IS so!
Just in a slightly different way.

It is true that 'CheckAllShips' does not call 'RefreshBattleInterface' directly.
But in LogInterface.c:
Code:
                    bool Recognized = false;
                    Recognized = Recognized || CheckAllShips("forts", false);
                    Recognized = Recognized || CheckAllShips("ships", false);
                    if (Recognized)
                    {
                        if(iRealismMode<2) 
                            LogIt(TranslateString("", "We are recognized, captain!"));
                        RefreshBattleInterface(true);
                    }
So 'CheckAllShips' returning true DOES trigger 'RefreshBattleInterface(true)' a few lines down.
And it does so ONLY when returning true; and only once.
I designed that specifically to minimize the amount of updates (for performance) and flag changes (remember those graphic anomalies) to a minimum.
ONLY update things IF there is actually an update.

In addition, it also gets called when logging first into 3D Sailing Mode here in BattleInterface.c:
Code:
    if (CheckRelations)
    {
        CheckAllShips("forts", true); // PB: Set initial relations for ships
        CheckAllShips("ships", true); // PB: Set initial relations for forts

        UpdateRelations();
    }
That is probably close to the part where to distinguish a "first HIGH chance false flag detection".
And, in fact, part of that functionality is already there. That's what the true/false flag is for:
'bool initialize' marks whether the call is when first loading the scene OR if it's part of the ever-minute-check instead.

Possibly because 'SetGroupHostile' is called directly by 'CheckForMainCharacterfalseflag' if the randomised check against the chance of detection triggers.
Not adding up yet...

It's also not a factor in any of these tests because I haven't been firing at anyone, so the only firing that happens is if a ship or fort detects my false flag and does turn properly hostile. (At which point I still don't fire, partly because I don't want to raise my true flag and provoke more hostility, but mainly because in that case this test has concluded successfully so I reload my savegame in San Juan port and try again.)
That doubly confirms then that indeed that part isn't relevant.

Santiago's fort is on a point of land. If you sail to the wrong side of that port, you end up at Playa de Sierra Maestra, which is also within range of the fort ("Ardent" makes significant use of this). And if that player was using an old game in which Playa de Sierra Maestra wasn't accessible outside the "Bartolomeu" storyline, he could quite easily fail to find Santiago.
I think it was Grenada in that video.
But sure, if you spend barely 5 seconds in 3D Sailing Mode to look around you to find a town, yeah, you can miss it.
(Spyglass, spyglass, spyglass!!)

For that matter, San Juan's fort is on a point guarding the entrance to the town and can easily be seen from the other side of that point. And then there's Cartagena fort, which is some way out of town, half way up a long peninsula. For some reason you can't get to Cartagena by worldmap, it always drops you some way out of town even if you have sailed right to the town on the map. So I can easily imagine a player running into that fort, not spotting the town, and trying to use worldmap to get closer to shore, which doesn't work.
Cartagena maybe the worldmap and 3D Sailing Mode islands don't quite line up...?
That WAS exceedingly tricky to set up, as I recall from @Armada.

As Barbossa might say, "Ah, we has us a problem there!" For one thing, I am one of those "worldmap-obsessed players" - if I'm playing a main story plus two or three sidequests together, especially if one of them is time-limited, I'm not inclined to switch to 3D sailing a long way out of town and take my chances with a low wind, or a wind pointing the wrong way, in conjunction with 1 hour days! For another, quoting from the new long comment near the end of "globals.c", "you are a pirate; and you are FREE!" :p The game gives the player various options - who's to say which one is the way the game is meant to be played? (The original game didn't have Direct Sail, so it could be argued that using worldmap to get near the destination and then Sail-To to finish the trip is the way it's meant to be played!)
Truth be told, I myself got even worse when playing.
I'd just console-magic myself to the next island altogether at some point. :rofl

I do reckon it's a bit of a 'fake' way of playing.
Because it really gets SO FAR removed from realistic sailing.
And "Iron Man Mode" is MUUUUUCH more awesome!!

But only in theory. In practice, it's often just not practicable.
And in the end, if the player has fun, that's all that matters.

If you spotted that comment, then did you also notice the one in the Save/Load menu?
The change I made there was probably EVEN WORSE!!!

I can't remember where it was from, but "we are pirates; and we are FREE" is something where I was inspired by some song lyrics.
One of those fun rock/shanty/pirate combo things.

I'm not sure if I can have a value which reduces with time. But it might be possible to set the chance higher at the first check and then drop it to the normal lower setting from then on.
Both are possible; and I am sure.
One option I already happened to spoil a bit above in this post.
For the other: I think it is 'pchar.seatime' where the amount of time in 3D Sailing Mode since the previous reload is stored.
That could be worked into a formula too.
I'd imagine some sort of 1/x effect; with a max and a min to prevent it going all the way from infinite to basically zero.
 
It is true that 'CheckAllShips' does not call 'RefreshBattleInterface' directly.
But in LogInterface.c:
Code:
                    bool Recognized = false;
                    Recognized = Recognized || CheckAllShips("forts", false);
                    Recognized = Recognized || CheckAllShips("ships", false);
                    if (Recognized)
                    {
                        if(iRealismMode<2)
                            LogIt(TranslateString("", "We are recognized, captain!"));
                        RefreshBattleInterface(true);
                    }
So 'CheckAllShips' returning true DOES trigger 'RefreshBattleInterface(true)' a few lines down.
The point is, 'CheckAllShips' does not call 'RefreshBattleInterface'. 'procUpdateTime()' in "LogInterface.c" calls 'CheckAllShips' and on the basis of the result may call 'RefreshBattleInterface'. It would seem that 'CheckAllShips', or more specifically 'CheckForMainCharacterfalseflag', is called somewhere else as well, without calling 'procUpdateTime()'. Because I got my traces from 'CheckForMainCharacterfalseflag' showing the false flag had been detected, but I did not see the message "We are recognized, captain!"

And it does so ONLY when returning true; and only once.
I designed that specifically to minimize the amount of updates (for performance) and flag changes (remember those graphic anomalies) to a minimum.
ONLY update things IF there is actually an update.

In addition, it also gets called when logging first into 3D Sailing Mode here in BattleInterface.c:
Code:
    if (CheckRelations)
    {
        CheckAllShips("forts", true); // PB: Set initial relations for ships
        CheckAllShips("ships", true); // PB: Set initial relations for forts

        UpdateRelations();
    }
That is probably close to the part where to distinguish a "first HIGH chance false flag detection".
And, in fact, part of that functionality is already there. That's what the true/false flag is for:
'bool initialize' marks whether the call is when first loading the scene OR if it's part of the ever-minute-check instead.
I hadn't got as far as checking where 'CheckAllShips' is called but I had spotted that "initialize" argument. However, it occurs to me that giving the enemy an enhanced chance of spotting you on first observation will cause more problems. You sail successfully into port, do whatever you came to do, then put to sea - right in front of the fort, which now gets the enhanced chance of detection at short range.

I think it was Grenada in that video.
But sure, if you spend barely 5 seconds in 3D Sailing Mode to look around you to find a town, yeah, you can miss it.
(Spyglass, spyglass, spyglass!!)
Even the best spyglass won't help you spot the town if you're on the other side of the peninsula. In fact, the fort is so far away from town that even if you are on the correct side of the peninsula (which you probably are if you have any idea where Cartagena is and are trying to get there by worldmap), you can be close enough to the fort and far enough from town that you can see the fort but not the town, especially in poor weather. Or you might spot the town and it's a long way off, you don't know that Cartagena doesn't work properly from worldmap, so you keep trying to get closer to town on the worldmap and keep getting placed some distance out.

Both are possible; and I am sure.
One option I already happened to spoil a bit above in this post.
For the other: I think it is 'pchar.seatime' where the amount of time in 3D Sailing Mode since the previous reload is stored.
That could be worked into a formula too.
I'd imagine some sort of 1/x effect; with a max and a min to prevent it going all the way from infinite to basically zero.
That 'pchar.seatime' could work, provided there's also a way to detect where you were before you reloaded. Apply a factor based on seatime if you reloaded from worldmap, don't apply it - or apply a reduced factor - if you reloaded from land, so that the fort doesn't get you almost automatically when you leave port.

There is, of course, another way to solve this. You presumably want players to direct-sail some distance to and from port, and also want a significant chance of false flags being detected. Whereas I often like to use worldmap to get to port, and want just enough chance of false flag detection that you're not guaranteed safe passage. Leaving the system as I have it now would satisfy both those sets of requirements. xD
 
The point is, 'CheckAllShips' does not call 'RefreshBattleInterface'. 'procUpdateTime()' in "LogInterface.c" calls 'CheckAllShips' and on the basis of the result may call 'RefreshBattleInterface'. It would seem that 'CheckAllShips', or more specifically 'CheckForMainCharacterfalseflag', is called somewhere else as well, without calling 'procUpdateTime()'. Because I got my traces from 'CheckForMainCharacterfalseflag' showing the false flag had been detected, but I did not see the message "We are recognized, captain!"
The "we are recognized" message is limited to Arcade mode; so that's not reliable data.
I recommend putting a proper Trace or TraceAndLog in there to double-check what is and isn't actually executing.

My explanation would also be that 'CheckForMainCharacterfalseflag' is called elsewhere; except that, no, it's not.
It is exclusively in 'CheckAllShips' and nowhere else.
And 'CheckAllShips' gets called from two points: LogInterface (every minute) and BattleInterface (first load to 3D Sailing).

This is what my Windows Search results tell me; plus I know it to be true, because all that code is stuff I added myself.

I hadn't got as far as checking where 'CheckAllShips' is called but I had spotted that "initialize" argument. However, it occurs to me that giving the enemy an enhanced chance of spotting you on first observation will cause more problems. You sail successfully into port, do whatever you came to do, then put to sea - right in front of the fort, which now gets the enhanced chance of detection at short range.
Would need to be an extra check invented then for "from worldmap" vs. "from anywhere else".

Even the best spyglass won't help you spot the town if you're on the other side of the peninsula. In fact, the fort is so far away from town that even if you are on the correct side of the peninsula (which you probably are if you have any idea where Cartagena is and are trying to get there by worldmap), you can be close enough to the fort and far enough from town that you can see the fort but not the town, especially in poor weather. Or you might spot the town and it's a long way off, you don't know that Cartagena doesn't work properly from worldmap, so you keep trying to get closer to town on the worldmap and keep getting placed some distance out.
Stupid game.

That 'pchar.seatime' could work, provided there's also a way to detect where you were before you reloaded. Apply a factor based on seatime if you reloaded from worldmap, don't apply it - or apply a reduced factor - if you reloaded from land, so that the fort doesn't get you almost automatically when you leave port.
Right now I'm not entirely sure on how, but I'm sure such a check could be invented.

There is, of course, another way to solve this. You presumably want players to direct-sail some distance to and from port, and also want a significant chance of false flags being detected. Whereas I often like to use worldmap to get to port, and want just enough chance of false flag detection that you're not guaranteed safe passage. Leaving the system as I have it now would satisfy both those sets of requirements. xD
What I want is irrelevant. I haven't played in years.

I do reckon the chance of false flag detection should be significant; because if is it INsignificant, the whole feature might as well not exist.
Which doesn't mean that chance should be over-the-top large.

I also know for sure that DirectSail was one of the most requested and appreciated features in the mod.
So it only makes sense to make to take players who use it into account.

Certainly you could keep the detection chances low across the board.
Sure, then effectively worldmap can be used as a "cheat" to circumvent a lot of the risk.
But if players want to cheat, let them cheat. We didn't add an easy cheatmode for nothing.

Effectively speaking though, do I understand you yourself basically spend zero time in 3D Sailing Mode at all?
Excepting sea battles, of course?
 
The "we are recognized" message is limited to Arcade mode; so that's not reliable data.
I recommend putting a proper Trace or TraceAndLog in there to double-check what is and isn't actually executing.
No, it's blocked in "Iron Man" mode. The condition is 'if(iRealismMode<2)'. And so I did see it when the enemy became properly hostile.

Would need to be an extra check invented then for "from worldmap" vs. "from anywhere else".
There will need to be some sort of check, because I've no intention of making it near impossible to leave port without the fort detecting your false flag!

I do reckon the chance of false flag detection should be significant; because if is it INsignificant, the whole feature might as well not exist.
Which doesn't mean that chance should be over-the-top large.

I also know for sure that DirectSail was one of the most requested and appreciated features in the mod.
So it only makes sense to make to take players who use it into account.
That is what I'm doing, which is why I've drastically reduced the final chance against which the random check is made for false flag detection! Players who want full realism can direct-sail everywhere and take their chances; players who are less interested in full realism and more interested with getting on with the quest or story of their choice still get a slight chance of recognition. And since the consequences of recognition are pretty severe (immediate attack by the fort, then needing to pay for amnesty or change ship if you ever want to get in there again), the probability of recognition should be fairly low.

Or else I'll need to see if adding "townsack" to beach locations really does make traders get their wares and money if you land at a beach. Then I can afford to bump up the chances of recognition a bit, because if you don't want to risk being detected then you can go for the beach instead.

Effectively speaking though, do I understand you yourself basically spend zero time in 3D Sailing Mode at all?
Excepting sea battles, of course?
Generally I'll stay in 3D sailing until the mooring icon disappears and is replaced by the worldmap icon. And sometimes I'll direct-sail the whole way to the next port just because I can. On the other hand, if the wind is blowing straight into port and I can't tack out, either because there isn't room or because I have other things to do with my real life time, I'll go to worldmap as soon as I set sail. (Or Sail-To a beach on the other side of the island, nearer to where I'm going next.)
 
Update: I think I've found why enemy ships sometimes turn properly hostile and sometimes don't. In "CheckAllShips":
Code:
        for (i = 0; i < num; i++) {
            shipstr = "l" + i;
            shipidx = sti(shipattr.(shipstr).idx);
            if (shipidx < 0) continue;
            chr = GetCharacter(shipidx);
            ship_range       = shipattr.(shipstr).distance;
            visibility_range = GetCharVisibilityRange(chr, 2); // KK: Ship nation is visible inside MEDIUM range
            if(Whr_IsNight() && HasCharacterShipAttribute(PChar, "night_stealth")) visibility_range /= 2;    // PB: Black Pearl stealth at night
            
            if (initialize)
            {
                CheckInitialFlagRelations(chr, visibility_range, ship_range);
            }
            else
            {
                if (ship_range < visibility_range)
                {
                    bool bCheckInitial = false;
                    if (!CheckAttribute(chr, "PlayerShip"))                                    bCheckInitial = true;    // GR: If you can be seen and aren't already logged, you are now
                    if (CheckAttribute(chr, "PlayerShip") && !HasThisShip(chr.PlayerShip))    bCheckInitial = true;    // GR: If you are already logged and the log is out of date, update it
                    if (bCheckInitial) CheckInitialFlagRelations(chr, visibility_range, ship_range);
                }
                Recognized = CheckForMainCharacterfalseflag(chr, visibility_range, ship_range);
            }
        }
For each ship, it sets variable "Recognized" based on the result of 'CheckForMainCharacterfalseflag' for that ship. So, in a group of two ships, ship 1 may have recognised you but ship 2 has not, which means 'CheckAllShips' returns false. Therefore my "compile.log" shows both ships continuing to try to check even though both ships have the "recognized" attribute" - 'procUpdateTime()' calls 'CheckAllShips' on the ships, gets a false result, and doesn't update anything. Also, 'CheckForMainCharacterfalseflag' doesn't seem to check the "Recognized" attribute.

So what I'm now trying is to change the line in 'CheckAllShips':
Code:
Recognized = Recognized || CheckForMainCharacterfalseflag(chr, visibility_range, ship_range);
And in 'CheckForMainCharacterfalseflag', I'm adding a few more exceptions at the start:
Code:
    if (iForceDetectionFalseFlag == 1)        return true;  // Don't bother calculating chances, 1 means always recognise you
    if (iForceDetectionFalseFlag == -1)        return false; // Also don't calculate chances because -1 means never recognise you
    if (CheckAttribute(chr, "Recognized"))        return true;  // This ship has already recognised you
(The check for "iForceDetectionFalseFlag == 1" was just after the chance calculations - I've moved it to the exceptions because there's no point doing all the calculating and calling 'GetChanceDetectFalseFlag()' if the ship is going to automatically recognise you anyway.)
 
GOOD DAM CATCH, @Grey Roger!
Indeed it would appear that you found the real eff-up of mine.
Did code it properly in LogInterface.c; but should've done the same in Screwface_functions and didn't.
That's officially MY BAD!!

You might want to avoid this one though:
Code:
if (iForceDetectionFalseFlag == 1)        return true;  // Don't bother calculating chances, 1 means always recognise you
That one implies that you DO get recognized, but because you immediately abort the function, these lines will never get executed:
Code:
                Trace("FLAGS: The " + GetMyShipNameShow(chr) + " has recognized our false " + GetNationDescByType(GetCurrentFlag()) + " flag at range=" + ship_range + " with visibility=" + visibility_range + ", chance=" + chance + " and frnd=" + randVal);
                Recognized = true;
                SetGroupHostile(chr, false); // They start firing on you, so it is no immediate betrayal

Actually, instead, it appears this line is superfluous:
Code:
if(iForceDetectionFalseFlag == 1) chance = 1.0; // PB: Obeys "iForceDetectionFalseFlag" setting to always see through false flag
That's already in nations.c:
Code:
float GetChanceDetectFalseFlag()
{
    // original code -->
    //    float rank = GetRankFromPoints(GetScore(GetMainCharacter()));
    //    return CHANCE_DETECT_FALSE_FLAG_BASE+(CHANCE_DETECT_FALSE_FLAG_MAX-CHANCE_DETECT_FALSE_FLAG_BASE)*rank/MAX_RANK;
    // original code <--

    // PB -->
    if (iForceDetectionFalseFlag ==  1)    return 1.0;
    if (iForceDetectionFalseFlag == -1)    return 0.0;
    // PB <--
Which got checked literally the line before; so it's just doing the same thing twice.

I also don't think you'll get any worthwhile performance by checking the "recognized" attribute.
Any ship with that attribute should be automatically hostile and therefore the 'SeaAI_GetRelation' check a few lines down will always fail.

So I'd suggest leaving the exceptions at the top as they are.
But definitely DO make that fix to 'CheckAllShips'.
That's a boo-boo of mine for sure. :thumbsdown2
 
You might want to avoid this one though:
Code:
if (iForceDetectionFalseFlag == 1)        return true;  // Don't bother calculating chances, 1 means always recognise you
That one implies that you DO get recognized, but because you immediately abort the function, these lines will never get executed:
Code:
                Trace("FLAGS: The " + GetMyShipNameShow(chr) + " has recognized our false " + GetNationDescByType(GetCurrentFlag()) + " flag at range=" + ship_range + " with visibility=" + visibility_range + ", chance=" + chance + " and frnd=" + randVal);
                Recognized = true;
                SetGroupHostile(chr, false); // They start firing on you, so it is no immediate betrayal
OK, I'll remove that one and put back this one:

Actually, instead, it appears this line is superfluous:
Code:
if(iForceDetectionFalseFlag == 1) chance = 1.0; // PB: Obeys "iForceDetectionFalseFlag" setting to always see through false flag
That's already in nations.c:
Code:
float GetChanceDetectFalseFlag()
{
    // original code -->
    //    float rank = GetRankFromPoints(GetScore(GetMainCharacter()));
    //    return CHANCE_DETECT_FALSE_FLAG_BASE+(CHANCE_DETECT_FALSE_FLAG_MAX-CHANCE_DETECT_FALSE_FLAG_BASE)*rank/MAX_RANK;
    // original code <--

    // PB -->
    if (iForceDetectionFalseFlag ==  1)    return 1.0;
    if (iForceDetectionFalseFlag == -1)    return 0.0;
    // PB <--
Which got checked literally the line before; so it's just doing the same thing twice.
Except that I've put my scaling factor to give direct-sailors a chance to get past the fort after the call on 'GetChanceDetectFalseFlag', which means if that returns 1.0 for forced flag recognition then it's going to end up as 0.04. Currently, anyway - I started by dividing by 50 because I'd been checked 50 times sailing past San Juan fort, then removed a line which adds 0.5 onto the chance before 'GetChanceDetectFalseFlag', so now I'm dividing by 25 instead, and may change the factor again depending on how often I'm recognised. So that line to put the chance back up to 1.0 if iForceDetectionFalseFlag is 1 needs to stay.

I also don't think you'll get any worthwhile performance by checking the "recognized" attribute.
Any ship with that attribute should be automatically hostile and therefore the 'SeaAI_GetRelation' check a few lines down will always fail.
The idea is to make 100% sure that if the ship has the "Recognized" attribute then 'CheckForMainCharacterfalseflag' returns positive, which feeds back right away to 'CheckAllShips', which then feeds back up the line to 'procUpdateTime()'. It's for reliability, not performance.

Also, note that 'CheckForMainCharacterfalseflag', if it gets past the exceptions, starts by setting variable "Recognized" to false. If it then does nothing because 'SeaAI_GetRelation(sti(chr.index), sti(PChar.index)) != RELATION_ENEMY' failed, then the function returns false. That may be another reason why ships which had recognised me weren't turning hostile.
 
Except that I've put my scaling factor to give direct-sailors a chance to get past the fort after the call on 'GetChanceDetectFalseFlag', which means if that returns 1.0 for forced flag recognition then it's going to end up as 0.04. Currently, anyway - I started by dividing by 50 because I'd been checked 50 times sailing past San Juan fort, then removed a line which adds 0.5 onto the chance before 'GetChanceDetectFalseFlag', so now I'm dividing by 25 instead, and may change the factor again depending on how often I'm recognised. So that line to put the chance back up to 1.0 if iForceDetectionFalseFlag is 1 needs to stay.
It doesn't make sense for it to be in two places though.
Couldn't you scale the factor by changing this number?
Code:
chance = 0.5 + chance; // 0.5 will be decreased if you are too easily recognized
Looks like that was already the idea there, at least.
0.5 also looks like an obvious default prior to balancing.

The idea is to make 100% sure that if the ship has the "Recognized" attribute then 'CheckForMainCharacterfalseflag' returns positive, which feeds back right away to 'CheckAllShips', which then feeds back up the line to 'procUpdateTime()'. It's for reliability, not performance.
That means changing more than one thing at the same time, which isn't always wise.
Things might appear to work better, but you won't know which change fixed things and sometimes remaining issues might've ended up swept under the rug.

At this point, I cannot quite oversee the potential ramifications of 'return true' on that function.
Because that is basically saying "yes, a false flag was detected" BUT it bypasses the the actual functionality of detection.

And actually, there WILL be one side-effect.
LogInterface will now get a 'true' every minute and therefore try to update the BattleInterface (and the flags!) every minute.
Basically forever as long as there is any "recognized" ship anywhere in the scene.
That runs contrary to my design where these updates are executed exclusive when necessary;
so when an actual detection happens (single event).

Chances are, that will reduce performance in some way; and could potentially increase the risk of Graphic Anomalies (because of those flags).

So also here...
Proceed with care.

Also, note that 'CheckForMainCharacterfalseflag', if it gets past the exceptions, starts by setting variable "Recognized" to false. If it then does nothing because 'SeaAI_GetRelation(sti(chr.index), sti(PChar.index)) != RELATION_ENEMY' failed, then the function returns false. That may be another reason why ships which had recognised me weren't turning hostile.
Which is exactly a good thing; because it's not meant to.
A "false flag detection" is meant to be a single moment where a ship realizes they cannot trust you.
At that moment, they turn FROM neutral TO hostile.
That isn't necessary if they are already hostile.

A hostile ship cannot detect your false flag; because they do not care.
They already know you cannot be trusted.


My (strong) recommendation:
Make ONLY that one change to 'CheckAllShips' to begin with.
I can 100% guarantee you that was wrong on my part.
And it absolutely explains why a ton of detections didn't trigger their required updates.

There's no need to keep searching for other potential causes,
UNLESS after fixing the bug you find that things STILL don't work as intended.

In this case, for certain, this WILL make a TON of difference:
Code:
Recognized = Recognized || CheckForMainCharacterfalseflag(chr, visibility_range, ship_range);
 
OK, I've taken out most of my changes. 'GetAttribute' is still changed to 'CheckAttribute', "Recognized = Recognized || CheckForMainCharacterfalseflag(chr, visibility_range, ship_range);" is still included, and the scaling factor to divide by 25 replaces the adding of 0.5, before the call on 'GetChanceDetectFalseFlag()'. In line with the suggestion to make ONLY one change (actually two, both confirmed necessary), that's all for now. (Well, not quite. But adding a load of 'trace' statements to see what's going on won't affect the way the function works!) Initial tests look alright.

Meanwhile, I'm trying to fix another bug which has been at the back of my mind for some time and is now at the front because I'm in a position to look into it. In "Tales of a Sea Hawk", you take Silehard's frigate in order to steal the special idol, then escape to the lighthouse, where you're told that Danielle isn't there. So you head for San Juan, are washed overboard, and end up on Bonaire. From there you get a ship by one means or another and make your way to San Juan, where you're reunited with your crew, your original ships, and Danielle. And if possible, the ship which brought you from Bonaire is given to one of your officers so you can keep it or sell it. It's that ship which is causing the trouble - if I then visit the shipyard, it gets scrambled. I tried using 'LAi_StoreFantom' to protect the officer who gets the ship and that didn't help. Odd thing - if I transfer the ship to another officer, even another random tavern recruit, and then go to the shipyard, it's fine.
 
Back
Top