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

Included in Build Joining Ambush/Random_Raid/Rapid_Raid functions together

"Rapid_Raid" has several levels of skills hardcoded in there. That bypasses the Levelling system and is therefore something I would prefer to not have to do.
It assigns "Melee", "Accuracy", "Defence" and "Luck" to whatever you supply as the "attackers_skill" variable. It does indeed bypass the levelling system, allowing you to set those skills to whatever you want, but it's not hardcoded as it's done with a variable.

Specifying a rank (or rank offset) and officer type should give quite a bit of control by itself.
If there's some easy way to figure out what skills the attacker will get from the rank or offset, fine. But then, if you're going to let people specify the skills indirectly that way, why not make it easy and just let them specify the skills directly?

Please make a Bug Tracker entry for that.
Also indicate exactly the type of NPCs and the situation where they are generated. It could be that they're initialized in the wrong way.
If done correctly, the nation-name function does do what it is meant to.
It won't be much of a bug report as the main place I've seen it is during a boarding, when it's impossible to save game and grab log files. I'm not sure off-hand whether the soldiers you find in a fort when you walk in through the land gate and loot the place are correct either.

I don't think I follow you there? In what way are you stuck?
If you want characters who look like sailors, but have "fighter" skills, that should be totally possible. :confused:
It is. You just call "Random_Raid" with "type" set to "sailors" and "attacker_skill" set to whatever value you like. At least for now, anyway...

But you were saying the Hornblower scenes do NOT use "Random_Raid"? Confused again.... :oops:
Correct, "Hornblower" does not use "Random_Raid", partly because the scenes Short Jack Gold wrote require even more control than "Random_Raid" allows (both the start location and the destination location, for example) and partly because I hadn't heard of it when I wrote the Voltigeurs scenes. It does use similar techniques to "Random_Raid", including taking away whatever random weapons had been assigned to them by 'LAi_CreateFantomCharacter' and giving them standard equipment.

One thing that COULD be made possible is to generate different characters in the attacking group at randomly chosen locators of a certain group.
That should not be too difficult. Of course then they'd end up being generated all around you. I think that is what happened with the "Merchant Guild Reinforcements" (though that may have changed now...? :unsure ).
It would be a problem in places like Santiago which don't have many locators. At best they'd be scattered all over town trying to find the few locators which exist; at worst you might end up losing some attackers because they can't find locators. The Merchant Guild isn't going to be a problem there, at least for now, because they show up if you rob a street trader and there are none of those in Santiago, mainly due to the lack of locators. Besides, having them teleport right to your position is just silly, it's better if they appear to come from somewhere sensible such as a nearby gate.
 
If there's some easy way to figure out what skills the attacker will get from the rank or offset, fine. But then, if you're going to let people specify the skills indirectly that way, why not make it easy and just let them specify the skills directly?
A certain officer type of a certain rank should always have a certain set of skills; give or take some randomization.

Why would you want to do it that way? Simply because that's how the system works! That would mean "making use of the existing system" instead of finding separate solutions.
"Separate solutions" can often seem like a good, quick fix. But it makes for the sort of solutions that make people in my position go COMPLETELY NUTS five years later. :facepalm

It won't be much of a bug report as the main place I've seen it is during a boarding, when it's impossible to save game and grab log files. I'm not sure off-hand whether the soldiers you find in a fort when you walk in through the land gate and loot the place are correct either.
If you can't supply log files or a savegame, then so be it. You can still make the report. :yes

It is. You just call "Random_Raid" with "type" set to "sailors" and "attacker_skill" set to whatever value you like. At least for now, anyway...
Even with the suggestions I made here, that would remain possible. Character models and officer type aren't necessarily linked.
So you can have a whole bunch of Navigators looking like Sailors if you want. :shrug

It would be a problem in places like Santiago which don't have many locators. At best they'd be scattered all over town trying to find the few locators which exist; at worst you might end up losing some attackers because they can't find locators. The Merchant Guild isn't going to be a problem there, at least for now, because they show up if you rob a street trader and there are none of those in Santiago, mainly due to the lack of locators. Besides, having them teleport right to your position is just silly, it's better if they appear to come from somewhere sensible such as a nearby gate.
If it uses random locators, it probably would end up being RANDOM. Which means there may be multiple characters generated at the same locator.
Depends on the function that we use for it; but that one would probably be our best bet.
 
Indeed the Random_Raid/Ambush combination needs more work. It does now indeed miss out on the "nation" input.
But that requires some proper thinking through, which I won't be doing this week.
I'd welcome anyone else to make a start though. :wp
 
For starters, I think it would be a good idea to restore the 'offset' option in the game code to being functional again.
In PROGRAM\Loc_ai\LAi_utils.c function LAi_CreateFantomCharacterExOtAt :
Code:
ref LAi_CreateFantomCharacterExOtAt(bool isfriend, int offset  , bool genrank, string officertype, string attr1, string attr2, string attr3, int rank  , bool hasblade,
                  float hasgun , string model, string ani  , string group  , string locator)
{
[...]
   if(!genrank)
   {
     //Log_SetStringToLog("Not gen");
     chr.skill.Leadership = 1; DeleteAttribute(&chr,"skill.Leadership.mod"); // NK/GZ items mod
     chr.skill.Fencing  = 1; DeleteAttribute(&chr,"skill.Fencing.mod"  ); // NK/GZ items mod
     chr.skill.Sailing  = 1; DeleteAttribute(&chr,"skill.Sailing.mod"  ); // NK/GZ items mod
     chr.skill.Accuracy  = 1; DeleteAttribute(&chr,"skill.Accuracy.mod"  ); // NK/GZ items mod
     chr.skill.Cannons  = 1; DeleteAttribute(&chr,"skill.Cannons.mod"  ); // NK/GZ items mod
     chr.skill.Grappling  = 1; DeleteAttribute(&chr,"skill.Grappling.mod" ); // NK/GZ items mod
     chr.skill.Repair  = 1; DeleteAttribute(&chr,"skill.Repair.mod"  ); // NK/GZ items mod
     chr.skill.Defence  = 1; DeleteAttribute(&chr,"skill.Defence.mod"  ); // NK/GZ items mod
     chr.skill.Commerce  = 1; DeleteAttribute(&chr,"skill.Commerce.mod"  ); // NK/GZ items mod
     chr.skill.Sneak  = 1; DeleteAttribute(&chr,"skill.Sneak.mod"  ); // NK/GZ items mod
     chr.rank  = 1;
     chr.skill.freeskill  = 0;
     chr.experience  = 0;
   }
   else
   {
     // PB: Restore offset -->
     chr.rank = rank + offset;
     if (sti(chr.rank) < 1) chr.rank = 1;
     // PB: Restore offset <--
   }
That way, if you use LAi_CreateFantomCharacter, you can make the encounters deliberately stronger or weaker again.
The assigning of character skills and abilities gets handled by the Levelling system based on the officer type.
There is supposed to be no need to manually do that.
 
@Grey Roger: It is my intention to do away with the original Rapid_Raid function in its current form.
That should clean up the multitude of functions that we have for basically the same purpose.

I've been spending some good time working on this now and came up with the following as a complete replacement for it:
Code:
// PB: More flexible function -->
void LAi_CreateFantomGroup(string modeltype, int bmax, string mainrel, string npcrel, int iNation, string officertype, int offset, string bladeID, string gunID, string attackers_name, string locator)
{
   ref chr;
   string model;

   // LAi Group
   string AIgroup = "ambush";
   if(modeltype == "Soldiers" || modeltype == "Navy_office4" || HasSubStr(modeltype, "Soldier")) // PB: Add ANY soldiers
   {
     AIgroup = GetSoldiersGroup(iNation);   // ccc Nov05: Make local guards if modeltype is "Soldiers"
     if (gunID == "") gunID == "All";   // PB: Soldiers always get guns
   }
  
   // Locator Group
   string group = "";
   if (HasSubStr(group, "reload"))   group = "reload";
   if (HasSubStr(group, "rld"))   group = "reload";
   if (HasSubStr(group, "goto"))   group = "goto";

   // Blade
   bool hasblade = true;
   if (bladeID == "None")
   {
     hasblade = false;
     bladeID == "";
   }
  
   // Gun
   float hasgun = 0.5;
   if (gunID == "None")
   {
     hasgun = 0.0;
     gunID == "";
   }
   if (gunID == "All")
   {
     hasgun = 1.0;
     gunID == "";
   }
  
   // Officer type
   if (officertype == "")   officertype = OFFIC_TYPE_GUARD;

   for(int i = 0; i < bmax; i++)
   {
     model = GetRandomModelForTypeExSubCheck(true, modeltype, "man", iNation); // If a female model was specified, it will still work regardless of "man" here
     chr = LAi_CreateFantomCharacterRk(npcrel ==  LAI_GROUP_FRIEND, offset, true, officertype, hasblade, hasgun, model, group, locator);
     // El Rapido: Assign a name to the attackers, maybe "Elite Soldiers" or "Pirate Hunters" or "Governor's Lifeguard".
     if (attackers_name != "")
     {
       chr.name  = attackers_name;
       chr.middlename = "";
       chr.lastname  = "";
     }
    
     // TIH: Custom Sword, used for tavernbrawl fists only mod Jul15'06
     if (bladeID != "")
     {
       TakeItemFromCharacter(chr, GetCharacterEquipByGroup(chr, BLADE_ITEM_TYPE));
       RemoveCharacterEquip(chr, BLADE_ITEM_TYPE);
       if(!CheckCharacterItem(chr, bladeID))   GiveItem2Character(chr, bladeID);
       EquipCharacterByItem(chr, bladeID);
     }
    
     // PB: Custom Gun
     if (gunID != "")
     {
       TakeItemFromCharacter(chr, GetCharacterEquipByGroup(chr, GUN_ITEM_TYPE));
       RemoveCharacterEquip(chr, GUN_ITEM_TYPE);
       if(!CheckCharacterItem(chr, gunID))   GiveItem2Character(chr, gunID);
       EquipCharacterByItem(chr, gunID);
     }
    
     LAi_SetWarriorType(chr);
     LAi_group_MoveCharacter(chr, AIgroup);
   }

   LAi_group_SetRelation(LAI_GROUP_PLAYER, AIgroup, mainrel);
   if(mainrel=="enemy")
   {
     // PB: Don't draw blades if not necessary -->
     if(CheckAttribute(GetMainCharacter(), "locationLock"))
     {
       LAi_group_SetHearRadius(AIgroup, 40000000.0);
       LAi_group_SetSayRadius(AIgroup, 40000000.0);
     }
     // PB: Don't draw blades if not necessary <--
     else
     {
       LAi_group_FightGroups(AIgroup, LAI_GROUP_PLAYER, true);
     }
   }

   LAi_group_SetRelation(LAI_GROUP_GUARDS, AIgroup, npcrel);
   LAi_group_SetRelation(LAI_DEFAULT_GROUP, AIgroup, npcrel);
   LAi_group_SetRelation(LAI_GROUP_MONSTERS, AIgroup, npcrel);

   // ccc Nov05 set relation to local soldiers (which are NOT! LAI_GROUP_GUARDS) with NK's new function
   SetAllNormalGroupsRel(AIgroup, npcrel);
  
   if(npcrel=="enemy") LAi_group_FightGroups(AIgroup, LAI_GROUP_GUARDS, true);
}
// PB: More flexible function <--
I think I included pretty much all functionality that should be necessary for general use.
If you have any additional requests, please let me know. :doff
 
That way, if you use LAi_CreateFantomCharacter, you can make the encounters deliberately stronger or weaker again.
The assigning of character skills and abilities gets handled by the Levelling system based on the officer type.
There is supposed to be no need to manually do that.

There are two fundamental problems with that strategy. One is that it relies on the levelling system, which right now can't even correctly level my officers, so I wouldn't trust it with NPC officers. The other is that it gives you only a choice of a level 1 self-propelled target and something tied to the character's level - everyone is either incompetent or levels up at the same time the player does. You can't set up an encounter which is tough until the player character has improved enough to take it on; either it's trivially simple, matched to the player character, or permanently superior to the player character.
 
Last edited:
@Grey Roger: It is my intention to do away with the original Rapid_Raid function in its current form.
That should clean up the multitude of functions that we have for basically the same purpose.
Thanks for the warning. That leaves me with two choices - copy the existing "RapidRaid" onto the end of my "quests_reaction.c" and continue using it anyway; or dispense with such functions and repeatedly call "LAi_CreateFantomCharacter" followed by "LAi_SetHP" to set them the way I want them. But it's a shame to remove ability from a currently working function.
 
Thanks for the warning. That leaves me with two choices - copy the existing "RapidRaid" onto the end of my "quests_reaction.c" and continue using it anyway
Having multiple copies of functions and several separate ones for the very same purpose is BAD, BAD, BAD!
I cannot stress enough how much we should want to NOT DO THAT! I've learned that the hard way.
We really must do everything in our power to avoid that in the future.

One is that it relies on the levelling system, which right now can't even correctly level my officers, so I wouldn't trust it with NPC officers.
The ONLY complaint I have heard from you about that is the whole "Shared XP" debacle.
I'm well aware of that and @Levis or @pedrwyth still need to look into that further and make it better.
But I cannot force their hand to make that happen, so we're just going to have to wait for that.

The system does in general work. Especially for newly generated characters.
They don't need to gain XP during the game anyway as they get assigned their skills and abilities in one go.
That is a different part of the system and I am not aware of any substantial issues with that side.

In other words: It should be perfectly safe to use it for this specific purpose and there is no reason to completely bypass the Levelling system here.
Can't even be done, because it affects ALL characters in the game already anyway. Current Rapid_Raid ones included.

If there are any actual issues with my new implementation, we'll find out from actually testing it.
Let's not get worked up just yet without even knowing how this works.

The other is that it gives you only a choice of a level 1 self-propelled target and something tied to the character's level - everyone is either incompetent or levels up at the same time the player does. You can't set up an encounter which is tough until the player character has improved enough to take it on; either it's trivially simple, matched to the player character, or permanently superior to the player character.
That is technically true. Is that a feature you need?
If so, I should be able to continue my rewrites to change the "bool genrank" to allow you to specify a specific level or something like that.
I'll need to look into the best way of handling that, but should be possible. :yes

Would that be fair enough? Any other specific things that you really do need?
 
That is technically true. Is that a feature you need?
If so, I should be able to continue my rewrites to change the "bool genrank" to allow you to specify a specific level or something like that.
I'll need to look into the best way of handling that, but should be possible. :yes

Would that be fair enough? Any other specific things that you really do need?
Yes, if you can specify the level, and if the levelling system does actually generate enemies believable at that level, then that could be a reasonable substitute for being able to specify HP directly.

I see you're looking for key strings in "locator" and picking a suitable group. Perhaps include 'if (HasSubStr(group, "monster")) group = "monsters";' as well?

What are valid values for "modeltype"?
 
Good call on "monster"; I was indeed wondering what other types should be added.
If that section ends up working it might be worth putting it in a separate function.
Would allow us to get rid of some of those extra "group" inputs.
Those always seemed to me like they should be superfluous.

I'll modify the code further so you can specify an absolute level value too.
Should be simple enough and does make sense.
Then we'll see what happens.

If I read the code correctly, the model type can be any group defined in initModels.c and also any individual model ID.
So there's no need for that separate "custom" option.
 
Yes, if you can specify the level
Done. This is the rewritten Rapid_Raid function now, including redone documentation:
Code:
void Rapid_Raid(string modeltype, int bmax, int nation, string mainrel, string npcrel, string alert, string attackers_name, string officertype, int offset, bool genrank, string bladeID, string gunID)
/* *** El Rapido's Rapid_Raid function *** PB: major simplification, 4 March 2016

Bind this to a key to put some flavour into your visits on land.
Creates a whole infantry regiment or a single raider that attacks the player.
Attention: When employing a high number of attackers the game may freeze for some seconds!
But the fun is definitely worth waiting 2 seconds! :)
Usage comparable to Random_Raid, but with slight differences.

Parameters:      (attacker modeltype, number of attackers, nation,
            main relation, npc relation, alert message, attackers' name,
            attacker's officer type, attacker's level offset, blade modeltype, gun modeltype)

attacker modeltype:      Try "soldiers", "smugglers", "land_officers", "sailors", "mates", "outlaws"... sets the models.
               If an existing custom model ID is specified, then the game will use that
number of attackers:     self-explanatory.
nation:             Choose ENGLAND, FRANCE, SPAIN, PORTUGAL, HOLLAND or PIRATE.
main relation:         Don't mess with this, 'cause we want an attack and no childrens' birthday party!
npc relation:         Think of hugging, cuddling, giving presents to each other, singing and dancing together...
               Only change, if you know what you're doing!
alert message:         this text is displayed at the start of the attack
attackers' name:       Assigns a name to the attackers, maybe "Elite Soldiers" or "Pirate Hunters" or "Governor's Lifeguard".
               In case of a captain you might call him "Capitaine Francois Chevalier".
attacker's officer type:   different officer types give different skill and ability distributions
attacker's level offset:   if 'rank related to player' is 'false':   number is used as absolute level
               if 'rank related to player' is 'true':   number is used relative to the player level
               set negative for easier enemies, positive for harder ones; 0 for default
rank related to player:     true/false, modifies how 'attacker's level offset' is used; see above
blade modeltype:        defines the item ID of blade, the soldiers are equipped with. Use "" for random!
gun modeltype:          defines the item ID of gun, the soldiers are equipped with. Use "" for random!

EXAMPLE: Rapid_Raid("soldiers", 10, FRANCE, LAI_GROUP_ENEMY, LAI_GROUP_NEUTRAL, "A French infantry unit suddenly appears and attacks you!", "French Musketeer", OFFIC_TYPE_GUARD, 5, "blade13", "");
EFFECT:  10 French soldiers named "French Musketeer" will appear and attack the player.
    They are of the "guard" officer type and are on average 5 levels stronger than the player
    The Frenchmen use Dueling Rapiers and a random gun.

UPDATE:    It is possible to add a captain to the squad by simply calling a second Rapid_Raid with model modeltype set to "Land_Officers" and number of attackers to 1!
EXAMPLE: Rapid_Raid("Land_Officers", 1, FRANCE, LAI_GROUP_ENEMY, LAI_GROUP_NEUTRAL, "You spot the evil villain Francois Chevalier.", "Capitaine Francois Chevalier", OFFIC_TYPE_GUARD, 0, "", "");

UPDATE:    You can even specify a certain model for your individual attacker!
    Maybe you want your attackers' captain or officer to look like Jack Sparrow.
EXAMPLE: Rapid_Raid("depp", 1, PIRATE, LAI_GROUP_ENEMY, LAI_GROUP_NEUTRAL, "Why the hell did you provoke Jack Sparrow?", "Jack Sparrow", OFFIC_TYPE_GUARD, 0, "", "");

Before you call the Rapid_Raid function you should use
PlaySound("OBJECTS\raid.wav");
for atmosphere.

*/
{
   if( bSeaActive || bAbordageStarted)     // Raids are only available on land.
   {                     // Might this code be faster than the large IF-ELSE statement?
     LogIt("No raids on High Sea or during boardings, mate!");
     return;
   }

   LAi_CreateFantomGroup(modeltype, bmax, mainrel, npcrel, nation, officertype, offset, genrank, bladeID, gunID, attackers_name, LAi_FindFirstLocator("reload"));
   if (alert != "")   LogIt(alert);                       // Don't show empty log messages
}
I think that should just about serve its purpose. You can now also again specify absolute rank values rather than having it automated relative to the player.

To get this working, I had to make a lot of changes in a lot of code, but it does seem quite a bit cleaner now.
Some quick tests suggest that it is at least functionally working.
 
@Grey Roger: Just so that you know, my intended-to-be-final version of this is included in this archive:
http://piratesahoy.net/build/temp/PB_Code_5Mar2016.7z
I think it should do what you want, but you may want to double-check on that.
I also changed the function calls in your storyline to work with this, but you may want to change those to determine how hard/easy you intend those encounters to be.
 
Thanks! I've yet to put it to the test as the two occasions in the storyline which call "Rapid_Raid" are relatively early and I'm now working on the next bit, but it will get a work-out when I next need to start a new game. Or you can take a break from work and play it yourself. ;) The first "Rapid_Raid" is straight after you escape from prison so you won't have long to wait.
 
Thanks! I've yet to put it to the test as the two occasions in the storyline which call "Rapid_Raid" are relatively early and I'm now working on the next bit, but it will get a work-out when I next need to start a new game. Or you can take a break from work and play it yourself. ;) The first "Rapid_Raid" is straight after you escape from prison so you won't have long to wait.
What I already tested:
- Killing a street merchant
- Offending a soldier in a tavern using a hostile flag
- Manually triggering a tavern brawl

All of these now call the same function (just via different routes) and I do get enemies that seem to work.
I didn't double-check their rank assignments and skills though, because that tends to be not so easy on enemies. (For friendly characters, I could have used the O-key)
I also don't know about the difficulty of the fights because I did it all using Godmode.

Anyway, I know for certain that this functionality technically works. The main question is balancing.
For your storyline, I set the calls to Rapid_Raid to simple use the "automated level with zero offset and no custom weapons".
That is pretty much the default behaviour. But I have no clue if that is actually what you want there.
 
I've raised the offset to +1 as you have three officers all of which have better "Melee" skill than you, plus you can usually drop one of the attackers with your own musket before they get in place to attack. But I've yet to see whether the net result is attackers who are easier, tougher or about the same as what I had originally.
 
I've raised the offset to +1 as you have three officers all of which have better "Melee" skill than you, plus you can usually drop one of the attackers with your own musket before they get in place to attack. But I've yet to see whether the net result is attackers who are easier, tougher or about the same as what I had originally.
If you are happy with that change, please include it in your next upload. Otherwise there is a risk of me forgetting to add that to my game.... :oops:
 
+1 wasn't enough. The fight was still too easy, so I've raised it to +3.

The soldiers now spawn about as far away as possible. Starting from the prison, there's a little bridge across a stream. Across that bridge, there's a flight of steps leading up to the left which exits to the town centre; a flight of steps leading up to the right to a balcony, under which is an arched door; and the main area, at the far end of which is another flight of steps leading to another part of town centre next to the shipyard and port gate. Previously the search squad spawned by the arched door under the balcony. Now they spawn from the steps leading to the shipyard. I'd rather have them spawn from the nearer steps leading to the town centre. I probably need to abandon "Rapid_Raid" and use "LAi_CreateFantomGroup" directly, as that accepts "locator" as an argument. "LAi_CreateFantomGroup" seems to be what I'd imagined "Rapid_Raid" to become, the fully flexible version with everything available as an argument which is then fed some default values by more restrictive functions such as "Ambush".

More seriously, the new system doesn't give correct ammo if you specify gun type. This is because "LAi_CreateFantomGroup" first calls "LAi_CreateFantomCharacterRk", which assigns a random gun with its ammo; then if "gunID" is specified, removes the random gun and assigns the specified gun, without replacing the ammo. So if I have 'Rapid_Raid("Soldiers", 5, SPAIN, LAI_GROUP_ENEMY, LAI_GROUP_NEUTRAL, "Run! They're after you!", "Search party", OFFIC_TYPE_GUARD, 3, true, "blade_mKnife", "pistolmket");' to give them muskets with bayonets, they get their muskets and bayonets along with pistol or grapeshot ammo.

Looking through the code, this seems to be an excessively long-winded process:
"LAi_CreateFantomCharacterRk" decides whether "offset" is a fixed rank or an offset, then calls "LAi_CreateFantomCharacterExOt".
"LAi_CreateFantomCharacterExOt" just calls "LAi_CreateFantomCharacterExOtAt" with a few arguments filled in as "" - literally, the entire definition of "LAi_CreateFantomCharacterExOt" is
Code:
return LAi_CreateFantomCharacterExOtAt(isfriend, officertype, "", "", "", rank, hasblade, hasgun, model, group, locator);
"LAi_CreateFantomCharacterExOtAt" does the actual work.

Wouldn't it be easier to move the offset/rank code into "LAi_CreateFantomGroup", then have that call "LAi_CreateFantomCharacterExOtAt" directly and skip the intermediate steps which end up there anyway?
 
Rapid Raid now also calls the "main" function.
If I recall, that never did have a locator input so now it still doesn't.
Indeed for my own purposes, I also just used a direct call to the new function.
If maximum flexibility is what you need, that is indeed what you should do. :yes

Good call on the ammo. I forgot about that.
Can you make a bug tracker entry for that one?
I think we should put the ammo giving in its own function; otherwise we'd get copied code again and that is just terrible practice. :facepalm

That is also specifically why I would very much not want to do what you suggest last.
It may seem more readable to do that, but the way it works now with one function calling another and then another does work.
It also gives flexibility between automated or manual inputs without there being any copied code.
Which is for certain a very good thing.

On my job, at one point I spent half a year(!) on merging a gazillion near identical copies of the same code.
Just making a copy often seems like a good and simple solution. But it is atrocious to maintain.
It is also begging for bugs. See here for an example that has been truly annoying me for quite some time now:
Planned Feature - Use Generic Captain and Ship Generation Functions | PiratesAhoy!

Long story short: It is always worth it to resist that temptation. Because it is a shortcut and sooner or later, somebody has to pay the price for it.
And on PotC, that someone usually ends up being me.
 
Good call on the ammo. I forgot about that.
Can you make a bug tracker entry for that one?
Done.
www.piratesahoy.net/threads/lai_createfantomgroup-does-not-assign-correct-ammo.26990/
I think we should put the ammo giving in its own function; otherwise we'd get copied code again and that is just terrible practice. :facepalm
That seems sensible. :yes

That is also specifically why I would very much not want to do what you suggest last.
It may seem more readable to do that, but the way it works now with one function calling another and then another does work.
It also gives flexibility between automated or manual inputs without there being any copied code.
Which is for certain a very good thing.
That explains "LAi_CreateFantomCharacterRk". But why does "LAi_CreateFantomCharacterExOt" exist, when it is a straight call to "LAi_CreateFantomCharacterExOtAt" with no additional code at all?
 
I've got to admit, I'm not entirely certain. That one is Levis' work. I assume it might be so you can call a function with less input parameters if you want to.
Might have been needed for some backwards compatibility or something. But I'm just making up excuses here, because I do not know his reasoning.

The Rk one was my addition because I needed it, that much I do remember.
 
Back
Top