From 656f433d57d3934fb4aad1537ffaa0ad3ee71466 Mon Sep 17 00:00:00 2001 From: Eric House Date: Tue, 2 Feb 2021 19:20:26 -0800 Subject: [PATCH] snapshot: using alert() and confirm() --- xwords4/wasm/assets_dir/ic_downarrow.png | Bin 0 -> 955 bytes xwords4/wasm/assets_dir/ic_origin.png | Bin 0 -> 1764 bytes xwords4/wasm/assets_dir/ic_rightarrow.png | Bin 0 -> 1011 bytes xwords4/wasm/main.c | 67 ++++-- xwords4/wasm/main.h | 7 +- xwords4/wasm/wasmdraw.c | 31 ++- xwords4/wasm/wasmutil.c | 235 ++++++++++++++++++++-- 7 files changed, 300 insertions(+), 40 deletions(-) create mode 100644 xwords4/wasm/assets_dir/ic_downarrow.png create mode 100644 xwords4/wasm/assets_dir/ic_origin.png create mode 100644 xwords4/wasm/assets_dir/ic_rightarrow.png diff --git a/xwords4/wasm/assets_dir/ic_downarrow.png b/xwords4/wasm/assets_dir/ic_downarrow.png new file mode 100644 index 0000000000000000000000000000000000000000..557f34818eef91592ac30298d88fc96203a97bdd GIT binary patch literal 955 zcmeAS@N?(olHy`uVBq!ia0vp^(?FPm4M^HB7CvHNU~cksaSW-r_4e-BZr?o?3l?7AYf!kGYt2lX@1JYl|KK%wJ^OrRTWI*&n?l#k#ji|RVdk3KSuiun z&TWy@`?PuM^$PT#d(R7;%l@nST+H6t<&|dF{w}eIwiCP|_S zm#3#jt+=);#7=jIdf=5$}r>0Vp))6z#bbJ-oShgsihGK96#*L};WzkU19#s^71 z^$(xTxmLZ(@s$HN-Fd(=1icVhwN-D*{jWPtPM+^yX||lN{NBuLt@yfg zOXZ%NF}=B7gl(n!+>J%PPpVfXzDn#q7qfL;$l@!H*Tj5X6LNdfCCwd9_gB1keN}$^ z;VPT;yMN7Fm8Jf0RZAATQ-SOJm2NK%h}JH<)z1@iQTwV~$b+tbpNh4W=85IjhpjtS z|Lf69{&gRwa%t^26nIuKAinm`&-9}+Pc`oATW)W!aa-(gxYq6YxrQZi&u%^yi{7~? zuyS$UQ?9w<0j8^e@;%TB_~~_Un}pT*g-xsb?5n@K$*#LlIqUh1Xtr>ZRfqFLV=msF zKR?q(x6S^q<5Syk3oZN0H^iKu7k)DCovK|i@5#-#Vi7wR#n=5h+%9Kw^8HS(kb5g` zi#exj{`5G%E#k1_-P8U%4)MSGthZLF(Drok3DwXijdhmi?WPA!)D{onIv#5CSGMG( zNat#YQiZ?2)_++d5Oeffxs=x0?XCMCL^XMZT224==Y8a~)1tZ8o?iSPw#GyJc-T6o ztC8AMm9)Z^t*(@tx?)WTS1izC=@>50NniTwm>M>B`sQ=$82~dSgQu&X%Q~loCIF4@ B!Jz;E literal 0 HcmV?d00001 diff --git a/xwords4/wasm/assets_dir/ic_origin.png b/xwords4/wasm/assets_dir/ic_origin.png new file mode 100644 index 0000000000000000000000000000000000000000..881c5cf72e1bd793513637c9b09a9895a979bf35 GIT binary patch literal 1764 zcmV3!G2m}Iwh(N43fmjiNKp-Mktk|j*h!ZO!5C{YU5pe>6 zKp?2P2)4?~QW+00000 z0000000000000p&M-$LLRkJ%Rhr=>Y|CwZeSPo*7YcMQ-7v&VWOfg^F@MZr*BUkTH zrIE{?R3{_)XJEbJ-4T^8%lWXpq;JhhRhGRNr7FwCuq@EW=Aa6x$Yooqvh?bzczXt^%5ps{4IHQ( z-=9&=#ibxpy|;SNZJ}I0DyrgWt<_;}Y407oa>f(oB6q zs+8+6V!2dOWp#+s%XKYk$YZ4Xk5o&!E&9zGMeWNRL$JWMFpn$yKl?$FKk(000*yH?FoF;dmcrmH8Uza^5& zUkiCEjNl(#_aeEr0*;gq#czWlT7gC`q+;Z%e9qH#x{!Ag%o*pkP%c8=Ge?=}rfR8H z=&rbE8kg$}QXy9?rz#+@TzAGss-NhVH1Ox6ZW*aSL8E55ZXBP_OBNrYb6JB_x5cOl z3FG7Mt{ABx=8=oWkdKme2@$41R_x-Gi59=4s0xsLKJv`06GWyje{&Y{c~ z(Wkq^&~r9d!dHslVC0Gr>$%>QQP;b4f1Xm6G=y>;IMQ-gN^GAz@yB9rkt=x;SBii@Ey6hPjdSIP#rS-h+NZ2rTofj$UF**P8ZUD>i7`mL{go&wBr2ye_o5O zi7(fWfimp9?%+}X-xor;7`cAHoYQ^5-pXC=Be2hek3~M^o6$%$O0M%vuC-Pcoh~}r zYD3QnUrvzAeamT}n$(^epVX>fQnJk#pSnYw(-z7V-S-mLgi_@gC9IMws$?YVj?i-js*wIDk0`RDmg-7^S*&VME?i z=T*gXF4@}FTrm_9suY)8RYYC)R257yk3ufIm{G32QYwNfR_{7cwT9b(Orzv*#h21sRE zuH%qmHQa2gw*RlpW4Vry%A8yWA;em&U_otEWp*8@qb;+q6szH?S*7hgad&`S_Ech3 z^#z3&< literal 0 HcmV?d00001 diff --git a/xwords4/wasm/assets_dir/ic_rightarrow.png b/xwords4/wasm/assets_dir/ic_rightarrow.png new file mode 100644 index 0000000000000000000000000000000000000000..cae42ee7b1081414fbacd1a55f3ca812f664c01b GIT binary patch literal 1011 zcmeAS@N?(olHy`uVBq!ia0vp^(?FPm4M^HB7CvHNVBY2F;uunK>+N0dtPn>Dhlf%Y z1rr?kjRayE1QZtt1YDfBXi0RMi{o_ERoav!Y+d$gGkG4tyHL3|$g>am{tprjt?QW8%plsO3 zi8}(6bqW_oMLgb7vt472);+T>fiT_o60RJpr}fX>*%Io_UX|F%UE8Xv2c-UDr=Etj zY*{&?t;ysJv9{A^*%U!+Kq8FL@!)NQ0$AV#BX1?m^cZ;}aebrIEd&8pqx_6%@ za-4q5@7wi5A*AH>+apKs9dYxKC$(e((e0{ zxV5dcgi8}!cj;**UhO!g%L-(w0hvE;?(W>R;n08A+nL_lYhJAIiwbjT3ze(ix6Cmk z;`Jh@k_c6;_{$0=YobqHH{sxWo%gLl)g>h&`y{`-fJ|8DDHqv=iEGuSe*tnVS4h_> znXD-auutA8AbD-_8&2=m6C3i<_@mWa+Ele#+C%UC>x-5H8o$VD*4>m!0nxC^KXb)J zl@3RViUJeA_0^qk(!85iZ14&>U8dzy^wB+}Osl2H%sO3?f#E>>54NHqbF*Y$uh No2RRv%Q~loCIF`{&xZg2 literal 0 HcmV?d00001 diff --git a/xwords4/wasm/main.c b/xwords4/wasm/main.c index 2cc6de9fd..65828b8ce 100644 --- a/xwords4/wasm/main.c +++ b/xwords4/wasm/main.c @@ -36,21 +36,29 @@ EM_JS(bool, call_confirm, (const char* str), { return confirm(UTF8ToString(str)); }); +EM_JS(void, call_alert, (const char* str), { + alert(UTF8ToString(str)); +}); static void initGlobals( Globals* globals ) { globals->cp.showBoardArrow = XP_TRUE; globals->cp.allowPeek = XP_TRUE; + globals->cp.showRobotScores = XP_TRUE; + globals->cp.sortNewTiles = XP_TRUE; globals->gi.serverRole = SERVER_STANDALONE; + globals->gi.phoniesAction = PHONIES_WARN; + globals->gi.nPlayers = 2; globals->gi.boardSize = 15; globals->gi.dictName = "myDict"; - globals->gi.players[0].name = "Eric"; + globals->gi.players[0].name = "You"; globals->gi.players[0].isLocal = XP_TRUE; - globals->gi.players[1].name = "Kati"; + globals->gi.players[1].name = "Robot"; globals->gi.players[1].isLocal = XP_TRUE; + globals->gi.players[1].robotIQ = 99; globals->mpool = mpool_make( "wasm" ); globals->vtMgr = make_vtablemgr( globals->mpool ); @@ -99,20 +107,33 @@ getCurMS() return result; } -static void +static XP_Bool checkForTimers( Globals* globals ) { + XP_Bool draw = XP_FALSE; time_t now = getCurMS(); for ( XWTimerReason why = 0; why < NUM_TIMERS_PLUS_ONE; ++why ) { TimerState* timer = &globals->timers[why]; XWTimerProc proc = timer->proc; if ( !!proc && now >= timer->when ) { timer->proc = NULL; - XP_LOGFF( "timer fired (why=%d): calling proc", why ); (*proc)( timer->closure, NULL, why ); - XP_LOGFF( "back from proc" ); + draw = XP_TRUE; /* just in case */ } } + return draw; +} + +static XP_Bool +checkForIdle( Globals* globals ) +{ + XP_Bool draw = XP_FALSE; + IdleProc proc = globals->idleProc; + if ( !!proc ) { + globals->idleProc = NULL; + draw = (*proc)(globals->idleClosure); + } + return draw; } void @@ -134,7 +155,21 @@ main_query( Globals* globals, const XP_UCHAR* query, QueryProc proc, void* closu (*proc)( closure, ok ); } -static void +void +main_alert( Globals* globals, const XP_UCHAR* msg ) +{ + call_alert( msg ); +} + +void +main_set_idle( Globals* globals, IdleProc proc, void* closure ) +{ + XP_ASSERT( !globals->idleProc ); + globals->idleProc = proc; + globals->idleClosure = closure; +} + +static XP_Bool checkForEvent( Globals* globals ) { XP_Bool handled; @@ -165,20 +200,24 @@ checkForEvent( Globals* globals ) } // XP_LOGFF( "draw: %d", draw ); - if ( draw ) { - SDL_RenderClear( globals->renderer ); - board_draw( globals->game.board, NULL ); - wasm_draw_render( globals->draw, globals->renderer ); - SDL_RenderPresent( globals->renderer ); - } + return draw; } static void looper( void* closure ) { Globals* globals = (Globals*)closure; - checkForTimers( globals ); - checkForEvent( globals ); + XP_Bool draw = checkForTimers( globals ); + draw = checkForIdle( globals ) || draw; + draw = checkForEvent( globals ) || draw; + + if ( draw ) { + SDL_RenderClear( globals->renderer ); + board_draw( globals->game.board, NULL ); + wasm_draw_render( globals->draw, globals->renderer ); + SDL_RenderPresent( globals->renderer ); + } + } int main( int argc, char** argv ) diff --git a/xwords4/wasm/main.h b/xwords4/wasm/main.h index bced9d765..28c612a25 100644 --- a/xwords4/wasm/main.h +++ b/xwords4/wasm/main.h @@ -14,6 +14,7 @@ typedef struct _TimerState { time_t when; } TimerState; +typedef XP_Bool (*IdleProc)(void* closure); typedef struct _Globals { SDL_Window* window; @@ -30,6 +31,9 @@ typedef struct _Globals { TimerState timers[NUM_TIMERS_PLUS_ONE]; + IdleProc idleProc; + void* idleClosure; + MemPoolCtx* mpool; } Globals; @@ -37,9 +41,10 @@ void main_set_timer( Globals* globals, XWTimerReason why, XP_U16 when, XWTimerProc proc, void* closure ); typedef void (*QueryProc)(void* closure, XP_Bool confirmed); - void main_query( Globals* globals, const XP_UCHAR* query, QueryProc proc, void* closure ); +void main_set_idle( Globals* globals, IdleProc proc, void* closure ); +void main_alert( Globals* globals, const XP_UCHAR* msg ); #endif diff --git a/xwords4/wasm/wasmdraw.c b/xwords4/wasm/wasmdraw.c index 0e0d85767..ecf3b0b0f 100644 --- a/xwords4/wasm/wasmdraw.c +++ b/xwords4/wasm/wasmdraw.c @@ -1,5 +1,6 @@ #include #include +#include #include "comtypes.h" #include "wasmdraw.h" @@ -17,6 +18,10 @@ typedef struct _WasmDrawCtx { TTF_Font* font36; TTF_Font* font48; + SDL_Surface* arrowDown; + SDL_Surface* arrowRight; + SDL_Surface* origin; + int trayOwner; } WasmDrawCtx; @@ -116,8 +121,8 @@ textInRect( WasmDrawCtx* wdctx, const XP_UCHAR* text, const XP_Rect* rect, int width, height; SDL_QueryTexture( texture, NULL, NULL, &width, &height ); - XP_LOGFF( "have w: %d; h: %d; got w: %d; h: %d", - tmpR.width, tmpR.height, width, height ); + /* XP_LOGFF( "have w: %d; h: %d; got w: %d; h: %d", */ + /* tmpR.width, tmpR.height, width, height ); */ tmpR.width = XP_MIN( width, tmpR.width ); tmpR.height = XP_MIN( height, tmpR.height ); @@ -127,6 +132,16 @@ textInRect( WasmDrawCtx* wdctx, const XP_UCHAR* text, const XP_Rect* rect, SDL_DestroyTexture( texture ); } +static void +imgInRect( WasmDrawCtx* wdctx, SDL_Surface* img, const XP_Rect* rect ) +{ + SDL_Texture* texture = SDL_CreateTextureFromSurface( wdctx->renderer, img ); + SDL_Rect sdlr; + rectXPToSDL( &sdlr, rect ); + SDL_RenderCopy( wdctx->renderer, texture, NULL, &sdlr ); + SDL_DestroyTexture( texture ); +} + static void drawTile( WasmDrawCtx* wdctx, const XP_UCHAR* face, int val, int owner, const XP_Rect* rect ) @@ -323,6 +338,9 @@ wasm_draw_drawCell( DrawCtx* dctx, XWEnv xwe, const XP_Rect* rect, } else { fillRect( wdctx, rect, sBonusColors[bonus-1] ); } + if ( 0 != (flags & CELL_ISSTAR) ) { + imgInRect( wdctx, wdctx->origin, rect ); + } } else if ( !!text ) { textInRect( wdctx, text, rect, NULL ); } @@ -400,10 +418,11 @@ wasm_draw_drawBoardArrow ( DrawCtx* dctx, XWEnv xwe, XWBonusType bonus, XP_Bool vert, HintAtts hintAtts, CellFlags flags ) { - LOG_FUNC(); WasmDrawCtx* wdctx = (WasmDrawCtx*)dctx; const XP_UCHAR* str = vert ? "|" : "-"; - textInRect( wdctx, str, rect, NULL ); + SDL_Surface* img = vert ? wdctx->arrowDown : wdctx->arrowRight; + + imgInRect( wdctx, img, rect ); } static void @@ -453,6 +472,10 @@ wasm_draw_make( MPFORMAL int width, int height ) wdctx->font36 = TTF_OpenFont( "assets_dir/FreeSans.ttf", 36 ); wdctx->font48 = TTF_OpenFont( "assets_dir/FreeSans.ttf", 48 ); + wdctx->arrowDown = IMG_Load( "assets_dir/ic_downarrow.png" ); + wdctx->arrowRight = IMG_Load( "assets_dir/ic_rightarrow.png" ); + wdctx->origin = IMG_Load( "assets_dir/ic_origin.png" ); + wdctx->vtable = XP_MALLOC( mpool, sizeof(*wdctx->vtable) ); SET_VTABLE_ENTRY( wdctx->vtable, draw_clearRect, wasm ); diff --git a/xwords4/wasm/wasmutil.c b/xwords4/wasm/wasmutil.c index 46df80316..c3c1d32a1 100644 --- a/xwords4/wasm/wasmutil.c +++ b/xwords4/wasm/wasmutil.c @@ -2,6 +2,7 @@ #include "util.h" #include "comtypes.h" #include "main.h" +#include "dbgutil.h" typedef struct _WasmUtilCtx { XW_UtilCtxt super; @@ -44,10 +45,159 @@ wasm_util_getSquareBonus( XW_UtilCtxt* uc, XWEnv xwe, XP_U16 boardSize, return s_buttsBoard[row][col]; } +static const XP_UCHAR* +wasm_getErrString( UtilErrID id, XP_Bool* silent ) +{ + *silent = XP_FALSE; + const char* message = NULL; + + switch( (int)id ) { + case ERR_TILES_NOT_IN_LINE: + message = "All tiles played must be in a line."; + break; + case ERR_NO_EMPTIES_IN_TURN: + message = "Empty squares cannot separate tiles played."; + break; + + case ERR_TOO_FEW_TILES_LEFT_TO_TRADE: + message = "Too few tiles left to trade."; + break; + + case ERR_TWO_TILES_FIRST_MOVE: + message = "Must play two or more pieces on the first move."; + break; + case ERR_TILES_MUST_CONTACT: + message = "New pieces must contact others already in place (or " + "the middle square on the first move)."; + break; + case ERR_NOT_YOUR_TURN: + message = "You can't do that; it's not your turn!"; + break; + case ERR_NO_PEEK_ROBOT_TILES: + message = "No peeking at the robot's tiles!"; + break; + +#ifndef XWFEATURE_STANDALONE_ONLY + case ERR_NO_PEEK_REMOTE_TILES: + message = "No peeking at remote players' tiles!"; + break; + case ERR_REG_UNEXPECTED_USER: + message = "Refused attempt to register unexpected user[s]."; + break; + case ERR_SERVER_DICT_WINS: + message = "Conflict between Host and Guest dictionaries; Host wins."; + XP_WARNF( "GTK may have problems here." ); + break; + case ERR_REG_SERVER_SANS_REMOTE: + message = "At least one player must be marked remote for a game " + "started as Host."; + break; +#endif + + case ERR_NO_EMPTY_TRADE: + message = "No tiles selected; trade cancelled."; + break; + + case ERR_TOO_MANY_TRADE: + message = "More tiles selected than remain in pool."; + break; + + case ERR_NO_HINT_FOUND: + message = "Unable to suggest any moves."; + break; + + case ERR_CANT_UNDO_TILEASSIGN: + message = "Tile assignment can't be undone."; + break; + + case ERR_CANT_HINT_WHILE_DISABLED: + message = "The hint feature is disabled for this game. Enable " + "it for a new game using the Preferences dialog."; + break; + +/* case INFO_REMOTE_CONNECTED: */ +/* message = "Another device has joined the game"; */ +/* break; */ + + case ERR_RELAY_BASE + XWRELAY_ERROR_LOST_OTHER: + *silent = XP_TRUE; + message = "XWRELAY_ERROR_LOST_OTHER"; + break; + + case ERR_RELAY_BASE + XWRELAY_ERROR_TIMEOUT: + message = "The relay timed you out; other players " + "have left or never showed up."; + break; + + case ERR_RELAY_BASE + XWRELAY_ERROR_HEART_YOU: + message = "You were disconnected from relay because it didn't " + "hear from you in too long."; + break; + case ERR_RELAY_BASE + XWRELAY_ERROR_HEART_OTHER: +/* *silent = XP_TRUE; */ + message = "The relay has lost contact with a device in this game."; + break; + + case ERR_RELAY_BASE + XWRELAY_ERROR_OLDFLAGS: + message = "You need to upgrade your copy of Crosswords."; + break; + + case ERR_RELAY_BASE + XWRELAY_ERROR_SHUTDOWN: + message = "Relay disconnected you to shut down (and probably reboot)."; + break; + + case ERR_RELAY_BASE + XWRELAY_ERROR_BADPROTO: + message = "XWRELAY_ERROR_BADPROTO"; + break; + case ERR_RELAY_BASE + XWRELAY_ERROR_RELAYBUSY: + message = "XWRELAY_ERROR_RELAYBUSY"; + break; + + case ERR_RELAY_BASE + XWRELAY_ERROR_OTHER_DISCON: + *silent = XP_TRUE; /* happens all the time, and shouldn't matter */ + message = "XWRELAY_ERROR_OTHER_DISCON"; + break; + + case ERR_RELAY_BASE + XWRELAY_ERROR_NO_ROOM: + message = "No such room. Has the host connected yet to reserve it?"; + break; + case ERR_RELAY_BASE + XWRELAY_ERROR_DUP_ROOM: + message = "That room is reserved by another host. Rename your room, " + "become a guest, or try again in a few minutes."; + break; + + case ERR_RELAY_BASE + XWRELAY_ERROR_TOO_MANY: + message = "You tried to supply more players than the host expected."; + break; + + case ERR_RELAY_BASE + XWRELAY_ERROR_DELETED: + message = "Game deleted ."; + break; + case ERR_RELAY_BASE + XWRELAY_ERROR_NORECONN: + message = "Cannot reconnect."; + break; + case ERR_RELAY_BASE + XWRELAY_ERROR_DEADGAME: + message = "Game is listed as dead on relay."; + break; + + default: + XP_LOGF( "no code for error: %d", id ); + message = ""; + } + + return (XP_UCHAR*)message; +} + static void wasm_util_userError( XW_UtilCtxt* uc, XWEnv xwe, UtilErrID id ) { - LOG_FUNC(); + WasmUtilCtx* wuctxt = (WasmUtilCtx*)uc; + Globals* globals = (Globals*)wuctxt->closure; + XP_Bool silent; + const XP_UCHAR* str = wasm_getErrString( id, &silent ); + if ( !silent ) { + main_alert( globals, str ); + } } static void @@ -81,6 +231,7 @@ wasm_util_notifyTrade( XW_UtilCtxt* uc, XWEnv xwe, const XP_UCHAR** tiles, { LOG_FUNC(); } + static void wasm_util_notifyPickTileBlank( XW_UtilCtxt* uc, XWEnv xwe, XP_U16 playerNum, XP_U16 col, XP_U16 row, @@ -92,9 +243,9 @@ wasm_util_notifyPickTileBlank( XW_UtilCtxt* uc, XWEnv xwe, XP_U16 playerNum, static void wasm_util_informNeedPickTiles( XW_UtilCtxt* uc, XWEnv xwe, XP_Bool isInitial, - XP_U16 player, XP_U16 nToPick, - XP_U16 nFaces, const XP_UCHAR** faces, - const XP_U16* counts ) + XP_U16 player, XP_U16 nToPick, + XP_U16 nFaces, const XP_UCHAR** faces, + const XP_U16* counts ) { LOG_FUNC(); } @@ -136,9 +287,17 @@ wasm_util_notifyDupStatus( XW_UtilCtxt* uc, XWEnv xwe, XP_Bool amHost, static void wasm_util_informMove( XW_UtilCtxt* uc, XWEnv xwe, XP_S16 turn, - XWStreamCtxt* expl, XWStreamCtxt* words ) + XWStreamCtxt* expl, XWStreamCtxt* words ) { - LOG_FUNC(); + XWStreamCtxt* useMe = expl; /*!!words ? words : expl;*/ + XP_U16 len = stream_getSize( useMe ); + XP_UCHAR buf[len+1]; + stream_getBytes( useMe, buf, len ); + buf[len] = '\0'; + + WasmUtilCtx* wuctxt = (WasmUtilCtx*)uc; + Globals* globals = (Globals*)wuctxt->closure; + main_alert( globals, buf ); } static void @@ -160,13 +319,16 @@ wasm_util_informNetDict( XW_UtilCtxt* uc, XWEnv xwe, XP_LangCode lang, static void wasm_util_notifyGameOver( XW_UtilCtxt* uc, XWEnv xwe, XP_S16 quitter ) { - LOG_FUNC(); + WasmUtilCtx* wuctxt = (WasmUtilCtx*)uc; + Globals* globals = (Globals*)wuctxt->closure; + main_alert( globals, "Game over" ); } -static XP_Bool wasm_util_engineProgressCallback( XW_UtilCtxt* uc, XWEnv xwe ) +static XP_Bool +wasm_util_engineProgressCallback( XW_UtilCtxt* uc, XWEnv xwe ) { - LOG_FUNC(); - return XP_FALSE; + // LOG_RETURN_VOID(); + return XP_TRUE; } static void @@ -186,10 +348,20 @@ wasm_util_clearTimer( XW_UtilCtxt* uc, XWEnv xwe, XWTimerReason why ) LOG_FUNC(); } +static XP_Bool +on_idle( void* closure ) +{ + WasmUtilCtx* wuctxt = (WasmUtilCtx*)closure; + Globals* globals = (Globals*)wuctxt->closure; + return server_do( globals->game.server, NULL ); +} + static void wasm_util_requestTime( XW_UtilCtxt* uc, XWEnv xwe ) { - LOG_FUNC(); + WasmUtilCtx* wuctxt = (WasmUtilCtx*)uc; + Globals* globals = (Globals*)wuctxt->closure; + main_set_idle( globals, on_idle, wuctxt ); } static XP_Bool @@ -208,20 +380,38 @@ wasm_util_makeEmptyDict( XW_UtilCtxt* uc, XWEnv xwe ) static void wasm_util_notifyIllegalWords( XW_UtilCtxt* uc, XWEnv xwe, BadWordInfo* bwi, - XP_U16 turn, XP_Bool turnLost ) + XP_U16 turn, XP_Bool turnLost ) +{ + XP_UCHAR words[256]; + int offset = 0; + + for ( int ii = 0; ; ) { + offset += XP_SNPRINTF( &words[offset], VSIZE(words) - offset, "%s", + bwi->words[ii] ); + if ( ++ii >= bwi->nWords ) { + break; + } + offset += XP_SNPRINTF( &words[offset], VSIZE(words) - offset, ", " ); + } + + XP_UCHAR buf[256]; + XP_SNPRINTF( buf, VSIZE(buf), "Word[s] \"%s\" not in the current " + "dictionary (%s). Use anyway?", words, bwi->dictName ); + + WasmUtilCtx* wuctxt = (WasmUtilCtx*)uc; + Globals* globals = (Globals*)wuctxt->closure; + main_query( globals, buf, query_proc_notifyMove, uc ); +} + +static void +wasm_util_remSelected( XW_UtilCtxt* uc, XWEnv xwe ) { LOG_FUNC(); } static void -wasm_util_remSelected(XW_UtilCtxt* uc, XWEnv xwe) -{ - LOG_FUNC(); -} - -static void -wasm_util_timerSelected(XW_UtilCtxt* uc, XWEnv xwe, XP_Bool inDuplicateMode, - XP_Bool canPause) +wasm_util_timerSelected( XW_UtilCtxt* uc, XWEnv xwe, XP_Bool inDuplicateMode, + XP_Bool canPause ) { LOG_FUNC(); } @@ -317,7 +507,6 @@ wasm_util_make( MPFORMAL CurGameInfo* gi, XW_DUtilCtxt* dctxt, void* closure ) SET_VTABLE_ENTRY( wuctxt->super.vtable, util_userError, wasm ); SET_VTABLE_ENTRY( wuctxt->super.vtable, util_makeStreamFromAddr, wasm ); SET_VTABLE_ENTRY( wuctxt->super.vtable, util_getSquareBonus, wasm ); - SET_VTABLE_ENTRY( wuctxt->super.vtable, util_userError, wasm ); SET_VTABLE_ENTRY( wuctxt->super.vtable, util_notifyMove, wasm ); SET_VTABLE_ENTRY( wuctxt->super.vtable, util_notifyTrade, wasm ); @@ -334,6 +523,7 @@ wasm_util_make( MPFORMAL CurGameInfo* gi, XW_DUtilCtxt* dctxt, void* closure ) SET_VTABLE_ENTRY( wuctxt->super.vtable, util_informUndo, wasm ); SET_VTABLE_ENTRY( wuctxt->super.vtable, util_informNetDict, wasm ); SET_VTABLE_ENTRY( wuctxt->super.vtable, util_notifyGameOver, wasm ); + SET_VTABLE_ENTRY( wuctxt->super.vtable, util_engineProgressCallback, wasm ); #ifdef XWFEATURE_HILITECELL SET_VTABLE_ENTRY( wuctxt->super.vtable, util_hiliteCell, wasm ); #endif @@ -359,6 +549,9 @@ wasm_util_make( MPFORMAL CurGameInfo* gi, XW_DUtilCtxt* dctxt, void* closure ) SET_VTABLE_ENTRY( wuctxt->super.vtable, util_showChat, wasm ); SET_VTABLE_ENTRY( wuctxt->super.vtable, util_getDevUtilCtxt, wasm ); + size_t sizeInBytes = sizeof(*wuctxt->super.vtable); + assertTableFull( wuctxt->super.vtable, sizeInBytes, "wasmutilctx" ); + LOG_RETURNF( "%p", wuctxt ); return (XW_UtilCtxt*)wuctxt; }