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

Confirmed Bug Unintentional Fights or Lack Thereof (aka. AI Group Relations)

What kind of behaviour would you like to see from the town guards?

  • It is fine as-is. They don't bother me and I don't bother them!

    Votes: 0 0.0%
  • Same as above, but I should be able to bribe them so they turn a blind eye

    Votes: 0 0.0%
  • Other, please specify below

    Votes: 0 0.0%

  • Total voters
    10
I was spotted as a traitor by a random guard in the tavern in Greenford. Now every time I enter the tavern and there is a guard there he starts attacking me instantly but all other guards in greenford don't.
That is specifically the tavern guards.
Any chance you can upload a save of yours that is affected? That may be fixable.
 
The random guards are created like this:
Code:
void Random_guards_group(int bmax, int nation)
{
   if(bmax==0) return;
   if(nation == PIRATE) return; // PB: No pirate guards in taverns

   ref chr;
   float hasgun;
   string ani, group, locator;
   hasgun = 0.5;
   ani = "man";
   group = "goto";
   
   for(int i = 0; i < bmax; i++)
   {
     locator = LAi_FindRandomLocator(group);
     chr=LAi_CreateFantomCharacterEx(false, 0, true, true, hasgun, GetRandomModelForTypeExSubCheck(1, "Soldiers", ani, nation), ani, group, locator);
     chr.Dialog.filename="random_guards_group_dialog.c";
     LAi_SetCivilianPatrolType(chr);
     chr.nation = nation;
     LAi_group_MoveCharacter(chr, "random_guards_group");
   }
   LAi_group_SetRelation(LAI_GROUP_PLAYER, "random_guard_group", LAI_GROUP_NEUTRAL);
   LAi_group_SetRelation("random_pirates_group", "random_guards_group", LAI_GROUP_NEUTRAL);
   LAi_group_SetRelation(LAI_GROUP_GUARDS, "random_guards_group", LAI_GROUP_NEUTRAL);
   LAi_group_SetRelation(LAI_DEFAULT_GROUP, "random_guards_group", LAI_GROUP_NEUTRAL);
   LAi_group_SetRelation(LAI_GROUP_MONSTERS, "random_guards_group", LAI_GROUP_NEUTRAL);
   LAi_group_SetRelation(GetCurrentCitizenGroup(), "random_guards_group", LAI_GROUP_NEUTRAL);
   LAi_group_SetRelation(GetCurrentSoldierGroup(), "random_guards_group", LAI_GROUP_NEUTRAL);
}
So regardless of what town you're in, they ALWAYS end up in the same AI group ("random_guards_group").
That is why they all behave the same.

Last week I tried to put them IN the local soldier groups, but then we got all sorts of brand new insanity, so I set that back to how it was.
Since that function already DOES contain plenty of lines to reset their relations whenever they're generated, I don't quite understand why this would go wrong.
Maybe it would help to reset the relations first and then create the guards themselves later?
If so, try:
Code:
void Random_guards_group(int bmax, int nation)
{
   if(bmax==0) return;
   if(nation == PIRATE) return; // PB: No pirate guards in taverns

   ref chr;
   float hasgun;
   string ani, group, locator;
   hasgun = 0.5;
   ani = "man";
   group = "goto";
   
   LAi_group_SetRelation(LAI_GROUP_PLAYER, "random_guard_group", LAI_GROUP_NEUTRAL);
   LAi_group_SetRelation("random_pirates_group", "random_guards_group", LAI_GROUP_NEUTRAL);
   LAi_group_SetRelation(LAI_GROUP_GUARDS, "random_guards_group", LAI_GROUP_NEUTRAL);
   LAi_group_SetRelation(LAI_DEFAULT_GROUP, "random_guards_group", LAI_GROUP_NEUTRAL);
   LAi_group_SetRelation(LAI_GROUP_MONSTERS, "random_guards_group", LAI_GROUP_NEUTRAL);
   LAi_group_SetRelation(GetCurrentCitizenGroup(), "random_guards_group", LAI_GROUP_NEUTRAL);
   LAi_group_SetRelation(GetCurrentSoldierGroup(), "random_guards_group", LAI_GROUP_NEUTRAL);
   for(int i = 0; i < bmax; i++)
   {
     locator = LAi_FindRandomLocator(group);
     chr=LAi_CreateFantomCharacterEx(false, 0, true, true, hasgun, GetRandomModelForTypeExSubCheck(1, "Soldiers", ani, nation), ani, group, locator);
     chr.Dialog.filename="random_guards_group_dialog.c";
     LAi_SetCivilianPatrolType(chr);
     chr.nation = nation;
     LAi_group_MoveCharacter(chr, "random_guards_group");
   }
}
 
@Pieter Boelen hope you can open it because I'm using this one atm to test. But you should be able to :).
 

Attachments

  • -=Player=- Barbados. Bridgetown March 19th, 1813 6.zip
    789 KB · Views: 167
Savegame loads and I confirmed that problem.
But for some reason, I have NO control over making those guards calm down again.
All the 'LAi_group_SetRelation' lines in the world refuse to do the trick.
 
I think I'm beginning to understand.... The "random_guards_group" guards isn't actually defined anywhere.
It just suddenly "made up" and used, but the game engine that handles all the AI group stuff doesn't ever get told that group even exists.
Just doing this DOES actually work:
Code:
  for(int i = 0; i < bmax; i++)
   {
     locator = LAi_FindRandomLocator(group);
     chr=LAi_CreateFantomCharacterEx(false, 0, true, true, hasgun, GetRandomModelForTypeExSubCheck(1, "Soldiers", ani, nation), ani, group, locator);
     chr.Dialog.filename="random_guards_group_dialog.c";
     LAi_SetCivilianPatrolType(chr);
     chr.nation = nation;
     LAi_group_MoveCharacter(chr, LAI_GROUP_GUARDS);
   }
   LAi_group_SetRelation(LAI_GROUP_PLAYER, LAI_GROUP_GUARDS, LAI_GROUP_NEUTRAL);

Which means one very clear thing: We should NOT randomly be making up AI groups and assume the game handles them properly!
I think this is a rather widespread problem throughout the game code and that doesn't simplify things.

Related code is void InitGroups() in PROGRAM\NATIONS\nations.c and bool LAi_group_Init() in PROGRAM\Loc_ai\LAi_groups.c .

Could it be that groups MUST be defined with 'LAi_group_Register' before working properly?
If so, why can I find no such lines for stock game groups like all the Citizen and Soldier ones?
 
It seems that ALL the actual group relations are stored in memory and I managed to make a dump of it on @Levis' save using:
Code:
DumpAttributes(&LAi_grp_relations);
See attached compile.log for all the contents.

For some reason, indeed "CONCEICAO_CITIZENS" is in there despite not getting 'registered'.
It also contains a whole bunch of mod-added groups that also aren't. And I'm not sure if the actual relations between groups are stored in there or not.
Could be the 'relstate'. But maybe not.

In other words: I've got some sort of a clue what this is all related to and it isn't simple.
I wonder if @Levis may have a better understanding of this business.

Also noteworthy is that it (almost?) seems that relations are set and stored between ALL groups in the game.
So adding one group adds a LOT more stuff to be stored. Based on that, I think it might be a good idea to reuse groups as much as possible.
Might not be wise to make a brand new group for every little thing if those one-off groups then linger in the game memory forever. :facepalm
 

Attachments

  • compile.log
    356.9 KB · Views: 177
From what I found till now a group is only added once its actually needed. A few groups are added at the start (the default ones). And indeed adding a new one adds more memory every time.
I think for example CONCEICAO_CITIZENS is in there because I visited that places. You can also see the coastgruard group in there because I did a failed smuggling run.
It works like a relation tabel, so each record is an relation between two entities. actstate and relstate have something todo with when they attack you etc, but I forgot how they work again. curstate is what you are at now.
Mind that this object is used by the engine so we can't change how it is made up. You could release it every now and then and only have the neccesary ones in it ....
 
If I understand correctly, the group relations still seemed OK-ish in the latest Beta 4 EXE and only went truly wonky with the new ZIP?
Did I get that right? If so, kicking out ALL changes related to that may help. Though that is hardly an ideal solution.
Therefore I am seriously considering diving into this issue the coming weekend because it has plagued us for a long time and has recently become only worse.

It should be added that this DOES bring with it a risk that I don't get it right in one go or that it takes more time than I would like.
So if anyone thinks it isn't worth the trouble right now, please say so.
 
From what I have seen till now the only real problem appears to be with the random generated people in taverns and towns etc because they seem to be in the same group and their relation doesn't seem to be reset or something like that.
Like I said in the PM I can also look into this if you want. Won't change anything drasticly hopefully but I might be able to shed some light on it if I do some digging (aka adding a lot of debug messages so we can see what is happening).
 
From what I have seen till now the only real problem appears to be with the random generated people in taverns and towns etc because they seem to be in the same group and their relation doesn't seem to be reset or something like that.
The strangest part is that I couldn't reset the relations to that guard in your save without putting him in another AI group.

According to @ANSEL, this code might do what I didn't manage at the time:
Code:
      LAi_group_SetAlarm(LAI_DEFAULT_GROUP, LAI_GROUP_PLAYER, 0.0);
       LAi_group_SetRelation(LAI_DEFAULT_GROUP, LAI_GROUP_PLAYER, LAI_GROUP_NEUTRAL);
       LAi_group_SetAlarm(LAI_DEFAULT_GROUP, LAI_GROUP_MONSTERS, 0.0);
       LAi_group_SetRelation(LAI_DEFAULT_GROUP, LAI_GROUP_MONSTERS, LAI_GROUP_NEUTRAL);

       string IslandID;
       int jopa;

       jopa = GetCharacterCurrentIsland(Pchar);
       IslandID = Islands[jopa].id;

       switch(IslandID)
       {
       case "FalaiseDeFleur":
     LAi_group_SetAlarm("FRANCE_SOLDIERS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetAlarm("FRANCE_CITIZENS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetRelation("FRANCE_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_FRIEND);
     LAi_group_SetRelation("FRANCE_CITIZENS", LAI_GROUP_PLAYER, LAI_GROUP_NEUTRAL);
     LAi_group_SetAlarmReaction("FRANCE_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_ENEMY, LAI_GROUP_FRIEND);
     break;

     case "Redmond":
     LAi_group_SetAlarm("ENGLAND_SOLDIERS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetAlarm("ENGLAND_CITIZENS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetRelation("ENGLAND_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_FRIEND);
     LAi_group_SetRelation("ENGLAND_CITIZENS", LAI_GROUP_PLAYER, LAI_GROUP_NEUTRAL);
     LAi_group_SetAlarmReaction("ENGLAND_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_ENEMY, LAI_GROUP_FRIEND);
     break;

     case "Conceicao":
     LAi_group_SetAlarm("CONCEICAO_SOLDIERS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetAlarm("CONCEICAO_CITIZENS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetRelation("CONCEICAO_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_FRIEND);
     LAi_group_SetRelation("CONCEICAO_CITIZENS", LAI_GROUP_PLAYER, LAI_GROUP_NEUTRAL);
     LAi_group_SetAlarmReaction("CONCEICAO_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_ENEMY, LAI_GROUP_FRIEND);

     LAi_group_SetAlarm("SMUGGLERS_SOLDIERS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetAlarm("SMUGGLERS_CITIZENS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetRelation("SMUGGLERS_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_FRIEND);
     LAi_group_SetRelation("SMUGGLERS_CITIZENS", LAI_GROUP_PLAYER, LAI_GROUP_NEUTRAL);
     LAi_group_SetAlarmReaction("SMUGGLERS_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_ENEMY, LAI_GROUP_FRIEND);
     break;

     case "Oxbay":
     LAi_group_SetAlarm("ENGLAND_SOLDIERS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetAlarm("ENGLAND_CITIZENS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetRelation("ENGLAND_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_FRIEND);
     LAi_group_SetRelation("ENGLAND_CITIZENS", LAI_GROUP_PLAYER, LAI_GROUP_NEUTRAL);
     LAi_group_SetAlarmReaction("ENGLAND_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_ENEMY, LAI_GROUP_FRIEND);
     break;

     case "IslaMuelle":
     LAi_group_SetAlarm("SPAIN_SOLDIERS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetAlarm("SPAIN_CITIZENS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetRelation("SPAIN_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_FRIEND);
     LAi_group_SetRelation("SPAIN_CITIZENS", LAI_GROUP_PLAYER, LAI_GROUP_NEUTRAL);
     LAi_group_SetAlarmReaction("SPAIN_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_ENEMY, LAI_GROUP_FRIEND);
     break;

     case "Douwesen":
     LAi_group_SetAlarm("DOUWESEN_SOLDIERS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetAlarm("DOUWESEN_CITIZENS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetRelation("DOUWESEN_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_FRIEND);
     LAi_group_SetRelation("DOUWESEN_CITIZENS", LAI_GROUP_PLAYER, LAI_GROUP_NEUTRAL);
     LAi_group_SetAlarmReaction("DOUWESEN_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_ENEMY, LAI_GROUP_FRIEND);

     LAi_group_SetAlarm("DOUWESEN_PIRATE_SOLDIERS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetAlarm("DOUWESEN_PIRATE_CITIZENS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetRelation("DOUWESEN_PIRATE_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_FRIEND);
     LAi_group_SetRelation("DOUWESEN_PIRATE_CITIZENS", LAI_GROUP_PLAYER, LAI_GROUP_NEUTRAL);
     LAi_group_SetAlarmReaction("DOUWESEN_PIRATE_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_ENEMY, LAI_GROUP_FRIEND);
     break;

     case "QuebradasCostillas":
     LAi_group_SetAlarm("QC_SOLDIERS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetAlarm("QC_CITIZENS", LAI_GROUP_PLAYER, 0.0);
     LAi_group_SetRelation("QC_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_FRIEND);
     LAi_group_SetRelation("QC_CITIZENS", LAI_GROUP_PLAYER, LAI_GROUP_NEUTRAL);
     LAi_group_SetAlarmReaction("QC_SOLDIERS", LAI_GROUP_PLAYER, LAI_GROUP_ENEMY, LAI_GROUP_FRIEND);
     break;

     case "KhaelRoa":

     break;
     }
That is from PROGRAM\DIALOGS\Enc_resident_dialog.c .

Maybe somehow the guard was in "LAI_DEFAULT_GROUP" or "LAI_GROUP_MONSTERS" for some reason?
That might explain it. Though that shouldn't be the case, because he was specifically being put in the "random_guards_group" one. o_O
 
Was doing some testing: used a thief knife in clear view of everyone, let myself get killed by guards (wanted to confirm their is no relation lost with nation). Woke up in tavern, walked outside.

Guards immediately began slaughtering every townsperson in sight. Drawing blades, killing them, sheething blade, drawing again as soon as another townsperson walked close.

Error log had this:
RUNTIME ERROR - file: seadogs.c; line: 749
Save - ARef to non existing attributes branch

Not sure if related or not.

Saved game midway through the slaughter attached. They keep attacking if you load the save, so it should reproduce the effect.

Note the guards do not attack the player and his officers, just the townspeople. Also if I change scenes and come back, they start slaughtering the citizens a second time. Also, the guards in the seperate dock scene are just as murderous, it seems town wide
 

Attachments

  • murderous guards.rar
    554.9 KB · Views: 145
Last edited:
There is a long standing bug tracker entry about this one.
It's called "Unintentional fights (or lack thereof)" about the AI Relation Groups if I recall.

Probably one of the more annoying issues we've still got left.
 
I looked up the thread you mentioned Pieter, and it covers 3 of my recent reports! Now I will know not to bother you with the othet issues mentioned there, should I run into them. ;)
 
Just for better noticing I will post here again:

Beta 4.0, ModDB version. Like Tinygun said, I got in a fight with town(raiders) quite early in the game. There was the first strange thing that EVERY citizen in this area turned against me. After this, now everytime I enter an english city (the brawl started in Bridgetown) the guards kill all armed citizens. They even appear in taverns and kill everyone they can reach.
 
This is getting pathetic.. one of my officers got hit by a I believe musket shot from a guard, and then guards started to fight us. Which resulted in death for us all because there came like 50 guards..
 
@Pillat yes sadly it is an instant reload for me if we anger the townsfolk.

The worst AI relations bug is if you hit one of your officers in a ship boarding battle. Then your crew and officers turn on each other, and that can mess up a nice boarding. We have a seperate bugtracker for that one open.
 
I wonder if executing this through console could possibly improve things:
Code:
InitGroups();

That function should set the correct relations at least between the citizens and soldiers of the various towns.
 
Back
Top