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

Skill value possibly being less than zero

Baste

Freebooter
Storm Modder
Hearts of Oak Donator
I realize that there might not be many people here these days who could see this thread but I'm asking anyway. Pinging @Levis in case he might see it because he worked on the relevant code, but any other programmer who might have an idea to do this could possibly also take a look at it. I'm not a programmer and haven't been able to check and do this myself.

If a skill value would ever be higher than the maximum, such as 10, it seems it will indeed be set to 10 and count as 10. This is how it should be. But, could a skill value, through items or other effects, ever be less than 0?

If it can this is a potential problem as the game could count it as a negative value. For example, if I have a Luck skill value of 1 and find an item that lowers Luck by 2 as long as I have the item, would the skill value be counted as 0 or would the game handle it as -1? If the game handles it as -1 I would need to find other items to raise Luck by 2 for it to be 1 again. I think it would be better to have 0 as the minimum, so even if an item lowers the skill by 2 it would still only be 0 so any other item that raises it by 1 will bring it to 1. It seems to work this way for the maximum, so if 10 is the maximum an item can never bring it to higher than 10.

If items or other effects can't bring a skill value to be less than 0, could someone please point me to where in the code this is handled?

Also, on the character screen, skill values are shown in green if they are being affected by a positive effect and in red if they are being affected by a negative effect, but if they are affected by both a positive and negative effect equally it will show in blue as usual. This could give the impression that the skill isn't being affected by anything, so in this case, could something be implemented to make the skill value show for example in yellow to indicate that it is being affected by both a positive and negative effect? Maybe with the way the game's code is that can't be done.
 
I was just able to check and yes, a skill value can be less than 0 and is counted as a negative value. Haven't found a way to fix it.
 
How did you manage to get a negative skill value? Perhaps I can poke around and find where the skill is not being properly limited to between 0 and 10.
 
I would prefer if all the item values where added together, and the result of that applied to your current skill. So if you have items giving +5, and items giving -4, they add up to +1, which when added to a skill level of say 5, should give a final result of 6.

Otherwise having items giving +10, and other items giving -10, the final level would always be either 0 or 10 (depending on which you apply first), regardless of original skill.
 
How did you manage to get a negative skill value? Perhaps I can poke around and find where the skill is not being properly limited to between 0 and 10.
Just to test I first edited PROGRAM\ITEMS\initItems.c and changed these two swords:
Code:
  // Reward for killing Malcolm Hatcher
  makeref(itm,Items[n]);
  itm.id                      = "bladeMH";
  itm.skiptrade               = false;  // you can sell the item
  itm.skipsell                = true;   // you can't buy it
  itm.skiprand                = true;   // you can't randomly find it
  itm.skipequip               = false;
  itm.groupID                 = BLADE_ITEM_TYPE;
  itm.name                    = "itmname_bladeMH";
  itm.describe                = "itmdescr_bladeMH";
  itm.folder                  = "ammo";
  itm.model                   = "bladeMH";// was "bladeSC"
  itm.picIndex                = 11;
  itm.picTexture              = "ITEMS_AS";
  itm.price                   = 2345;  //
  itm.dmg_min                 = 30.0;
  itm.dmg_max                 = 44.0;
  itm.piercing                = 65;     //BB (90)
  itm.block                   = 30;
  itm.minlevel                = 99;     //BB+PB
  itm.rare                    = 0.00;   // should be unique
  itm.param.time              = 0.1;
  itm.skill.sneak             = +2;
  itm.param.colorstart        = argb(64, 64, 64, 64);
  itm.param.colorend          = argb(0, 32, 32, 32);
  itm.nation                  = SPAIN;
  n++;

  // Sword of Bartolomeu (Russian Team)
  makeref(itm,Items[n]);
  itm.id                      = "bladeBP";
  itm.skiptrade               = false;  //BB you can sell the item
  itm.skipsell                = true;   // you can't buy it
  itm.skiprand                = true;   // you can't randomly find it
  itm.skipequip               = false;
//itm.groupID                 = BLADE_ITEM_TYPE;
  itm.name                    = "itmname_bladeBP";
  itm.describe                = "itmdescr_bladeBP";
  itm.folder                  = "ammo";
  itm.model                   = "bladeBP";
  itm.picIndex                = 14;
  itm.picTexture              = "ITEMS_ccc";
  itm.price                   = 18350;  //BB (25000)
  itm.dmg_min                 = 29.0;   //BB (20.0)
  itm.dmg_max                 = 46.0;   //BB (36.0)
  itm.piercing                = 75;
  itm.block                   = 80;
  itm.minlevel                = 99;     //BB+PB
  itm.rare                    = 0.00;   // should be unique
  itm.param.time              = 0.1;
  itm.skill.sneak             = -5;
  itm.param.colorstart        = argb(64, 64, 64, 64);
  itm.param.colorend          = argb(0, 32, 32, 32);
  itm.nation                  = PIRATE;
  n++;

The first one to give +2 to Luck, the second to give -5 to Luck. Also changed the second to be just an item so I could test the effect of both.
Then edited PROGRAM\Storyline\standard\StartStoryline.c to start the standard storyline with those two swords:
Code:
    // PB: Override Character Type -->
    PChar.start_weapon.blade = FindCharacterItemByGroup(&PChar, BLADE_ITEM_TYPE);
    PChar.start_weapon.gun   = FindCharacterItemByGroup(&PChar, GUN_ITEM_TYPE);
    TakeItemFromCharacter(Pchar, PChar.start_weapon.blade);
    TakeItemFromCharacter(Pchar, PChar.start_weapon.gun);
    TakeItemFromCharacter(Pchar, "spyglass2");
    GiveItem2Character(Pchar, "bladeMH");
    GiveItem2Character(Pchar, "bladeBP");
    // PB: Override Character Type <--

Then I started the standard storyline and Luck shows as 0 in red as could be expected. The sword that is now just an item gives the -5 effect. Then I equipped the first sword and Luck still shows as 0 in red. I'm guessing this means the skill is now 1 - 5 + 2 = -2 or -6 depending on how it is calculated but still shows as 0 for some reason. Would be preferable if it could be 0 and any positive effect here of +1 would bring it to 1. Might not be possible.

I'm thinking it could be a problem if a player never raises the skill and gathers enough items to negatively affect it to below 0.

It seems to involve this in PROGRAM\Characters\skills\skill_utils.c:
Code:
// Set skill modifier from items
int CalcSkillModifier(ref character, string skillName)
{
    int j, qty;
    int mod = 0;
    ref itm;

    int iChrCabin = FindCharacterShipCabin(character); // KK
    for(j = 0; j < SKILLITEMS_QUANTITY; j++)
    {
        itm = &Items[NativeFindCharacter(&Items, SkillItems[j].id)];
        if(!CheckAttribute(itm, "skill." + skillName))
            continue;
// KK -->

        string itmid = itm.id;
        qty = GetCharacterItem(character, itmid);

        if (iChrCabin >= 0 && CheckAttribute(&Locations[iChrCabin], "box1.items." + itmid) == true)
            qty += sti(Locations[iChrCabin].box1.items.(itmid));
// <-- KK
        if( qty >= sti(itm.skill.num)) // *.skill.num = num required for effect. Default = 1
        {
            if(CheckAttribute(itm, "groupID") && IsCanEquiping(character, itm.groupID) && !IsEquipCharacterByItem(character, itmid))
                continue; // if equipable and not equipped, skip // KK

            // *.stack = bool indicating if items can be stacked together. Default = false (JRH)
            if(sti(itm.skill.stack) == false) qty = 1;
            mod += sti(itm.skill.(skillName)) * qty; // PB: Used to end with '/sti(itm.skill.num)'
        }
    }

//    mod = iclamp(-MAX_SKILL_INCREASE, MAX_SKILL_INCREASE, mod); // PB: Single line
    mod = iclamp(-100, MAX_SKILL_INCREASE, mod);                // JRH: for cursed coins
    character.skill.(skillName).modifier = mod;
    return mod;
}

Which seems to be based on older code from PROGRAM\Characters\CharacterUtilite.c, here in Build 12.1:
Code:
int GetCharacterSkill(ref _refCharacter, string skillName)
{
    if( !CheckAttribute(_refCharacter,"Skill."+skillName) ) return 0;
    int skillN = sti(_refCharacter.Skill.(skillName));
    // GZ/NK -->
    int mod = 0;
    string tempattr = "Skill." + skillName + ".mod";
    if(CheckAttribute(_refCharacter,tempattr))
    {
        mod = sti(_refCharacter.(tempattr));
        if(skillN + mod > 10) skillN = 10;
        else skillN += mod;
    }
    else
    {
        int i, qty, lowest;
        lowest = 11;
        mod = 0;
        ref itm;
        bool uselow = false;
        //uncomment these if you want to disallow stacking different items. See below for more.
        //bool canchange = true;
        //bool temp = false;
        for(i = 0; i < SKILLITEMS_QUANTITY; i++)
        {
            itm = &Items[NativeFindCharacter(&Items, SkillItems[i].id)];
            if(!CheckAttribute(itm,"skill."+skillName)) continue;
            qty = GetCharacterItem(_refCharacter, itm.id);
            if( qty >= sti(itm.skill.num)) // *.skill.num = num required for effect. Default = 1
            {
                if(CheckAttribute(itm,"groupID"))
                {
                    string tstr = itm.groupID;
                    if(!CheckAttribute(_refCharacter,"equip."+tstr)) continue;
                    if(_refCharacter.equip.(tstr) != itm.id) continue; // if equipable and not equipped, skip
                }
                //uncomment below lines if you want to disallow stacking different items
                //temp = canchange;

                //if(CheckAttribute(itm,"skill.diffstack") && sti(itm.skill.diffstack)) temp = true;
                //if(temp)
                //{
                    // *.stack = num of item that can be stacked together. Default = 1
                    if(sti(itm.skill.stack) >= qty/sti(itm.skill.num)) { mod += sti(itm.skill.(skillName)) * qty/sti(itm.skill.num); }
                    else { mod += sti(itm.skill.(skillName)) * sti(itm.skill.stack) / sti(itm.skill.num); }
                    if(CheckAttribute(itm,"skill."+skillName+".set"))
                    {
                        if(sti(itm.skill.(skillName).set) < lowest) lowest = sti(itm.skill.(skillName).set);
                        uselow = true;
                    }
                    //canchange = false;
                //}
            }
        }
        if(uselow)
        {
            _refCharacter.(tempattr) = lowest + mod - skillN;
            if(lowest + mod > 10) skillN = 10;
            else skillN = lowest + mod;
        }
        else
        {
            if(skillN + mod > 10) skillN = 10;
            else skillN += mod;
            _refCharacter.(tempattr) = mod;
        }
    }
    // GZ/NK <--
    if( skillN<=10 ) return skillN;
    trace("Character ID = "+_refCharacter.id + "have skill "+skillName + " = "+skillN);
    return 10;
}

With that code it shows blank when it is a negative value. I can get it to show as 0 with this:
Code:
        if(skillN + mod < 0)
        {
            skillN = 0;
        }
        else
        {
            if(skillN + mod > 10)
            {
                skillN = 10;
            }
            else
            {
                skillN += mod;
            }
        }

            if(lowest + mod < 0)
            {
                skillN = 0;
            }
            else
            {
                if(lowest + mod > 10)
                {
                    skillN = 10;
                }
                else
                {
                    skillN = lowest + mod;
                }
            }

            if(skillN + mod < 0)
            {
                skillN = 0;
            }
            else
            {
                if(skillN + mod > 10)
                {
                    skillN = 10;
                }
                else
                {
                    skillN += mod;
                }
            }

    if(skillN >= 0 && skillN <= 10) return skillN; // Don't know if this change makes a difference.

But that just makes it show as 0 as in Build 14. So, somewhere in B14 it is at least set to not show blank.

If this could be made to work I would appreciate help with also getting it to work with the older code. Some of my projects involve use of older code and so I need to keep compatibility. Or, if a larger rewrite is necessary, details on what needs to be changed so it could also be adapted to an older codebase.

I would prefer if all the item values where added together, and the result of that applied to your current skill. So if you have items giving +5, and items giving -4, they add up to +1, which when added to a skill level of say 5, should give a final result of 6.

Otherwise having items giving +10, and other items giving -10, the final level would always be either 0 or 10 (depending on which you apply first), regardless of original skill.
That's what I'm hoping can be done. Also if a skill that is equally affected by both positive and negative effects could be made to show in for example yellow like positively affected skills are shown in green and negatively affected skills are shown in red that would also be useful. Stuff for that is in PROGRAM\INTERFACE\character.c:
Code:
void SetSkillShow(string skillName, int skillVal)
{
    int modval = CalcCharacterSkill(&xi_refCharacter,skillName);
    int baseval = GetCharacterBaseSkill(&xi_refCharacter,skillName);
    int color = COLOR_NORMAL;
 
    //GameInterface.strings.(skillName) = skillVal + " - " + CalcCharacterSkill(&xi_refCharacter,skillName); // NK
    //Levis -->
    string stringname = skillName;
    GameInterface.strings.(stringname) = skillVal;
    if(skillVal < baseval) color = COLOR_RED;
    if(skillVal > baseval) color = COLOR_GREEN;
    if(skillVal==MAX_CHARACTER_SKILL)    color = COLOR_MONEY;
    ChangeStringColor(stringname,SetAlphaIntoColor(color,GetAlphaFromSkill(skillVal)));
 
    color = COLOR_NORMAL;
    stringname = skillName+"_SEP";
    GameInterface.strings.(stringname) = " - ";
    ChangeStringColor(stringname,SetAlphaIntoColor(COLOR_MONEY,GetAlphaFromSkill(1)));
 
    stringname = skillName+"_MOD";
    GameInterface.strings.(stringname) = modval;
    if(modval==MAX_CHARACTER_SKILL)    color = COLOR_MONEY;
    if(modval > skillVal)    color = COLOR_GREEN;
    if(modval < skillVal)    color = COLOR_RED;
    ChangeStringColor(stringname,SetAlphaIntoColor(color,GetAlphaFromSkill(modval)));
    //Levis <--
    /*int color = COLOR_NORMAL;
    if(skillVal==MAX_CHARACTER_SKILL)    color = COLOR_MONEY;
    ChangeStringColor(skillName,SetAlphaIntoColor(color,GetAlphaFromSkill(skillVal)));*/
}

Here's how I've adapted it to older code:
Code:
void SetSkillShow(string skillName, int skillVal)
{
    xi_refCharacter.Skill.(skillName) = skillVal;
    int modval = GetCharacterSkill(&xi_refCharacter,skillName);

    int color = COLOR_NORMAL;
    string stringname = skillName;
    GameInterface.strings.(stringname) = skillVal;
    if(skillVal == SKILL_MAX) color = COLOR_MONEY;
    ChangeStringColor(stringname,SetAlphaIntoColor(color,GetAlphaFromSkill(skillVal)));
   
    //color = COLOR_NORMAL;
    stringname = skillName+"_SEP";
    GameInterface.strings.(stringname) = "-";
    ChangeStringColor(stringname,SetAlphaIntoColor(COLOR_MONEY,GetAlphaFromSkill(modval)));
   
    stringname = skillName+"_MOD";
    GameInterface.strings.(stringname) = modval;
    if(modval == SKILL_MAX) color = COLOR_MONEY;
    if(modval > skillVal) color = COLOR_GREEN;
    if(modval < skillVal) color = COLOR_RED;
    ChangeStringColor(stringname,SetAlphaIntoColor(color,GetAlphaFromSkill(modval)));
}

It could be said that since I'm not a programmer I should stay out of it, but I'm trying to learn.
 
Last edited:
Console can be your friend here. Instead of this:
Then edited PROGRAM\Storyline\standard\StartStoryline.c to start the standard storyline with those two swords:
... just edit "PROGRAM\console.c". Right near the top you'll see this:
Code:
    ref pchar = GetMainCharacter();
    ref ch;
    int i;
    int limit;
                                            // Case 0 = Enable reload (useful when you get stuck on boarding) + Set player type (if you cannot move anymore)
    switch(0)                                // Case 1 = Various test and cheat codes
Add whatever you like immediately under the 'int limit' line and before the 'switch(0)' line. Then, while playing the game, press F12 to run it. You should see an on-screen message "Executed Console".

The sword that is now just an item gives the -5 effect. Then I equipped the first sword and Luck still shows as 0 in red. I'm guessing this means the skill is now 1 - 5 + 2 = -2 or -6 depending on how it is calculated but still shows as 0 for some reason. Would be preferable if it could be 0 and any positive effect here of +1 would bring it to 1.
If all items are added together and then added to your skill, the result here should be 1 - 5 + 2 = -2, then you acquire something with +1, and the final result is 1 - 5 + 2 + 1 = -1. This should then be capped to 0 so you don't get a negative skill in the game, but there's still that -1 lurking in the background. You would then need a further +2 item, not a +1, before you see an overall bonus of +1.

It could be said that since I'm not a programmer I should stay out of it, but I'm trying to learn.
I certainly wouldn't say that you should stay out of it! I'm no professional programmer either and learned all I know about modding PoTC by poking around with the game code. Go ahead and do likewise! :onya
 
Good point about the console. I should try to keep that in mind.

If all items are added together and then added to your skill, the result here should be 1 - 5 + 2 = -2, then you acquire something with +1, and the final result is 1 - 5 + 2 + 1 = -1. This should then be capped to 0 so you don't get a negative skill in the game, but there's still that -1 lurking in the background. You would then need a further +2 item, not a +1, before you see an overall bonus of +1.
I noticed that it is the same for the maximum. Maybe it actually works as intended and is as you say, with it being capped to 0 or 10 so it's not a negative or higher than maximum value in the game, but mathematically being below 0 or above 10 so further items would be needed to raise or lower the skill again. As long as the game doesn't actually count it as below 0 or above 10 in skill checks and so on it should be good.

I certainly wouldn't say that you should stay out of it! I'm no professional programmer either and learned all I know about modding PoTC by poking around with the game code. Go ahead and do likewise! :onya
It's the same for me, just about everything I know about programming is from modding this game! :D
 
I noticed that it is the same for the maximum. Maybe it actually works as intended and is as you say, with it being capped to 0 or 10 so it's not a negative or higher than maximum value in the game, but mathematically being below 0 or above 10 so further items would be needed to raise or lower the skill again. As long as the game doesn't actually count it as below 0 or above 10 in skill checks and so on it should be good.
And so back to the original question - have you seen a displayed skill less than 0? If so, what did you do to get it?

If the displayed skill is 0 but remains at 0 when you get another +1 item because of a hidden -1, that's how it should be. If you see -1 on the "Character" screen then that needs to be fixed.

There's a further intentional limit. You can't get more than +4 total bonus. If you have five +1 items, you'll still only get +4 total even if you have no items with negative modifiers. (Though if you have five +1 items and a -1 item, you should still have +4 total.) That's to prevent you from going from 1 to 10 just by collecting items and not doing anything to earn the higher skill.
 
And so back to the original question - have you seen a displayed skill less than 0? If so, what did you do to get it?

If the displayed skill is 0 but remains at 0 when you get another +1 item because of a hidden -1, that's how it should be. If you see -1 on the "Character" screen then that needs to be fixed.
Nope, I haven't actually seen a skill value being displayed as less than 0. I should have made that more clear. It was from my belief that since a skill value can mathematically be negative then that could possibly also mean that the game would use that negative value in calculations.

I just tested further and can now confirm that the mathematically negative value is not used in calculations - it is being capped to 0, and the skill value is displayed as 0. Likewise for mathematical skill values higher than 10 being capped to 10.

Tested by making an item give me a mathematical Melee skill of -10, being shown as 0, and I still did the same amount of damage as I did with a Melee skill of 1. Might be some variation in damage between Melee at 0 and at 1, but the -10 did no difference.
Further tested by making an item give me a Luck skill of -5, also shown as 0, and making Malcolm Hatcher not talk to me unless it is 0 or higher. He talked to me, so the mathematical value is indeed being capped and the displayed value works as intended.

Thus the answers to our questions are no, a skill value can't be less than 0, and no, a skill value can't be displayed as less than 0. Only the mathematical value can be less than 0 or higher than 10, but the actual used and displayed value never will be.

I should have thought to test this more thoroughly earlier.

That just leaves the question if a skill that is equally affected by both positive and negative effects could be made to show in another color, as to not give the impression that it isn't being affected by anything. At least there is no bug with the skill values.
 
Back
Top