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

Medium Priority Fix for error in "danielle_quests_pirate_dialog.c"

Grey Roger

Sea Dog
Staff member
Administrator
Storm Modder
You've escorted Vigila Mendes to Martinique and back, and now you're helping Zaid Murro by going after the bandits who have been killing his cattle. So you talk to the bandit leader and there's a message in "error.log". This is why:
Code:
if (pchar.quest.gambling_with_girl == "prisoned")
The system isn't going to like that if attribute "gambling_with_girl" doesn't exist because you haven't started the "Girl Won in a Card Game" side quest.

So here's a version of the file with that condition replaced by this:
Code:
if (CheckQuestAttribute("gambling_with_girl", "prisoned"))
Can someone who is playing the side quest copy this into "PROGRAM\DIALOGS" and then see what happens if you take Virginie d'Espivant prisoner rather than offer to help her? This condition is supposed to check that she's a prisoner because, as well as being bandit leader, the same character also shows up in the tavern and offers to buy Virginie from you.
 

Attachments

  • danielle_quests_pirate_dialog.c
    3.5 KB · Views: 316
Definitely makes sense to replace that, @Grey Roger! :onya

The only thing that can possibly go wrong here is if somehow this never caused a problem because it failed.
I've had that before: Fix an actual coding error and because the code then actually works like it was apparently intended, weird stuff happened that never did before when it still failed. :facepalm
 
And... it didn't work. That is, the whole scene with the pirate didn't work. He didn't show up.

The whole quest seems to have been rewritten. For one thing, if I recall correctly, originally you had to gamble a lot before it would trigger - it seemed as though you needed to defeat literally every gambler in the archipelago. This time I fleeced one guy in Port Royale tavern, then talked to the second permanent resident and he triggered the quest right away. I took the precaution of saving game while we were on the way up to the tavern room, so that if there turned out to be a problem with "danielle_quests_pirate_dialog.c", I could edit it and try again. That wasn't the problem, though.

In "quests_common.c":
Code:
       case "girl_for_sale":
           LAi_type_actor_Reset(CharacterFromID("Virginie d'Espivant"));
           ChangeCharacterAddress(CharacterFromID("Virginie d'Espivant"), "none", "none");/*
           PostEvent("CheckQuestPossibility", 100, "1", 0);
           pchar.quest.not_to_the_ship_2.win_condition.l1 = "ExitFromLocation";
           pchar.quest.not_to_the_ship_2.win_condition.l1.location = pchar.location;
           pchar.quest.not_to_the_ship_2.win_condition = "girl_for_sale_2";*///MAXIMUS: moved to MAXIMUS_Functions.c
       break;
The code to set up the encounter with the pirate when you leave the tavern room has been commented out. Following the clue from the comment, in MAXIMUS_Functions.c:
Code:
#event_handler("CheckQuestPossibility", "CheckGambledQuest");
void CheckGambledQuest()
{
   ref PChar = GetMainCharacter();
   if(!HasSubStr(PChar.location,"tavern") && !CheckAttribute(PChar,"IsOnDeck"))
   {
       PChar.quest.not_to_the_ship_2.win_condition.l1 = "ExitFromLocation";
       PChar.quest.not_to_the_ship_2.win_condition.l1.location = PChar.location;
       PChar.quest.not_to_the_ship_2.win_condition = "girl_for_sale_2";
   }
   else { PostEvent("CheckQuestPossibility", 100, "1", 0); }
}
I don't know how events work, but at a guess, the idea is that when you're in a location that isn't a tavern and isn't a deck, then the encounter happens when you move to a new location. So the event triggers when I leave the tavern and am in the town centre. Now "PChar.quest.not_to_the_ship_2.win_condition" should trigger when I leave the town centre, which then leads to "girl_for_sale_2". Back to "quests_common.c":
Code:
       case "girl_for_sale_2":
           LAi_SetHP(characterFromID("danielle_quests_corsair_1"), 80.0, 80.0);
           ChangeCharacterAddressGroup(characterFromID("danielle_quests_corsair_1"), pchar.location, "reload", "reload1");
           LAi_SetActorType(characterFromID("danielle_quests_corsair_1"));
           LAi_ActorDialog(characterFromID("danielle_quests_corsair_1"), pchar, "", 2.0, 1.0);
       break;
The pirate tries to spawn at locator "reload/reload1". This fails because I went to the port, and "REDMOND_PORT" has no such locator.

There seem to be two ways out of this. One is to put the code back the way it used to be so that the pirate spawns in the main tavern as soon as you leave the room. The other is to replace that 'ChangeCharacterAddressGroup' with:
Code:
PlaceCharacter(characterFromID("danielle_quests_corsair_1"), "reload");
That should put him at the nearest "reload" locator to you, whichever it happens to be. I tried the latter, the pirate did indeed appear when I entered the port, and the dialog still works properly.
 
The whole quest seems to have been rewritten.
Indeed @Maximus did some major work on it many, many, many years ago.
Can't remember the specifics, but I think he tried to make it work in "any tavern", rather than just the stock game ones.

I don't know how events work,
PostEvent with '100' calls the desired event after a delay of 100 milliseconds.
So effectively the code you show there is an infinite loop that is broken by going outside of the tavern (and NOT onto your ship's deck).
 
I'm not sure how that loop is started, given that the 'PostEvent' at case "girl_for_sale" is part of the block which is commented out, but apparently it does start. But as it now triggers case "girl_for_sale_2" when you leave the tavern and then go somewhere else, it doesn't even work in stock game taverns such as Port Royale if the next place you went does not have locator "reload1". The easiest and probably most sensible fix is the one I tried, which is to replace the 'ChangeCharacterAddressGroup' line with the 'PlaceCharacter' line. Then the pirate should appear at whatever nearby locator exists in the place where you went to trigger "girl_for_sale_2".
 
I'm not sure how that loop is started, given that the 'PostEvent' at case "girl_for_sale" is part of the block which is commented out, but apparently it does start.
Search for "CheckQuestPossibility" and "CheckGambledQuest"; either of those could trigger it.
 
Got it - there's a "CheckQuestPossibility" in "Virgine d'Espivant_dialog.c".

I'm not sure this part of the quest is ever going to work reliably. With the current 'ChangeCharacterAddressGroup' line, the pirate will try to spawn on "reload1" and fail if you're in a location which has no such locator. With that 'PlaceCharacter' line, he spawns on the nearest "reload" locator other than the one on which you're standing, which may put him a long way away depending on where the nearest other "reload" locator is. For example, if you go back into the tavern, the only other "reload" is the one to the room upstairs, so he spawns upstairs and talks to you from there while you're standing at the door to outside. I don't know if there are gamblers in the Santiago tavern but if there are, and you go from tavern to town centre to port, then the pirate will probably spawn at the jungle exit gate or by the shipyard, both of which are a very long way from the town gate where you enter. And if you enter somewhere which has no other "reload" locator, such as the store, then he won't spawn at all, which may be a good thing but means he's missed his chance and will never spawn anywhere else.

If the 'PlaceCharacter' is changed to use a "goto" locator then the pirate will probably spawn closer to you, and will also spawn when you enter the store, the shipyard, or even the church.

Can gamblers show up in all taverns? In particular, can they show up in those taverns whose inside models were imported from another game, e.g. the one in Santiago and one of the taverns in Cartagena? Most taverns should be able to use the original code because even if the town didn't exist in the stock game, the tavern model did. Otherwise, perhaps rewrite the code for 'CheckGambledQuest()' in "MAXIMUS_Functions.c" so that it doesn't block "tavern" locations. That should allow it to set up the "ExitFromLocation" check either in the tavern room or in the main tavern hall. So the pirate will spawn either in the main tavern hall when you leave the room (as he originally did) or in the town centre when you leave the tavern.
 
I'm not sure this part of the quest is ever going to work reliably. With the current 'ChangeCharacterAddressGroup' line, the pirate will try to spawn on "reload1" and fail if you're in a location which has no such locator. With that 'PlaceCharacter' line, he spawns on the nearest "reload" locator other than the one on which you're standing, which may put him a long way away depending on where the nearest other "reload" locator is. For example, if you go back into the tavern, the only other "reload" is the one to the room upstairs, so he spawns upstairs and talks to you from there while you're standing at the door to outside. I don't know if there are gamblers in the Santiago tavern but if there are, and you go from tavern to town centre to port, then the pirate will probably spawn at the jungle exit gate or by the shipyard, both of which are a very long way from the town gate where you enter. And if you enter somewhere which has no other "reload" locator, such as the store, then he won't spawn at all, which may be a good thing but means he's missed his chance and will never spawn anywhere else.
Isn't there a "FindNearLocator()" function or something like that? Search for a function with "near" in the name.
Maybe that will work?

You can also have a look in quests_common.c for the "Quest Trader" character.
I recall I worked hard at ensuring he would ALWAYS be generated close to you when finishing the quest, but I don't remember how I did that.

Can gamblers show up in all taverns?
I do believe so, but I'm not 100% sure how they work with the AoP tavern models such as the one in Cartagena.
 
Isn't there a "FindNearLocator()" function or something like that? Search for a function with "near" in the name.
Maybe that will work?

You can also have a look in quests_common.c for the "Quest Trader" character.
I recall I worked hard at ensuring he would ALWAYS be generated close to you when finishing the quest, but I don't remember how I did that.
The function you used is 'SetCharacterToNearLocatorFromMe("quest trader", 3)', along with some special code for Antigua. I've copied the entire section, replaced "quest trader" with "danielle_quests_corsair_1", and will need to do a bit of testing to see if it works.

The same fundamental problem still applies, though. If it only starts looking after you've left the tavern, and then waits until you go to another location, then you could be in a store, the governor's house or a church when the pirate shows up.

I do believe so, but I'm not 100% sure how they work with the AoP tavern models such as the one in Cartagena.
The stock tavern in Cartagena is also liable to cause trouble if the game starts its "ExitFromLocation" check when you leave the tavern, because then that check is going to trigger when you enter the main Cartagena town. The nearest locator is likely to be some distance away... Turks Island, in which there is just one big location for the whole town, could also have odd consequences.
 
The same fundamental problem still applies, though. If it only starts looking after you've left the tavern, and then waits until you go to another location, then you could be in a store, the governor's house or a church when the pirate shows up.
Should it not trigger as soon as you get outside?
If not, maybe that would make the most sense?
 
At the moment, the event triggers as soon as you're in a location which isn't the tavern and isn't your ship. The event sets up the check for "ExitFromLocation", which then triggers quest case "girl_for_sale_2". So, assuming you're not fast-travelling, you leave the tavern and are probably in a town centre. The next place you go from there is where the pirate attempts to spawn. Hence the existing problem, which is that he can't spawn in Port Royale port because the existing line wants him to go to "reload1", which Port Royale port doesn't have.

A possible solution might be to change the conditon in 'CheckGambledQuest()' in "MAXIMUS_Functions.c":
Code:
if(!HasSubStr(PChar.location,"upstairs") && !CheckAttribute(PChar,"IsOnDeck"))
Now it's looking to avoid any location whose name includes "upstairs" rather than anywhere whose name includes "tavern", so the event will trigger when you leave the room, and the "ExitFromLocation" check will then trigger when you go somewhere else. Barring fast-travel, the only place you can go when you leave the room is the main tavern hall, and the only places you can go from there are outside the tavern or back into the room if you rent it again. The main problem will be if there are any tavern rooms whose location names do not contain "upstairs", in which case the pirate will probably spawn when you leave the room and go into the main tavern, which is where he used to spawn anyway.
 
Now it's looking to avoid any location whose name includes "upstairs" rather than anywhere whose name includes "tavern", so the event will trigger when you leave the room, and the "ExitFromLocation" check will then trigger when you go somewhere else.
That sounds like it's worth a try! :onya

The main problem will be if there are any tavern rooms whose location names do not contain "upstairs"
I can confirm that there aren't any. EVERY tavern room is named "upstairs" because the "sleep in tavern" code assumes that it is always named like that.
Even the Eleuthera Cellar should have "_upstairs" in its location ID, even though technically it is "downstairs".
You can double-check this if you want, because it has been a very long time ago since I messed around with that code....
 
It works, at least in Port Royale. I changed "MAXIMUS_Functions.c" to look for "upstairs" rather than "tavern" and then replaced the code in "girl_for_sale_2" with your code to place the trader in convoy escorts. The pirate met me as soon as I left the tavern. This is going into the next update.
 
Back
Top