• 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 Virgil Boon has reinforcements

Grey Roger

Sea Dog
Staff member
Administrator
Storm Modder
reinforcements.jpg

I've just boarded the Oiseau and killed Virgil Boon. A garrison commander sends immediate reinforcements. The main effect of this is that I can't save game until I dock at Port Royale, at which point I get the message that I took one of the soldiers' uniforms. In fact there's a new pirate outfit in my wardrobe.

Log files plus a savegame from open sea just before switching to 3D sailing and fighting the Oiseau.
 

Attachments

  • -=Player=- Open Sea June 3rd, 1750.zip
    757.8 KB · Views: 87
  • compile.log
    33.2 KB · Views: 90
  • error.log
    2.9 KB · Views: 134
  • system.log
    3.3 KB · Views: 117
During BOARDING? Wow! :shock

Can you upload the CCCfunctions.c file? That one triggers those reinforcements.
There are several conditions in place to prevent that in cases where it doesn't belong.
Apparently none of those conditions prevent it here though. :facepalm
 
Here's the one from the 18th June update, though the file is dated 17th April so presumably wasn't changed in the last two updates.
 

Attachments

  • CCCFunctions.c
    23.5 KB · Views: 109
Relevant section:
Code:
void SoldierReinforcements(ref refCharacter)
{
ref PChar = GetMainCharacter();
if (sti(GetAttribute(refCharacter, "quest.guard_protection")) < 1)
{
if (GetAttribute(PChar , "vcskip") == true) return;
if (GetAttribute(LoadedLocation, "vcskip") == true) return;
if(!HasSubStr(GetAttribute(refCharacter, "id"), "soldier")) return;
if(!HasSubStr(GetAttribute(refCharacter, "Dialog.Filename"), "Soldier_dialog.c")) return;
if(!HasSubStr(GetAttribute(refCharacter, "location"), "port") && !HasSubStr(GetAttribute(refCharacter, "location"), "town")) return;
}

I'm quite surprised that doesn't prevent it for Mr. Boon. Does he REALLY have a character ID that contains "soldier" and a dialog file that has "Soldier_dialog.c"???
And is his location actually IN a port or town WHILE being at sea?

On second thought, this is probably because he has the quest.guard_protection attribute; virtually no other characters have that!
Probably that has to be removed from him as soon as you set sail.
 
This can probably be fixed here:
Code:
    case "Story_Blaze_and_Boon_leaving":
       characters[GetCharacterIndex("Virgile Boon")].location = "none";
       Characters[GetCharacterIndex("Virgile Boon")].nation = FRANCE; // RM
       //------------Выдача Квестов на нападение Буна на игрока
       Pchar.quest.Story_Convoy_Virgile_Boon_1.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_1.win_condition.l1.location = "Oxbay";
       Pchar.quest.Story_Convoy_Virgile_Boon_1.win_condition = "Convoy_Virgile_Boon";

       Pchar.quest.Story_Convoy_Virgile_Boon_2.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_2.win_condition.l1.location = "Redmond";
       Pchar.quest.Story_Convoy_Virgile_Boon_2.win_condition = "Convoy_Virgile_Boon";

       Pchar.quest.Story_Convoy_Virgile_Boon_3.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_3.win_condition.l1.location = "IslaMuelle";
       Pchar.quest.Story_Convoy_Virgile_Boon_3.win_condition = "Convoy_Virgile_Boon";

       Pchar.quest.Story_Convoy_Virgile_Boon_4.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_4.win_condition.l1.location = "Conceicao";
       Pchar.quest.Story_Convoy_Virgile_Boon_4.win_condition = "Convoy_Virgile_Boon";

       Pchar.quest.Story_Convoy_Virgile_Boon_5.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_5.win_condition.l1.location = "Douwesen";
       Pchar.quest.Story_Convoy_Virgile_Boon_5.win_condition = "Convoy_Virgile_Boon";

       Pchar.quest.Story_Convoy_Virgile_Boon_6.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_6.win_condition.l1.location = "QuebradasCostillas";
       Pchar.quest.Story_Convoy_Virgile_Boon_6.win_condition = "Convoy_Virgile_Boon";

       Pchar.quest.Story_Convoy_Virgile_Boon_7.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_7.win_condition.l1.location = "KhaelRoa";
       Pchar.quest.Story_Convoy_Virgile_Boon_7.win_condition = "Convoy_Virgile_Boon";

       Pchar.quest.Story_Convoy_Virgile_Boon_8.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_8.win_condition.l1.location = "";
       Pchar.quest.Story_Convoy_Virgile_Boon_8.win_condition = "Convoy_Virgile_Boon2";
       character_SetCompanionEnemyEnable(characterFromID("Virgile Boon"), true);

       LAi_SetCitizenType(characterFromID("Tancrede Rimbaud"));
       LAi_group_MoveCharacter(characterFromID("Tancrede Rimbaud"), "FRANCE_CITIZENS");
       LAi_RemoveCheckMinHP(characterFromID("Virgile Boon"));//MAXIMUS
     break;
By adding this line:
Code:
DeleteAttribute(characterFromID("Virgile Boon"), "quest.guard_protection");
That whole section of code looks quite curious though, since it has a whole list of the stock game islands, but NOT any of the new ones.
I wonder if all that can not be replaced with a single "MapEnter" condition?

Also, here in his dialog, there is some false flag detection code:
Code:
    case "Quest_exit":
       //------------Присоединение Вирджила Буна.
       LAi_SetActorType(characterFromID("Tancrede Rimbaud"));
       LAi_type_actor_Reset(characterFromID("Tancrede Rimbaud"));
       LAi_ActorFollow(characterFromID("Tancrede Rimbaud"),characterFromID("Virgile Boon"),"Story_ReturnToFFPortToFindBoon_2",-1);
       if(GetCompanionQuantity(Pchar)>3) { Diag.CurrentNode = "Node_4"; DialogExit(); LaunchKAMShipBerthing(); }//MAXIMUS: -[what will be happened, if we have 3 companions already?]->
       else
       {
         Locations[FindLocation("Falaise_de_fleur_port_01")].reload.l3.disable = 0;
         SetCompanionIndex(Pchar, -1, GetCharacterIndex("Virgile Boon"));
         SetCharacterRemovable(&Characters[GetCharacterIndex("Virgile Boon")], false);

         iForceDetectionFalseFlag = -1;// KK

         Pchar.quest.Story_Blaze_and_Boon_leaving.win_condition.l1 = "location";
         Pchar.quest.Story_Blaze_and_Boon_leaving.win_condition.l1.location = "FalaisedeFleur";
         Pchar.quest.Story_Blaze_and_Boon_leaving.win_condition = "Story_Blaze_and_Boon_leaving";

         Diag.CurrentNode = "Third time";
         DialogExit();
       }//MAXIMUS: <-[what will be happened, if we have 3 companions already?]-
     break;
But I don't see where that is set from -1 back to 0.
Should that not be SafePortLeave?

@Grey Roger, any thoughts?
Also, if you see the chance to look at this more thoroughly, that would be much appreciated.
At the moment I only have time to figure out minor hints like these....
 
This can probably be fixed here:
Code:
    case "Story_Blaze_and_Boon_leaving":
       characters[GetCharacterIndex("Virgile Boon")].location = "none";
       Characters[GetCharacterIndex("Virgile Boon")].nation = FRANCE; // RM
       //------------Выдача Квестов на нападение Буна на игрока
       Pchar.quest.Story_Convoy_Virgile_Boon_1.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_1.win_condition.l1.location = "Oxbay";
       Pchar.quest.Story_Convoy_Virgile_Boon_1.win_condition = "Convoy_Virgile_Boon";

       Pchar.quest.Story_Convoy_Virgile_Boon_2.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_2.win_condition.l1.location = "Redmond";
       Pchar.quest.Story_Convoy_Virgile_Boon_2.win_condition = "Convoy_Virgile_Boon";

       Pchar.quest.Story_Convoy_Virgile_Boon_3.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_3.win_condition.l1.location = "IslaMuelle";
       Pchar.quest.Story_Convoy_Virgile_Boon_3.win_condition = "Convoy_Virgile_Boon";

       Pchar.quest.Story_Convoy_Virgile_Boon_4.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_4.win_condition.l1.location = "Conceicao";
       Pchar.quest.Story_Convoy_Virgile_Boon_4.win_condition = "Convoy_Virgile_Boon";

       Pchar.quest.Story_Convoy_Virgile_Boon_5.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_5.win_condition.l1.location = "Douwesen";
       Pchar.quest.Story_Convoy_Virgile_Boon_5.win_condition = "Convoy_Virgile_Boon";

       Pchar.quest.Story_Convoy_Virgile_Boon_6.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_6.win_condition.l1.location = "QuebradasCostillas";
       Pchar.quest.Story_Convoy_Virgile_Boon_6.win_condition = "Convoy_Virgile_Boon";

       Pchar.quest.Story_Convoy_Virgile_Boon_7.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_7.win_condition.l1.location = "KhaelRoa";
       Pchar.quest.Story_Convoy_Virgile_Boon_7.win_condition = "Convoy_Virgile_Boon";

       Pchar.quest.Story_Convoy_Virgile_Boon_8.win_condition.l1 = "location";
       Pchar.quest.Story_Convoy_Virgile_Boon_8.win_condition.l1.location = "";
       Pchar.quest.Story_Convoy_Virgile_Boon_8.win_condition = "Convoy_Virgile_Boon2";
       character_SetCompanionEnemyEnable(characterFromID("Virgile Boon"), true);

       LAi_SetCitizenType(characterFromID("Tancrede Rimbaud"));
       LAi_group_MoveCharacter(characterFromID("Tancrede Rimbaud"), "FRANCE_CITIZENS");
       LAi_RemoveCheckMinHP(characterFromID("Virgile Boon"));//MAXIMUS
     break;
By adding this line:
Code:
DeleteAttribute(characterFromID("Virgile Boon"), "quest.guard_protection");
Yes, I'd guessed as much. It should be in any recent version of "quests_reaction.c" I uploaded.

That whole section of code looks quite curious though, since it has a whole list of the stock game islands, but NOT any of the new ones.
I wonder if all that can not be replaced with a single "MapEnter" condition?
No, because that detects when you go into worldmap, whereas "Convoy_Virgile_Boon" and "Convoy_Virgile_Boon2" need to happen when you're at sea and ready for the battle to start. It's probably a list of stock islands because most of the code dates back to the stock game. I borrowed some of the "Virgile Boon" code for my convoy battle in "Ardent" and had to do something similar, so I picked a few islands near where you join the convoy (if you direct-sail the whole time, you'll probably run into one of them) plus a couple of likely end destinations, plus the same check for location "" which is triggered if you went to worldmap and then exited out of range of any island. Possibly add a check for Guadeloupe to the above list. Otherwise if you start from Martinique, the next places you're likely to hit if you direct-sail are Barbados or Puerto Rico. Or you may intentionally be leading the Oiseau] to an English fort, which means Jamaica, Barbados or Nevis, and they're all checked.

Also, here in his dialog, there is some false flag detection code:
Code:
    case "Quest_exit":
       //------------Присоединение Вирджила Буна.
       LAi_SetActorType(characterFromID("Tancrede Rimbaud"));
       LAi_type_actor_Reset(characterFromID("Tancrede Rimbaud"));
       LAi_ActorFollow(characterFromID("Tancrede Rimbaud"),characterFromID("Virgile Boon"),"Story_ReturnToFFPortToFindBoon_2",-1);
       if(GetCompanionQuantity(Pchar)>3) { Diag.CurrentNode = "Node_4"; DialogExit(); LaunchKAMShipBerthing(); }//MAXIMUS: -[what will be happened, if we have 3 companions already?]->
       else
       {
         Locations[FindLocation("Falaise_de_fleur_port_01")].reload.l3.disable = 0;
         SetCompanionIndex(Pchar, -1, GetCharacterIndex("Virgile Boon"));
         SetCharacterRemovable(&Characters[GetCharacterIndex("Virgile Boon")], false);

         iForceDetectionFalseFlag = -1;// KK

         Pchar.quest.Story_Blaze_and_Boon_leaving.win_condition.l1 = "location";
         Pchar.quest.Story_Blaze_and_Boon_leaving.win_condition.l1.location = "FalaisedeFleur";
         Pchar.quest.Story_Blaze_and_Boon_leaving.win_condition = "Story_Blaze_and_Boon_leaving";

         Diag.CurrentNode = "Third time";
         DialogExit();
       }//MAXIMUS: <-[what will be happened, if we have 3 companions already?]-
     break;
But I don't see where that is set from -1 back to 0.
Should that not be SafePortLeave?
Yes, that might be a good idea. "SafePortLeave" sets up a quest which, upon mapenter, cancels "iForceDetectionFalseFlag" and hoists your served nation flag, which at this point is probably British. (Which flag will it hoist if your served nation is Personal, e.g. if you've bought a second LoM? Because if it's going to auto-hoist a Personal flag then I'm avoiding it like the plague!)
 
No, because that detects when you go into worldmap, whereas "Convoy_Virgile_Boon" and "Convoy_Virgile_Boon2" need to happen when you're at sea and ready for the battle to start.
Use a MapEnter to trigger another quest case that has a SeaEnter condition? And then it doesn't matter where you exit Worldmap.
Would that work?

Yes, that might be a good idea. "SafePortLeave" sets up a quest which, upon mapenter, cancels "iForceDetectionFalseFlag" and hoists your served nation flag, which at this point is probably British. (Which flag will it hoist if your served nation is Personal, e.g. if you've bought a second LoM? Because if it's going to auto-hoist a Personal flag then I'm avoiding it like the plague!)
It hoists your Served Nation Flag, which is the most straightforwatrd thing to do.
You should be able to change it to store what flag you had before it was called and restore that instead.
That would also be fine by me. :yes
 
Use a MapEnter to trigger another quest case that has a SeaEnter condition? And then it doesn't matter where you exit Worldmap.
Would that work?
I'm not sure. I think "MapEnter" triggers if you direct-sail out of range of the current island, even if direct-sail means you've just gone to a different island. So the video of Hornblower being captured by the Spanish, which is triggered by "MapEnter", happens if you direct-sail away from Jamaica. Does "SeaEnter" also trigger at the same time?

It hoists your Served Nation Flag, which is the most straightforwatrd thing to do.
You should be able to change it to store what flag you had before it was called and restore that instead.
That would also be fine by me. :yes
Alright, see if you think this will work. In "quests.c":
Code:
void SafePortLeave(int iNation, bool bOverride)
{
   ref mchr = GetMainCharacter();
   if (GetNationRelation2MainCharacter(iNation) == RELATION_ENEMY || bOverride) // Only if Required
   {
     HoistFlag(iNation); // PB: Hoist False Flag

     mchr.quest.Safe_Port_Leave.flag = GetCurrentFlag();
     mchr.quest.Safe_port_leave.win_condition.l1 = "MapEnter";
     mchr.quest.Safe_port_leave.win_condition = "Safe_port_leave";

     iForceDetectionFalseFlag = -1;
   }
}
And in "quests_common.c":
Code:
    case "Safe_port_leave":
       iForceDetectionFalseFlag = 0;
//       HoistFlag(GetServedNation()); // PB: Restore original flag after false flag
       HoistFlag(PChar.quest.Safe_Port_Leave.flag); // GR: *really* restore original flag after false flag
       DeleteQuestAttribute("Safe_Port_Leave.flag");
     break;
As usual, for now I leave the original line there, commented out, in case this doesn't work and the original needs to be put back.
 
You would need to put the Hoist Flag command later than the line where you store the flag (otherwise you store the new flag instead of the old one).
And you may need an sti around the attribute use as the game stores all attributes as strings, but you need it to be an integer.
Other than that, looks like it should work.

Not sure if "completing a quest" also deletes is attributes. I think it might do.
If so, you might have to store that attribute outside the "quests" section. But that is easy enough to test and change of required. :onya

Map Enter deliberately triggers also when using DirectSail.
Not sure if Sea Enter does too. Maybe it is good enough if the command executes on worldmap/first DirectSail reload?
 
You would need to put the Hoist Flag command later than the line where you store the flag (otherwise you store the new flag instead of the old one).
And you may need an sti around the attribute use as the game stores all attributes as strings, but you need it to be an integer.
Other than that, looks like it should work.
Now modified accordingly and included in the "Ardent" update.

Not sure if "completing a quest" also deletes is attributes. I think it might do.
If so, you might have to store that attribute outside the "quests" section. But that is easy enough to test and change of required. :onya
I don't think so. When playtesting that "Ardent" update, I noticed that the citizens of Santiago still gave the kidnap hint even though I'd completed the "Kidnap" section ages ago in that playthrough, because I'd missed out deleting the attribute which they detect at one of the places where the quest completes. Besides, once quest "Safe_port_leave" has completed, I want that attribute deleted! It won't be needed again unless "SafePortLeave" is called again, at which point it will presumably be set again.

Map Enter deliberately triggers also when using DirectSail.
Not sure if Sea Enter does too. Maybe it is good enough if the command executes on worldmap/first DirectSail reload?
The problem I can foresee is that if the command is triggered by "MapEnter" then it will trigger correctly if you DirectSail out of range of your current island, but it will also trigger when you go to WorldMap. If "MapEnter" is used to trigger another quest case which sets a check for "SeaEnter", that would probably work if you go to WorldMap and then exit, but I'm less certain that it would work if you're DirectSailing the whole way. Will it trigger at once because you're already at sea, or wait until you hit the next island and the game reloads to that island, or will it not trigger at all because you aren't entering sea as you're always there?

Whereas detecting a few strategically chosen islands plus blank location for if you exited WorldMap out in the open sea does work, at least for what I'm doing in "Ardent". If someone plays "Tales of a Sea Hawk" and complains that they can't trigger the battle with Oiseau, it may be time to revisit this. Otherwise there are enough problems which do need fixing without looking for problems which don't need fixing. ;)
 
I don't think so. When playtesting that "Ardent" update, I noticed that the citizens of Santiago still gave the kidnap hint even though I'd completed the "Kidnap" section ages ago in that playthrough, because I'd missed out deleting the attribute which they detect at one of the places where the quest completes.
There is definitely some sort of clearing going on of unused quest attributes though; I've seen the code for it.
Also, if you do a DumpAttributes on your player character, you should see that the 'quests' tree doesn't actually contain all quests that you ever executed.
But I don't remember exactly when that is done.

Besides, once quest "Safe_port_leave" has completed, I want that attribute deleted! It won't be needed again unless "SafePortLeave" is called again, at which point it will presumably be set again.
Of course. I just thought it may end up being deleted too early.
But if that is indeed the case, you'd get a "missed attribute" message in error.log, so you'd definitely notice. :cheeky

The problem I can foresee is that if the command is triggered by "MapEnter" then it will trigger correctly if you DirectSail out of range of your current island, but it will also trigger when you go to WorldMap. If "MapEnter" is used to trigger another quest case which sets a check for "SeaEnter", that would probably work if you go to WorldMap and then exit, but I'm less certain that it would work if you're DirectSailing the whole way.
Not sure about that either. My preferred solution would be to use only the "MapEnter" one.
Is there any harm in that quest update being done while on the WorldMap?

Whereas detecting a few strategically chosen islands plus blank location for if you exited WorldMap out in the open sea does work, at least for what I'm doing in "Ardent". If someone plays "Tales of a Sea Hawk" and complains that they can't trigger the battle with Oiseau, it may be time to revisit this. Otherwise there are enough problems which do need fixing without looking for problems which don't need fixing. ;)
I don't particularly like having stuff "hardcoded" like this, instead of generic so it'll work regardless of an "island list".
But indeed you do have a valid point there. :yes
 
Back
Top