• 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 Random effects of ship upgrades rerolled on new upgrade (fix included, removing randomness)

Tingyun

Corsair
Storm Modder
Odd experience today: I added cotton sails to my new bermuda sloop, and the top speed went up substantially. Delighted, I added copper plating, and the top speed then went DOWN.

Confused, I reloaded and tried again. That time, it went up a different, smaller amount for cotton sails, and then went up again for copper plating, which was good at least.

I realized the game is randomly rolling the magnitude of upgrades, and then rerolling the earlier upgrades when you add a new upgrade of the same type, resulting in the potential to actually lose performance when adding an upgrade.

Aside from that rerolling being unrealistic, I think there is no need to make the effects of ship upgrades random (certainly not to the degree they currently are--where a sailing upgrade generates a random number of 0 to 5 for how much speed it increases, meaning sometimes cotton sails do nothing and other times they are over twice as effective as average).

Moreover, there is enough randomness in ship stats. Already even after nations are defined as the origin of ships, the game introduces another random pass upgrading or reducing certain stats of ships (meaning a british design sloop, of the same model and type, can be substantially faster, or slower). That amount of randomness is enough I think.

PROPOSED FIX:Just remove the randomness from the upgrades.

Question: The influence on ship inertia was still not implemented according to the comments? So no need to worry about removing the randomness from that? Didn't want to touch that part since I didn't understand it.

Proposed new values below for internal settings, I just set the mins and maxes for everything but inertia to the same, usually the midpoint rounding up, but for the staysails I set one parameter to the max and the other to a much reduced value, both to differentiate its function and because I didn't want to add additional decimal places (since I'm not sure how it works exactly).

EDIT: Modified interia range as well, as it looks like it might be used.



// ---- ADD ONS ---- All need shipyards. All can take out.

//Copper plates
#define CPSPEEDRANGEMAX 3 // int 0-100
#define CPSPEEDRANGEMIN 3 // int 0-100
#define CPTURNINGRANGEMAX 1 // int 0-100
#define CPTURNINGRANGEMIN 1 // int 0-100
#define CPINERTIARANGEMAX -3 // Not implemented
#define CPINERTIARANGEMIN -3 // Not implemented
#define CPTIMEMULT 1 // Time to repair all hull multiply by CPTIMEMULT
#define CPDISP 5 // int 0-100 Chance of being available
#define CPCOSTMULT 4 //Ships price * CPCOSTMULT

//Bronze cannons
#define BCACC 10.0 //float 0-100 increase of accuracy
#define BCRELOAD 10.0 //float 0-100 decrease of reload time
#define BCCRITICALCANNON 2.0 //float Multiplies the chance of loss a normal cannon
#define BCWEIGH -5 //Not implemented
#define BCDISP 10 // Availability
#define BCCOSTMULT 1750 // Cannons price per BCCOSTMULT

//Good chasers
#define GCACCADD 10.0 //float 0-100 - increase of accuracy
#define GCRANGEADD 1.1 //increase of speed - be careful: too big and the Fantoms will not aim correctly
#define GCSAILCRIT 8.0 //float 0-100 - % of sail crit - to be added to CSAILCRIT
#define GCMASTCRIT 20.0 //float 0-100 - % of mast crit
#define GCDISP 10 // int 0-100 Chance of being available
#define GCCOSTMULT 2000 // GCCOSTMULT * rcannons.cost(depending cannons fitted) * 2

// Common chasers
#define CSAILCRIT 5.0 //float 0-100 - % of sail crit
#define CSAILCRITDMG 4.0 // Damage multiplier if sail crit , either with chasers or good chasers
#define CMASTCRIT 15.0 // float 0-100 - % of mast crit

// Guns
#define MASTCRIT 8.0 //float 0-100 - % of mast crit

//New sails and ropes
#define NSSPEEDRANGEMAX 3 //int 0-100
#define NSSPEEDRANGEMIN 3 //int 0-100
#define NSSAILHPRANGEMAX 5 //int 0-100 % of damage reduction
#define NSSAILHPRANGEMIN 5 //int 0-100
#define NSINERTIARANGEMAX -5 //Not implemente
#define NSINERTIARANGEMIN -5 //Not implemente
#define NSTIMEMULT 1 // Time to repair all rigging multiply by NSTIMEMULT
#define NSDISP 25 // int 0-100 Chance of being available
#define NSCOSTMULT 0.5 // Cost of repair all rigging multiply by NSCOSTMULT

//Long top-masts
#define TMSPEEDRANGEMAX 5 //int 0-100
#define TMSPEEDRANGEMIN 5 //int 0-100
#define TMINERTIARANGEMAX -5 //Not implemente
#define TMINERTIARANGEMIN -5 //Not implemente
#define TMSAILCRIT 4 //int 0-100 increase of % of mastcrit
#define TMTIMEMULT 1 // Time to repair all rigging multiply by TMTIMEMULT
#define TMDISP 15 // int 0-100 Chance of being available
#define TMCOSTMULT 0.5 //Cost of repair all rigging multiply by TMCOSTMULT

//Staysails
#define SSTACKRANGEMAX -0.1 // float 0 - 1 Degrees of improve ClosestPoint - remmeber that ClosestPoint goes from 0 to 1
#define SSTACKRANGEMIN -0.1 // float 0 - 1 Degrees of improve ClosestPoint - remmeber that ClosestPoint goes from 0 to 1
#define SSTURNINGRANGEMAX 1 // int 0-100
#define SSTURNINGRANGEMIN 1 // int 0-100
#define SSTIMEMULT 1 // Time to repair all rigging multiply by SSTIMEMULT
#define SSDISP 3 // int 0-100 Chance of being available // Rare
#define SSCOSTMULT 0.5 //Cost of repair all rigging multiply by SSCOSTMULT

//Reinforced Hull --- No way back!!!!
#define RHHULLHPRANGEMAX 5 //int 0-100
#define RHHULLHPRANGEMIN 5 //int 0-100
#define RHINERTIARANGEMAX 5 //Not implemented
#define RHINERTIARANGEMIN 5 //Not implemented
#define RHCALIBERADD 1 // Number of calibers up
#define RHTIMEMULT 1 // Time to repair all hull multiply by RHTIMEMULT
#define RHDISP 50 // int 0-100 Chance of being available // Rather easy
#define RHCOSTMULT 40 // Cost of repair all hull multiply by RHCOSTMULT

// Pirate "flush" of ships - reduce the superstructure of captured ships in order to make them more "frigate-like"
// Need pirate or smuggler shipyard
// Just One way and only once in a ship
// Should change the model of ship in certain cases???

#define FLUSHSPEEDRANGEMAX 10 //int 0-100
#define FLUSHSPEEDRANGEMIN 10 //int 0-100
#define FLUSHTURNINGRANGEMAX 10 //int 0-100
#define FLUSHTURNINGRANGEMIN 10 //int 0-100
#define FLUSHHULLHPRANGEMAX -6 //int 0-100
#define FLUSHHULLHPRANGEMIN -6 //int 0-100
#define FLUSHLOADRANGEMAX 15 //int 0-100
#define FLUSHLOADRANGEMIN 15 //int 0-100
#define FLUSHEDCOSTMULT 6 //int 0-100
#define FLUSHEDTIMEMULT 1 //int 0-100
#define FLUSHEDPROB 10 //int 0-100 Chance of being on in a fantom
#define FLUSHEDPROB_IFPIRATE 60 //int 0-100 Chance of being on in a fantom
 
Last edited:
I suppose the randomness does indeed encourage "save/reload" exploits, which are a bit useless.
And if already applied upgrades are being modified, that definitely makes no sense.
 
Pieter,

Great! I will post this proposed change in the thread, but one question:

Do you know if inertiarange modifiers from upgrades have been implemented, or are the comments next to them saying not implemented still correct? I left them alone for now, as I didn't want to change anything I didn't understand, and they didn't show up in the ship stats in game. Just want to make sure you agree with that, or whether I should change them too.
 
Last edited:
Those comments are most likely still true.
To be sure, see if you can find where else those variable names are used.
 
hmmm..... if we do a little bit more work on this and remove the random effect from the shipyard interface we can get rid of a lot of defines. I always like removing defines because it makes the internal settings easier to read :).
 
That makes sense Levis. Would it preserve saved game compatibility if the defines were removed? I really love my current campaign. ;)

I'll post this fix for now, and then we can replace it if you decide to do the broader thing you mention. :)

It looks like the interia effects are used, I found this in KB_routines.c.

Unless it just goes nowhere afterwords? Anyway, that is all I found by searching for the defines.

int ApplyTun (int _idx, string _improvement, int _time)
{
int i,j;
float pertoadd;
ref char;

if (_idx == 0 ) { char = GetMainCharacter(); }
else { char = GetCharacter(_idx); }
switch (_improvement ) {

case "cplates":
applytunspeed(char,"cplates",CPSPEEDRANGEMAX,CPSPEEDRANGEMIN);
applytunturning(char,"cplates",CPTURNINGRANGEMAX,CPTURNINGRANGEMIN);
applytuninertia(char,"cplates",CPINERTIARANGEMAX,CPINERTIARANGEMIN);
break;

case "rhull":
applytunhullhp(char,"rhull",RHHULLHPRANGEMAX,RHHULLHPRANGEMIN);
applytuninertia(char,"rhull",RHINERTIARANGEMAX,RHINERTIARANGEMIN);
applytunupcaliber(char,"rhull",RHCALIBERADD);
break;

case "flushed":
applytunspeed(char,"flushed",FLUSHSPEEDRANGEMAX,FLUSHSPEEDRANGEMIN);
applytunturning(char,"flushed",FLUSHTURNINGRANGEMAX,FLUSHTURNINGRANGEMIN);
applytunhullhp(char,"flushed",FLUSHHULLHPRANGEMAX,FLUSHHULLHPRANGEMIN);
applytunload(char,"flushed",FLUSHLOADRANGEMAX,FLUSHLOADRANGEMIN);
break;

case "nsails":
applytunspeed(char,"nsails",NSSPEEDRANGEMAX,NSSPEEDRANGEMIN);
applytuninertia(char,"nsails",NSINERTIARANGEMAX,NSINERTIARANGEMIN);
applytunsailhp(char,"nsails",NSSAILHPRANGEMAX,NSSAILHPRANGEMIN);
//KB -Tuning ships - removed functionality applytunsailcrit(char,"nsails",NSSAILCRIT);
break;

case "ltopmasts":
applytunspeed(char,"ltopmasts",TMSPEEDRANGEMAX,TMSPEEDRANGEMIN);
applytuninertia(char,"ltopmasts",TMINERTIARANGEMAX,TMINERTIARANGEMIN);
applytunsailcrit(char,"ltopmasts",TMSAILCRIT);
break;
 
Last edited:
Removing a #define should not affect savegame compatibility in virtually all cases.
 
Great!

One downside of me being ignorant of how coding works, is it is easy for me to worry about silly things. :)
 
@Tingyun maybe you can do this yourself :).
Search in KB_routines.c for the functions mentioned above. Here is one of those as an example:
Code:
void applytunload(ref _char, string _improvement, float rangemax, float rangemin) {
    float j;
    float pertoadd;
    aref temparef;
   
    j = rangemax - rangemin;
    pertoadd = j*frnd()+rangemin;
    if (rand(11) <= GetShipSkill(_char, SKILL_SNEAK)) { pertoadd=pertoadd+1; } // KK
    if (rand(11) <= GetShipSkill(_char, SKILL_SAILING)) { pertoadd=pertoadd+(0.5*j); } // KK
    if (pertoadd > rangemax) { pertoadd = rangemax;}
    _char.ship.tune.(_improvement).on = 1;
    // KB & PB: Error control -->
    makearef(temparef,_char.ship.stats);
    if (!CheckAttribute(temparef,"origcapacity"))
    {
        if(!CheckAttribute(temparef, "capacity"))
        {
            int Capacity = GetCharacterShipValue(_char, "Capacity");
            temparef.capacity = Capacity; // PB: Why does "temparef.capacity = GetCharacterShipValue(_char, "Capacity");" return 0???
        }
        temparef.origcapacity = temparef.capacity;
    }
    // KB & PB: Error control <--

    _char.ship.tune.(_improvement).capacity = stf(_char.ship.stats.origcapacity) * pertoadd/100;
    _char.ship.stats.capacity = sti(_char.ship.stats.capacity) + sti(_char.ship.tune.(_improvement).capacity);
/*    if(IsMainCharacter(_char))
    {
        LogIt("Ships capacity increased by " + _char.ship.tune.(_improvement).capacity);
        LogIt("Max possible improvement = " + (stf(_char.ship.stats.origcapacity) * rangemax/100));
        LogIt("Ships new capacity = " + _char.ship.stats.capacity);
    }*/
}

the random elements should be removed from here. So this should become something like this:
void applytunload(ref _char, string _improvement, float mod) {
aref temparef;

_char.ship.tune.(_improvement).on = 1;
// KB & PB: Error control -->
makearef(temparef,_char.ship.stats);
if (!CheckAttribute(temparef,"origcapacity"))
{
if(!CheckAttribute(temparef, "capacity"))
{
int Capacity = GetCharacterShipValue(_char, "Capacity");
temparef.capacity = Capacity; // PB: Why does "temparef.capacity = GetCharacterShipValue(_char, "Capacity");" return 0???
}
temparef.origcapacity = temparef.capacity;
}
// KB & PB: Error control <--

_char.ship.tune.(_improvement).capacity = stf(_char.ship.stats.origcapacity) * mod;
_char.ship.stats.capacity = sti(_char.ship.stats.capacity) + sti(_char.ship.tune.(_improvement).capacity);
/* if(IsMainCharacter(_char))
{
LogIt("Ships capacity increased by " + _char.ship.tune.(_improvement).capacity);
LogIt("Max possible improvement = " + (stf(_char.ship.stats.origcapacity) * mod));
LogIt("Ships new capacity = " + _char.ship.stats.capacity);
}*/
}

the things in bold are changed. and I removed some lines.
I have no idea if this works. but this should give you an idea. As you see the arguments for the function are also changed. so you need to find all cases where "applytunload" is called and change it to only give it 1 of those ranges. I sugest renaming them all together. You can remove 1 of each from the internal setting and rename the other one to something like
Code:
#define FLUSHSPEEDMOD 10 //int 0-100

And in the cases you posted above you change it to something like this:
Code:
applytunspeed(char,"cplates",CPSPEEDMOD);

then you need to test it to see if it really works and gives the same kind of values.
 
Levis, I am afraid this is a bit beyond me right now. You gave great guidance, and I sort of understsnd how it works, but I need some more time to get comfortable with these sorts of things.

How about this? I am trying to learn as I go along, and will probably be ready to try something like that soon.

Let's table this more extensive change for now, and I'll come back and do it later after I practice some more (and when I have time to finish working through your tutorials). I'll make a seperate bugtracker entry for "cleaning up the defines" when I am ready, and post a fix there. And we resolve this one with the temporary solution in the meantime. :)
 
Levis, I am afraid this is a bit beyond me right now. You gave great guidance, and I sort of understsnd how it works, but I need some more time to get comfortable with these sorts of things.

How about this? I am trying to learn as I go along, and will probably be ready to try something like that soon.

Let's table this more extensive change for now, and I'll come back and do it later after I practice some more (and when I have time to finish working through your tutorials). I'll make a seperate bugtracker entry for "cleaning up the defines" when I am ready, and post a fix there. And we resolve this one with the temporary solution in the meantime. :)
No problem. I will just leave this one open as a fix in progress. You can post the new interalsettings file as a temporary fix so we can include that in the build and when you feel confortable you can tackle this :).
 
Back
Top