mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-18 22:26:30 +01:00
add more info to game "buttons"
Toward a games-list substitute. New game_summarize method will get fleshed out and eventually replace what's in jni?
This commit is contained in:
parent
8c920d6537
commit
f3b76da8e1
5 changed files with 124 additions and 35 deletions
|
@ -545,6 +545,30 @@ game_getState( const XWGame* game, XWEnv xwe, GameStateInfo* gsi )
|
|||
gsi->canUnpause = server_canUnpause( server );
|
||||
}
|
||||
|
||||
void
|
||||
game_summarize( XWGame* game, CurGameInfo* gi, GameSummary* summary )
|
||||
{
|
||||
XP_MEMSET( summary, 0, sizeof(*summary) );
|
||||
ServerCtxt* server = game->server;
|
||||
summary->turn = server_getCurrentTurn( server, &summary->turnIsLocal );
|
||||
summary->lastMoveTime = server_getLastMoveTime(server);
|
||||
summary->lang = gi->dictLang;
|
||||
for ( int ii = 0; ii < gi->nPlayers; ++ii ) {
|
||||
LocalPlayer* lp = &gi->players[ii];
|
||||
if ( LP_IS_ROBOT(lp) || !LP_IS_LOCAL(lp) ) {
|
||||
if ( '\0' != summary->opponents[0] ) {
|
||||
XP_STRCAT( summary->opponents, ", " );
|
||||
}
|
||||
XP_STRCAT( summary->opponents, lp->name );
|
||||
}
|
||||
}
|
||||
if ( !!game->comms ) {
|
||||
CommsCtxt* comms = game->comms;
|
||||
summary->missingPlayers = server_getMissingPlayers( server );
|
||||
summary->nPacketsPending = comms_countPendingPackets( comms );
|
||||
}
|
||||
}
|
||||
|
||||
XP_Bool
|
||||
game_getIsServer( const XWGame* game )
|
||||
{
|
||||
|
|
|
@ -51,6 +51,17 @@ typedef struct _GameStateInfo {
|
|||
XP_Bool canUnpause; /* duplicate-mode only */
|
||||
} GameStateInfo;
|
||||
|
||||
typedef struct _GameSummary {
|
||||
XP_Bool turnIsLocal;
|
||||
XP_Bool inPlay;
|
||||
XP_S8 turn;
|
||||
XP_U32 lastMoveTime;
|
||||
XP_U8 missingPlayers;
|
||||
XP_U8 nPacketsPending;
|
||||
XP_LangCode lang;
|
||||
XP_UCHAR opponents[64];
|
||||
} GameSummary;
|
||||
|
||||
typedef struct _XWGame {
|
||||
XW_UtilCtxt* util;
|
||||
BoardCtxt* board;
|
||||
|
@ -97,6 +108,7 @@ XP_Bool game_receiveMessage( XWGame* game, XWEnv xwe, XWStreamCtxt* stream,
|
|||
|
||||
void game_dispose( XWGame* game, XWEnv xwe );
|
||||
|
||||
void game_summarize( XWGame* game, CurGameInfo* gi, GameSummary* summary );
|
||||
void game_getState( const XWGame* game, XWEnv xwe, GameStateInfo* gsi );
|
||||
XP_Bool game_getIsServer( const XWGame* game );
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
#define KEY_LAST_GID "cur_game"
|
||||
#define KEY_PLAYER_NAME "player_name"
|
||||
#define KEY_GAMES "games"
|
||||
#define KEY_SUMMARY "summary"
|
||||
#define KEY_GAME "game_data"
|
||||
#define KEY_NAME "game_name"
|
||||
#define KEY_NEXT_GAME "next_game"
|
||||
|
@ -84,7 +85,7 @@
|
|||
#define BUTTON_INVITE "Invite"
|
||||
|
||||
#define BUTTON_GAME_NEW "New Game"
|
||||
#define BUTTON_GAME_OPEN "Open Game"
|
||||
#define BUTTON_GAME_OPEN "Games"
|
||||
#define BUTTON_GAME_RENAME "Rename Game"
|
||||
#define BUTTON_GAME_DELETE "Delete Game"
|
||||
#define BUTTON_NAME "My Name"
|
||||
|
@ -144,8 +145,10 @@ EM_JS(void, show_name, (const char* name), {
|
|||
});
|
||||
|
||||
EM_JS(void, show_pool, (int cur, int max), {
|
||||
let msg = 'cur: ' + cur + 'b; max: ' + max + 'b';
|
||||
document.getElementById('mempool').textContent = msg;
|
||||
const msg = 'cur: ' + cur + 'b; max: ' + max + 'b';
|
||||
const div = document.getElementById('mempool');
|
||||
div.textContent = msg;
|
||||
div.parentNode.hidden = 0;
|
||||
});
|
||||
|
||||
EM_JS(void, call_dialog, (const char* str, const char** but_strs,
|
||||
|
@ -497,6 +500,16 @@ updateGameButtons( Globals* globals )
|
|||
setButtons( BUTTONS_ID_GAME, buttons, onGameButton, gs );
|
||||
}
|
||||
|
||||
static bool
|
||||
langNameFor( Globals* globals, XP_LangCode code, char buf[], size_t buflen )
|
||||
{
|
||||
const char* lc = lcToLocale( code );
|
||||
const XP_UCHAR* keys[] = { KEY_DICTS, lc, KEY_LANG_NAME, NULL };
|
||||
XP_U32 len = buflen;
|
||||
dutil_loadPtr( globals->dutil, NULL, keys, buf, &len );
|
||||
return 0 < len;
|
||||
}
|
||||
|
||||
static void
|
||||
showName( GameState* gs )
|
||||
{
|
||||
|
@ -507,14 +520,10 @@ showName( GameState* gs )
|
|||
char buf[64];
|
||||
if ( true || 1 < countDicts( globals ) ) {
|
||||
char langName[32];
|
||||
const char* lc = lcToLocale(gs->gi.dictLang);
|
||||
const XP_UCHAR* keys[] = {KEY_DICTS, lc, KEY_LANG_NAME, NULL };
|
||||
XP_U32 len = sizeof(langName);
|
||||
dutil_loadPtr( globals->dutil, NULL, keys, langName, &len );
|
||||
if ( 0 != len ) {
|
||||
lc = langName;
|
||||
if ( !langNameFor( globals, gs->gi.dictLang, langName, sizeof(langName) ) ) {
|
||||
strcpy( langName, "??" );
|
||||
}
|
||||
sprintf( buf, "%s (%s)", title, lc );
|
||||
sprintf( buf, "%s (%s)", title, langName );
|
||||
title = buf;
|
||||
}
|
||||
}
|
||||
|
@ -541,8 +550,7 @@ typedef struct _NameIterState {
|
|||
static void
|
||||
onGameChosen( void* closure, const char* key )
|
||||
{
|
||||
NameIterState* nis = (NameIterState*)closure;
|
||||
Globals* globals = nis->globals;
|
||||
CAST_GLOB(Globals*, globals, closure);
|
||||
|
||||
/* To be safe, let's make sure the game exists. We don't want to create
|
||||
* another if somehow it doesn't */
|
||||
|
@ -552,13 +560,41 @@ onGameChosen( void* closure, const char* key )
|
|||
loadAndDraw( globals, NULL, gameID, NULL );
|
||||
}
|
||||
|
||||
XP_FREE( globals->mpool, nis->names );
|
||||
XP_FREE( globals->mpool, nis->ids );
|
||||
XP_FREE( globals->mpool, nis );
|
||||
|
||||
updateDeviceButtons( globals );
|
||||
}
|
||||
|
||||
static char*
|
||||
formatForGame(Globals* globals, bool multiLangs, const XP_UCHAR* gameKey )
|
||||
{
|
||||
const XP_UCHAR* keys[] = {KEY_GAMES, gameKey, KEY_NAME, NULL};
|
||||
char gameName[32];
|
||||
XP_U32 len = sizeof(gameName);
|
||||
dutil_loadPtr( globals->dutil, NULL, keys, gameName, &len );
|
||||
|
||||
char buf[256];
|
||||
int offset = snprintf( buf, sizeof(buf), "%s", gameName );
|
||||
|
||||
GameSummary summary;
|
||||
len = sizeof(summary);
|
||||
keys[2] = KEY_SUMMARY;
|
||||
dutil_loadPtr( globals->dutil, NULL, keys, &summary, &len );
|
||||
if ( len == sizeof(summary) ) {
|
||||
if ( multiLangs ) {
|
||||
char langName[32];
|
||||
if ( langNameFor( globals, summary.lang, langName, sizeof(langName) ) ) {
|
||||
offset += snprintf( buf+offset, sizeof(buf)-offset, " (in %s)", langName );
|
||||
}
|
||||
}
|
||||
offset += snprintf( buf+offset, sizeof(buf)-offset, " My turn: %s",
|
||||
summary.turnIsLocal ? "YES" : "NO" );
|
||||
offset += snprintf( buf+offset, sizeof(buf)-offset, " Opponent: %s",
|
||||
summary.opponents );
|
||||
}
|
||||
char* result = NULL;
|
||||
replaceStringIfDifferent( globals->mpool, &result, buf );
|
||||
return result;
|
||||
}
|
||||
|
||||
static XP_Bool
|
||||
onOneGameName( void* closure, const XP_UCHAR* keys[] )
|
||||
{
|
||||
|
@ -566,6 +602,7 @@ onOneGameName( void* closure, const XP_UCHAR* keys[] )
|
|||
if ( 0 != strcmp( gameIDStr, "0" ) ) { /* temporary */
|
||||
NameIterState* nis = (NameIterState*)closure;
|
||||
Globals* globals = nis->globals;
|
||||
bool multiLangs = 1 < countDicts(globals);
|
||||
|
||||
/* Make sure game exists. This may be unnecessary later */
|
||||
const XP_UCHAR* dataKeys[] = { keys[0], keys[1], KEY_GAME, NULL };
|
||||
|
@ -575,12 +612,7 @@ onOneGameName( void* closure, const XP_UCHAR* keys[] )
|
|||
int cur = nis->count++;
|
||||
nis->names = XP_REALLOC( globals->mpool, nis->names,
|
||||
nis->count * sizeof(nis->names[0]) );
|
||||
|
||||
XP_U32 valLen;
|
||||
dutil_loadPtr( globals->dutil, NULL, keys, NULL, &valLen );
|
||||
nis->names[cur] = XP_MALLOC( globals->mpool, valLen );
|
||||
dutil_loadPtr( globals->dutil, NULL, keys, nis->names[cur], &valLen );
|
||||
|
||||
nis->names[cur] = formatForGame( globals, multiLangs, keys[1] );
|
||||
nis->ids = XP_REALLOC( globals->mpool, nis->ids,
|
||||
nis->count * sizeof(nis->ids[0]) );
|
||||
nis->ids[cur] = XP_MALLOC( globals->mpool, 1 + strlen(gameIDStr) );
|
||||
|
@ -594,14 +626,16 @@ static void
|
|||
pickGame( Globals* globals )
|
||||
{
|
||||
XW_DUtilCtxt* dutil = globals->dutil;
|
||||
NameIterState* nis = XP_CALLOC( globals->mpool, sizeof(*nis) );
|
||||
nis->globals = globals;
|
||||
NameIterState nis = { .globals = globals, };
|
||||
|
||||
const XP_UCHAR* keys[] = {KEY_GAMES, KEY_WILDCARD, KEY_NAME, NULL};
|
||||
dutil_forEach( dutil, NULL, keys, onOneGameName, nis );
|
||||
dutil_forEach( dutil, NULL, keys, onOneGameName, &nis );
|
||||
|
||||
const char* msg = "Choose game to open:";
|
||||
call_pickGame(msg, nis->ids, nis->names, nis->count, onGameChosen, nis);
|
||||
call_pickGame(msg, nis.ids, nis.names, nis.count, onGameChosen, globals);
|
||||
|
||||
XP_FREE( globals->mpool, nis.names );
|
||||
XP_FREE( globals->mpool, nis.ids );
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1066,6 +1100,7 @@ getSavedGame( Globals* globals, int gameID )
|
|||
{
|
||||
GameState* gs;
|
||||
|
||||
/* Is it already open? */
|
||||
for ( gs = globals->games; !!gs; gs = gs->next ) {
|
||||
if ( gameID == gs->gi.gameID ) {
|
||||
break;
|
||||
|
@ -1100,6 +1135,7 @@ getSavedGame( Globals* globals, int gameID )
|
|||
updateScreen( gs, false );
|
||||
} else {
|
||||
removeGameState( gs );
|
||||
gs = NULL;
|
||||
}
|
||||
} else {
|
||||
XP_LOGFF( "ERROR: no saved data for game %s", gameIDStr );
|
||||
|
@ -1672,12 +1708,18 @@ updateScreen( GameState* gs, bool doSave )
|
|||
game_saveToStream( &gs->game, NULL, &gs->gi,
|
||||
stream, ++gs->saveToken );
|
||||
|
||||
GameSummary summary;
|
||||
game_summarize( &gs->game, &gs->gi, &summary );
|
||||
|
||||
char gameIDStr[32];
|
||||
formatGameID( gameIDStr, sizeof(gameIDStr), gs->gi.gameID );
|
||||
const XP_UCHAR* keys[] = { KEY_GAMES, gameIDStr, KEY_GAME, NULL };
|
||||
dutil_storeStream( globals->dutil, NULL, keys, stream );
|
||||
stream_destroy( stream, NULL );
|
||||
game_saveSucceeded( &gs->game, NULL, gs->saveToken );
|
||||
|
||||
keys[2] = KEY_SUMMARY;
|
||||
dutil_storePtr( globals->dutil, NULL, keys, &summary, sizeof(summary) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@
|
|||
<table class='centered'>
|
||||
<tr><td>MQTT Dev ID:</td><td id="mqtt_span"></td></tr>
|
||||
<tr><td>MQTT Status:</td><td id="mqtt_status">Unconnected</td></tr>
|
||||
<tr><td>MemPool used:</td><td id="mempool">0</td></tr>
|
||||
<tr hidden=1><td>MemPool used:</td><td id="mempool">0</td></tr>
|
||||
</table>
|
||||
<hr/>
|
||||
<!-- Remove until I figure out how this works
|
||||
|
|
|
@ -218,7 +218,7 @@ function newDlgWMsg(msg) {
|
|||
return dlg;
|
||||
}
|
||||
|
||||
function newButtonDiv(buttons, proc) {
|
||||
function newButtonDiv(buttons, proc, asDivs) {
|
||||
let div = document.createElement('div');
|
||||
div.classList.add('buttonRow');
|
||||
for ( let ii = 0; ii < buttons.length; ++ii ) {
|
||||
|
@ -226,7 +226,12 @@ function newButtonDiv(buttons, proc) {
|
|||
let button = document.createElement('button');
|
||||
button.textContent = buttonTxt;
|
||||
button.onclick = function() { proc(ii); };
|
||||
div.appendChild( button );
|
||||
if ( asDivs ) {
|
||||
let bdiv = document.createElement('div');
|
||||
bdiv.appendChild(button);
|
||||
button = bdiv;
|
||||
}
|
||||
div.appendChild(button);
|
||||
}
|
||||
|
||||
return div;
|
||||
|
@ -239,7 +244,7 @@ function nbDialog(msg, buttons, proc, closure) {
|
|||
dlg.parentNode.removeChild(dlg);
|
||||
ccallString(proc, closure, buttons[indx]);
|
||||
}
|
||||
dlg.appendChild( newButtonDiv( buttons, butProc ) );
|
||||
dlg.appendChild( newButtonDiv( buttons, butProc, false ) );
|
||||
addDepthNote(dlg);
|
||||
}
|
||||
|
||||
|
@ -251,7 +256,7 @@ function nbBlankPick(title, buttons, proc, closure) {
|
|||
ccallString(proc, closure, indx.toString());
|
||||
}
|
||||
|
||||
dlg.appendChild( newButtonDiv( buttons, butProc ) );
|
||||
dlg.appendChild( newButtonDiv( buttons, butProc, false ) );
|
||||
addDepthNote(dlg);
|
||||
}
|
||||
|
||||
|
@ -281,8 +286,14 @@ function nbGamePick(title, gameMap, proc, closure) {
|
|||
dlg.parentNode.removeChild(dlg);
|
||||
ccallString(proc, closure, pairs[indx].id);
|
||||
}
|
||||
dlg.appendChild( newButtonDiv( buttons, butProc, true ) );
|
||||
|
||||
cancelProc = function() {
|
||||
dlg.parentNode.removeChild(dlg);
|
||||
ccallString(proc, closure, null);
|
||||
};
|
||||
dlg.appendChild( newButtonDiv( ['Cancel'], cancelProc, false ) );
|
||||
|
||||
dlg.appendChild( newButtonDiv( buttons, butProc ) );
|
||||
addDepthNote(dlg);
|
||||
}
|
||||
|
||||
|
@ -296,7 +307,7 @@ function setDivButtons(divid, buttons, proc, closure) {
|
|||
ccallString(proc, closure, buttons[indx]);
|
||||
}
|
||||
|
||||
parent.appendChild( newButtonDiv( buttons, butProc ) );
|
||||
parent.appendChild( newButtonDiv( buttons, butProc, false ) );
|
||||
}
|
||||
|
||||
function nbGetString(msg, dflt, proc, closure) {
|
||||
|
@ -320,7 +331,7 @@ function nbGetString(msg, dflt, proc, closure) {
|
|||
dismissed(tarea.value);
|
||||
}
|
||||
}
|
||||
dlg.appendChild( newButtonDiv( buttons, butProc ) );
|
||||
dlg.appendChild( newButtonDiv( buttons, butProc, false ) );
|
||||
addDepthNote(dlg);
|
||||
}
|
||||
|
||||
|
@ -383,7 +394,7 @@ function nbGetNewGame(closure, msg, langs) {
|
|||
dlg.parentNode.removeChild(dlg);
|
||||
}
|
||||
|
||||
dlg.appendChild( newButtonDiv( ['Cancel', 'OK'], butProc ) );
|
||||
dlg.appendChild( newButtonDiv( ['Cancel', 'OK'], butProc, false ) );
|
||||
addDepthNote(dlg);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue