I've mapped the width of the most basic characters ( Basically ASCII 32 to 126 )
and developed a function to easily calculate the amount of whitespaces
required to pad a string in order to create formatted tables, like this:
Screenshot:
Please note that because the total width of a string does not always become the equivalent of a rational number of whitespaces, it is not always possible to get the exact equivalent width.
This means that the end result can deviate between the equivalent width of 0.25 to 0.75 whitespaces.
However, if the delta ( padding - calculated string width ) is greater
than 9.75 perfect padding are always guaranteed because ot the utilization of
an horizontal tab character that is the equivalent of 3.25 whitespaces in width.
The Font Problem
Spoiler
The font used in the console of Half-Life games is not monospaced, essentially meaning that some characters are wider than others.
This creates a problem every time you wish to line up rows of strings printed to the console in a table like fashion.
Imagine that we wish to create two rows of data to display in the console that looks something like this:
PHP Code:
Property Value
Name Zynda
Health 100.0
Armor 100.0
Speed 255.0
Seemingly an easy task, but doing this manually would require an painstaking "trial and error" approach to find the amount of whitespace required to pad the space between
the rows.
But what if the data of the first row is dynamic and there is no way of knowing it's width in advance.
Like this:
PHP Code:
Player Name Health
Richard 90.0
Hariwini 100.0
Rambert 87.5
Oda 0.0
This is where we have to calculate the amount of whitespaces required during runtime.
Usage Example
PHP Code:
public TableTest( id, level, cid )
{
if ( !cmd_access( id, level, cid, 1 ) )
{
return PLUGIN_HANDLED
}
new firstRowString[ 128 ]
new secondRowString[ 32 ]
new const padding = 60
FormatConsolePadding( const inputString[], padding, outputString[], outputStringLength )
{
new whitespaceString[ 512 ]
new currentChar = 0
// ### Calucate length equivalent
new Float:inputLength = 0.0
for( new i = 0; i < strlen( inputString ); i++ )
{
switch( inputString[ i ] )
{
// ### LOWERCASE ###
case 97: // a
{
inputLength += 1.75
}
case 98: // b
{
inputLength += 1.75
}
case 99: // c
{
inputLength += 1.5
}
case 100: // d
{
inputLength += 1.75
}
case 101: // e
{
inputLength += 1.75
}
case 102: // f
{
inputLength += 1.0
}
case 103: // g
{
inputLength += 1.75
}
case 104: // h
{
inputLength += 1.75
}
case 105: // i
{
inputLength += 0.75
}
case 106: // j
{
inputLength += 1.0
}
case 107: // k
{
inputLength += 1.5
}
case 108: // l
{
inputLength += 0.75
}
case 109: // m
{
inputLength += 2.75
}
case 110: // n
{
inputLength += 1.75
}
case 111: // o
{
inputLength += 1.75
}
case 112: // p
{
inputLength += 1.75
}
case 113: // q
{
inputLength += 1.75
}
case 114: // r
{
inputLength += 1.25
}
case 115: // s
{
inputLength += 1.5
}
case 116: // t
{
inputLength += 1.0
}
case 117: // u
{
inputLength += 1.75
}
case 118: // v
{
inputLength += 1.5
}
case 119: // w
{
inputLength += 2.5
}
case 120: // x
{
inputLength += 1.5
}
case 121: // y
{
inputLength += 1.5
}
case 122: // z
{
inputLength += 1.5
}
// ### UPPERCASE ###
case 65: // A
{
inputLength += 2.0
}
case 66: // B
{
inputLength += 1.75
}
case 67: // C
{
inputLength += 2.0
}
case 68: // D
{
inputLength += 2.0
}
case 69: // E
{
inputLength += 1.75
}
case 70: // F
{
inputLength += 1.75
}
case 71: // G
{
inputLength += 2.0
}
case 72: // H
{
inputLength += 2.0
}
case 73: // I
{
inputLength += 1.0
}
case 74: // J
{
inputLength += 1.25
}
case 75: // K
{
inputLength += 1.75
}
case 76: // L
{
inputLength += 1.5
}
case 77: // M
{
inputLength += 2.5
}
case 78: // N
{
inputLength += 2.0
}
case 79: // O
{
inputLength += 2.25
}
case 80: // P
{
inputLength += 1.75
}
case 81: // Q
{
inputLength += 2.25
}
case 82: // R
{
inputLength += 2.0
}
case 83: // S
{
inputLength += 2.0
}
case 84: // T
{
inputLength += 2.0
}
case 85: // U
{
inputLength += 2.0
}
case 86: // V
{
inputLength += 2.0
}
case 87: // W
{
inputLength += 3.0
}
case 88: // X
{
inputLength += 2.0
}
case 89: // Y
{
inputLength += 1.75
}
case 90: // Z
{
inputLength += 1.75
}
// ### NUMBER ###
case 48: // 0
{
inputLength += 1.75
}
case 49: // 1
{
inputLength += 1.75
}
case 50: // 2
{
inputLength += 1.75
}
case 51: // 3
{
inputLength += 1.75
}
case 52: // 4
{
inputLength += 1.75
}
case 53: // 5
{
inputLength += 1.75
}
case 54: // 6
{
inputLength += 1.75
}
case 55: // 7
{
inputLength += 1.75
}
case 56: // 8
{
inputLength += 1.75
}
case 57: // 9
{
inputLength += 1.75
}
// ### SPECIAL ###
case 33: // !
{
inputLength += 1.0
}
case 34: // "
{
inputLength += 1.25
}
case 35: // #
{
inputLength += 2.25
}
case 36: // $
{
inputLength += 1.75
}
case 37: // %
{
inputLength += 1.5
}
case 38: // &
{
inputLength += 2.25
}
case 39: // '
{
inputLength += 0.75
}
case 40: // (
{
inputLength += 1.25
}
case 41: // )
{
inputLength += 1.25
}
case 42: // *
{
inputLength += 2.0
}
case 43: // +
{
inputLength += 2.0
}
case 44: // ,
{
inputLength += 1.0
}
case 45: // -
{
inputLength += 1.25
}
case 46: // .
{
inputLength += 1.0
}
case 47: // /
{
inputLength += 1.25
}
case 58: // :
{
inputLength += 1.25
}
case 59: // ;
{
inputLength += 1.25
}
case 60: // <
{
inputLength += 2.25
}
case 61: // =
{
inputLength += 2.25
}
case 62: // >
{
inputLength += 2.25
}
case 63: // ?
{
inputLength += 1.5
}
case 64: // @
{
inputLength += 3.0
}
case 91: // [
{
inputLength += 1.25
}
case 92: // ( BACKWARDS SLASH )
{
inputLength += 1.25
}
case 93: // ]
{
inputLength += 1.25
}
case 94: // ^
{
inputLength += 2.25
}
case 95: // _
{
inputLength += 1.75
}
case 96: // `
{
inputLength += 1.75
}
case 123: // {
{
inputLength += 1.5
}
case 124: // |
{
inputLength += 1.5
}
case 125: // }
{
inputLength += 1.5
}
case 126: // ~
{
inputLength += 2.25
}
It would be nice to reduce all that switch conditional with an array. It's trivial but reminds a good coding style. Remember that you must priorize CPU over Memory.
Aren't game fonts changeable? Ubuntu users by default have a diffrrent font than Windows users.
Initially i did look into changing the font as a user but i remeber not finding much. As a mod developer it is possible for sure, Sven-Coop got an option to use an monospaced font for example.
I'll also admit that i put little thought into linux versions, odds are my method will fail completely for linux users.
It would be nice to reduce all that switch conditional with an array. It's trivial but reminds a good coding style. Remember that you must priorize CPU over Memory.
I'm not sure i follow your thinking, could you enlighten me with an example of how that would be done?
Aren't game fonts changeable? Ubuntu users by default have a diffrrent font than Windows users.
Even if they are user-changeable, they probably are different in Linux regardless of what the user wants because most fonts on Windows® are proprietary and cannot legally be used on Linux without a license. So, Linux typically uses open-source fonts.
Even if they are user-changeable, they probably are different in Linux regardless of what the user wants because most fonts on Windows® are proprietary and cannot legally be used on Linux without a license. So, Linux typically uses open-source fonts.
My point was that this solution isn't universal, not just about Linux clients using different fonts. Windows users could most likely have different fonts too.