make 21x21 work on Android

Still needs default colors and the bonus square values working for
smaller sizes.
This commit is contained in:
Eric House 2022-03-10 16:56:09 -08:00
parent cb2d847e6d
commit b34190d62d
14 changed files with 123 additions and 189 deletions

View file

@ -173,7 +173,9 @@ public class BoardCanvas extends Canvas implements DrawCtx {
int[] ids = { R.string.bonus_l2x_summary,
R.string.bonus_w2x_summary ,
R.string.bonus_l3x_summary,
R.string.bonus_w3x_summary };
R.string.bonus_w3x_summary,
R.string.bonus_l4x_summary,
R.string.bonus_w4x_summary };
m_bonusSummaries = new String[1 + ids.length];
for ( int ii = 0; ii < ids.length; ++ii ) {
m_bonusSummaries[ ii+1 ] = res.getString( ids[ii] );

View file

@ -1123,9 +1123,12 @@ public class GameConfigDelegate extends DelegateBase
private int positionToSize( int position ) {
switch( position ) {
case 0: return 15;
case 1: return 13;
case 2: return 11;
case 0: return 21;
case 1: return 19;
case 2: return 17;
case 3: return 15;
case 4: return 13;
case 5: return 11;
default:
Assert.failDbg();
}
@ -1137,15 +1140,24 @@ public class GameConfigDelegate extends DelegateBase
int size = m_gi.boardSize;
int selection = 0;
switch( size ) {
case 15:
case 21:
selection = 0;
break;
case 13:
case 19:
selection = 1;
break;
case 11:
case 17:
selection = 2;
break;
case 15:
selection = 3;
break;
case 13:
selection = 4;
break;
case 11:
selection = 5;
break;
default:
Assert.failDbg();
break;

View file

@ -79,7 +79,7 @@ public class CommonPrefs extends XWPrefs {
private CommonPrefs()
{
playerColors = new int[4];
bonusColors = new int[5];
bonusColors = new int[7];
bonusColors[0] = 0xF0F0F0F0; // garbage
otherColors = new int[COLOR_LAST];
}

View file

@ -26,8 +26,10 @@
<string name="key_player3">key_clr_player3</string>
<string name="key_bonus_l2x">key_clr_bonus_l2x</string>
<string name="key_bonus_l3x">key_clr_bonus_l3x</string>
<string name="key_bonus_l4x">key_clr_bonus_l4x</string>
<string name="key_bonus_w2x">key_clr_bonus_w2x</string>
<string name="key_bonus_w3x">key_clr_bonus_w3x</string>
<string name="key_bonus_w4x">key_clr_bonus_w4x</string>
<string name="key_tile_back">key_clr_tile_back</string>
<string name="key_empty">key_clr_empty</string>
<string name="key_background">key_clr_background</string>
@ -42,8 +44,10 @@
<string name="key_player3_dark">key_clr_player3_dark</string>
<string name="key_bonus_l2x_dark">key_clr_bonus_l2x_dark</string>
<string name="key_bonus_l3x_dark">key_clr_bonus_l3x_dark</string>
<string name="key_bonus_l4x_dark">key_clr_bonus_l4x_dark</string>
<string name="key_bonus_w2x_dark">key_clr_bonus_w2x_dark</string>
<string name="key_bonus_w3x_dark">key_clr_bonus_w3x_dark</string>
<string name="key_bonus_w4x_dark">key_clr_bonus_w4x_dark</string>
<string name="key_tile_back_dark">key_clr_tile_back_dark</string>
<string name="key_empty_dark">key_clr_empty_dark</string>
<string name="key_background_dark">key_clr_background_dark</string>
@ -198,6 +202,9 @@
<string name="faq_uri_fmt">https://eehouse.org/xw4/faq.html#%1$s</string>
<string-array name="board_sizes">
<item>21x21</item>
<item>19x19</item>
<item>17x17</item>
<item>15x15</item>
<item>13x13</item>
<item>11x11</item>
@ -389,6 +396,8 @@
<item>@string/key_bonus_w2x</item>
<item>@string/key_bonus_l3x</item>
<item>@string/key_bonus_w3x</item>
<item>@string/key_bonus_l4x</item>
<item>@string/key_bonus_w4x</item>
<item>@string/key_tile_back</item>
<item>@string/key_empty</item>
@ -408,6 +417,8 @@
<item>@string/key_bonus_w2x_dark</item>
<item>@string/key_bonus_l3x_dark</item>
<item>@string/key_bonus_w3x_dark</item>
<item>@string/key_bonus_l4x_dark</item>
<item>@string/key_bonus_w4x_dark</item>
<item>@string/key_tile_back_dark</item>
<item>@string/key_empty_dark</item>

View file

@ -445,6 +445,12 @@
<!-- Bonus value hint that's displayed in gray text in the colored
bonus square. Triple-word -->
<string name="bonus_w3x_summary">3W</string>
<!-- Bonus value hint that's displayed in gray text in the colored
bonus square. Quadruple-letter -->
<string name="bonus_l4x_summary">4L</string>
<!-- Bonus value hint that's displayed in gray text in the colored
bonus square. Quadruple-word -->
<string name="bonus_w4x_summary">4W</string>
<!-- displayed when you long-tap a scoreboard entry and there's no
most recent score to show -->
<string name="no_moves_made">(No moves yet)</string>
@ -863,10 +869,12 @@
<string name="bonus_l2x">Double letter</string>
<!-- (color for) triple-letter bonus squares on the board -->
<string name="bonus_l3x">Triple letter</string>
<string name="bonus_l4x">Quadruple letter</string>
<!-- (color for) double-word squares on the board -->
<string name="bonus_w2x">Double word</string>
<!-- (color for) triple-word squares on the board -->
<string name="bonus_w3x">Triple word</string>
<string name="bonus_w4x">Quadruple word</string>
<!-- color of the "crosshairs", lines drawn vertically and
horizontally through the square the user is currently
touching in order to guide the fat-fingered (most of us) in

View file

@ -36,6 +36,11 @@
android:title="@string/bonus_l3x"
android:defaultValue="0x003F3F"
/>
<org.eehouse.android.xw4.EditColorPreference
android:key="@string/key_bonus_l4x_dark"
android:title="@string/bonus_l4x"
android:defaultValue="0x003F3F"
/>
<org.eehouse.android.xw4.EditColorPreference
android:key="@string/key_bonus_w2x_dark"
android:title="@string/bonus_w2x"
@ -46,6 +51,11 @@
android:title="@string/bonus_w3x"
android:defaultValue="0x3F3F3F"
/>
<org.eehouse.android.xw4.EditColorPreference
android:key="@string/key_bonus_w4x_dark"
android:title="@string/bonus_w4x"
android:defaultValue="0x3F3F3F"
/>
<org.eehouse.android.xw4.EditColorPreference
android:key="@string/key_clr_bonushint_dark"

View file

@ -1,6 +1,6 @@
/* -*- compile-command: "find-and-gradle.sh inXw4dDeb"; -*- */
/*
* Copyright 2001 - 2020 by Eric House (xwords@eehouse.org). All rights
* Copyright 2001 - 2022 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program is free software; you can redistribute it and/or
@ -99,34 +99,6 @@ and_util_makeStreamFromAddr( XW_UtilCtxt* uc, XWEnv XP_UNUSED(xwe),
jmethodID mid = getMethodID( env, dutil->jdutil, nam, sig )
#define DUTIL_CBK_TAIL() UTIL_CBK_TAIL()
static XWBonusType and_util_getSquareBonus( XW_UtilCtxt* XP_UNUSED(uc),
XWEnv XP_UNUSED(xwe),
XP_U16 boardSize,
XP_U16 col, XP_U16 row )
{
#define BONUS_DIM 8
static const int s_buttsBoard[BONUS_DIM][BONUS_DIM] = {
{ BONUS_TRIPLE_WORD, BONUS_NONE, BONUS_NONE,BONUS_DOUBLE_LETTER,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_TRIPLE_WORD },
{ BONUS_NONE, BONUS_DOUBLE_WORD, BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_TRIPLE_LETTER,BONUS_NONE,BONUS_NONE },
{ BONUS_NONE, BONUS_NONE, BONUS_DOUBLE_WORD,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_DOUBLE_LETTER,BONUS_NONE },
{ BONUS_DOUBLE_LETTER,BONUS_NONE, BONUS_NONE,BONUS_DOUBLE_WORD,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_DOUBLE_LETTER },
{ BONUS_NONE, BONUS_NONE, BONUS_NONE,BONUS_NONE,BONUS_DOUBLE_WORD,BONUS_NONE,BONUS_NONE,BONUS_NONE },
{ BONUS_NONE, BONUS_TRIPLE_LETTER,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_TRIPLE_LETTER,BONUS_NONE,BONUS_NONE },
{ BONUS_NONE, BONUS_NONE, BONUS_DOUBLE_LETTER,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_DOUBLE_LETTER,BONUS_NONE },
{ BONUS_TRIPLE_WORD, BONUS_NONE, BONUS_NONE,BONUS_DOUBLE_LETTER,BONUS_NONE,BONUS_NONE,BONUS_NONE,BONUS_DOUBLE_WORD },
}; /* buttsBoard */
int half = boardSize / 2;
if ( col > half ) { col = (half*2) - col; }
if ( row > half ) { row = (half*2) - row; }
XP_ASSERT( col < BONUS_DIM && row < BONUS_DIM );
return s_buttsBoard[row][col];
#undef BONUS_DIM
}
static void
and_util_userError( XW_UtilCtxt* uc, XWEnv xwe, UtilErrID id )
@ -998,7 +970,6 @@ makeUtil( MPFORMAL JNIEnv* env,
#ifndef XWFEATURE_STANDALONE_ONLY
SET_PROC(makeStreamFromAddr);
#endif
SET_PROC(getSquareBonus);
SET_PROC(userError);
SET_PROC(notifyMove);
SET_PROC(notifyTrade);

View file

@ -1371,7 +1371,7 @@ timerFiredForPen( BoardCtxt* board, XWEnv xwe )
#endif
if ( !listWords ) {
XWBonusType bonus;
bonus = model_getSquareBonus( board->model, xwe, col, row );
bonus = model_getSquareBonus( board->model, col, row );
if ( bonus != BONUS_NONE ) {
#ifdef XWFEATURE_MINIWIN
text = draw_getMiniWText( board->draw,

View file

@ -339,7 +339,7 @@ drawBoard( BoardCtxt* board, XWEnv xwe )
XWBonusType bonus;
HintAtts hintAtts;
CellFlags flags = CELL_NONE;
bonus = model_getSquareBonus( model, xwe, col, row );
bonus = model_getSquareBonus( model, col, row );
hintAtts = figureHintAtts( board, col, row );
#ifdef KEYBOARD_NAV
if ( cellFocused( board, col, row ) ) {
@ -438,7 +438,7 @@ drawCell( BoardCtxt* board, XWEnv xwe, const XP_U16 col,
}
textP = dict_getTileString( dict, tile );
}
bonus = model_getSquareBonus( model, xwe, col, row );
bonus = model_getSquareBonus( model, col, row );
hintAtts = figureHintAtts( board, col, row );
if ( (col==board->star_row) && (row==board->star_row) ) {

View file

@ -375,31 +375,65 @@ model_popToHash( ModelCtxt* model, XWEnv xwe, const XP_U32 hash, PoolContext* po
#ifdef STREAM_VERS_BIGBOARD
void
model_setSquareBonuses( ModelCtxt* model, XWBonusType* bonuses, XP_U16 nBonuses )
model_setSquareBonuses( ModelCtxt* XP_UNUSED(model), XWBonusType* XP_UNUSED(bonuses),
XP_U16 XP_UNUSED(nBonuses) )
{
#ifdef DEBUG
XP_U16 nCols = (1 + model_numCols( model )) / 2;
XP_ASSERT( 0 < nCols );
XP_U16 wantLen = 0;
while ( nCols > 0 ) {
wantLen += nCols--;
}
XP_ASSERT( wantLen == nBonuses );
#endif
if ( !!model->vol.bonuses ) {
XP_FREE( model->vol.mpool, model->vol.bonuses );
}
model->vol.bonuses = XP_MALLOC( model->vol.mpool,
nBonuses * sizeof(model->vol.bonuses[0]) );
XP_MEMCPY( model->vol.bonuses, bonuses,
nBonuses * sizeof(model->vol.bonuses[0]) );
model->vol.nBonuses = nBonuses;
XP_LOGFF( "doing nothing" );
}
#endif
#define EM BONUS_NONE
#define DL BONUS_DOUBLE_LETTER
#define DW BONUS_DOUBLE_WORD
#define TL BONUS_TRIPLE_LETTER
#define TW BONUS_TRIPLE_WORD
#define QL BONUS_QUAD_LETTER
#define QW BONUS_QUAD_WORD
static XWBonusType sTwentyOne[] = {
QW,
EM, DW,
EM, EM, DW,
DL, EM, EM, TW,
EM, TL, EM, EM, DW,
EM, EM, QL, EM, EM, DW,
EM, EM, EM, DL, EM, EM, DW,
TW, EM, EM, EM, EM, EM, EM, DW,
EM, DW, EM, EM, TL, EM, EM, EM, TL,
EM, EM, DW, EM, EM, DL, EM, EM, EM, DL,
DL, EM, EM, TW, EM, EM, DL, EM, EM, EM, DW,
}; /* sTwentyOne */
static XWBonusType
getSquareBonus( XP_U16 nCols, XP_U16 col, XP_U16 row )
{
XWBonusType result = BONUS_NONE;
if ( col > (nCols/2) ) {
col = nCols - 1 - col;
}
if ( row > (nCols/2) ) {
row = nCols - 1 - row;
}
if ( col > row ) {
XP_U16 tmp = col;
col = row;
row = tmp;
}
XP_U16 index = col;
for ( XP_U16 ii = 1; ii <= row; ++ii ) {
index += ii;
}
if ( index < VSIZE(sTwentyOne)) {
result = sTwentyOne[index];
}
return result;
}
XWBonusType
model_getSquareBonus( const ModelCtxt* model, XWEnv xwe, XP_U16 col, XP_U16 row )
model_getSquareBonus( const ModelCtxt* model, XP_U16 col, XP_U16 row )
{
XWBonusType result = BONUS_NONE;
#ifdef STREAM_VERS_BIGBOARD
@ -431,9 +465,7 @@ model_getSquareBonus( const ModelCtxt* model, XWEnv xwe, XP_U16 col, XP_U16 row
}
#endif
} else {
result = util_getSquareBonus( model->vol.util, xwe,
model_numRows(model),
col, row );
result = getSquareBonus( model_numRows(model), col, row );
}
return result;
}

View file

@ -288,7 +288,7 @@ XP_Bool model_listWordsThrough( ModelCtxt* model, XWEnv xwe, XP_U16 col,
XP_Bool model_recentPassCountOk( ModelCtxt* model );
XWBonusType model_getSquareBonus( const ModelCtxt* model,
XWEnv xwe, XP_U16 col, XP_U16 row );
XP_U16 col, XP_U16 row );
#ifdef STREAM_VERS_BIGBOARD
void model_setSquareBonuses( ModelCtxt* model, XWBonusType* bonuses,
XP_U16 nBonuses );

View file

@ -34,8 +34,7 @@ extern "C" {
/****************************** prototypes ******************************/
static XP_Bool isLegalMove( ModelCtxt* model, XWEnv xwe, MoveInfo* moves,
XP_Bool silent );
static XP_U16 word_multiplier( const ModelCtxt* model, XWEnv xwe,
XP_U16 col, XP_U16 row );
static XP_U16 word_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row );
static XP_U16 find_end( const ModelCtxt* model, XP_U16 col, XP_U16 row,
XP_Bool isHorizontal );
static XP_U16 find_start( const ModelCtxt* model, XP_U16 col, XP_U16 row,
@ -43,7 +42,7 @@ static XP_U16 find_start( const ModelCtxt* model, XP_U16 col, XP_U16 row,
static XP_S16 checkScoreMove( ModelCtxt* model, XWEnv xwe, XP_S16 turn,
EngineCtxt* engine, XWStreamCtxt* stream,
XP_Bool silent, WordNotifierInfo* notifyInfo );
static XP_U16 scoreWord( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
static XP_U16 scoreWord( const ModelCtxt* model, XP_U16 turn,
const MoveInfo* movei, EngineCtxt* engine,
XWStreamCtxt* stream, WordNotifierInfo* notifyInfo );
@ -555,10 +554,10 @@ figureMoveScore( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
for ( ii = 0; ii < nTiles; ++ii ) {
*incr = moveInfo->tiles[ii].varCoord;
moveMultiplier *= multipliers[ii] =
word_multiplier( model, xwe, col, row );
word_multiplier( model, col, row );
}
oneScore = scoreWord( model, xwe, turn, moveInfo, (EngineCtxt*)NULL,
oneScore = scoreWord( model, turn, moveInfo, (EngineCtxt*)NULL,
stream, notifyInfo );
if ( !!stream ) {
formatWordScore( stream, oneScore, moveMultiplier );
@ -576,7 +575,7 @@ figureMoveScore( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
tmpMI.commonCoord = tiles->varCoord;
tmpMI.tiles[0].tile = tiles->tile;
oneScore = scoreWord( model, xwe, turn, &tmpMI, engine, stream, notifyInfo );
oneScore = scoreWord( model, turn, &tmpMI, engine, stream, notifyInfo );
if ( !!stream ) {
formatWordScore( stream, oneScore, multipliers[ii] );
}
@ -612,9 +611,9 @@ figureMoveScore( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
} /* figureMoveScore */
static XP_U16
word_multiplier( const ModelCtxt* model, XWEnv xwe, XP_U16 col, XP_U16 row )
word_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row )
{
XWBonusType bonus = model_getSquareBonus( model, xwe, col, row );
XWBonusType bonus = model_getSquareBonus( model, col, row );
switch ( bonus ) {
case BONUS_DOUBLE_WORD:
return 2;
@ -628,9 +627,9 @@ word_multiplier( const ModelCtxt* model, XWEnv xwe, XP_U16 col, XP_U16 row )
} /* word_multiplier */
static XP_U16
tile_multiplier( const ModelCtxt* model, XWEnv xwe, XP_U16 col, XP_U16 row )
tile_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row )
{
XWBonusType bonus = model_getSquareBonus( model, xwe, col, row );
XWBonusType bonus = model_getSquareBonus( model, col, row );
switch ( bonus ) {
case BONUS_DOUBLE_LETTER:
return 2;
@ -644,7 +643,7 @@ tile_multiplier( const ModelCtxt* model, XWEnv xwe, XP_U16 col, XP_U16 row )
} /* tile_multiplier */
static XP_U16
scoreWord( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
scoreWord( const ModelCtxt* model, XP_U16 turn,
const MoveInfo* movei, /* new tiles */
EngineCtxt* engine,/* for crosswise caching */
XWStreamCtxt* stream,
@ -693,7 +692,7 @@ scoreWord( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
thisTileValue = dict_getTileValue( dict, tile );
XP_ASSERT( *incr == tiles[0].varCoord );
thisTileValue *= tile_multiplier( model, xwe, col, row );
thisTileValue *= tile_multiplier( model, col, row );
XP_ASSERT( engine == NULL || nTiles == 1 );
@ -729,7 +728,7 @@ scoreWord( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
* mode, as the blank won't be known there. (Assert will
* fail.) */
tileMultiplier = tile_multiplier( model, xwe, col, row );
tileMultiplier = tile_multiplier( model, col, row );
++tiles;
--nTiles;
} else { /* placed on the board before this move */

View file

@ -89,9 +89,6 @@ typedef struct UtilVtable {
XWStreamCtxt* (*m_util_makeStreamFromAddr)(XW_UtilCtxt* uc, XWEnv xwe,
XP_PlayerAddr channelNo );
#endif
XWBonusType (*m_util_getSquareBonus)( XW_UtilCtxt* uc, XWEnv xwe, XP_U16 boardSize,
XP_U16 col, XP_U16 row );
void (*m_util_userError)( XW_UtilCtxt* uc, XWEnv xwe, UtilErrID id );
void (*m_util_notifyMove)( XW_UtilCtxt* uc, XWEnv xwe, XWStreamCtxt* stream );
@ -221,9 +218,6 @@ struct XW_UtilCtxt {
#define util_makeStreamFromAddr(uc,e,a) \
(uc)->vtable->m_util_makeStreamFromAddr((uc), (e),(a))
#define util_getSquareBonus(uc,e,b,c,r) \
(uc)->vtable->m_util_getSquareBonus((uc), (e),(b),(c),(r))
#define util_userError(uc,e,err) \
(uc)->vtable->m_util_userError((uc),(e),(err))

View file

@ -195,110 +195,6 @@ setSquareBonuses( const CommonGlobals* cGlobals )
}
#endif
static XWBonusType*
parseBonusFile( XP_U16 nCols, const char* bonusFile )
{
XWBonusType* result = NULL;
FILE* file = fopen( bonusFile, "r" );
if ( !!file ) {
XP_U16 row = 0;
XP_U16 col;
result = malloc( nCols * nCols * sizeof(*result) );
char line[1024];
while ( line == fgets( line, sizeof(line), file ) && row < nCols ) {
bool inComment = false;
char* ch;
XWBonusType bonus;
col = 0;
for ( ch = line; '\0' != *ch; ++ch ) {
switch( *ch ) {
case '#': /* comment; line is done */
inComment = true;
break;
case '+':
bonus = BONUS_DOUBLE_LETTER;
break;
case '*':
bonus = BONUS_DOUBLE_WORD;
break;
case '^':
bonus = BONUS_TRIPLE_LETTER;
break;
case '!':
bonus = BONUS_TRIPLE_WORD;
break;
case '.':
case ' ':
bonus = BONUS_NONE;
break;
case '\n':
case '\a':
break;
default:
if ( !inComment ) {
fprintf( stderr, "unexpected char '%c' in %s\n", *ch, bonusFile );
exit( 1 );
}
break;
}
if ( !inComment && col < nCols ) {
result[(row * nCols) + col] = bonus;
++col;
/* Let's just allow anything to follow the 15 letters we
care about, e.g. comments */
if ( col >= nCols ) {
inComment = true;
}
}
}
if ( col > 0 && row < nCols - 1) {
++row;
}
}
fclose( file );
}
return result;
}
static XWBonusType
linux_util_getSquareBonus( XW_UtilCtxt* uc, XWEnv XP_UNUSED(xwe), XP_U16 nCols,
XP_U16 col, XP_U16 row )
{
static XWBonusType* parsedFile = NULL;
XWBonusType result = EM;
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
if ( NULL == parsedFile && NULL != cGlobals->params->bonusFile ) {
if ( !parsedFile ) {
parsedFile = parseBonusFile( nCols, cGlobals->params->bonusFile );
}
}
if ( NULL != parsedFile ) {
result = parsedFile[(row*nCols) + col];
} else {
XP_U16 nEntries;
XWBonusType* scrabbleBoard = bonusesFor( 15, &nEntries );
XP_U16 index, ii;
if ( col > (nCols/2) ) col = nCols - 1 - col;
if ( row > (nCols/2) ) row = nCols - 1 - row;
if ( col > row ) {
XP_U16 tmp = col;
col = row;
row = tmp;
}
index = col;
for ( ii = 1; ii <= row; ++ii ) {
index += ii;
}
if ( index < nEntries) {
result = scrabbleBoard[index];
}
}
return result;
} /* linux_util_getSquareBonus */
static const DictionaryCtxt*
linux_util_getDict( XW_UtilCtxt* uc, XWEnv xwe,
XP_LangCode XP_UNUSED(lang), const XP_UCHAR* dictName )
@ -338,7 +234,6 @@ linux_util_vt_init( MPFORMAL XW_UtilCtxt* util )
util->vtable = XP_MALLOC( mpool, sizeof(UtilVtable) );
util->vtable->m_util_makeEmptyDict = linux_util_makeEmptyDict;
util->vtable->m_util_getSquareBonus = linux_util_getSquareBonus;
util->vtable->m_util_getDict = linux_util_getDict;
util->vtable->m_util_getInviteeName = linux_util_getInviteeName;