• 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 Levelling: Cannonball Hits Slow Down Game

..\PROGRAM\SEA_AI\AIShip.c

Search for the function I posted above.

Start with commenting out (if you use notepad ++ there are options to comment everything you selected) after:

// NK 05-04-18 to handle relation change for REAL_CANNONS

Then slowly add pieces back untill the performance becomes bad again
 
..\PROGRAM\SEA_AI\AIShip.c

Search for the function I posted above.

Start with commenting out (if you use notepad ++ there are options to comment everything you selected) after:

// NK 05-04-18 to handle relation change for REAL_CANNONS

Then slowly add pieces back untill the performance becomes bad again

Do I need to start a new game or I can use existing save games?
 
Do I need to start a new game or I can use existing save games?
existing. But you do need to restart the game after you made a change (so closing the game and opening it again in windows).
 
existing. But you do need to restart the game after you made a change (so closing the game and opening it again in windows).

With only these lines left, the stuttering disappears completely!

void Ship_HullHitEvent()
{
float fHP;

int iBallType = sti(AIBalls.CurrentBallType);

aref rShipObject = GetEventData();

int iBallCharacterIndex = GetEventData();
int iOurCharacterIndex = GetEventData();

ref rBallCharacter = GetCharacter(iBallCharacterIndex);
ref rOurCharacter = GetCharacter(iOurCharacterIndex);

rOurCharacter.Ship.LastBallCharacter = iBallCharacterIndex;
rBallCharacter.Ship.lasttgt = iOurCharacterIndex; // NK 04-09-16 to see who AI is attacking

int iCompanion = GetCompanionNumber(rBallCharacter, iOurCharacterIndex);

float x = GetEventData();
float y = GetEventData();
float z = GetEventData();

int iFirePlaceIndex = GetEventData();
float fFirePlaceDistance = GetEventData();

bool bDead = LAi_IsDead(rOurCharacter);

bool bSeriousBoom = false;
bool bInflame = false;

// NK 05-04-18 to handle relation change for REAL_CANNONS
if(iBallCharacterIndex == GetMainCharacterIndex() && USE_REAL_CANNONS && EXTRA_HIT_CHECK && rOurCharacter.ship.type != SHIP_FORT_NAME)
{
int currel = SeaAI_GetRelation(iOurCharacterIndex, iBallCharacterIndex) ;
if(currel != RELATION_ENEMY && !CheckAttribute(rOurCharacter,"surrendered")) // NK surrender 05-04-20
{
aref aShips; makearef(aShips, rBallCharacter.SeaAI.Update.Ships);
int iShipsNum = GetAttributesNum(aShips);
int s;
bool enemy = false;
for (s=0; s<iShipsNum; s++)
{
aref aShip = GetAttributeN(aShips, s);
if (sti(aShip.relation) == RELATION_ENEMY) { enemy = true; break; }
}
ref cmdr = Group_GetGroupCommander(GetGroupIDFromCharacter(&rOurCharacter));
if (!enemy) {
Event(SHIP_FIRE_ACTION, "iil", &rOurCharacter, &cmdr, currel); // if there's no enemy, then you have no excuse.
} else {
if (!CheckAttribute(rOurCharacter, "numhits")) {
rOurCharacter.numhits = 1;
} else {
int curhits = sti(rOurCharacter.numhits); // max of cqty / 2 hits.
if (curhits > GetCannonMaxQuantity(&rBallCharacter) / 2) {
Event(SHIP_FIRE_ACTION, "iil", &rOurCharacter, &cmdr, currel);
} else {
curhits++;
rOurCharacter.numhits = curhits;
}
}
}
}
}
if(iBallCharacterIndex != GetMainCharacterIndex() && CheckAttribute(rOurCharacter,"surrendered")) return; // NK because AI doesn't respect surrender. 05-04-23
// NK <--

// Cannon damage multiply
ref rCannon = GetCannonByType(sti(rBallCharacter.Ship.Cannons.Type));
float maxqty, fCannonDamageMultiply;
// THIS IS NOT NEEDED ANY MORE. But the comment is left and the code commented. NK 04-09-15 to simulate fewer crew manning fewer guns. Hence reload rate will now go back to constant.
// KNB 05-02-04 changed this a bit: there is no penalty for >60% crew and the minimum damage is 10%
// now use cannon qty rather than crew mult. 05-04-18
// KK -->
fCannonDamageMultiply = stf(rCannon.DamageMultiply);
if(USE_REAL_CANNONS)
{
// KNB 04-01-17 distance/aspect based damage multipliers -->
float fShotDistance = Ship_GetDistance2D(rBallCharacter, rOurCharacter);
if(fShotDistance < 0) fShotDistance = 500; // NK for when dist < 0 05-04-15
if (rOurCharacter.Ship.Type != SHIP_FORT_NAME && rBallCharacter.Ship.Type != SHIP_FORT_NAME)
{
float fShotSpeed = rCannon.SpeedV0 * stf(Goods[iBallType].SpeedV0);
float fBallAngle = 0;
float fOurAngle = 0;

fCannonDamageMultiply *= 2 * pow(1-1/(2.25*fShotSpeed),fShotDistance); // 2x at point blank, decreasing exponentially with range

if (iBallType != GOOD_GRAPES)
{
if(CheckAttribute(rOurCharacter,"ship.ang.y")) // NK for checking atttributes first before we need CheckAttribute(rBallCharacter,"ship.ang.y") && to
{
// NK now get angle from AIBalls, this requires reversing of the B2R.
fBallAngle = clampangle(stf(AIBalls.Dir)+PI); fOurAngle = stf(rOurCharacter.Ship.Ang.y);
fCannonDamageMultiply *= Bring2Range(0.50, 2.0, 0.0, 1.0, abs(GetDotProduct(fBallAngle,fOurAngle))); //50%-200% depending on angle
}
}
}
}
// <-- KNB
// <-- KK

if (sti(rBallCharacter.TmpPerks.CriticalShoot) && rand(19)==10) { bSeriousBoom = true; } // +5%
if (sti(rBallCharacter.TmpPerks.CannonProfessional) && rand(9)==4) { bSeriousBoom = true; } // +10%

ref rBall = GetGoodByType(iBallType);
switch (iBallType)
{
// TIH --> this section adjusted to be a bit more understandable in setting, and reasonable in graphics Nov13'06
// Removal of "CreateBlastM()" function due to that function causing a CTD in battles Nov12'06
// NK add USE_PARTICLES switch // TIH changed to own switch SHIPHIT_PARTICLES 7-7-06
// Ball_impact and splinters by MM
// By MM, Flames and Critical hits only present on bombs now. // changed to add a rare chance (otherwise what's the POINT of the PERKS?)
case GOOD_BALLS:
if (rand(1)) { bSeriousBoom = false; }// pref toggle and 50% chance a possible critical hit is allowed
if (rand(32) == 1) { bInflame = true; }// pref toggle and 3% chance ship catches on fire from hit
Play3DSound("ball2bort", x, y, z);
switch(SHIPHIT_PARTICLES)
{
case 0: CreateParticleSystem("blast", x, y, z, 0.0, 0.0, 0.0, 0); break; // one orange puff // stock behavior
case 1:
CreateParticleSystem("ball_impact", x, y, z, 0.0, 0.0, 0.0, 0); // two small gray puffs
break;
case 2:
CreateParticleSystem("ball_impact_enhanced", x, y, z, 0.0, 0.0, 0.0, 0); // wood dust
CreateParticleSystem("splinters_enhanced", x, y, z, 0.0, 0.0, 0.0, 0); // twenty-four small splinters
CreateParticleSystem("splinters2_enhanced", x, y, z, 0.0, 0.0, 0.0, 0); // twenty-four medium splinters
break;
case 3:
CreateBlast(x,y,z); // excessive plume of planks and barrels, causing big water splashes
CreateParticleSystem("ball_impact", x, y, z, 0.0, 0.0, 0.0, 0); // two small gray puffs
CreateParticleSystem("splinters2", x, y, z, 0.0, 0.0, 0.0, 0); // six medium splinters
CreateParticleSystem("splinters3", x, y, z, 0.0, 0.0, 0.0, 0); // five large splinters
CreateParticleSystem("flyers", x, y, z, 0.0, 0.0, 0.0, 0);
CreateParticleSystem("flyers2", x, y, z, 0.0, 0.0, 0.0, 0);
break;
}
break;
case GOOD_GRAPES:
bSeriousBoom = false;
bInflame = false;
Play3DSound("grapes2bort", x, y, z);
switch(SHIPHIT_PARTICLES)
{
case 0: CreateParticleSystem("blast", x, y, z, 0.0, 0.0, 0.0, 0); break; // one orange puff // stock behavior
case 1:
CreateParticleSystem("ball_impact", x, y, z, 0.0, 0.0, 0.0, 0);
break;
case 2:
CreateParticleSystem("ball_impact", x, y, z, 0.0, 0.0, 0.0, 0);
CreateParticleSystem("splinters", x, y, z, 0.0, 0.0, 0.0, 0);
break;
case 3:
CreateBlast(x,y,z);
CreateParticleSystem("ball_impact", x, y, z, 0.0, 0.0, 0.0, 0);
break;
}
break;
case GOOD_KNIPPELS:
bSeriousBoom = false;
bInflame = false;
Play3DSound("knippel2bort", x, y, z);
switch(SHIPHIT_PARTICLES)
{
case 0: CreateParticleSystem("blast", x, y, z, 0.0, 0.0, 0.0, 0); break; // one orange puff // stock behavior
case 1:
CreateParticleSystem("ball_impact", x, y, z, 0.0, 0.0, 0.0, 0);
break;
case 2:
CreateParticleSystem("ball_impact", x, y, z, 0.0, 0.0, 0.0, 0);
CreateParticleSystem("splinters", x, y, z, 0.0, 0.0, 0.0, 0);
CreateParticleSystem("splinters2", x, y, z, 0.0, 0.0, 0.0, 0);
break;
case 3:
CreateBlast(x,y,z);
CreateParticleSystem("ball_impact", x, y, z, 0.0, 0.0, 0.0, 0);
CreateParticleSystem("flyers", x, y, z, 0.0, 0.0, 0.0, 0);
CreateParticleSystem("flyers2", x, y, z, 0.0, 0.0, 0.0, 0);
break;
}
break;
case GOOD_BOMBS:
if (rand(20) == 10) { bSeriousBoom = true; }
if (rand(2) == 1) { bInflame = true; }
Play3DSound("bomb2bort", x, y, z);
switch(SHIPHIT_PARTICLES)
{
case 0: CreateParticleSystem("blast", x, y, z, 0.0, 0.0, 0.0, 0); break; // one orange puff // stock behavior
case 1:
CreateParticleSystem("blast", x, y, z, 0.0, 0.0, 0.0, 0);
break;
case 2:
CreateBlast(x,y,z);
CreateParticleSystem("blast", x, y, z, 0.0, 0.0, 0.0, 0);
CreateParticleSystem("flyers", x, y, z, 0.0, 0.0, 0.0, 0);
CreateParticleSystem("flyers2", x, y, z, 0.0, 0.0, 0.0, 0);
break;
case 3:
CreateBlast(x,y,z);
CreateParticleSystem("blast", x, y, z, 0.0, 0.0, 0.0, 0);
CreateParticleSystem("blast_inv", x, y, z, 0.0, 0.0, 0.0, 0);
CreateParticleSystem("splinters2", x, y, z, 0.0, 0.0, 0.0, 0);
CreateParticleSystem("splinters3", x, y, z, 0.0, 0.0, 0.0, 0);
CreateParticleSystem("flyers", x, y, z, 0.0, 0.0, 0.0, 0);
CreateParticleSystem("flyers2", x, y, z, 0.0, 0.0, 0.0, 0);
break;
}
break;
// TIH <-- end adjustment
}

// PB: Queen Anne's Revenge -->
if(sti(GetAttribute(AIBalls, "GreekFire")))
{
bInflame = true;
LogIt("Greek Fire hits the " + rOurCharacter.ship.name + "!")
}
// PB: Queen Anne's Revenge <--

if (sti(rOurCharacter.TmpPerks.ShipDefenceProfessional) && frnd() < PROSHIPDEF_NOCRITCH) { bSeriousBoom = false; } // no seriouse boom, NK 05-04-19 add setting

if (!bDead)
{
float fCrewDamage;
if (USE_REAL_CANNONS)
fCrewDamage = stf(rBall.DamageCrew) * fCannonDamageMultiply * AIShip_isPerksUse(rBallCharacter.TmpPerks.CrewDamageUp, 1.0, 1.10); // 1.15 KNB;
else
fCrewDamage = stf(rBall.DamageCrew) * fCannonDamageMultiply * AIShip_isPerksUse(rBallCharacter.TmpPerks.CrewDamageUp, 1.0, 1.15);
// KK -->
//trace("fCrewDamage="+fCrewDamage);

}

}
 
This one also worked. Other lines, when removed, caused the game not to run, I got an error message: abnormal program termination...
 

Attachments

  • No_stuttering.txt
    9.1 KB · Views: 122
I haven't had the chance to look at this.
Still have some other non PotC things to take care of this weekend and have another busy week ahead again.
So can't make any promises on when I do get the chance.
 
Maybe Levis can take a look at this? The lines I removed are all related to auto_skill_system. I think that this way, I won't be leveling anymore. But if it is possible to play without it, it would make the whole gameplay completely different for me, cause the stuttering is gone.
 
We will probably remove (most of) these lines for the next update as well:
Code:
  if (IsMainCharacter(rBallCharacter))
  {
  if (iRelation != RELATION_ENEMY)
  {
  AttackFriendlyShip(rOurCharacter, iRelation, false);  // PB: General function also used by Ship_FireAction
  }
  // PB: Warning Note -->
  if (iRelation == RELATION_ENEMY && GetFlagRMRelation(sti(rOurCharacter.nation)) != RELATION_ENEMY)
  {
  if (sti(rOurCharacter.nation) != PIRATE && !CheckAttribute(rBallCharacter, "false_flag_note"))
  {
  LogIt("Captain, we are under a flag friendly to the ship we're attacking. We may be branded a pirate if we don't hoist our true colours!");
  PlaySound("INTERFACE\notebook.wav");
  rBallCharacter.false_flag_note = true;
  }
  }
  // PB: Warning Note <--
  }

Maybe Levis can take a look at this? The lines I removed are all related to auto_skill_system. I think that this way, I won't be leveling anymore. But if it is possible to play without it, it would make the whole gameplay completely different for me, cause the stuttering is gone.
What are the lines you removed that make it all smooth again? I can see how giving XP for EVERY ball that hits could be calculation-intensive.
Maybe a proper solution could be to maintain a counter of "number of hits" and then add the XP for all of the hits, say, every 5 seconds or so?
 
We will probably remove (most of) these lines for the next update as well:
What are the lines you removed that make it all smooth again? I can see how giving XP for EVERY ball that hits could be calculation-intensive.
Maybe a proper solution could be to maintain a counter of "number of hits" and then add the XP for all of the hits, say, every 5 seconds or so?

Let me check, I have them in a notepad file. I will post them here.
 
We will probably remove (most of) these lines for the next update as well:
What are the lines you removed that make it all smooth again? I can see how giving XP for EVERY ball that hits could be calculation-intensive.
Maybe a proper solution could be to maintain a counter of "number of hits" and then add the XP for all of the hits, say, every 5 seconds or so?

Ok, these are the lines that I removed and that made a drastic effect in performance...
 

Attachments

  • Removed lines.txt
    3.4 KB · Views: 121
At the very least, you should try to put this back to maintain a somewhat functioning game:

Code:
 if (bSeriousBoom)
 {
 //fCrewDamage = fCrewDamage * 2.0; // stock
 //fHP = fCannonDamageMultiply * stf(rBall.DamageHull) * (4.0 + frnd() * 2.0); // stock
 //fCrewDamage = fCrewDamage * 5.0; // excessive
 //fHP = fCannonDamageMultiply * stf(rBall.DamageHull) * (80.0 + frnd() * 40.0); // excessive
 fHP = fCannonDamageMultiply * stf(rBall.DamageHull) * (2.0 + frnd());
 rOurCharacter.cannonhit.critchance = true; // NK 05-04-20 higher chance for loss of cannon on crit // TIH attribute renamed to critchance Nov13'06
 if (!LAi_IsImmortal(rOurCharacter)) Ship_ApplyHullHitpoints(rOurCharacter, fHP, KILL_BY_BALL, iBallCharacterIndex); // KK
 if (!LAi_IsImmortal(rOurCharacter) && !LAi_IsCrewImmortal(rOurCharacter)) Ship_ApplyCrewHitpoints(rOurCharacter, fCrewDamage  * (2.0 + frnd()) ); // KK
 //Ship_ApplyCrewHitpoints(rOurCharacter, fCrewDamage * 1.5); // stock

 if (iBallCharacterIndex == GetMainCharacterIndex())
 {
 Log_SetStringToLog(LanguageConvertString(iSeaSectionLang, "Ship_critical"));
 }
 }
 else
 {
 fHP = fCannonDamageMultiply * stf(rBall.DamageHull);
 if (!LAi_IsImmortal(rOurCharacter)) Ship_ApplyHullHitpoints(rOurCharacter, fHP, KILL_BY_BALL, iBallCharacterIndex); // KK 
 if (!LAi_IsImmortal(rOurCharacter) && !LAi_IsCrewImmortal(rOurCharacter)) Ship_ApplyCrewHitpoints(rOurCharacter, fCrewDamage); // moved from below, so not applied twice during crits // KK
  }
 DeleteAttribute(&rOurCharacter, "cannonhit"); // NK 05-04-20 cannon lost FX

 //Ship_ApplyCrewHitpoints(rOurCharacter, fCrewDamage); // moved up, so not applied twice during crits
 }

 if (bInflame == true && fFirePlaceDistance < 4.0 && iFirePlaceIndex >= 0)
 {
 int iRandStartTime = rand(1000);
 float fTotalFireTime = Ship_GetTotalFireTime(rOurCharacter);

 PostEvent(SHIP_ACTIVATE_FIRE_PLACE, iRandStartTime, "ialsf", rShipObject, rOurCharacter, iFirePlaceIndex, "ship_onfire", fTotalFireTime);
 PostEvent(SHIP_FIRE_DAMAGE, iRandStartTime, "lllf", iOurCharacterIndex, iBallCharacterIndex, iFirePlaceIndex, fTotalFireTime);
 }

 if (bSeriousBoom == true) //{ Ship_Serious_Boom(x, y, z); } // NK modify coords some 05-04-18 -->
 {
 if(SHIPHIT_PARTICLES==3) { Ship_Detonate(rOurCharacter, false, false); }//{ Ship_Serious_Boom(x-1+frnd()*2, y-1+frnd()*2, z-1+frnd()*2); }
 else { Ship_Serious_Boom(x, y, z); }
 }
I may have messed up the brackets there, so you should double-check it. This removed all XP stuff, but DOES keep the "actually doing damage" part of the code.
Would be good to know if that does still run smoothly or not.
 
At the very least, you should try to put this back to maintain a somewhat functioning game:
I may have messed up the brackets there, so you should double-check it. This removed all XP stuff, but DOES keep the "actually doing damage" part of the code.
Would be good to know if that does still run smoothly or not.

Ok, so I have put back the lines you wrote. Again, there is no stuttering at all. Very nice performance. I guess I'm having problems with auto_skill_system... :/
 
Can you upload the full copy of the file? Seems like we now know the reason.
Which means that @Levis has yet more to be done. Oh dear.... :facepalm
 
Can you upload the full copy of the file? Seems like we now know the reason.
Which means that @Levis has yet more to be done. Oh dear.... :facepalm

This is it. With all the lines related to Auto_skill removed... And with the last codes added that you told me to try.
 

Attachments

  • No_stuttering.txt
    13.2 KB · Views: 118
And here is the modified file:
And with that one, there is no lag when your cannonballs hit a target?
That's pretty conclusive proof indeed. Now what we were hoping for, of course, but not all that surprising either.

This code also looks really quite strange to me:
Code:
      if (iCompanion == - 1)
       {
         if(AUTO_SKILL_SYSTEM)
         {
           Ship_AddCharacterExpChar(rBallCharacter, "Cannons", 20);
         }
         else
         {
           Ship_AddCharacterExp(rBallCharacter, 20);
         }
       }
       if(AUTO_SKILL_SYSTEM)
       {
         // LDH divide experience between cannons and accuracy - 27Dec08
         Ship_AddCharacterExpChar(GetCharacter(iBallCharacterIndex), "Cannons", 125);
         Ship_AddCharacterExpChar(GetCharacter(iBallCharacterIndex), "Accuracy", 125);
       }
That is like it adds some "Cannons" skill if a character is NOT a companion.
And then for ALL characters, it will add "Cannons" and "Accuracy" afterwards.
Which means that all non-companion ships get "Cannons" twice.

Try attached copy of the file instead. In there, I removed those apparent double calls, which should reduce the strain a fair bit.
And since you get "Cannons" AND "Accuracy" for every single cannonball hit, I multiplied their values by 2 but added 50% chance to them.
So on average, you would get the same amount of points as before; but for one single hit, it is "Cannons" OR "Accuracy".
That should reduce the amount of function calls per broadside as well.

I'm still not sure what that 'iCompanion == - 1' check is for. Doesn't make all that much sense to me.
That makes it look like the player gains NO experience at all with Auto Skill System OFF, unless you make a "Critical Hit".
But all NPC ships DO. But for what purpose? What are they going to do with that XP in the first place???
 

Attachments

  • AIShip.zip
    54.8 KB · Views: 105
And with that one, there is no lag when your cannonballs hit a target?
That's pretty conclusive proof indeed. Now what we were hoping for, of course, but not all that surprising either.

This code also looks really quite strange to me:
Code:
      if (iCompanion == - 1)
       {
         if(AUTO_SKILL_SYSTEM)
         {
           Ship_AddCharacterExpChar(rBallCharacter, "Cannons", 20);
         }
         else
         {
           Ship_AddCharacterExp(rBallCharacter, 20);
         }
       }
       if(AUTO_SKILL_SYSTEM)
       {
         // LDH divide experience between cannons and accuracy - 27Dec08
         Ship_AddCharacterExpChar(GetCharacter(iBallCharacterIndex), "Cannons", 125);
         Ship_AddCharacterExpChar(GetCharacter(iBallCharacterIndex), "Accuracy", 125);
       }
That is like it adds some "Cannons" skill if a character is NOT a companion.
And then for ALL characters, it will add "Cannons" and "Accuracy" afterwards.
Which means that all non-companion ships get "Cannons" twice.

Try attached copy of the file instead. In there, I removed those apparent double calls, which should reduce the strain a fair bit.
And since you get "Cannons" AND "Accuracy" for every single cannonball hit, I multiplied their values by 2 but added 50% chance to them.
So on average, you would get the same amount of points as before; but for one single hit, it is "Cannons" OR "Accuracy".
That should reduce the amount of function calls per broadside as well.

I'm still not sure what that 'iCompanion == - 1' check is for. Doesn't make all that much sense to me.
That makes it look like the player gains NO experience at all with Auto Skill System OFF, unless you make a "Critical Hit".
But all NPC ships DO. But for what purpose? What are they going to do with that XP in the first place???

The file that you provided brought back all the stuttering... :/
 
Back
Top