The method of accomplishing this is via using feats which are set up to be invisible. I set up multiple feats in a contiguous block, and turn them on and off to store a binary number. They don't have a category so the player cannot see them, they just work as boolean registers. This is the main limitation, you need a custom feats.2da but it's very good for features related to feats and classes which require customizing that 2da to begin with.
This is not intended for massive amounts of data, there are likely issues caused by having too many feats, and using local ints is a lot faster. This is for critical integers related to your build, which need to be in a safer place than on items or stored as integers on the player himself. I am thinking this is good for psionic power points, mana points, custom skill points and other features which require us to sidestep the entire engine to implement ( like the language points ). To use more than 1000 feats for this would likely require testing for unforseen bugs, and my thoughts are about 200 or so is all that will be needed at the very most. ( there are issues when you have more than 255 spells for example )
2 example rows for feats which i am actually using, this actually goes from row 8800 to 8807 to handle this one range:
8800 FEAT_FEATGROUP_LANGPOINTS1 10000 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** FEAT_FEATGROUP_PRIORLORE1 6 0 **** **** **** **** 0 **** 1 0 **** **** 0 0 **** **** **** 8801 FEAT_FEATGROUP_LANGPOINTS2 10000 **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** FEAT_FEATGROUP_LANGPOINTS2 6 0 **** **** **** **** 0 **** 1 0 **** **** 0 0 **** **** ****
Then i include my math library which i added the following two functions ( forgive the formatting as this site messing it up ):
// stores an integer onto a character as a set of feats
void CSLIntegerToFeatGroup( int iInteger, int iStartingFeat, int iEndingFeat, object oTarget = OBJECT_SELF )
{
int iRow = 0;
int iCurrentBit = 1;
int iTotalRows = (iEndingFeat-iStartingFeat);
//SendMessageToPC(GetFirstPC(),"Integer "+IntToString(iInteger)+" to feat. "+IntToString(iStartingFeat)+" to "+IntToString(iEndingFeat));
for (iRow = 0; iRow <= iTotalRows; iRow++)
{
if ( iInteger & ( 1 << iRow ) ) // the syntax for getting a given bit is "1 << iColumn" which shifts the value by that amount
{
FeatAdd( oTarget, iStartingFeat+iRow, FALSE, FALSE, FALSE );
//SendMessageToPC(GetFirstPC(),"1 - Adding Feat "+IntToString(iStartingFeat+iRow)+" Bit="+IntToString(iRow));
}
else
{
FeatRemove( oTarget, iStartingFeat+iRow );
//SendMessageToPC(GetFirstPC(),"0 - Removing Feat "+IntToString(iStartingFeat+iRow)+" Bit="+IntToString(iRow));
}
}
}
// stores an integer onto a character as a set of feats
int CSLFeatGroupToInteger( int iStartingFeat, int iEndingFeat, object oTarget = OBJECT_SELF )
{
int iInteger;
int iRow = 0;
int iCurrentBit = 1;
int iTotalRows = (iEndingFeat-iStartingFeat);
//SendMessageToPC(GetFirstPC(),"Getting Integer from feat. "+IntToString(iStartingFeat)+" to "+IntToString(iEndingFeat));
for (iRow = 0; iRow <= iTotalRows; iRow++)
{
if ( GetHasFeat( iStartingFeat+iRow, oTarget, TRUE ) )
{
iInteger |= ( 1 << iRow ); // the syntax for getting a given bit is "1 << iColumn" which shifts the value by that amount
//SendMessageToPC(GetFirstPC(),"1 - Has Feat "+IntToString(iStartingFeat+iRow)+" Bit="+IntToString(iRow));
}
}
return iInteger;
}
Usage is simple, the functions basically do all the work.
The parameters for each function.
int iInteger - the integer being set
int iStartingFeat - the first feat in the range defined in feats.2da
int iEndingFeat - the last feat in the range defined in feats.2da
oTarget = character you store the value on.
The first function sets the integer.
void CSLIntegerToFeatGroup( int iInteger, int iStartingFeat, int iEndingFeat, object
This function retrieves it.
int CSLFeatGroupToInteger( int iStartingFeat, int iEndingFeat, object oTarget = OBJECT_SELF )
Note that this uses 8 bits ( 0-7 ) to store a number from 1-255. To store the largest number you can use in game you'd need 31 bits. Storing larger numbers than 255 in 8 rows would result in seemingly random results as it will just ignore parts of the number, very similar to an odometer when it uses more spaces than are available it just starts at zero again.
1 = 0 - 1 2 = 0 - 3 3 = 0 - 7 4 = 0 - 15 5 = 0 - 31 6 = 0 - 63 7 = 0 - 127 8 = 0 - 255 9 = 0 - 511 10 = 0 - 1023 11 = 0 - 2047 12 = 0 - 4095 13 = 0 - 8191 14 = 0 - 16383 15 = 0 - 32767 16 = 0 - 65535 17 = 0 - 131071 18 = 0 - 262143 19 = 0 - 524287 20 = 0 - 1048575 21 = 0 - 2097151 22 = 0 - 4194303 23 = 0 - 8388607 24 = 0 - 16777215 25 = 0 - 33554431 26 = 0 - 67108863 27 = 0 - 134217727 28 = 0 - 268435455 29 = 0 - 536870911 30 = 0 - 1073741823 31* = 0 - 2147483647
This is how i am using it, to store language points and also increase language points when a characters base lore goes up after leveling up.
int CSLLanguageGetLanguagePoints( object oPlayer )
{
int iLanguagePoints = CSLFeatGroupToInteger( 8800, 8807, oPlayer );
// increases in lore base rank are added directly to language points
int iCurrentLore = GetSkillRank(SKILL_LORE, oPlayer, TRUE );
int iPreviousLore = CSLFeatGroupToInteger( 8808, 8815, oPlayer );
if ( iCurrentLore > iPreviousLore )
{
CSLIntegerToFeatGroup( iCurrentLore, 8808, 8815, oPlayer );
iLanguagePoints += ( iCurrentLore - iPreviousLore );
CSLIntegerToFeatGroup( iLanguagePoints, 8800, 8807, oPlayer );
}
return iLanguagePoints;
}
This will be part of the next release of the CSL library, once i'm finished implementing all the features related to this.





Retour en haut






