1. Dismiss Notice
  2. GOG.com logo

    Thanks to YOUR votes, GOG.com now sells:
    - Sea Dogs - Sea Dogs: Caribbean Tales
    - Sea Dogs: City of Abandoned Ships

    Vote now to add Pirates of the Caribbean to the list!

    Dismiss Notice
  3. Under the Crossbones Podcast

    A Pirate Podcast with Interviews
    Music, Comedy and all things Pirate!

    - Episode Guide - About - Subscribe -
    - Twitter - Facebook - iTunes - Android -
    - Youtube - Fill the Coffers -

    Dismiss Notice
  4. New Horizons logo

    Quick links for PotC: New Horizons
    - Download latest version
    - Wiki - FAQ - Report bugs here
    - ModDB profile

  5. GOF logo

    Quick links for AoP2: Gentlemen of Fortune 2
    - Downloads and info
    - Historical Immersion Supermod
    - ModDB Profile

Dismiss Notice
New to the forum?
Please take a moment to read our Welcome Message and Forum Rules.

Fix in Progress Captive captains are just clones

Discussion in 'Build Mod Bug Tracker' started by Grey Roger, Nov 2, 2017.

  1. Grey Roger

    Grey Roger Sea Dog Staff Member Storm Modder

    Joined:
    Feb 12, 2007
    Messages:
    6,405
    In "Tales of a Sea Hawk", it is possible to take Silehard - and, for that matter, Isenbrandt Jurcksen - prisoner when you sail to Cozumel. When you return to Port Royale to visit the new governor, he says "Well, His Majesty will be sorry not to have Silehard in the Tower. But this was just as final." I've always taken that as being an unofficial way of telling you to dispose of Silehard yourself so that there isn't the potential embarrassment of a governor being in court for corruption. But in fact there is supposed to be alternative dialog if Silehard is your prisoner. And it's not being triggered. It turns out that character "Robert Christopher Silehard" does not have the "prisoned" attribute, which is what the dialog checks.

    A bit of console jiggery-pokery:
    Code:
    if (isprisoner(characterFromID("Robert Christopher Silehard"))) traceandlog("Silehard is a prisoner");
    else traceandlog("Silehard is NOT a prisoner");
    if (IsPassenger(characterFromID("Robert Christopher Silehard"))) traceandlog("Silehard is a passenger");
    else traceandlog("Silehard is NOT a passenger");
    
    traceandlog("Passengers:");
       for(i=0; i < GetPassengersQuantity(pchar); i++)
       {
           n = GetPassenger(pchar, i);
           if (n < 0)           continue;                   // Skip invalid characters
           ch = GetCharacter(n);                                                                   // Reference to the character
           if(!CheckAttribute(ch,"index"))   continue;                   // Skip invalid characters
           traceandlog("ID: " + ch.id + " - Name: " + GetMySimpleName(ch));
       }
    And this is the result:
    Code:
    Silehard is NOT a prisoner
    Silehard is NOT a passenger
    Passengers:
    ID: Danielle - Name: Nathaniel Hawk
    ID: Researcher - Name: Clement Barnabas Aurentius
    ID: Enc_Officer_2 - Name: Symon Hoppe
    ID: Enc_Officer_3 - Name: Peter Verplancken
    ID: Fred Bob - Name: Fred Bob
    ID: Enc_Officer_4 - Name: GhibeDender Schuiling
    ID: Enc_Officer_1 - Name: Hilary Trinder
    ID: Rys Bloom - Name: Rys Bloom
    ID: Edgar Attwood - Name: Edgar Attwood
    ID: Enc_Officer_12 - Name: Bebe Caballero
    ID: Enc_Officer_13 - Name: Argentina Chissano
    ID: Enc_CabinCaptain_4 - Name: Fiebras Nattier
    ID: Enc_CabinCaptain_18 - Name: Lewellyn Belt
    ID: Enc_Officer_7 - Name: Bastian Froelich
    ID: Enc_Officer_8 - Name: Simone Aubarat
    ID: Virginie d'Espivant - Name: Virginie d'Espivant
    ID: Enc_CabinCaptain_13 - Name: Gaspar Gomiz
    ID: Enc_Officer_14 - Name: Julia Parlabean
    ID: Enc_Officer_6 - Name: Alison Martyr
    ID: Sabine Matton - Name: Sabine Matton
    ID: Enc_Officer_15 - Name: Isenbrandt Jurcksen
    ID: Enc_CabinCaptain_14 - Name: Robert Christopher Silehard
    Notable entries in that list are "Enc_CabinCaptain_18", alias Lewellyn Belt, one of Silehard's captains during the Bridgetown counter-attack; "Enc_Officer_15", alias Isenbrandt Jurcksen; and "Enc_CabinCaptain_14", alias Robert Christopher Silehard. And that's why character "Robert Christopher Silehard" doesn't show up as a prisoner, or for that matter, even as a passenger.
     
  2. Pieter Boelen

    Pieter Boelen (Not So) Old Seadog Staff Member Administrator Storm Modder Hearts of Oak Donator

    Joined:
    Nov 11, 2004
    Messages:
    66,609
    Gender:
    Male
    Occupation:
    Maritime Research: Project Engineer (Analysis)
    Location:
    Wageningen, The Netherlands
    Whenever you take a captain prisoner or hire one, indeed a clone is made.
    This is needed so the code still believes the captain "died", allowing quests and other game functionality to proceed as if he did.

    How do prisoners work again? I remember they used to only show up in the Passengers interface, with buttons to handle them.
    But that was changed so they show up in the cargo hold instead for you to talk with.
    Do they still show in the Passengers interface at all now? Do Silehard and Jurcksen show anywhere in the interfaces after the battle?

    If Silehard is recognized as neither a passenger or a prisoner, then what IS Silehard marked as?
    Your console check proves that he IS some sort of "passenger", even though the functions don't seem to realise.
    Could you show the function definitions for 'IsPassenger' and 'IsPrisoner'?
     
  3. Grey Roger

    Grey Roger Sea Dog Staff Member Storm Modder

    Joined:
    Feb 12, 2007
    Messages:
    6,405
    Prisoners show up in the "Passengers" interface but there is no button to ransom them. You do indeed go to the hold to talk to them. That's how, in previous games, I was able to follow the new governor's apparent sneaky command to execute Silehard.

    The result of the console code shows that Silehard isn't marked as anything. Another console version with a simple 'dumpattributes(CharacterFromID("Robert Christopher Silehard"));' confirmed that. The prisoner in your hold is not "Robert Christopher Silehard", it's "Enc_CabinCaptain_14". Likewise, I don't have character "Isenbrandt Jurcksen", I have "Enc_Officer_15", who probably changed from "Enc_CabinCaptain" to "Enc_Officer" because I hired him.

    Here's "IsPassenger":
    Code:
    bool IsPassenger(ref _refCharacter)
    {
       // Old check Depreciated by PB
    //   if(!CheckAttribute(_refCharacter,"index"))        return false;                               // MAXIMUS
    //   if (CheckAttribute(_refCharacter, "passenger"))   return sti(_refCharacter.passenger);
    
       int cn;
       ref chr;
       ref pchar = GetMainCharacter();
       for(int i=0; i < GetPassengersQuantity(pchar); i++)
       {
           cn = GetPassenger(pchar, i);
           if (cn < 0)                                                   continue;                   // Skip invalid characters
           chr = GetCharacter(cn);                                                                   // Reference to the character
           if(!CheckAttribute(chr,"index"))                           continue;                   // Skip invalid characters
           if(CheckAttribute(_refCharacter, "index") && CheckAttribute(chr, "index"))
           {
               if(sti(_refCharacter.index) == sti(chr.index))           return true;               // This character is in the captain's passenger list
           }
       }
    
       return false;
    }
    Now looking at function "TIH_PrisonerTakenProcess", defined in "Dialog_func.c", which is what does the cloning. What I'm now thinking is to add a new attribute, perhaps call it "OldID", which stores the prisoner's original ID. And then have "IsPassenger" check if each character has the "OldID" attribute; if so, does it match the ID of "_refCharacter"; if so, return true, you've just found _refCharacter's clone.
     
  4. Pieter Boelen

    Pieter Boelen (Not So) Old Seadog Staff Member Administrator Storm Modder Hearts of Oak Donator

    Joined:
    Nov 11, 2004
    Messages:
    66,609
    Gender:
    Male
    Occupation:
    Maritime Research: Project Engineer (Analysis)
    Location:
    Wageningen, The Netherlands
    Ah, of course! Different character ID. :facepalm

    Sounds interesting, but potentially complicated.

    Alternatively, maybe you could use your loop through passengers to check for a character with name "Robert Christopher Silehard" in that single spot where it is needed for the quest dialog?
     
  5. Grey Roger

    Grey Roger Sea Dog Staff Member Storm Modder

    Joined:
    Feb 12, 2007
    Messages:
    6,405
    It shouldn't be that complicated. The whole idea is not to alter the existing operation of "TIH_PrisonerTakenProcess" except to add a new attribute, so it will still create the clone, and the original character will still be marked as dead.
    That doesn't help with any other quest captains you may capture in other storylines.
     
  6. Pieter Boelen

    Pieter Boelen (Not So) Old Seadog Staff Member Administrator Storm Modder Hearts of Oak Donator

    Joined:
    Nov 11, 2004
    Messages:
    66,609
    Gender:
    Male
    Occupation:
    Maritime Research: Project Engineer (Analysis)
    Location:
    Wageningen, The Netherlands
    True. Unless you make it a function that checks on 'SimpleName'.
    But effectively then you end up with something very similar to what you were already proposing anyway. :cheeky

    Fair point.
    I do wonder is if it could cause problems further down the line, because the same character IDs are being cycled through.
    But if there is a 'ClearCharacter' statement first (I think; it is a function that completely erases an earlier character before his ID is reused), it should be fine.

    And even if not, a newly-added attribute doesn't harm anything, except potentially in the functionality that was added to use it.
    But the specific quest case where it is checked for that character should really only happen once.

    Long story short: You're probably safe to do exactly what you have in mind. :onya
     
  7. Grey Roger

    Grey Roger Sea Dog Staff Member Storm Modder

    Joined:
    Feb 12, 2007
    Messages:
    6,405
    Generic ID's are reused. Specific ID's such as quest characters aren't. This is the relevant part from "TIH_PrisonerTakenProcess":
    Code:
           if(!HasSubStr(RefChar.id,"Enc_CabinCaptain"))
           {
               CopyAttributes(&Prisoner, &RefChar);// copy all attr from the reference character (the hiring officer) to the new officer char
    
               Prisoner.index = PrisonerIdx;// reset these after the copyattr
               Prisoner.id    = PrisonerID; // reset these after the copyattr
               Prisoner.oldID = RefChar.id; // Note the reference character's ID. Checks such as 'IsPassenger' can pass if a clone's "oldID" matches the ID being checked
           }
    The "oldID" attribute is only set if the original character isn't already a generic "Enc_CabinCaptain". Then "IsPassenger" checks it:
    Code:
        for(int i=0; i < GetPassengersQuantity(pchar); i++)
       {
           cn = GetPassenger(pchar, i);
           if (cn < 0)                                   continue;   // Skip invalid characters
           chr = GetCharacter(cn);                                                                   // Reference to the character
           if(!CheckAttribute(chr,"index"))                       continue;   // Skip invalid characters
           if(CheckAttribute(_refCharacter, "index") && CheckAttribute(chr, "index"))
           {
               if(sti(_refCharacter.index) == sti(chr.index))               return true;   // This character is in the captain's passenger list
               if(CheckAttribute(chr,"oldID") && chr.oldID == _refCharacter.id)   return true;   // This character was taken prisoner and this passenger is the character's prisoner clone
           }
       }
    Next: make "RemovePassenger" look for and remove a clone. Otherwise the game is going to detect that Silehard is a passenger and try to remove the original, leaving you still stuck with the clone. :facepalm
     
    Pieter Boelen and DeathDaisy like this.
  8. Levis

    Levis Find(Rum) = false; Staff Member Programmer Creative Support Storm Modder

    Joined:
    Oct 6, 2013
    Messages:
    6,691
    Gender:
    Male
    Occupation:
    ICT
    Location:
    University Twente (Netherlands)
    SO quick question, why would a copy need to be made if it isn't a generic character? can't you just use the normal character?
     
  9. Grey Roger

    Grey Roger Sea Dog Staff Member Storm Modder

    Joined:
    Feb 12, 2007
    Messages:
    6,405
    ;)

    This applies equally to quest characters. For example, the code to detect the end of the penultimate battle at Cozumel, against Silehard and his pirate pals, is:
    Code:
               Pchar.quest.Story_SinkPiratesAtKhaelRoa.win_condition.l1 = "NPC_Death";
               Pchar.quest.Story_SinkPiratesAtKhaelRoa.win_condition.l1.character = "Isenbrandt Jurcksen";
               Pchar.quest.Story_SinkPiratesAtKhaelRoa.win_condition.l2 = "NPC_Death";
               Pchar.quest.Story_SinkPiratesAtKhaelRoa.win_condition.l2.character = "Brian The Slayer";
               Pchar.quest.Story_SinkPiratesAtKhaelRoa.win_condition.l3 = "NPC_Death";
               Pchar.quest.Story_SinkPiratesAtKhaelRoa.win_condition.l3.character = "Thomas Norton";
               Pchar.quest.Story_SinkPiratesAtKhaelRoa.win_condition.l4 = "NPC_Death";
               Pchar.quest.Story_SinkPiratesAtKhaelRoa.win_condition.l4.character = "Robert Christopher Silehard";
    That won't work unless the real Silehard and pirates are dead, so if any of them surrenders, he still dies and you get his clone instead.
     
  10. Levis

    Levis Find(Rum) = false; Staff Member Programmer Creative Support Storm Modder

    Joined:
    Oct 6, 2013
    Messages:
    6,691
    Gender:
    Male
    Occupation:
    ICT
    Location:
    University Twente (Netherlands)
    Ah right forgot about that.
    So is this fixed now?
     
  11. Grey Roger

    Grey Roger Sea Dog Staff Member Storm Modder

    Joined:
    Feb 12, 2007
    Messages:
    6,405
    No. I ran into trouble trying to make "RemovePassenger" and any associated functions look for clones, and since then I've been trying to compile the next update archive without including anything that might upset game stability. Once that's out of the way, and barring other projects requiring my attention, I may try again.
     
    Pieter Boelen likes this.
  12. Pieter Boelen

    Pieter Boelen (Not So) Old Seadog Staff Member Administrator Storm Modder Hearts of Oak Donator

    Joined:
    Nov 11, 2004
    Messages:
    66,609
    Gender:
    Male
    Occupation:
    Maritime Research: Project Engineer (Analysis)
    Location:
    Wageningen, The Netherlands
    At the end of a boarding action, the captain MUST die or the process does not continue.
    So the captured captain has to be a copy.
     

Share This Page