2021-02-16 14:59:54 +01:00
|
|
|
/* -*- compile-command: "cd ../wasm && make MEMDEBUG=TRUE install -j3"; -*- */
|
2021-02-06 17:54:08 +01:00
|
|
|
/*
|
|
|
|
* Copyright 2021 by Eric House (xwords@eehouse.org). All rights reserved.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
2021-02-01 17:30:34 +01:00
|
|
|
|
2021-02-02 22:49:27 +01:00
|
|
|
#include <sys/time.h>
|
2021-02-01 17:30:34 +01:00
|
|
|
#include <stdio.h>
|
2021-02-02 05:13:25 +01:00
|
|
|
#include <stdarg.h>
|
2021-02-01 17:30:34 +01:00
|
|
|
#include <SDL2/SDL.h>
|
2021-02-02 18:08:41 +01:00
|
|
|
#include <SDL2/SDL_ttf.h>
|
2021-02-01 17:30:34 +01:00
|
|
|
#include <emscripten.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2021-02-02 05:13:25 +01:00
|
|
|
#include "game.h"
|
2021-02-04 01:19:16 +01:00
|
|
|
#include "device.h"
|
2021-02-02 05:13:25 +01:00
|
|
|
#include "mempool.h"
|
2021-02-07 21:48:06 +01:00
|
|
|
#include "nli.h"
|
|
|
|
#include "strutils.h"
|
2021-02-10 23:16:22 +01:00
|
|
|
#include "movestak.h"
|
2021-02-02 05:13:25 +01:00
|
|
|
|
2021-02-02 21:04:31 +01:00
|
|
|
#include "main.h"
|
2021-02-02 05:13:25 +01:00
|
|
|
#include "wasmdraw.h"
|
|
|
|
#include "wasmutil.h"
|
|
|
|
#include "wasmdutil.h"
|
|
|
|
#include "wasmdict.h"
|
2021-02-17 00:32:33 +01:00
|
|
|
#include "wasmasm.h"
|
2021-02-02 05:13:25 +01:00
|
|
|
|
2021-02-01 17:30:34 +01:00
|
|
|
#ifdef __EMSCRIPTEN__
|
|
|
|
#include <emscripten.h>
|
|
|
|
#endif
|
|
|
|
|
2021-02-02 05:13:25 +01:00
|
|
|
#define WASM_BOARD_LEFT 0
|
|
|
|
#define WASM_HOR_SCORE_TOP 0
|
2021-02-02 21:04:31 +01:00
|
|
|
|
|
|
|
#define WINDOW_WIDTH 400
|
|
|
|
#define WINDOW_HEIGHT 600
|
2021-02-07 02:36:53 +01:00
|
|
|
#define BDWIDTH WINDOW_WIDTH
|
|
|
|
#define BDHEIGHT WINDOW_HEIGHT
|
2021-02-01 17:30:34 +01:00
|
|
|
|
2021-02-19 05:30:24 +01:00
|
|
|
#define KEY_LAST "cur_game"
|
2021-02-17 00:32:33 +01:00
|
|
|
#define KEY_PLAYER_NAME "player_name"
|
2021-02-19 20:19:16 +01:00
|
|
|
#define KEY_GAME_PREFIX "key_data_"
|
|
|
|
#define KEY_NAME_PREFIX "key_name_"
|
|
|
|
|
2021-02-08 01:31:32 +01:00
|
|
|
#define DICTNAME "assets_dir/CollegeEng_2to8.xwd"
|
2021-02-06 17:54:08 +01:00
|
|
|
|
2021-02-19 20:19:16 +01:00
|
|
|
|
2021-02-13 19:37:47 +01:00
|
|
|
#define BUTTON_OK "OK"
|
|
|
|
#define BUTTON_CANCEL "Cancel"
|
|
|
|
|
2021-02-19 04:20:20 +01:00
|
|
|
#define BUTTONS_ID_GAME "game_buttons"
|
|
|
|
#define BUTTONS_ID_DEVICE "device_buttons"
|
|
|
|
|
|
|
|
#define BUTTON_HINTDOWN "Prev Hint"
|
|
|
|
#define BUTTON_HINTUP "Next Hint"
|
|
|
|
#define BUTTON_TRADE "Trade"
|
|
|
|
#define BUTTON_STOPTRADE "Cancel Trade"
|
|
|
|
#define BUTTON_COMMIT "Commit"
|
|
|
|
#define BUTTON_FLIP "Flip"
|
|
|
|
#define BUTTON_UNDO "Undo"
|
|
|
|
#define BUTTON_REDO "Redo"
|
|
|
|
#define BUTTON_VALS "Vals"
|
2021-02-20 02:03:14 +01:00
|
|
|
#define BUTTON_INVITE "Invite"
|
2021-02-19 04:20:20 +01:00
|
|
|
#define BUTTON_EXIT "Quit"
|
|
|
|
|
|
|
|
#define BUTTON_GAME_NEW "New Game"
|
|
|
|
#define BUTTON_GAME_OPEN "Open Game"
|
|
|
|
#define BUTTON_GAME_RENAME "Rename Game"
|
|
|
|
#define BUTTON_GAME_DELETE "Delete Game"
|
2021-02-19 20:19:16 +01:00
|
|
|
#define MAX_BUTTONS 20 /* not sure what's safe here */
|
|
|
|
|
2021-02-19 22:18:53 +01:00
|
|
|
typedef struct _NewGameParams {
|
|
|
|
bool isRobotNotRemote;
|
|
|
|
bool hintsNotAllowed;
|
|
|
|
} NewGameParams;
|
2021-02-19 04:20:20 +01:00
|
|
|
|
2021-02-19 05:30:24 +01:00
|
|
|
static void loadAndDraw( Globals* globals, const NetLaunchInfo* invite,
|
2021-02-19 22:18:53 +01:00
|
|
|
const char* key, NewGameParams* params );
|
2021-02-19 20:19:16 +01:00
|
|
|
static void nameGame( Globals* globals );
|
|
|
|
static void ensureName( Globals* globals );
|
|
|
|
static void loadName( Globals* globals );
|
|
|
|
static void saveName( Globals* globals );
|
2021-02-19 04:20:20 +01:00
|
|
|
|
|
|
|
|
2021-02-13 19:37:47 +01:00
|
|
|
typedef void (*AlertProc)(void* closure, const char* button);
|
|
|
|
|
|
|
|
/* typedef struct _Buttons { */
|
|
|
|
/* int nButtons; */
|
|
|
|
/* const char** buttons; */
|
|
|
|
/* } Buttons; */
|
|
|
|
|
|
|
|
EM_JS(void, call_dialog, (const char* str, const char** but_strs,
|
|
|
|
AlertProc proc, void* closure), {
|
|
|
|
var buttons = [];
|
2021-02-18 03:58:46 +01:00
|
|
|
for ( let ii = 0; ; ++ii ) {
|
2021-02-13 19:37:47 +01:00
|
|
|
const mem = HEAP32[(but_strs + (ii * 4)) >> 2];
|
|
|
|
if ( 0 == mem ) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
const str = UTF8ToString(mem);
|
|
|
|
buttons.push(str);
|
|
|
|
}
|
|
|
|
nbDialog(UTF8ToString(str), buttons, proc, closure);
|
|
|
|
} );
|
|
|
|
|
2021-02-18 03:58:46 +01:00
|
|
|
EM_JS(void, call_pickBlank, (const char* msg, const char** strs, int nStrs,
|
2021-02-19 05:30:24 +01:00
|
|
|
AlertProc proc, void* closure), {
|
2021-02-18 03:58:46 +01:00
|
|
|
var buttons = [];
|
|
|
|
for ( let ii = 0; ii < nStrs; ++ii ) {
|
|
|
|
const mem = HEAP32[(strs + (ii * 4)) >> 2];
|
|
|
|
const str = UTF8ToString(mem);
|
|
|
|
buttons.push(str);
|
|
|
|
}
|
|
|
|
nbBlankPick(UTF8ToString(msg), buttons, proc, closure);
|
2021-02-19 05:30:24 +01:00
|
|
|
} );
|
|
|
|
|
|
|
|
EM_JS(void, call_pickGame, (const char* msg, AlertProc proc, void* closure), {
|
2021-02-19 20:19:16 +01:00
|
|
|
var map = {};
|
2021-02-19 05:30:24 +01:00
|
|
|
for (var ii = 0; ii < localStorage.length; ++ii ) {
|
|
|
|
var key = localStorage.key(ii);
|
2021-02-19 20:19:16 +01:00
|
|
|
if ( key.startsWith('key_data_') ) { // KEY_GAME_PREFIX
|
|
|
|
/* This is a legit stored game. Get the gameID part as key,
|
|
|
|
mapped to name if known. */
|
|
|
|
let arr = key.split('_');
|
|
|
|
let id = arr[arr.length - 1];
|
|
|
|
|
|
|
|
let name = localStorage.getItem('key_name_' + id);
|
|
|
|
if (! name ) {
|
|
|
|
name = key;
|
|
|
|
}
|
|
|
|
map[id] = name;
|
|
|
|
console.log('added ' + id + ' -> ' + name);
|
2021-02-19 05:30:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-19 20:19:16 +01:00
|
|
|
nbGamePick(UTF8ToString(msg), map, proc, closure);
|
2021-02-19 05:30:24 +01:00
|
|
|
} );
|
2021-02-18 03:58:46 +01:00
|
|
|
|
2021-02-16 23:25:22 +01:00
|
|
|
EM_JS(void, call_get_string, (const char* msg, const char* dflt,
|
|
|
|
AlertProc proc, void* closure), {
|
|
|
|
let jsMgs = UTF8ToString(msg);
|
|
|
|
let jsDflt = UTF8ToString(dflt);
|
|
|
|
nbGetString( jsMgs, jsDflt, proc, closure );
|
|
|
|
} );
|
|
|
|
|
2021-02-10 02:53:30 +01:00
|
|
|
EM_JS(void, call_haveDevID, (void* closure, const char* devid), {
|
|
|
|
onHaveDevID(closure, UTF8ToString(devid));
|
2021-02-07 21:48:06 +01:00
|
|
|
});
|
|
|
|
|
2021-02-10 03:56:13 +01:00
|
|
|
EM_JS(bool, call_mqttSend, (const char* topic, const uint8_t* ptr, int len), {
|
2021-02-07 21:48:06 +01:00
|
|
|
let topStr = UTF8ToString(topic);
|
|
|
|
let buffer = new Uint8Array(Module.HEAPU8.buffer, ptr, len);
|
2021-02-10 03:56:13 +01:00
|
|
|
return mqttSend(topStr, buffer);
|
2021-02-07 21:48:06 +01:00
|
|
|
});
|
2021-02-02 23:52:25 +01:00
|
|
|
|
2021-02-19 20:19:16 +01:00
|
|
|
EM_JS(int, getNextGameNo, (void), {
|
|
|
|
let jskey = UTF8ToString('next_gameno_2');
|
|
|
|
let val = localStorage.getItem(jskey);
|
|
|
|
if (val) {
|
|
|
|
val = parseInt(val);
|
|
|
|
} else {
|
|
|
|
val = 0;
|
|
|
|
}
|
|
|
|
++val;
|
|
|
|
localStorage.setItem(jskey, val);
|
|
|
|
return val;
|
|
|
|
});
|
|
|
|
|
2021-02-10 22:21:28 +01:00
|
|
|
typedef void (*JSCallback)(void* closure);
|
|
|
|
|
|
|
|
EM_JS(void, jscallback_set, (JSCallback proc, void* closure, int inMS), {
|
|
|
|
let timerproc = function(closure) {
|
|
|
|
ccall('jscallback', null, ['number', 'number'], [proc, closure]);
|
|
|
|
};
|
|
|
|
setTimeout( timerproc, inMS, closure );
|
|
|
|
});
|
|
|
|
|
2021-02-11 00:46:52 +01:00
|
|
|
EM_JS(void, setButtonText, (const char* id, const char* text), {
|
|
|
|
let jsid = UTF8ToString(id);
|
|
|
|
let jstext = UTF8ToString(text);
|
|
|
|
document.getElementById(jsid).textContent = jstext;
|
|
|
|
});
|
|
|
|
|
2021-02-19 04:20:20 +01:00
|
|
|
EM_JS(void, setButtons, (const char* id, const char** bstrs,
|
|
|
|
AlertProc proc, void* closure), {
|
|
|
|
var buttons = [];
|
|
|
|
for ( let ii = 0; ; ++ii ) {
|
|
|
|
const mem = HEAP32[(bstrs + (ii * 4)) >> 2];
|
|
|
|
if ( 0 == mem ) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
const str = UTF8ToString(mem);
|
|
|
|
buttons.push(str);
|
|
|
|
}
|
|
|
|
setDivButtons(UTF8ToString(id), buttons, proc, closure);
|
|
|
|
});
|
|
|
|
|
2021-02-19 22:18:53 +01:00
|
|
|
EM_JS(void, callNewGame, (const char* msg, void* closure), {
|
|
|
|
let jsmsg = UTF8ToString(msg);
|
|
|
|
nbGetNewGame(closure, jsmsg);
|
|
|
|
});
|
|
|
|
|
2021-02-10 21:18:15 +01:00
|
|
|
static void updateScreen( Globals* globals, bool doSave );
|
2021-02-06 18:23:39 +01:00
|
|
|
|
2021-02-15 23:59:44 +01:00
|
|
|
typedef void (*ConfirmProc)( void* closure, bool confirmed );
|
|
|
|
|
|
|
|
typedef struct _ConfirmState {
|
|
|
|
Globals* globals;
|
|
|
|
ConfirmProc proc;
|
|
|
|
void* closure;
|
|
|
|
} ConfirmState;
|
|
|
|
|
|
|
|
static void
|
|
|
|
onConfirmed( void* closure, const char* button )
|
|
|
|
{
|
|
|
|
bool confirmed = 0 == strcmp( button, BUTTON_OK );
|
|
|
|
ConfirmState* cs = (ConfirmState*)closure;
|
|
|
|
(*cs->proc)( cs->closure, confirmed );
|
|
|
|
XP_FREE( cs->globals->mpool, cs );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
call_confirm( Globals* globals, const char* msg,
|
|
|
|
ConfirmProc proc, void* closure )
|
|
|
|
{
|
|
|
|
const char* buttons[] = { BUTTON_CANCEL, BUTTON_OK, NULL };
|
|
|
|
ConfirmState* cs = XP_MALLOC( globals->mpool, sizeof(*cs) );
|
|
|
|
cs->globals = globals;
|
|
|
|
cs->proc = proc;
|
|
|
|
cs->closure = closure;
|
|
|
|
call_dialog( msg, buttons, onConfirmed, cs );
|
|
|
|
}
|
|
|
|
|
2021-02-13 19:37:47 +01:00
|
|
|
static void
|
|
|
|
call_alert( const char* msg )
|
|
|
|
{
|
|
|
|
const char* buttons[] = { BUTTON_OK, NULL };
|
|
|
|
call_dialog( msg, buttons, NULL, NULL );
|
|
|
|
}
|
|
|
|
|
2021-02-20 02:03:14 +01:00
|
|
|
static bool
|
|
|
|
sendStreamToDev( XWStreamCtxt* stream, const MQTTDevID* devID )
|
|
|
|
{
|
|
|
|
XP_S16 nSent = -1;
|
|
|
|
XP_UCHAR topic[64];
|
|
|
|
formatMQTTTopic( devID, topic, sizeof(topic) );
|
|
|
|
|
|
|
|
XP_U16 streamLen = stream_getSize( stream );
|
|
|
|
bool success = call_mqttSend( topic, stream_getPtr( stream ), streamLen );
|
|
|
|
stream_destroy( stream, NULL );
|
|
|
|
LOG_RETURNF("%d", nSent);
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2021-02-07 21:48:06 +01:00
|
|
|
static XP_S16
|
|
|
|
send_msg( XWEnv xwe, const XP_U8* buf, XP_U16 len,
|
|
|
|
const XP_UCHAR* msgNo, const CommsAddrRec* addr,
|
|
|
|
CommsConnType conType, XP_U32 gameID, void* closure )
|
|
|
|
{
|
|
|
|
XP_S16 nSent = -1;
|
|
|
|
Globals* globals = (Globals*)closure;
|
|
|
|
|
|
|
|
if ( addr_hasType( addr, COMMS_CONN_MQTT ) ) {
|
2021-02-20 02:03:14 +01:00
|
|
|
// MQTTDevID devID = addr->u.mqtt.devID;
|
2021-02-07 21:48:06 +01:00
|
|
|
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(globals->mpool)
|
|
|
|
globals->vtMgr );
|
|
|
|
dvc_makeMQTTMessage( globals->dutil, NULL, stream,
|
|
|
|
gameID, buf, len );
|
2021-02-20 02:03:14 +01:00
|
|
|
if ( sendStreamToDev( stream, &addr->u.mqtt.devID ) ) {
|
2021-02-10 03:56:13 +01:00
|
|
|
nSent = len;
|
|
|
|
}
|
2021-02-07 21:48:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
LOG_RETURNF( "%d", nSent );
|
|
|
|
return nSent;
|
|
|
|
}
|
|
|
|
|
2021-02-11 00:46:52 +01:00
|
|
|
static void
|
2021-02-19 04:20:20 +01:00
|
|
|
doExit( Globals* globals )
|
2021-02-11 00:46:52 +01:00
|
|
|
{
|
2021-02-19 04:20:20 +01:00
|
|
|
call_alert( "Control passed to another tab" );
|
|
|
|
XP_MEMSET( globals, 0, sizeof(*globals) ); /* stop everything :-) */
|
|
|
|
// emscripten_cancel_main_loop(); <-- does nothing
|
|
|
|
}
|
|
|
|
|
2021-02-19 20:19:16 +01:00
|
|
|
static void
|
|
|
|
formatGameID( char* buf, size_t len, int gameID )
|
|
|
|
{
|
|
|
|
snprintf( buf, len, "%X", gameID );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-02-19 22:18:53 +01:00
|
|
|
formatGameKeyStr( char* buf, size_t len, const char* gameID )
|
2021-02-19 20:19:16 +01:00
|
|
|
{
|
|
|
|
snprintf( buf, len, KEY_GAME_PREFIX "%s", gameID );
|
|
|
|
}
|
|
|
|
|
2021-02-19 22:18:53 +01:00
|
|
|
static void
|
|
|
|
formatGameKeyInt( char* buf, size_t len, int gameID )
|
|
|
|
{
|
|
|
|
snprintf( buf, len, KEY_GAME_PREFIX "%X", gameID );
|
|
|
|
}
|
|
|
|
|
2021-02-19 20:19:16 +01:00
|
|
|
static void
|
|
|
|
formatNameKey( char* buf, size_t len, int gameID )
|
|
|
|
{
|
|
|
|
snprintf( buf, len, KEY_NAME_PREFIX "%X", gameID );
|
|
|
|
}
|
|
|
|
|
2021-02-20 02:03:14 +01:00
|
|
|
static void
|
|
|
|
makeSelfAddr( Globals* globals, CommsAddrRec* addr )
|
|
|
|
{
|
|
|
|
addr_setType( addr, COMMS_CONN_MQTT );
|
|
|
|
dvc_getMQTTDevID( globals->dutil, NULL, &addr->u.mqtt.devID );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
onGotInviteeID( void* closure, const char* mqttid )
|
|
|
|
{
|
|
|
|
MQTTDevID remoteDevID;
|
|
|
|
if ( strToMQTTCDevID( mqttid, &remoteDevID ) ) {
|
|
|
|
Globals* globals = (Globals*)closure;
|
|
|
|
CommsAddrRec myAddr = {0};
|
|
|
|
makeSelfAddr( globals, &myAddr );
|
|
|
|
|
|
|
|
NetLaunchInfo nli = {0}; /* include everything!!! */
|
|
|
|
nli_init( &nli, &globals->gs.gi, &myAddr, 1, 1 );
|
|
|
|
|
|
|
|
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(globals->mpool)
|
|
|
|
globals->vtMgr );
|
|
|
|
dvc_makeMQTTInvite( globals->dutil, NULL, stream, &nli );
|
|
|
|
|
|
|
|
sendStreamToDev( stream, &remoteDevID );
|
|
|
|
} else {
|
|
|
|
call_alert( "MQTT id looks badly formed" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-19 04:20:20 +01:00
|
|
|
static void
|
|
|
|
onGameButton( void* closure, const char* button )
|
|
|
|
{
|
|
|
|
if ( !!button ) {
|
|
|
|
Globals* globals = (Globals*)closure;
|
|
|
|
|
|
|
|
XP_Bool draw = XP_FALSE;
|
2021-02-19 04:41:18 +01:00
|
|
|
BoardCtxt* board = globals->gs.game.board;
|
2021-02-19 04:20:20 +01:00
|
|
|
XP_Bool redo;
|
|
|
|
|
|
|
|
if ( 0 == strcmp(button, BUTTON_HINTDOWN ) ) {
|
|
|
|
draw = board_requestHint( board, NULL, XP_TRUE, &redo );
|
|
|
|
} else if ( 0 == strcmp(button, BUTTON_HINTUP) ) {
|
|
|
|
draw = board_requestHint( board, NULL, XP_FALSE, &redo );
|
|
|
|
} else if ( 0 == strcmp(button, BUTTON_TRADE ) ) {
|
|
|
|
draw = board_beginTrade( board, NULL );
|
|
|
|
} else if ( 0 == strcmp(button, BUTTON_STOPTRADE ) ) {
|
|
|
|
draw = board_endTrade( board );
|
|
|
|
} else if ( 0 == strcmp(button, BUTTON_COMMIT) ) {
|
|
|
|
draw = board_commitTurn( board, NULL, XP_FALSE, XP_FALSE, NULL );
|
|
|
|
} else if ( 0 == strcmp(button, BUTTON_FLIP) ) {
|
|
|
|
draw = board_flip( board );
|
|
|
|
} else if ( 0 == strcmp(button, BUTTON_REDO) ) {
|
|
|
|
draw = board_redoReplacedTiles( board, NULL )
|
|
|
|
|| board_replaceTiles( board, NULL );
|
|
|
|
} else if ( 0 == strcmp(button, BUTTON_VALS) ) {
|
|
|
|
globals->cp.tvType = (globals->cp.tvType + 1) % TVT_N_ENTRIES;
|
|
|
|
draw = board_prefsChanged( board, &globals->cp );
|
2021-02-20 02:03:14 +01:00
|
|
|
} else if ( 0 == strcmp(button, BUTTON_INVITE) ) {
|
|
|
|
call_get_string( "Invitee's MQTT Device ID?", "",
|
|
|
|
onGotInviteeID, globals );
|
2021-02-19 04:20:20 +01:00
|
|
|
} else if ( 0 == strcmp(button, BUTTON_EXIT) ) {
|
|
|
|
doExit( globals );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( draw ) {
|
|
|
|
updateScreen( globals, true );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
updateGameButtons( Globals* globals )
|
|
|
|
{
|
|
|
|
const char* buttons[MAX_BUTTONS];
|
|
|
|
int cur = 0;
|
|
|
|
|
2021-02-19 22:18:53 +01:00
|
|
|
if ( !!globals->gs.util ) {
|
|
|
|
GameStateInfo gsi;
|
|
|
|
game_getState( &globals->gs.game, NULL, &gsi );
|
2021-02-19 04:20:20 +01:00
|
|
|
|
2021-02-19 22:18:53 +01:00
|
|
|
if ( gsi.canHint ) {
|
|
|
|
buttons[cur++] = BUTTON_HINTDOWN;
|
|
|
|
buttons[cur++] = BUTTON_HINTUP;
|
|
|
|
}
|
2021-02-19 04:20:20 +01:00
|
|
|
|
2021-02-19 22:18:53 +01:00
|
|
|
if ( gsi.inTrade ) {
|
|
|
|
buttons[cur++] = BUTTON_STOPTRADE;
|
|
|
|
} else if ( gsi.canTrade ) {
|
|
|
|
buttons[cur++] = BUTTON_TRADE;
|
|
|
|
}
|
|
|
|
buttons[cur++] = BUTTON_COMMIT;
|
|
|
|
buttons[cur++] = BUTTON_FLIP;
|
2021-02-19 04:20:20 +01:00
|
|
|
|
2021-02-19 22:18:53 +01:00
|
|
|
if ( gsi.canUndo ) {
|
|
|
|
buttons[cur++] = BUTTON_UNDO;
|
|
|
|
} else if ( gsi.canRedo ) {
|
|
|
|
buttons[cur++] = BUTTON_REDO;
|
|
|
|
}
|
2021-02-19 04:20:20 +01:00
|
|
|
|
2021-02-19 22:18:53 +01:00
|
|
|
buttons[cur++] = BUTTON_VALS;
|
2021-02-20 02:03:14 +01:00
|
|
|
|
|
|
|
XP_U16 nPending = server_getPendingRegs( globals->gs.game.server );
|
|
|
|
if ( 0 < nPending ) {
|
|
|
|
buttons[cur++] = BUTTON_INVITE;
|
|
|
|
}
|
2021-02-19 22:18:53 +01:00
|
|
|
}
|
2021-02-19 04:20:20 +01:00
|
|
|
buttons[cur++] = NULL;
|
|
|
|
|
|
|
|
setButtons( BUTTONS_ID_GAME, buttons, onGameButton, globals );
|
|
|
|
}
|
|
|
|
|
2021-02-19 05:30:24 +01:00
|
|
|
static void
|
|
|
|
onGameChosen( void* closure, const char* key )
|
|
|
|
{
|
|
|
|
Globals* globals = (Globals*)closure;
|
2021-02-19 22:18:53 +01:00
|
|
|
loadAndDraw( globals, NULL, key, NULL );
|
2021-02-19 05:30:24 +01:00
|
|
|
}
|
|
|
|
|
2021-02-19 20:19:16 +01:00
|
|
|
static void
|
|
|
|
onGameRanamed( void* closure, const char* newName )
|
|
|
|
{
|
|
|
|
if ( !!newName ) {
|
|
|
|
Globals* globals = (Globals*)closure;
|
|
|
|
snprintf( globals->gs.gameName, sizeof(globals->gs.gameName) - 1,
|
|
|
|
"%s", newName );
|
|
|
|
// be safe
|
|
|
|
globals->gs.gameName[sizeof(globals->gs.gameName)-1] = '\0';
|
|
|
|
saveName( globals );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-19 22:18:53 +01:00
|
|
|
static void
|
|
|
|
cleanupGame( Globals* globals )
|
|
|
|
{
|
|
|
|
if ( !!globals->gs.util ) {
|
|
|
|
game_dispose( &globals->gs.game, NULL );
|
2021-02-20 02:03:14 +01:00
|
|
|
gi_disposePlayerInfo( MPPARM(globals->mpool) &globals->gs.gi );
|
2021-02-19 22:18:53 +01:00
|
|
|
wasm_util_destroy( globals->gs.util );
|
|
|
|
XP_MEMSET( &globals->gs, 0, sizeof(globals->gs) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
deleteCurGame( Globals* globals )
|
|
|
|
{
|
|
|
|
int gameID = globals->gs.gi.gameID; /* remember it */
|
|
|
|
cleanupGame( globals );
|
|
|
|
|
|
|
|
char key[32];
|
|
|
|
formatNameKey( key, sizeof(key), gameID );
|
|
|
|
remove_stored_value( key );
|
|
|
|
|
|
|
|
formatGameKeyInt( key, sizeof(key), gameID );
|
|
|
|
remove_stored_value( key );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
onDeleteConfirmed( void* closure, bool confirmed )
|
|
|
|
{
|
|
|
|
if ( confirmed ) {
|
|
|
|
Globals* globals = (Globals*)closure;
|
|
|
|
deleteCurGame( globals );
|
|
|
|
updateScreen( globals, false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-19 04:20:20 +01:00
|
|
|
static void
|
|
|
|
onDeviceButton( void* closure, const char* button )
|
|
|
|
{
|
2021-02-19 05:30:24 +01:00
|
|
|
Globals* globals = (Globals*)closure;
|
2021-02-19 04:20:20 +01:00
|
|
|
XP_LOGFF( "(button=%s)", button );
|
|
|
|
if ( 0 == strcmp(button, BUTTON_GAME_NEW) ) {
|
2021-02-19 22:18:53 +01:00
|
|
|
callNewGame("Configure your new game", globals);
|
2021-02-19 04:20:20 +01:00
|
|
|
} else if ( 0 == strcmp(button, BUTTON_GAME_OPEN) ) {
|
2021-02-19 05:30:24 +01:00
|
|
|
const char* msg = "Choose game to open";
|
|
|
|
call_pickGame( msg, onGameChosen, globals);
|
2021-02-19 04:20:20 +01:00
|
|
|
} else if ( 0 == strcmp(button, BUTTON_GAME_RENAME ) ) {
|
2021-02-19 20:19:16 +01:00
|
|
|
ensureName( globals );
|
|
|
|
call_get_string( "Rename your game", globals->gs.gameName,
|
|
|
|
onGameRanamed, globals );
|
2021-02-19 04:20:20 +01:00
|
|
|
} else if ( 0 == strcmp(button, BUTTON_GAME_DELETE) ) {
|
2021-02-19 22:18:53 +01:00
|
|
|
char msg[256];
|
|
|
|
snprintf( msg, sizeof(msg), "Are you sure you want to delete the game \"%s\"?"
|
|
|
|
"\nThis action cannot be undone.",
|
|
|
|
globals->gs.gameName );
|
|
|
|
call_confirm( globals, msg, onDeleteConfirmed, globals );
|
2021-02-19 04:20:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
updateDeviceButtons( Globals* globals )
|
|
|
|
{
|
|
|
|
const char* buttons[MAX_BUTTONS];
|
|
|
|
int cur = 0;
|
|
|
|
buttons[cur++] = BUTTON_GAME_NEW;
|
|
|
|
buttons[cur++] = BUTTON_GAME_OPEN;
|
|
|
|
buttons[cur++] = BUTTON_GAME_RENAME;
|
|
|
|
buttons[cur++] = BUTTON_GAME_DELETE;
|
|
|
|
buttons[cur++] = NULL;
|
|
|
|
|
|
|
|
setButtons( BUTTONS_ID_DEVICE, buttons, onDeviceButton, globals );
|
2021-02-11 00:46:52 +01:00
|
|
|
}
|
|
|
|
|
2021-02-02 05:13:25 +01:00
|
|
|
static void
|
2021-02-04 00:22:08 +01:00
|
|
|
initDeviceGlobals( Globals* globals )
|
2021-02-02 05:13:25 +01:00
|
|
|
{
|
|
|
|
globals->cp.showBoardArrow = XP_TRUE;
|
2021-02-02 22:49:27 +01:00
|
|
|
globals->cp.allowPeek = XP_TRUE;
|
2021-02-03 20:47:03 +01:00
|
|
|
// globals->cp.showRobotScores = XP_TRUE;
|
2021-02-03 04:20:26 +01:00
|
|
|
globals->cp.sortNewTiles = XP_TRUE;
|
2021-02-12 03:31:31 +01:00
|
|
|
globals->cp.showColors = XP_TRUE;
|
2021-02-02 05:13:25 +01:00
|
|
|
|
2021-02-07 21:48:06 +01:00
|
|
|
globals->procs.send = send_msg;
|
|
|
|
globals->procs.closure = globals;
|
|
|
|
|
2021-02-11 01:46:15 +01:00
|
|
|
#ifdef MEMDEBUG
|
2021-02-04 00:22:08 +01:00
|
|
|
globals->mpool = mpool_make( "wasm" );
|
2021-02-11 01:46:15 +01:00
|
|
|
#endif
|
|
|
|
globals->vtMgr = make_vtablemgr( MPPARM_NOCOMMA(globals->mpool) );
|
|
|
|
globals->dutil = wasm_dutil_make( MPPARM(globals->mpool) globals->vtMgr, globals );
|
2021-02-08 01:31:32 +01:00
|
|
|
globals->dictMgr = dmgr_make( MPPARM_NOCOMMA(globals->mpool) );
|
|
|
|
globals->dict = wasm_dictionary_make( MPPARM(globals->mpool) NULL,
|
|
|
|
globals, DICTNAME, true );
|
|
|
|
|
2021-02-07 21:48:06 +01:00
|
|
|
dict_ref( globals->dict, NULL );
|
2021-02-04 00:22:08 +01:00
|
|
|
|
|
|
|
globals->draw = wasm_draw_make( MPPARM(globals->mpool)
|
|
|
|
WINDOW_WIDTH, WINDOW_HEIGHT );
|
2021-02-04 01:19:16 +01:00
|
|
|
|
|
|
|
MQTTDevID devID;
|
|
|
|
dvc_getMQTTDevID( globals->dutil, NULL, &devID );
|
2021-02-07 21:48:06 +01:00
|
|
|
XP_UCHAR buf[32];
|
|
|
|
XP_SNPRINTF( buf, VSIZE(buf), MQTTDevID_FMT, devID );
|
|
|
|
XP_LOGFF( "got mqtt devID: %s", buf );
|
2021-02-10 02:53:30 +01:00
|
|
|
call_haveDevID( globals, buf );
|
2021-02-07 21:48:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-02-17 00:32:33 +01:00
|
|
|
startGame( Globals* globals, const char* name )
|
2021-02-07 21:48:06 +01:00
|
|
|
{
|
|
|
|
LOG_FUNC();
|
|
|
|
BoardDims dims;
|
2021-02-19 04:41:18 +01:00
|
|
|
board_figureLayout( globals->gs.game.board, NULL, &globals->gs.gi,
|
2021-02-07 21:48:06 +01:00
|
|
|
WASM_BOARD_LEFT, WASM_HOR_SCORE_TOP, BDWIDTH, BDHEIGHT,
|
|
|
|
110, 150, 200, BDWIDTH-25, BDWIDTH/15, BDHEIGHT/15,
|
|
|
|
XP_FALSE, &dims );
|
|
|
|
XP_LOGFF( "calling board_applyLayout" );
|
2021-02-19 04:41:18 +01:00
|
|
|
board_applyLayout( globals->gs.game.board, NULL, &dims );
|
2021-02-07 21:48:06 +01:00
|
|
|
XP_LOGFF( "calling model_setDictionary" );
|
2021-02-19 04:41:18 +01:00
|
|
|
model_setDictionary( globals->gs.game.model, NULL, globals->dict );
|
2021-02-07 21:48:06 +01:00
|
|
|
|
2021-02-19 04:41:18 +01:00
|
|
|
if ( SERVER_ISCLIENT == globals->gs.gi.serverRole ) {
|
2021-02-17 00:32:33 +01:00
|
|
|
if ( !!name ) {
|
|
|
|
replaceStringIfDifferent( globals->mpool,
|
2021-02-19 04:41:18 +01:00
|
|
|
&globals->gs.gi.players[0].name,
|
2021-02-17 00:32:33 +01:00
|
|
|
name );
|
|
|
|
}
|
2021-02-19 04:41:18 +01:00
|
|
|
server_initClientConnection( globals->gs.game.server, NULL );
|
2021-02-07 21:48:06 +01:00
|
|
|
}
|
|
|
|
|
2021-02-19 04:41:18 +01:00
|
|
|
(void)server_do( globals->gs.game.server, NULL ); /* assign tiles, etc. */
|
|
|
|
if ( !!globals->gs.game.comms ) {
|
|
|
|
comms_resendAll( globals->gs.game.comms, NULL, COMMS_CONN_MQTT, XP_TRUE );
|
2021-02-10 02:53:30 +01:00
|
|
|
}
|
2021-02-07 21:48:06 +01:00
|
|
|
|
2021-02-10 21:18:15 +01:00
|
|
|
updateScreen( globals, true );
|
2021-02-07 21:48:06 +01:00
|
|
|
LOG_RETURN_VOID();
|
2021-02-04 00:22:08 +01:00
|
|
|
}
|
|
|
|
|
2021-02-15 23:59:44 +01:00
|
|
|
typedef struct _AskReplaceState {
|
|
|
|
Globals* globals;
|
|
|
|
NetLaunchInfo invite;
|
|
|
|
} AskReplaceState;
|
|
|
|
|
2021-02-17 00:32:33 +01:00
|
|
|
static void
|
|
|
|
onPlayerNamed( void* closure, const char* name )
|
|
|
|
{
|
|
|
|
Globals* globals = (Globals*)closure;
|
|
|
|
if ( !!name ) {
|
|
|
|
set_stored_value( KEY_PLAYER_NAME, name );
|
|
|
|
startGame( globals, name );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-15 23:59:44 +01:00
|
|
|
static void
|
|
|
|
onReplaceConfirmed( void* closure, bool confirmed )
|
|
|
|
{
|
|
|
|
AskReplaceState* ars = (AskReplaceState*)closure;
|
|
|
|
Globals* globals = ars->globals;
|
|
|
|
|
|
|
|
if ( confirmed ) {
|
2021-02-19 20:19:16 +01:00
|
|
|
cleanupGame( globals );
|
2021-02-15 23:59:44 +01:00
|
|
|
|
2021-02-19 04:41:18 +01:00
|
|
|
gi_disposePlayerInfo( MPPARM(globals->mpool) &globals->gs.gi );
|
|
|
|
XP_MEMSET( &globals->gs.gi, 0, sizeof(globals->gs.gi) );
|
2021-02-15 23:59:44 +01:00
|
|
|
|
2021-02-19 04:41:18 +01:00
|
|
|
globals->gs.util = wasm_util_make( MPPARM(globals->mpool) &globals->gs.gi,
|
2021-02-15 23:59:44 +01:00
|
|
|
globals->dutil, globals );
|
|
|
|
|
|
|
|
game_makeFromInvite( MPPARM(globals->mpool) NULL, &ars->invite,
|
2021-02-19 04:41:18 +01:00
|
|
|
&globals->gs.game, &globals->gs.gi,
|
2021-02-15 23:59:44 +01:00
|
|
|
globals->dict, NULL,
|
2021-02-19 04:41:18 +01:00
|
|
|
globals->gs.util, globals->draw,
|
2021-02-15 23:59:44 +01:00
|
|
|
&globals->cp, &globals->procs );
|
|
|
|
|
2021-02-17 00:32:33 +01:00
|
|
|
const char* name = get_stored_value( KEY_PLAYER_NAME );
|
|
|
|
if ( NULL != name ) {
|
|
|
|
startGame( globals, name );
|
|
|
|
free( (void*)name );
|
|
|
|
} else {
|
|
|
|
const char* msg = "Please enter your name so you opponent knows it's you";
|
|
|
|
call_get_string( msg, "Player 1", onPlayerNamed, globals );
|
|
|
|
}
|
2021-02-15 23:59:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
XP_FREE( globals->mpool, ars );
|
|
|
|
}
|
|
|
|
|
2021-02-10 05:59:33 +01:00
|
|
|
static bool
|
|
|
|
gameFromInvite( Globals* globals, const NetLaunchInfo* invite )
|
|
|
|
{
|
2021-02-10 21:18:15 +01:00
|
|
|
bool needsLoad = true;
|
2021-02-17 00:32:33 +01:00
|
|
|
|
2021-02-19 04:41:18 +01:00
|
|
|
if ( NULL != globals->gs.game.model ) {
|
2021-02-10 21:18:15 +01:00
|
|
|
/* there's a current game. Ignore the invitation if it has the same
|
|
|
|
gameID. Otherwise ask to replace */
|
2021-02-19 04:41:18 +01:00
|
|
|
if ( globals->gs.gi.gameID == invite->gameID ) {
|
2021-02-17 00:32:33 +01:00
|
|
|
call_alert( "Duplicate invitation: game already open" );
|
2021-02-10 21:18:15 +01:00
|
|
|
needsLoad = false;
|
2021-02-13 19:37:47 +01:00
|
|
|
} else {
|
2021-02-15 23:59:44 +01:00
|
|
|
AskReplaceState* ars = XP_MALLOC( globals->mpool, sizeof(*ars) );
|
|
|
|
ars->globals = globals;
|
|
|
|
XP_MEMCPY( &ars->invite, invite, sizeof(ars->invite) );
|
|
|
|
call_confirm( globals, "Invitation received; replace current game?",
|
|
|
|
onReplaceConfirmed, ars );
|
|
|
|
needsLoad = false;
|
2021-02-10 21:18:15 +01:00
|
|
|
}
|
2021-02-10 05:59:33 +01:00
|
|
|
} else if ( invite->lang != 1 ) {
|
|
|
|
call_alert( "Invitations are only supported for play in English right now." );
|
2021-02-10 21:18:15 +01:00
|
|
|
needsLoad = false;
|
|
|
|
}
|
|
|
|
|
2021-02-15 23:59:44 +01:00
|
|
|
bool loaded = !needsLoad;
|
2021-02-10 21:18:15 +01:00
|
|
|
LOG_RETURNF( "%d", loaded );
|
|
|
|
return loaded;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2021-02-19 05:30:24 +01:00
|
|
|
loadSavedGame( Globals* globals, const char* key )
|
2021-02-10 21:18:15 +01:00
|
|
|
{
|
2021-02-19 20:19:16 +01:00
|
|
|
XP_LOGFF( "key: %s", key );
|
2021-02-10 21:18:15 +01:00
|
|
|
bool loaded = false;
|
|
|
|
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(globals->mpool)
|
|
|
|
globals->vtMgr );
|
2021-02-19 20:19:16 +01:00
|
|
|
char buf[32];
|
2021-02-19 22:18:53 +01:00
|
|
|
formatGameKeyStr( buf, sizeof(buf), key );
|
2021-02-19 20:19:16 +01:00
|
|
|
dutil_loadStream( globals->dutil, NULL, buf, NULL, stream );
|
2021-02-10 21:18:15 +01:00
|
|
|
if ( 0 < stream_getSize( stream ) ) {
|
2021-02-19 04:41:18 +01:00
|
|
|
XP_ASSERT( !globals->gs.util );
|
|
|
|
globals->gs.util = wasm_util_make( MPPARM(globals->mpool) &globals->gs.gi,
|
2021-02-10 21:18:15 +01:00
|
|
|
globals->dutil, globals );
|
|
|
|
|
|
|
|
XP_LOGFF( "there's a saved game!!" );
|
|
|
|
loaded = game_makeFromStream( MPPARM(globals->mpool) NULL, stream,
|
2021-02-19 04:41:18 +01:00
|
|
|
&globals->gs.game, &globals->gs.gi,
|
2021-02-10 21:18:15 +01:00
|
|
|
globals->dict, NULL,
|
2021-02-19 04:41:18 +01:00
|
|
|
globals->gs.util, globals->draw,
|
2021-02-10 21:18:15 +01:00
|
|
|
&globals->cp, &globals->procs );
|
|
|
|
|
|
|
|
if ( loaded ) {
|
2021-02-19 20:19:16 +01:00
|
|
|
loadName( globals );
|
|
|
|
ensureName( globals );
|
2021-02-10 21:18:15 +01:00
|
|
|
updateScreen( globals, false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
stream_destroy( stream, NULL );
|
|
|
|
return loaded;
|
2021-02-10 05:59:33 +01:00
|
|
|
}
|
|
|
|
|
2021-02-19 05:30:24 +01:00
|
|
|
static void
|
2021-02-19 20:19:16 +01:00
|
|
|
saveName( Globals* globals )
|
|
|
|
{
|
|
|
|
char key[32];
|
|
|
|
formatNameKey( key, sizeof(key), globals->gs.gi.gameID );
|
|
|
|
set_stored_value( key, globals->gs.gameName );
|
|
|
|
XP_LOGFF( "wrote %s => %s", key, globals->gs.gameName );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
loadName( Globals* globals )
|
|
|
|
{
|
|
|
|
char key[32];
|
|
|
|
formatNameKey( key, sizeof(key), globals->gs.gi.gameID );
|
|
|
|
const char* ptr = get_stored_value( key );
|
|
|
|
if ( !!ptr ) {
|
|
|
|
snprintf( globals->gs.gameName, sizeof(globals->gs.gameName),
|
|
|
|
"%s", ptr );
|
|
|
|
free( (void*)ptr );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ensureName( Globals* globals )
|
|
|
|
{
|
|
|
|
if ( '\0' == globals->gs.gameName[0] ) {
|
|
|
|
nameGame( globals );
|
|
|
|
saveName( globals );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nameGame( Globals* globals )
|
2021-02-19 05:30:24 +01:00
|
|
|
{
|
2021-02-19 20:19:16 +01:00
|
|
|
snprintf( globals->gs.gameName, sizeof(globals->gs.gameName),
|
|
|
|
"Game %d", getNextGameNo() );
|
|
|
|
XP_LOGFF( "named game: %s", globals->gs.gameName );
|
2021-02-19 05:30:24 +01:00
|
|
|
}
|
|
|
|
|
2021-02-04 00:22:08 +01:00
|
|
|
static void
|
2021-02-10 21:18:15 +01:00
|
|
|
loadAndDraw( Globals* globals, const NetLaunchInfo* invite,
|
2021-02-19 22:18:53 +01:00
|
|
|
const char* key, NewGameParams* params )
|
2021-02-04 00:22:08 +01:00
|
|
|
{
|
2021-02-19 20:19:16 +01:00
|
|
|
cleanupGame( globals );
|
2021-02-04 00:22:08 +01:00
|
|
|
|
2021-02-10 21:18:15 +01:00
|
|
|
bool haveGame;
|
2021-02-19 22:18:53 +01:00
|
|
|
if ( !!params ) {
|
2021-02-10 21:18:15 +01:00
|
|
|
haveGame = false;
|
|
|
|
} else {
|
|
|
|
/* First, load any saved game. We need it e.g. to confirm that an incoming
|
|
|
|
invite is a dup and should be dropped. */
|
2021-02-19 05:30:24 +01:00
|
|
|
if ( !!key ) {
|
|
|
|
haveGame = loadSavedGame( globals, key );
|
|
|
|
}
|
2021-02-10 21:18:15 +01:00
|
|
|
if ( !!invite ) {
|
|
|
|
haveGame = gameFromInvite( globals, invite );
|
|
|
|
}
|
|
|
|
}
|
2021-02-02 05:13:25 +01:00
|
|
|
|
2021-02-10 21:18:15 +01:00
|
|
|
if ( !haveGame ) {
|
2021-02-19 22:18:53 +01:00
|
|
|
globals->gs.gi.serverRole = !!params && !params->isRobotNotRemote
|
|
|
|
? SERVER_ISSERVER : SERVER_STANDALONE;
|
|
|
|
|
2021-02-19 04:41:18 +01:00
|
|
|
globals->gs.gi.phoniesAction = PHONIES_WARN;
|
2021-02-19 22:18:53 +01:00
|
|
|
globals->gs.gi.hintsNotAllowed = !!params && params->hintsNotAllowed || false;
|
2021-02-19 04:41:18 +01:00
|
|
|
globals->gs.gi.gameID = 0;
|
2021-02-20 02:03:14 +01:00
|
|
|
globals->gs.gi.dictLang = 1; /* English only for now */
|
|
|
|
replaceStringIfDifferent( globals->mpool, &globals->gs.gi.dictName,
|
|
|
|
"CollegeEng_2to8" );
|
2021-02-19 04:41:18 +01:00
|
|
|
globals->gs.gi.nPlayers = 2;
|
|
|
|
globals->gs.gi.boardSize = 15;
|
2021-02-19 22:18:53 +01:00
|
|
|
globals->gs.gi.players[0].name = copyString( globals->mpool, "Player 1" ); /* FIXME */
|
2021-02-19 04:41:18 +01:00
|
|
|
globals->gs.gi.players[0].isLocal = XP_TRUE;
|
2021-02-19 22:18:53 +01:00
|
|
|
globals->gs.gi.players[0].robotIQ = 0;
|
2021-02-19 04:41:18 +01:00
|
|
|
|
|
|
|
globals->gs.gi.players[1].name = copyString( globals->mpool, "Player 2" );
|
2021-02-19 22:18:53 +01:00
|
|
|
globals->gs.gi.players[1].isLocal = !!params ? params->isRobotNotRemote : true;
|
|
|
|
XP_LOGFF( "set isLocal[1]: %d", globals->gs.gi.players[1].isLocal );
|
|
|
|
globals->gs.gi.players[1].robotIQ = 99; /* doesn't matter if remote */
|
2021-02-19 04:41:18 +01:00
|
|
|
|
|
|
|
globals->gs.util = wasm_util_make( MPPARM(globals->mpool) &globals->gs.gi,
|
2021-02-19 22:18:53 +01:00
|
|
|
globals->dutil, globals );
|
2021-02-06 18:23:39 +01:00
|
|
|
|
|
|
|
XP_LOGFF( "calling game_makeNewGame()" );
|
|
|
|
game_makeNewGame( MPPARM(globals->mpool) NULL,
|
2021-02-19 04:41:18 +01:00
|
|
|
&globals->gs.game, &globals->gs.gi,
|
|
|
|
globals->gs.util, globals->draw,
|
2021-02-06 18:23:39 +01:00
|
|
|
&globals->cp, &globals->procs );
|
2021-02-19 20:19:16 +01:00
|
|
|
nameGame( globals );
|
2021-02-20 02:03:14 +01:00
|
|
|
if ( !!globals->gs.game.comms ) {
|
|
|
|
CommsAddrRec addr = {0};
|
|
|
|
makeSelfAddr( globals, &addr );
|
|
|
|
comms_augmentHostAddr( globals->gs.game.comms, NULL, &addr );
|
|
|
|
}
|
2021-02-06 18:23:39 +01:00
|
|
|
}
|
2021-02-17 00:32:33 +01:00
|
|
|
startGame( globals, NULL );
|
2021-02-07 21:48:06 +01:00
|
|
|
}
|
2021-02-02 05:13:25 +01:00
|
|
|
|
2021-02-07 21:48:06 +01:00
|
|
|
void
|
|
|
|
main_gameFromInvite( Globals* globals, const NetLaunchInfo* invite )
|
|
|
|
{
|
2021-02-10 05:59:33 +01:00
|
|
|
if ( gameFromInvite( globals, invite ) ) {
|
2021-02-17 00:32:33 +01:00
|
|
|
startGame( globals, NULL );
|
2021-02-07 21:48:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-08 01:31:32 +01:00
|
|
|
void
|
|
|
|
main_onGameMessage( Globals* globals, XP_U32 gameID,
|
|
|
|
const CommsAddrRec* from, XWStreamCtxt* stream )
|
|
|
|
{
|
2021-02-19 04:41:18 +01:00
|
|
|
if ( gameID == globals->gs.gi.gameID ) {
|
|
|
|
XP_Bool draw = game_receiveMessage( &globals->gs.game, NULL, stream, from );
|
2021-02-15 23:59:44 +01:00
|
|
|
if ( draw ) {
|
|
|
|
updateScreen( globals, true );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
XP_LOGFF( "dropping packet for wrong game" );
|
|
|
|
|
|
|
|
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(globals->mpool)
|
|
|
|
globals->vtMgr );
|
|
|
|
dvc_makeMQTTNoSuchGame( globals->dutil, NULL, stream, gameID );
|
|
|
|
|
|
|
|
XP_UCHAR topic[64];
|
|
|
|
formatMQTTTopic( &from->u.mqtt.devID, topic, sizeof(topic) );
|
|
|
|
|
|
|
|
XP_U16 streamLen = stream_getSize( stream );
|
|
|
|
call_mqttSend( topic, stream_getPtr( stream ), streamLen );
|
|
|
|
stream_destroy( stream, NULL );
|
2021-02-08 01:31:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-07 21:48:06 +01:00
|
|
|
void
|
|
|
|
main_sendOnClose( XWStreamCtxt* stream, XWEnv env, void* closure )
|
|
|
|
{
|
|
|
|
Globals* globals = (Globals*)closure;
|
|
|
|
XP_LOGFF( "called with msg of len %d", stream_getSize(stream) );
|
2021-02-19 04:41:18 +01:00
|
|
|
(void)comms_send( globals->gs.game.comms, NULL, stream );
|
2021-02-02 05:13:25 +01:00
|
|
|
}
|
2021-02-01 17:30:34 +01:00
|
|
|
|
2021-02-10 23:16:22 +01:00
|
|
|
void
|
|
|
|
main_playerScoreHeld( Globals* globals, XP_U16 player )
|
|
|
|
{
|
|
|
|
LastMoveInfo lmi;
|
|
|
|
XP_UCHAR buf[128];
|
2021-02-19 04:41:18 +01:00
|
|
|
if ( model_getPlayersLastScore( globals->gs.game.model, NULL, player, &lmi ) ) {
|
2021-02-10 23:16:22 +01:00
|
|
|
switch ( lmi.moveType ) {
|
|
|
|
case ASSIGN_TYPE:
|
|
|
|
XP_SNPRINTF( buf, sizeof(buf), "Tiles assigned to %s", lmi.names[0] );
|
|
|
|
break;
|
|
|
|
case MOVE_TYPE:
|
|
|
|
XP_SNPRINTF( buf, sizeof(buf), "%s formed %s for %d points", lmi.names[0],
|
|
|
|
lmi.word, lmi.score );
|
|
|
|
break;
|
|
|
|
case TRADE_TYPE:
|
|
|
|
XP_SNPRINTF( buf, sizeof(buf), "%s traded %d tiles", lmi.names[0],
|
|
|
|
lmi.nTiles );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
buf[0] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( buf[0] ) {
|
|
|
|
call_alert( buf );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-17 02:22:50 +01:00
|
|
|
void
|
|
|
|
main_showRemaining( Globals* globals )
|
|
|
|
{
|
|
|
|
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(globals->mpool)
|
|
|
|
globals->vtMgr );
|
2021-02-19 04:41:18 +01:00
|
|
|
board_formatRemainingTiles( globals->gs.game.board, NULL, stream );
|
2021-02-17 02:22:50 +01:00
|
|
|
stream_putU8( stream, 0 );
|
|
|
|
call_alert( (const XP_UCHAR*)stream_getPtr( stream ) );
|
|
|
|
stream_destroy( stream, NULL );
|
|
|
|
}
|
2021-02-13 21:16:09 +01:00
|
|
|
|
2021-02-18 03:58:46 +01:00
|
|
|
typedef struct _BlankPickState {
|
|
|
|
Globals* globals;
|
|
|
|
int col, row;
|
|
|
|
int nTiles;
|
|
|
|
int playerNum;
|
|
|
|
char** faces;
|
|
|
|
} BlankPickState;
|
|
|
|
|
|
|
|
static void
|
|
|
|
onBlankPicked( void* closure, const char* face )
|
|
|
|
{
|
|
|
|
XP_LOGFF( "face: %s", face );
|
|
|
|
BlankPickState* bps = (BlankPickState*)closure;
|
|
|
|
Globals* globals = bps->globals;
|
|
|
|
|
|
|
|
int indx = -1;
|
|
|
|
for ( int ii = 0; ii < bps->nTiles; ++ii ) {
|
|
|
|
char* oneFace = bps->faces[ii];
|
|
|
|
if ( indx < 0 && 0 == strcmp( face, oneFace ) ) {
|
|
|
|
indx = ii;
|
|
|
|
}
|
|
|
|
XP_FREE( globals->mpool, oneFace );
|
|
|
|
}
|
|
|
|
XP_FREE( globals->mpool, bps->faces );
|
|
|
|
|
2021-02-19 04:41:18 +01:00
|
|
|
if ( board_setBlankValue( globals->gs.game.board, bps->playerNum,
|
2021-02-18 03:58:46 +01:00
|
|
|
bps->col, bps->row, indx ) ) {
|
|
|
|
updateScreen( globals, true );
|
|
|
|
}
|
|
|
|
|
|
|
|
XP_FREE( bps->globals->mpool, bps );
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
main_pickBlank( Globals* globals, int playerNum, int col, int row,
|
|
|
|
const char** tileFaces, int nTiles )
|
|
|
|
{
|
|
|
|
BlankPickState* bps = XP_MALLOC( globals->mpool, sizeof(*bps) );
|
|
|
|
bps->globals = globals;
|
|
|
|
bps->row = row;
|
|
|
|
bps->col = col;
|
|
|
|
bps->playerNum = playerNum;
|
|
|
|
bps->nTiles = nTiles;
|
|
|
|
bps->faces = XP_CALLOC( globals->mpool, nTiles * sizeof(bps->faces[0]) );
|
|
|
|
for ( int ii = 0; ii < nTiles; ++ii ) {
|
|
|
|
replaceStringIfDifferent( globals->mpool, &bps->faces[ii], tileFaces[ii] );
|
|
|
|
}
|
|
|
|
|
|
|
|
call_pickBlank( "Pick for your blank", tileFaces, nTiles,
|
|
|
|
onBlankPicked, bps );
|
|
|
|
}
|
|
|
|
|
2021-02-13 21:16:09 +01:00
|
|
|
void
|
|
|
|
main_showGameOver( Globals* globals )
|
|
|
|
{
|
|
|
|
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(globals->mpool)
|
|
|
|
globals->vtMgr );
|
2021-02-19 04:41:18 +01:00
|
|
|
server_writeFinalScores( globals->gs.game.server, NULL, stream );
|
2021-02-13 21:16:09 +01:00
|
|
|
stream_putU8( stream, 0 );
|
|
|
|
call_alert( (const XP_UCHAR*)stream_getPtr( stream ) );
|
|
|
|
stream_destroy( stream, NULL );
|
|
|
|
}
|
|
|
|
|
2021-02-02 22:49:27 +01:00
|
|
|
static time_t
|
|
|
|
getCurMS()
|
|
|
|
{
|
|
|
|
struct timeval tv;
|
|
|
|
gettimeofday( &tv, NULL );
|
|
|
|
time_t result = tv.tv_sec * 1000; /* convert to millis */
|
|
|
|
result += tv.tv_usec / 1000; /* convert to millis too */
|
|
|
|
// LOG_RETURNF( "%x", result );
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-02-10 23:16:22 +01:00
|
|
|
void
|
|
|
|
main_clear_timer( Globals* globals, XWTimerReason why )
|
2021-02-02 22:49:27 +01:00
|
|
|
{
|
2021-02-10 23:16:22 +01:00
|
|
|
XP_LOGFF( "why: %d" );
|
2021-02-10 23:25:25 +01:00
|
|
|
// XP_ASSERT(0); fires when start new game
|
2021-02-03 04:20:26 +01:00
|
|
|
}
|
|
|
|
|
2021-02-10 23:16:22 +01:00
|
|
|
typedef struct _TimerClosure {
|
|
|
|
Globals* globals;
|
|
|
|
XWTimerReason why;
|
|
|
|
XWTimerProc proc;
|
|
|
|
void* closure;
|
|
|
|
} TimerClosure;
|
2021-02-02 22:49:27 +01:00
|
|
|
|
2021-02-10 23:16:22 +01:00
|
|
|
static void
|
|
|
|
onTimerFired( void* closure )
|
2021-02-07 21:48:06 +01:00
|
|
|
{
|
2021-02-10 23:16:22 +01:00
|
|
|
LOG_FUNC();
|
|
|
|
TimerClosure* tc = (TimerClosure*)closure;
|
|
|
|
XP_Bool draw = (*tc->proc)( tc->closure, NULL, tc->why );
|
|
|
|
if ( draw ) {
|
|
|
|
updateScreen( tc->globals, true );
|
|
|
|
}
|
|
|
|
XP_FREE( tc->globals->mpool, tc );
|
2021-02-07 21:48:06 +01:00
|
|
|
}
|
|
|
|
|
2021-02-02 22:49:27 +01:00
|
|
|
void
|
|
|
|
main_set_timer( Globals* globals, XWTimerReason why, XP_U16 when,
|
|
|
|
XWTimerProc proc, void* closure )
|
|
|
|
{
|
2021-02-10 23:16:22 +01:00
|
|
|
XP_LOGFF( "why: %d", why );
|
|
|
|
TimerClosure* tc = XP_MALLOC( globals->mpool, sizeof(*tc) );
|
|
|
|
tc->globals = globals;
|
|
|
|
tc->proc = proc;
|
|
|
|
tc->closure = closure;
|
|
|
|
tc->why = why;
|
|
|
|
|
|
|
|
if ( 0 == when ) {
|
|
|
|
when = 1;
|
|
|
|
}
|
|
|
|
when *= 1000; /* convert to ms */
|
2021-02-02 22:49:27 +01:00
|
|
|
|
2021-02-10 23:16:22 +01:00
|
|
|
jscallback_set( onTimerFired, tc, when );
|
2021-02-02 22:49:27 +01:00
|
|
|
}
|
|
|
|
|
2021-02-13 19:37:47 +01:00
|
|
|
typedef struct _QueryState {
|
|
|
|
Globals* globals;
|
|
|
|
QueryProc proc;
|
|
|
|
void* closure;
|
|
|
|
} QueryState;
|
|
|
|
|
|
|
|
static void
|
|
|
|
onQueryCalled( void* closure, const char* button )
|
|
|
|
{
|
|
|
|
QueryState* qs = (QueryState*)closure;
|
|
|
|
bool ok = 0 == strcmp( button, BUTTON_OK );
|
|
|
|
(*qs->proc)( qs->closure, ok );
|
|
|
|
XP_FREE( qs->globals->mpool, qs );
|
|
|
|
}
|
|
|
|
|
2021-02-02 23:52:25 +01:00
|
|
|
void
|
|
|
|
main_query( Globals* globals, const XP_UCHAR* query, QueryProc proc, void* closure )
|
|
|
|
{
|
2021-02-13 19:37:47 +01:00
|
|
|
QueryState* qs = XP_MALLOC( globals->mpool, sizeof(*qs) );
|
|
|
|
qs->proc = proc;
|
|
|
|
qs->closure = closure;
|
|
|
|
qs->globals = globals;
|
|
|
|
|
|
|
|
const char* buttons[] = { BUTTON_CANCEL, BUTTON_OK, NULL };
|
|
|
|
call_dialog( query, buttons, onQueryCalled, qs );
|
2021-02-02 23:52:25 +01:00
|
|
|
}
|
|
|
|
|
2021-02-03 04:20:26 +01:00
|
|
|
void
|
|
|
|
main_alert( Globals* globals, const XP_UCHAR* msg )
|
|
|
|
{
|
|
|
|
call_alert( msg );
|
|
|
|
}
|
|
|
|
|
2021-02-10 22:21:28 +01:00
|
|
|
typedef struct _IdleClosure {
|
|
|
|
Globals* globals;
|
|
|
|
IdleProc proc;
|
|
|
|
void* closure;
|
|
|
|
} IdleClosure;
|
|
|
|
|
|
|
|
static void
|
|
|
|
onIdleFired( void* closure )
|
|
|
|
{
|
|
|
|
LOG_FUNC();
|
|
|
|
IdleClosure* ic = (IdleClosure*)closure;
|
|
|
|
XP_Bool draw = (*ic->proc)(ic->closure);
|
|
|
|
if ( draw ) {
|
|
|
|
updateScreen( ic->globals, true );
|
|
|
|
}
|
|
|
|
XP_FREE( ic->globals->mpool, ic );
|
|
|
|
}
|
|
|
|
|
2021-02-03 04:20:26 +01:00
|
|
|
void
|
|
|
|
main_set_idle( Globals* globals, IdleProc proc, void* closure )
|
|
|
|
{
|
2021-02-10 22:21:28 +01:00
|
|
|
LOG_FUNC();
|
|
|
|
IdleClosure* ic = XP_MALLOC( globals->mpool, sizeof(*ic) );
|
|
|
|
ic->globals = globals;
|
|
|
|
ic->proc = proc;
|
|
|
|
ic->closure = closure;
|
|
|
|
|
|
|
|
jscallback_set( onIdleFired, ic, 0 );
|
2021-02-03 04:20:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static XP_Bool
|
2021-02-02 21:04:31 +01:00
|
|
|
checkForEvent( Globals* globals )
|
|
|
|
{
|
|
|
|
XP_Bool handled;
|
|
|
|
XP_Bool draw = XP_FALSE;
|
2021-02-19 04:41:18 +01:00
|
|
|
BoardCtxt* board = globals->gs.game.board;
|
2021-02-02 23:19:57 +01:00
|
|
|
|
2021-02-02 21:04:31 +01:00
|
|
|
SDL_Event event;
|
|
|
|
if ( SDL_PollEvent(&event) ) {
|
|
|
|
switch ( event.type ) {
|
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
|
|
draw = event.button.button == SDL_BUTTON_LEFT
|
2021-02-02 23:19:57 +01:00
|
|
|
&& board_handlePenDown( board, NULL,
|
2021-02-02 21:04:31 +01:00
|
|
|
event.button.x, event.button.y,
|
|
|
|
&handled );
|
|
|
|
break;
|
|
|
|
case SDL_MOUSEBUTTONUP:
|
|
|
|
draw = event.button.button == SDL_BUTTON_LEFT
|
2021-02-02 23:19:57 +01:00
|
|
|
&& board_handlePenUp( board, NULL,
|
2021-02-02 21:04:31 +01:00
|
|
|
event.button.x, event.button.y );
|
|
|
|
break;
|
2021-02-02 23:19:57 +01:00
|
|
|
case SDL_MOUSEMOTION:
|
|
|
|
draw = board_handlePenMove( board, NULL,
|
|
|
|
event.motion.x, event.motion.y );
|
|
|
|
break;
|
2021-02-02 21:04:31 +01:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// XP_LOGFF( "draw: %d", draw );
|
2021-02-03 04:20:26 +01:00
|
|
|
return draw;
|
|
|
|
}
|
|
|
|
|
2021-02-03 07:10:26 +01:00
|
|
|
static void
|
2021-02-10 21:18:15 +01:00
|
|
|
updateScreen( Globals* globals, bool doSave )
|
2021-02-03 07:10:26 +01:00
|
|
|
{
|
|
|
|
SDL_RenderClear( globals->renderer );
|
2021-02-19 22:18:53 +01:00
|
|
|
if ( !!globals->gs.game.board ) {
|
|
|
|
board_draw( globals->gs.game.board, NULL );
|
|
|
|
wasm_draw_render( globals->draw, globals->renderer );
|
|
|
|
}
|
2021-02-03 07:10:26 +01:00
|
|
|
SDL_RenderPresent( globals->renderer );
|
2021-02-06 17:54:08 +01:00
|
|
|
|
2021-02-19 04:20:20 +01:00
|
|
|
updateGameButtons( globals );
|
|
|
|
|
2021-02-06 17:54:08 +01:00
|
|
|
/* Let's save state here too, though likely too often */
|
2021-02-10 21:18:15 +01:00
|
|
|
if ( doSave ) {
|
|
|
|
XWStreamCtxt* stream = mem_stream_make_raw( MPPARM(globals->mpool)
|
|
|
|
globals->vtMgr );
|
2021-02-19 04:41:18 +01:00
|
|
|
game_saveToStream( &globals->gs.game, NULL, &globals->gs.gi,
|
|
|
|
stream, ++globals->gs.saveToken );
|
2021-02-19 20:19:16 +01:00
|
|
|
|
|
|
|
char buf[32];
|
2021-02-19 22:18:53 +01:00
|
|
|
formatGameKeyInt( buf, sizeof(buf), globals->gs.gi.gameID );
|
2021-02-19 20:19:16 +01:00
|
|
|
dutil_storeStream( globals->dutil, NULL, buf, stream );
|
2021-02-10 21:18:15 +01:00
|
|
|
stream_destroy( stream, NULL );
|
2021-02-19 04:41:18 +01:00
|
|
|
game_saveSucceeded( &globals->gs.game, NULL, globals->gs.saveToken );
|
2021-02-19 20:19:16 +01:00
|
|
|
|
2021-02-19 22:18:53 +01:00
|
|
|
char gidBuf[16];
|
|
|
|
formatGameID( gidBuf, sizeof(gidBuf), globals->gs.gi.gameID );
|
2021-02-19 20:19:16 +01:00
|
|
|
set_stored_value( KEY_LAST, gidBuf );
|
|
|
|
XP_LOGFF( "saved KEY_LAST: %s", gidBuf );
|
2021-02-10 21:18:15 +01:00
|
|
|
}
|
2021-02-03 07:10:26 +01:00
|
|
|
}
|
|
|
|
|
2021-02-03 04:20:26 +01:00
|
|
|
static void
|
|
|
|
looper( void* closure )
|
|
|
|
{
|
|
|
|
Globals* globals = (Globals*)closure;
|
2021-02-10 23:16:22 +01:00
|
|
|
if ( checkForEvent( globals ) ) {
|
2021-02-10 21:18:15 +01:00
|
|
|
updateScreen( globals, true );
|
2021-02-03 07:10:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-10 05:59:33 +01:00
|
|
|
static bool
|
|
|
|
loadInvite( Globals* globals, NetLaunchInfo* nlip,
|
|
|
|
int argc, const char** argv )
|
|
|
|
{
|
|
|
|
LOG_FUNC();
|
|
|
|
CurGameInfo gi = {0};
|
|
|
|
CommsAddrRec addr = {0};
|
|
|
|
MQTTDevID mqttDevID = 0;
|
|
|
|
XP_U16 nPlayersH = 0;
|
|
|
|
XP_U16 forceChannel = 0;
|
|
|
|
const XP_UCHAR* gameName = NULL;
|
|
|
|
const XP_UCHAR* inviteID = NULL;
|
|
|
|
|
|
|
|
for ( int ii = 0; ii < argc; ++ii ) {
|
|
|
|
const char* argp = argv[ii];
|
|
|
|
char* param = strchr(argp, '=');
|
|
|
|
if ( !param ) { /* no '='? */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
char arg[8];
|
|
|
|
int argLen = param - argp;
|
|
|
|
XP_MEMCPY( arg, argp, argLen );
|
|
|
|
arg[argLen] = '\0';
|
|
|
|
++param; /* skip the '=' */
|
|
|
|
|
|
|
|
if ( 0 == strcmp( "lang", arg ) ) {
|
|
|
|
gi.dictLang = atoi(param);
|
|
|
|
} else if ( 0 == strcmp( "np", arg ) ) {
|
|
|
|
gi.nPlayers = atoi(param);
|
|
|
|
} else if ( 0 == strcmp( "nh", arg ) ) {
|
|
|
|
nPlayersH = atoi(param);
|
|
|
|
} else if ( 0 == strcmp( "gid", arg ) ) {
|
|
|
|
gi.gameID = atoi(param);
|
|
|
|
} else if ( 0 == strcmp( "fc", arg ) ) {
|
|
|
|
gi.forceChannel = atoi(param);
|
|
|
|
} else if ( 0 == strcmp( "nm", arg ) ) {
|
|
|
|
gameName = param;
|
|
|
|
} else if ( 0 == strcmp( "id", arg ) ) {
|
|
|
|
inviteID = param;
|
|
|
|
} else if ( 0 == strcmp( "wl", arg ) ) {
|
|
|
|
replaceStringIfDifferent( globals->mpool, &gi.dictName, param );
|
|
|
|
} else if ( 0 == strcmp( "r2id", arg ) ) {
|
|
|
|
if ( strToMQTTCDevID( param, &addr.u.mqtt.devID ) ) {
|
|
|
|
addr_addType( &addr, COMMS_CONN_MQTT );
|
|
|
|
} else {
|
|
|
|
XP_LOGFF( "bad devid %s", param );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
XP_LOGFF( "dropping arg %s, param %s", arg, param );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool success = 0 < nPlayersH &&
|
|
|
|
addr_hasType( &addr, COMMS_CONN_MQTT );
|
|
|
|
|
|
|
|
if ( success ) {
|
|
|
|
nli_init( nlip, &gi, &addr, nPlayersH, forceChannel );
|
|
|
|
if ( !!gameName ) {
|
|
|
|
nli_setGameName( nlip, gameName );
|
|
|
|
}
|
|
|
|
if ( !!inviteID ) {
|
|
|
|
nli_setInviteID( nlip, inviteID );
|
|
|
|
}
|
|
|
|
LOGNLI( nlip );
|
|
|
|
}
|
|
|
|
gi_disposePlayerInfo( MPPARM(globals->mpool) &gi );
|
|
|
|
LOG_RETURNF( "%d", success );
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2021-02-06 18:23:39 +01:00
|
|
|
static void
|
2021-02-10 05:59:33 +01:00
|
|
|
initNoReturn( int argc, const char** argv )
|
2021-02-02 05:13:25 +01:00
|
|
|
{
|
2021-02-04 05:18:15 +01:00
|
|
|
time_t now = getCurMS();
|
|
|
|
srandom( now );
|
2021-02-06 17:54:08 +01:00
|
|
|
XP_LOGFF( "called(srandom( %x )", now );
|
2021-02-04 05:18:15 +01:00
|
|
|
|
2021-02-04 00:22:08 +01:00
|
|
|
Globals* globals = calloc(1, sizeof(*globals));
|
|
|
|
|
2021-02-10 05:59:33 +01:00
|
|
|
NetLaunchInfo nli = {0};
|
|
|
|
NetLaunchInfo* nlip = NULL;
|
|
|
|
if ( loadInvite( globals, &nli, argc, argv ) ) {
|
|
|
|
nlip = &nli;
|
|
|
|
}
|
|
|
|
|
2021-02-02 21:04:31 +01:00
|
|
|
SDL_Init( SDL_INIT_EVENTS );
|
2021-02-02 18:08:41 +01:00
|
|
|
TTF_Init();
|
2021-02-02 21:04:31 +01:00
|
|
|
|
|
|
|
SDL_CreateWindowAndRenderer( WINDOW_WIDTH, WINDOW_HEIGHT, 0,
|
2021-02-04 00:22:08 +01:00
|
|
|
&globals->window, &globals->renderer );
|
2021-02-01 17:30:34 +01:00
|
|
|
|
2021-02-04 00:22:08 +01:00
|
|
|
/* whip the canvas to background */
|
|
|
|
SDL_SetRenderDrawColor( globals->renderer, 155, 155, 155, 255 );
|
|
|
|
SDL_RenderClear( globals->renderer );
|
|
|
|
|
|
|
|
initDeviceGlobals( globals );
|
2021-02-02 05:13:25 +01:00
|
|
|
|
2021-02-19 05:30:24 +01:00
|
|
|
const char* lastKey = get_stored_value( KEY_LAST );
|
2021-02-19 20:19:16 +01:00
|
|
|
XP_LOGFF( "loaded KEY_LAST: %s", lastKey );
|
2021-02-19 22:18:53 +01:00
|
|
|
loadAndDraw( globals, nlip, lastKey, NULL );
|
2021-02-19 05:30:24 +01:00
|
|
|
if ( !!lastKey ) {
|
|
|
|
free( (void*)lastKey );
|
|
|
|
}
|
2021-02-06 18:23:39 +01:00
|
|
|
|
2021-02-19 04:20:20 +01:00
|
|
|
updateDeviceButtons( globals );
|
|
|
|
|
2021-02-06 18:23:39 +01:00
|
|
|
emscripten_set_main_loop_arg( looper, globals, -1, 1 );
|
2021-02-04 00:22:08 +01:00
|
|
|
}
|
|
|
|
|
2021-02-15 23:59:44 +01:00
|
|
|
void
|
|
|
|
MQTTConnectedChanged( void* closure, bool connected )
|
|
|
|
{
|
|
|
|
XP_LOGFF( "connected=%d", connected);
|
|
|
|
Globals* globals = (Globals*)closure;
|
2021-02-19 04:41:18 +01:00
|
|
|
if ( connected && !!globals->gs.game.comms ) {
|
|
|
|
comms_resendAll( globals->gs.game.comms, NULL, COMMS_CONN_MQTT, XP_TRUE );
|
2021-02-15 23:59:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-07 21:48:06 +01:00
|
|
|
void
|
2021-02-10 02:53:30 +01:00
|
|
|
gotMQTTMsg( void* closure, int len, const uint8_t* msg )
|
2021-02-07 21:48:06 +01:00
|
|
|
{
|
2021-02-10 02:53:30 +01:00
|
|
|
Globals* globals = (Globals*)closure;
|
|
|
|
dvc_parseMQTTPacket( globals->dutil, NULL, msg, len );
|
2021-02-07 21:48:06 +01:00
|
|
|
}
|
|
|
|
|
2021-02-10 22:21:28 +01:00
|
|
|
void
|
|
|
|
jscallback( JSCallback proc, void* closure )
|
|
|
|
{
|
|
|
|
LOG_FUNC();
|
|
|
|
(*proc)(closure);
|
|
|
|
}
|
|
|
|
|
2021-02-13 19:37:47 +01:00
|
|
|
void
|
|
|
|
onDlgButton( AlertProc proc, void* closure, const char* button )
|
|
|
|
{
|
|
|
|
if ( !!proc ) {
|
|
|
|
(*proc)( closure, button );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-19 22:18:53 +01:00
|
|
|
void
|
|
|
|
onNewGame( void* closure, bool opponentIsRobot )
|
|
|
|
{
|
|
|
|
Globals* globals = (Globals*)closure;
|
|
|
|
XP_LOGFF( "isRobot: %d", opponentIsRobot );
|
|
|
|
|
|
|
|
NewGameParams ngp = {0};
|
|
|
|
ngp.isRobotNotRemote = opponentIsRobot;
|
|
|
|
loadAndDraw( globals, NULL, NULL, &ngp );
|
|
|
|
}
|
|
|
|
|
2021-02-04 00:22:08 +01:00
|
|
|
int
|
2021-02-10 05:59:33 +01:00
|
|
|
main( int argc, const char** argv )
|
2021-02-04 00:22:08 +01:00
|
|
|
{
|
2021-02-06 18:23:39 +01:00
|
|
|
XP_LOGFF( "(argc=%d)", argc );
|
2021-02-10 05:59:33 +01:00
|
|
|
initNoReturn( argc, argv );
|
2021-02-01 17:30:34 +01:00
|
|
|
return 0;
|
|
|
|
}
|