Merge branch 'android_branch' into french_xlation

Conflicts:
	xwords4/android/XWords4/res/values/strings.xml
This commit is contained in:
Eric House 2011-09-07 22:02:04 -07:00
commit 8a856721cd
28 changed files with 250 additions and 217 deletions

View file

@ -1,4 +1,4 @@
/* Keep these in sync with the constants in XW_UtilCtxt.java */
/* Keep these in sync with the constants in UtilCtxt.java */
#ifndef _LOCALIZEDSTRINCLUDES_H_
@ -24,10 +24,8 @@
# define STRD_TRADED 18
# define STR_LOSTTURN 19
# define STR_COMMIT_CONFIRM 20
# define STR_LOCAL_NAME 21
# define STR_NONLOCAL_NAME 22
# define STR_BONUS_ALL 23
# define STRD_TURN_SCORE 24
# define STR_BONUS_ALL 21
# define STRD_TURN_SCORE 22
# define N_AND_USER_STRINGS 24
# define N_AND_USER_STRINGS 22
#endif

View file

@ -513,6 +513,7 @@ makeDict( MPFORMAL JNIEnv *env, JNIUtilCtxt* jniutil, jstring jname,
/* copy the name */
anddict->super.name = getStringCopy( MPPARM(mpool) env, jname );
XP_LOGF( "%s: setting dict name: %s", __func__, anddict->super.name );
anddict->super.langName = getStringCopy( MPPARM(mpool) env, jlangname );
return (DictionaryCtxt*)anddict;

View file

@ -399,12 +399,10 @@ and_util_bonusSquareHeld( XW_UtilCtxt* uc, XWBonusType bonus )
}
static void
and_util_playerScoreHeld( XW_UtilCtxt* uc, const XP_UCHAR* txt )
and_util_playerScoreHeld( XW_UtilCtxt* uc, XP_U16 player )
{
UTIL_CBK_HEADER( "playerScoreHeld", "(Ljava/lang/String;)V" );
jstring jmsg = (*env)->NewStringUTF( env, txt );
(*env)->CallVoidMethod( env, util->jutil, mid, jmsg );
(*env)->DeleteLocalRef( env, jmsg );
UTIL_CBK_HEADER( "playerScoreHeld", "(I)V" );
(*env)->CallVoidMethod( env, util->jutil, mid, player );
UTIL_CBK_TAIL();
}
#endif

View file

@ -907,6 +907,25 @@ Java_org_eehouse_android_xw4_jni_XwJNI_model_1getNMoves
return result;
}
JNIEXPORT jstring JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_model_1getPlayersLastScore
(JNIEnv* env, jclass C, jint gamePtr, jint player )
{
jstring result = NULL;
XWJNI_START();
XP_ASSERT( !!state->game.model );
XP_UCHAR buf[64];
XP_U16 buflen = sizeof(buf);
if ( !model_getPlayersLastScore( state->game.model, player, buf,
&buflen ) ) {
buf[0] = '\0';
}
result = (*env)->NewStringUTF( env, buf );
(*env)->DeleteLocalRef( env, result );
XWJNI_END();
return result;
}
JNIEXPORT jstring JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_server_1writeFinalScores
( JNIEnv* env, jclass C, jint gamePtr )

View file

@ -98,8 +98,6 @@
<string name="strsd_summaryscored"></string>
<string name="str_lostturn">Torn perdut</string>
<string name="str_commit_confirm">Voleu fer la jugada?\n</string>
<string name="str_local_name">%s</string>
<string name="str_nonlocal_namef">%s (remot)</string>
<string name="str_bonus_all">Bonificació per usar totes les fitxes: 50\n</string>
<string name="strd_turn_score">Puntuació del torn: %d\n</string>
@ -110,7 +108,6 @@
<string name="str_tiles_must_contact">Les fitxes noves han de tocar alguna de les que ja estan jugades al tauler (o la casella central en la primera jugada).</string>
<string name="str_not_your_turn">No podeu fer això, no és el vostre torn!</string>
<string name="str_no_peek_robot_tiles">No podeu mirar les fitxes del robot!</string>
<string name="str_cant_trade_mid_move">Recolliu les fitxes posades al tauler abans de canviar fitxer.</string>
<string name="str_too_few_tiles_left_to_trade">Hi ha poques fitxes al saquet i ja no podeu canviar-les.</string>
<string name="str_cant_undo_tileassign">L\'assignació de fitxers no es pot desfer.</string>
<string name="str_cant_hint_while_disabled">Les pistes es troben inhabilitades per a aquesta partida. Habiliteu-les per a una partida nova al menú Preferències.</string>

View file

@ -97,8 +97,6 @@
<string name="strsd_summaryscored">%1$s:%2$d</string>
<string name="str_lostturn">Tah byl ztracen</string>
<string name="str_commit_confirm">Potvrdit tento tah?\n</string>
<string name="str_local_name">%s</string>
<string name="str_nonlocal_namef">%s (vzdálený)</string>
<string name="str_bonus_all">Bonus za využití všech kamenů: 50\n</string>
<string name="strd_turn_score">Skóre za tah: %d\n</string>
@ -109,7 +107,6 @@
<string name="str_tiles_must_contact">Nové kameny musí navazovat na již položené kameny (nebo se s nimi křížit).</string>
<string name="str_not_your_turn">To nemůžete udělat; není to váš tah!</string>
<string name="str_no_peek_robot_tiles">Nenakukujte na kameny robota!</string>
<string name="str_cant_trade_mid_move">Vzdálený hráč hrál s kameny před výměnou.</string>
<string name="str_too_few_tiles_left_to_trade">Zbývá příliš málo kamenů pro výměnu.</string>
<string name="str_cant_undo_tileassign">Přiřazení kamene nemůže být vráceno zpět.</string>
<string name="str_cant_hint_while_disabled">Pro tuto hru je zakázána nápověda. Pro novou hru ji můžete povolit v Předvolbách.</string>

View file

@ -96,8 +96,6 @@
<string name="strsd_summaryscored">%1$s:%2$d</string>
<string name="str_lostturn">Ťah bol stratený</string>
<string name="str_commit_confirm">Potvrdiť tento ťah?\n</string>
<string name="str_local_name">%s</string>
<string name="str_nonlocal_namef">%s (vzdialený)</string>
<string name="str_bonus_all">Bonus za využitie všetkých kameňov: 50\n</string>
<string name="strd_turn_score">Skóre za ťah: %d\n</string>
@ -108,7 +106,6 @@
<string name="str_tiles_must_contact">Nové kamene musia naväzovať na už položené kamene (alebo sa s nimi krížiť).</string>
<string name="str_not_your_turn">To nemôžete spraviť; nie je to váš ťah!</string>
<string name="str_no_peek_robot_tiles">Nenakúkajte na kamene robota!</string>
<string name="str_cant_trade_mid_move">Vzdialený hráč hral s kameňmi pred výmenou.</string>
<string name="str_too_few_tiles_left_to_trade">Zostáva príliž málo kameňov na výmenu.</string>
<string name="str_cant_undo_tileassign">Priradenie kameňa nemôže byť vrátené spät.</string>
<string name="str_cant_hint_while_disabled">Pre túto hru je zakázaná nápoveda. Pre novú hru ju môžete povoliť v Predvolbách.</string>

View file

@ -91,6 +91,7 @@
<string name="git_rev_title">Source version id</string>
<string name="relay_port">Relay game port</string>
<string name="proxy_port">Relay device port</string>
<string name="name_dict_fmt">%1$s/%2$s</string>
<!--string name="dict_url">http://10.0.2.2/~eehouse/and_dicts</string-->

View file

@ -479,6 +479,10 @@
bonus square. Triple-word -->
<string name="bonus_w3x_summary">3W</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>
<!-- If a networked game is opened and is not complete, i.e. if it
is listed as expecting remote players who have not yet shown
up, then the most likely explanation is that none has been
@ -691,7 +695,7 @@
<string name="strsd_summaryscored">%1$s:%2$d</string>
<!-- Used in formatting reports of trades (exchanges of tiles).
Number of tiles traded is substituted for %d-->
<string name="strd_traded">Traded %d</string>
<string name="strd_traded">Exchanged %d tiles</string>
<!-- Used in formatting history and move reports; means user
skipped a turn because of an attempted illegal move/play of a
phony -->

View file

@ -14,11 +14,13 @@
<org.eehouse.android.xw4.XWEditTextPreference
android:key="@string/key_player1_name"
android:title="@string/pref_player1_name"
android:capitalize="words"
android:defaultValue=""
/>
<org.eehouse.android.xw4.XWEditTextPreference
android:key="@string/key_player2_name"
android:title="@string/pref_player2_name"
android:capitalize="words"
android:defaultValue="ignored"
android:summary="@string/tell_unused"
android:enabled="false"
@ -26,6 +28,7 @@
<org.eehouse.android.xw4.XWEditTextPreference
android:key="@string/key_player3_name"
android:title="@string/pref_player3_name"
android:capitalize="words"
android:defaultValue=""
android:summary="@string/tell_unused"
android:enabled="false"
@ -33,6 +36,7 @@
<org.eehouse.android.xw4.XWEditTextPreference
android:key="@string/key_player4_name"
android:title="@string/pref_player4_name"
android:capitalize="words"
android:defaultValue=""
android:summary="@string/tell_unused"
android:enabled="false"

View file

@ -342,8 +342,6 @@ public class BoardActivity extends XWActivity
setContentView( R.layout.board );
m_timers = new TimerRunnable[4]; // needs to be in sync with
// XWTimerReason
m_gi = new CurGameInfo( this );
m_view = (BoardView)findViewById( R.id.board_view );
m_tradeButtons = findViewById( R.id.exchange_buttons );
m_exchCommmitButton = (Button)findViewById( R.id.exchange_commit );
@ -930,8 +928,15 @@ public class BoardActivity extends XWActivity
}
@Override
public void playerScoreHeld( final String text )
public void playerScoreHeld( int player )
{
String expl = XwJNI.model_getPlayersLastScore( m_jniGamePtr,
player );
if ( expl.length() == 0 ) {
expl = getString( R.string.no_moves_made );
}
String name = m_gi.players[player].name;
final String text = String.format( "%s\n%s", name, expl );
post( new Runnable() {
public void run() {
Toast.makeText( BoardActivity.this, text,
@ -1072,9 +1077,6 @@ public class BoardActivity extends XWActivity
case UtilCtxt.ERR_NO_PEEK_ROBOT_TILES:
resid = R.string.str_no_peek_robot_tiles;
break;
case UtilCtxt.ERR_CANT_TRADE_MID_MOVE:
resid = R.string.str_cant_trade_mid_move;
break;
case UtilCtxt.ERR_NO_EMPTY_TRADE:
resid = R.string.str_no_empty_trade;
break;
@ -1167,20 +1169,19 @@ public class BoardActivity extends XWActivity
private void loadGame()
{
if ( 0 == m_jniGamePtr ) {
String[] dictNames = m_gi.dictNames();
String[] dictNames = GameUtils.dictNames( this, m_rowid );
GameUtils.DictPairs pairs = GameUtils.openDicts( this, dictNames );
if ( pairs.anyMissing( dictNames ) ) {
showDictGoneFinish();
} else {
String langName = m_gi.langName();
Assert.assertNull( m_gameLock );
m_gameLock = new GameUtils.GameLock( m_rowid, true ).lock();
byte[] stream = GameUtils.savedGame( this, m_gameLock );
m_gi = new CurGameInfo( this );
XwJNI.gi_from_stream( m_gi, stream );
String langName = m_gi.langName();
m_jniGamePtr = XwJNI.initJNI();
@ -1404,6 +1405,7 @@ public class BoardActivity extends XWActivity
XwJNI.game_dispose( m_jniGamePtr );
m_jniGamePtr = 0;
m_gi = null;
m_gameLock.unlock();
m_gameLock = null;

View file

@ -128,11 +128,11 @@ public class DBUtils {
setGiFlags( cursor.getInt(cursor.
getColumnIndex(DBHelper.GIFLAGS))
);
summary.players =
parsePlayers( cursor.getString(cursor.
getColumnIndex(DBHelper.
PLAYERS)),
summary.nPlayers );
String players = cursor.
getString(cursor.getColumnIndex( DBHelper.PLAYERS ));
summary.readPlayers( players );
summary.dictLang =
cursor.getInt(cursor.
getColumnIndex(DBHelper.DICTLANG));
@ -761,31 +761,6 @@ public class DBUtils {
}
}
private static String[] parsePlayers( final String players, int nPlayers ){
String[] result = null;
if ( null != players ) {
result = new String[nPlayers];
String sep = "vs. ";
if ( players.contains("\n") ) {
sep = "\n";
}
int ii, nxt;
for ( ii = 0, nxt = 0; ; ++ii ) {
int prev = nxt;
nxt = players.indexOf( sep, nxt );
String name = -1 == nxt ?
players.substring( prev ) : players.substring( prev, nxt );
result[ii] = name;
if ( -1 == nxt ) {
break;
}
nxt += sep.length();
}
}
return result;
}
private static void initDB( Context context )
{
if ( null == s_dbHelper ) {

View file

@ -167,7 +167,7 @@ public class GameConfig extends XWActivity
onClick( DialogInterface dlg,
int button ) {
getPlayerSettings( dlg );
loadPlayers();
loadPlayersList();
}
})
.setNegativeButton( R.string.button_cancel, null )
@ -192,18 +192,19 @@ public class GameConfig extends XWActivity
// break;
case FORCE_REMOTE:
dlpos = new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg,
int whichButton ) {
loadPlayersList();
}
};
dialog = new AlertDialog.Builder( this )
.setTitle( R.string.force_title )
.setView( Utils.inflate( this, layoutForDlg(id) ) )
.setPositiveButton( R.string.button_ok,
new DialogInterface.OnClickListener() {
public void onClick( DialogInterface dlg,
int whichButton ) {
loadPlayers();
}
})
.setPositiveButton( R.string.button_ok, dlpos )
.create();
dialog.setOnDismissListener( new DialogInterface.OnDismissListener() {
DialogInterface.OnDismissListener dismiss =
new DialogInterface.OnDismissListener() {
@Override
public void onDismiss( DialogInterface di )
{
@ -211,10 +212,11 @@ public class GameConfig extends XWActivity
Toast.makeText( GameConfig.this,
R.string.forced_consistent,
Toast.LENGTH_SHORT).show();
loadPlayers();
loadPlayersList();
}
}
});
};
dialog.setOnDismissListener( dismiss );
break;
case CONFIRM_CHANGE_PLAY:
case CONFIRM_CHANGE:
@ -348,9 +350,11 @@ public class GameConfig extends XWActivity
Spinner spinner =
(Spinner)((Dialog)di).findViewById( R.id.dict_spinner );
int position = spinner.getSelectedItemPosition();
String[] dicts = DictLangCache.getHaveLang( this, m_gi.dictLang );
if ( position < dicts.length ) {
lp.dictName = dicts[position];
ArrayAdapter<String> adapter =
(ArrayAdapter<String>)spinner.getAdapter();
if ( position < adapter.getCount() ) {
lp.dictName = adapter.getItem(position);
}
lp.setIsRobot( Utils.getChecked( dialog, R.id.robot_check ) );
@ -453,7 +457,9 @@ public class GameConfig extends XWActivity
handleLockedChange();
}
m_gi = new CurGameInfo( this, m_giOrig );
if ( null == m_gi ) {
m_gi = new CurGameInfo( this, m_giOrig );
}
m_carOrig = new CommsAddrRec( this );
if ( XwJNI.game_hasComms( gamePtr ) ) {
@ -493,7 +499,7 @@ public class GameConfig extends XWActivity
adjustConnectStuff();
}
loadPlayers();
loadPlayersList();
configLangSpinner();
m_phoniesSpinner.setSelection( m_gi.phoniesAction.ordinal() );
@ -530,7 +536,7 @@ public class GameConfig extends XWActivity
public void deleteCalled( int myPosition, final String name )
{
if ( m_gi.delete( myPosition ) ) {
loadPlayers();
loadPlayersList();
}
}
@ -560,11 +566,11 @@ public class GameConfig extends XWActivity
int curIndex = m_gi.nPlayers;
if ( curIndex < CurGameInfo.MAX_NUM_PLAYERS ) {
m_gi.addPlayer(); // ups nPlayers
loadPlayers();
loadPlayersList();
}
} else if ( m_jugglePlayersButton == view ) {
m_gi.juggle();
loadPlayers();
loadPlayersList();
} else if ( m_joinPublicCheck == view ) {
adjustConnectStuff();
} else if ( m_gameLockedCheck == view ) {
@ -617,11 +623,11 @@ public class GameConfig extends XWActivity
return consumed || super.onKeyDown( keyCode, event );
}
private void loadPlayers()
private void loadPlayersList()
{
m_playerLayout.removeAllViews();
String[] names = m_gi.visibleNames();
String[] names = m_gi.visibleNames( false );
// only enable delete if one will remain (or two if networked)
boolean canDelete = names.length > 2
|| (m_notNetworkedGame && names.length > 1);
@ -667,7 +673,7 @@ public class GameConfig extends XWActivity
showDialog( FORCE_REMOTE );
}
adjustPlayersLabel();
} // loadPlayers
} // loadPlayersList
private String[] buildListWithBrowse( String[] input )
{
@ -683,7 +689,7 @@ public class GameConfig extends XWActivity
return result;
}
private void configDictSpinner( final Dialog dialog, final LocalPlayer lp )
private void configDictSpinner( final Dialog dialog, LocalPlayer lp )
{
Spinner dictsSpinner =
(Spinner)dialog.findViewById( R.id.dict_spinner );
@ -703,8 +709,6 @@ public class GameConfig extends XWActivity
if ( chosen.equals( m_browseText ) ) {
DictsActivity.launchAndDownload( GameConfig.this,
m_gi.dictLang );
} else {
lp.dictName = chosen;
}
}

View file

@ -460,6 +460,23 @@ public class GameUtils {
}
}
public static String[] dictNames( Context context, long rowid,
int[] missingLang )
{
byte[] stream = savedGame( context, rowid );
CurGameInfo gi = new CurGameInfo( context );
XwJNI.gi_from_stream( gi, stream );
if ( null != missingLang ) {
missingLang[0] = gi.dictLang;
}
return gi.dictNames();
}
public static String[] dictNames( Context context, long rowid )
{
return dictNames( context, rowid, null );
}
public static boolean gameDictsHere( Context context, long rowid )
{
return gameDictsHere( context, rowid, null, null );
@ -471,17 +488,10 @@ public class GameUtils {
String[][] missingNames,
int[] missingLang )
{
byte[] stream = savedGame( context, rowid );
CurGameInfo gi = new CurGameInfo( context );
XwJNI.gi_from_stream( gi, stream );
final String[] dictNames = gi.dictNames();
String[] dictNames = dictNames( context, rowid, missingLang );
HashSet<String> missingSet;
String[] installed = dictList( context );
if ( null != missingLang ) {
missingLang[0] = gi.dictLang;
}
missingSet = new HashSet<String>( Arrays.asList( dictNames ) );
missingSet.remove( null );
missingSet.removeAll( Arrays.asList(installed) );

View file

@ -235,18 +235,22 @@ public class CurGameInfo {
return !consistent;
}
public String[] visibleNames()
public String[] visibleNames( boolean withDicts )
{
String nameFmt = withDicts? m_context.getString( R.string.name_dict_fmt )
: "%s";
String[] names = new String[nPlayers];
for ( int ii = 0; ii < nPlayers; ++ii ) {
LocalPlayer lp = players[ii];
if ( lp.isLocal || serverRole == DeviceRole.SERVER_STANDALONE ) {
String name;
if ( lp.isRobot() ) {
String format = m_context.getString( R.string.robot_namef );
names[ii] = String.format( format, lp.name );
name = String.format( format, lp.name );
} else {
names[ii] = lp.name;
name = lp.name;
}
names[ii] = String.format( nameFmt, name, dictName(lp) );
} else {
names[ii] = m_context.getString( R.string.guest_name );
}

View file

@ -97,6 +97,33 @@ public class GameSummary {
return result;
}
public void readPlayers( String playersStr )
{
if ( null != playersStr ) {
players = new String[nPlayers];
String sep;
if ( playersStr.contains("\n") ) {
sep = "\n";
} else {
sep = m_context.getString( R.string.vs_join );
}
int ii, nxt;
for ( ii = 0, nxt = 0; ; ++ii ) {
int prev = nxt;
nxt = playersStr.indexOf( sep, nxt );
String name = -1 == nxt ?
playersStr.substring( prev ) :
playersStr.substring( prev, nxt );
players[ii] = name;
if ( -1 == nxt ) {
break;
}
nxt += sep.length();
}
}
}
public void setPlayerSummary( String summary )
{
m_playersSummary = summary;
@ -213,7 +240,7 @@ public class GameSummary {
{
String[] names = null;
if ( null != m_gi ) {
names = m_gi.visibleNames();
names = m_gi.visibleNames( false );
} else if ( null != m_playersSummary ) {
names = TextUtils.split( m_playersSummary, "\n" );
}

View file

@ -48,7 +48,7 @@ public interface UtilCtxt {
void setIsServer( boolean isServer );
void bonusSquareHeld( int bonus );
void playerScoreHeld( String text );
void playerScoreHeld( int player );
static final int STRD_ROBOT_TRADED = 1;
static final int STR_ROBOT_MOVED = 2;
@ -70,10 +70,8 @@ public interface UtilCtxt {
static final int STRD_TRADED = 18;
static final int STR_LOSTTURN = 19;
static final int STR_COMMIT_CONFIRM = 20;
static final int STR_LOCAL_NAME = 21;
static final int STR_NONLOCAL_NAME = 22;
static final int STR_BONUS_ALL = 23;
static final int STRD_TURN_SCORE = 24;
static final int STR_BONUS_ALL = 21;
static final int STRD_TURN_SCORE = 22;
String getUserString( int stringCode );
static final int QUERY_COMMIT_TURN = 0;
@ -97,11 +95,10 @@ public interface UtilCtxt {
static final int ERR_REG_UNEXPECTED_USER = 10;
static final int ERR_REG_SERVER_SANS_REMOTE = 11;
static final int STR_NEED_BT_HOST_ADDR = 12;
static final int ERR_CANT_TRADE_MID_MOVE = 13;
static final int ERR_NO_EMPTY_TRADE = 14;
static final int ERR_CANT_UNDO_TILEASSIGN = 15;
static final int ERR_CANT_HINT_WHILE_DISABLED = 16;
static final int ERR_RELAY_BASE = 17;
static final int ERR_NO_EMPTY_TRADE = 13;
static final int ERR_CANT_UNDO_TILEASSIGN = 14;
static final int ERR_CANT_HINT_WHILE_DISABLED = 15;
static final int ERR_RELAY_BASE = 16;
void userError( int id );
void notifyGameOver();

View file

@ -87,7 +87,7 @@ public class UtilCtxtImpl implements UtilCtxt {
{
}
public void playerScoreHeld( String text )
public void playerScoreHeld( int player )
{
}
@ -155,12 +155,6 @@ public class UtilCtxtImpl implements UtilCtxt {
case UtilCtxt.STR_COMMIT_CONFIRM:
id = R.string.str_commit_confirm;
break;
case UtilCtxt.STR_LOCAL_NAME:
id = R.string.str_local_name;
break;
case UtilCtxt.STR_NONLOCAL_NAME:
id = R.string.str_nonlocal_name;
break;
case UtilCtxt.STR_BONUS_ALL:
id = R.string.str_bonus_all;
break;

View file

@ -202,6 +202,7 @@ public class XwJNI {
public static native String model_writeGameHistory( int gamePtr,
boolean gameOver );
public static native int model_getNMoves( int gamePtr );
public static native String model_getPlayersLastScore( int gamePtr, int player );
// Server
public static native void server_reset( int gamePtr );

View file

@ -720,20 +720,21 @@ hideMiniWindow( BoardCtxt* board, XP_Bool destroy, MiniWindowType winType )
#endif
static XP_Bool
warnBadWords( XP_UCHAR* word, void* closure )
warnBadWords( const XP_UCHAR* word, XP_Bool isLegal, void* closure )
{
BadWordInfo bwi;
XP_Bool ok;
BoardCtxt* board = (BoardCtxt*)closure;
XP_S16 turn = server_getCurrentTurn( board->server );
XP_Bool ok = XP_TRUE;
if ( !isLegal ) {
BadWordInfo bwi;
BoardCtxt* board = (BoardCtxt*)closure;
XP_S16 turn = server_getCurrentTurn( board->server );
bwi.nWords = 1;
bwi.words[0] = word;
ok = !board->badWordRejected
&& util_warnIllegalWord( board->util, &bwi, turn, XP_FALSE );
board->badWordRejected = !ok || board->badWordRejected;
bwi.nWords = 1;
bwi.words[0] = word;
ok = !board->badWordRejected
&& util_warnIllegalWord( board->util, &bwi, turn, XP_FALSE );
board->badWordRejected = !ok || board->badWordRejected;
}
return ok;
} /* warnBadWords */
@ -757,18 +758,18 @@ board_commitTurn( BoardCtxt* board )
nothing */
} else if ( checkRevealTray( board ) ) {
if ( pti->tradeInProgress ) {
TileBit traySelBits = pti->traySelBits;
result = XP_TRUE; /* there's at least the window to clean up
after */
/* server_commitTrade() changes selPlayer, so board_endTrade
must be called first() */
(void)board_endTrade( board );
if ( NO_TILES == pti->traySelBits ) {
if ( NO_TILES == traySelBits ) {
util_userError( board->util, ERR_NO_EMPTY_TRADE );
} else if ( util_userQuery( board->util, QUERY_COMMIT_TRADE,
(XWStreamCtxt*)NULL ) ) {
TileBit traySelBits = pti->traySelBits;
/* server_commitTrade() changes selPlayer, so board_endTrade
must be called first() */
(void)board_endTrade( board );
result = server_commitTrade( board->server, traySelBits );
(void)server_commitTrade( board->server, traySelBits );
}
} else {
XP_Bool warn, legal;
@ -945,7 +946,9 @@ timerFiredForPen( BoardCtxt* board )
{
XP_Bool draw = XP_FALSE;
const XP_UCHAR* text = (XP_UCHAR*)NULL;
#ifdef XWFEATURE_MINIWIN
XP_UCHAR buf[80];
#endif
if ( board->penDownObject == OBJ_BOARD ) {
if ( !dragDropInProgress( board ) || !dragDropHasMoved( board ) ) {
@ -974,7 +977,6 @@ timerFiredForPen( BoardCtxt* board )
board->penTimerFired = XP_TRUE;
}
} else if ( board->penDownObject == OBJ_SCORE ) {
LocalPlayer* lp;
XP_S16 scoreIndex = figureScoreRectTapped( board, board->penDownX,
board->penDownY );
/* I've seen this assert fire on simulator. No log is kept so I can't
@ -982,11 +984,11 @@ timerFiredForPen( BoardCtxt* board )
/* XP_ASSERT( player >= 0 ); */
if ( scoreIndex > CURSOR_LOC_REM ) {
XP_U16 player = scoreIndex - 1;
#ifdef XWFEATURE_MINIWIN
const XP_UCHAR* format;
XP_UCHAR scoreExpl[48];
XP_U16 explLen;
lp = &board->gi->players[player];
LocalPlayer* lp = &board->gi->players[player];
format = util_getUserString( board->util, lp->isLocal?
STR_LOCAL_NAME: STR_NONLOCAL_NAME );
XP_SNPRINTF( buf, sizeof(buf), format, emptyStringIfNull(lp->name) );
@ -998,10 +1000,9 @@ timerFiredForPen( BoardCtxt* board )
XP_ASSERT( XP_STRLEN(buf) + explLen < sizeof(buf) );
XP_STRCAT( buf, scoreExpl );
}
#ifdef XWFEATURE_MINIWIN
text = buf;
#else
util_playerScoreHeld( board->util, buf );
util_playerScoreHeld( board->util, player );
#endif
}
@ -2077,13 +2078,12 @@ board_beginTrade( BoardCtxt* board )
result = preflight( board );
if ( result ) {
/* check turn before tradeInProgress so I can't tell my opponent's in a
trade */
if ( 0 != model_getCurrentMoveCount( board->model, board->selPlayer )){
util_userError( board->util, ERR_CANT_TRADE_MID_MOVE );
} else if ( server_countTilesInPool(board->server) < MIN_TRADE_TILES){
if ( server_countTilesInPool(board->server) < MIN_TRADE_TILES){
util_userError( board->util, ERR_TOO_FEW_TILES_LEFT_TO_TRADE );
} else {
model_resetCurrentTurn( board->model, board->selPlayer );
XP_ASSERT( 0 == model_getCurrentMoveCount( board->model,
board->selPlayer ) );
#ifdef XWFEATURE_MINIWIN
board->tradingMiniWindowInvalid = XP_TRUE;
#endif

View file

@ -1118,7 +1118,7 @@ considerScoreWordHasBlanks( EngineCtxt* engine, XP_U16 blanksLeft,
score = figureMoveScore( engine->model, engine->turn,
&posmove->moveInfo,
engine, (XWStreamCtxt*)NULL,
(WordNotifierInfo*)NULL, NULL, 0 );
(WordNotifierInfo*)NULL );
/* First, check that the score is even what we're interested in. If
it is, then go to the expense of filling in a PossibleMove to be

View file

@ -1933,6 +1933,23 @@ model_writeGameHistory( ModelCtxt* model, XWStreamCtxt* stream,
}
} /* model_writeGameHistory */
typedef struct _FirstWordData {
XP_UCHAR word[32];
} FirstWordData;
static XP_Bool
getFirstWord( const XP_UCHAR* word, XP_Bool isLegal, void* closure )
{
LOG_FUNC();
if ( isLegal ) {
FirstWordData* data = (FirstWordData*)closure;
if ( '\0' == data->word[0] && '\0' != word[0] ) {
XP_STRCAT( data->word, word );
}
}
return XP_TRUE;
}
static void
scoreLastMove( ModelCtxt* model, MoveInfo* moveInfo, XP_U16 howMany,
XP_UCHAR* buf, XP_U16* bufLen )
@ -1945,8 +1962,9 @@ scoreLastMove( ModelCtxt* model, MoveInfo* moveInfo, XP_U16 howMany,
XP_STRNCPY( buf, str, len + 1 );
} else {
XP_U16 score;
XP_UCHAR wordBuf[MAX_ROWS+1];
const XP_UCHAR* format;
WordNotifierInfo notifyInfo;
FirstWordData data;
ModelCtxt* tmpModel = makeTmpModel( model, NULL, NULL, NULL, NULL );
XP_U16 turn;
@ -1959,14 +1977,16 @@ scoreLastMove( ModelCtxt* model, MoveInfo* moveInfo, XP_U16 howMany,
XP_ASSERT( 0 );
}
data.word[0] = '\0';
notifyInfo.proc = getFirstWord;
notifyInfo.closure = &data;
score = figureMoveScore( tmpModel, turn, moveInfo, (EngineCtxt*)NULL,
(XWStreamCtxt*)NULL, (WordNotifierInfo*)NULL,
wordBuf, VSIZE(wordBuf) );
(XWStreamCtxt*)NULL, &notifyInfo );
model_destroy( tmpModel );
format = util_getUserString( model->vol.util, STRSD_SUMMARYSCORED );
*bufLen = XP_SNPRINTF( buf, *bufLen, format, wordBuf, score );
*bufLen = XP_SNPRINTF( buf, *bufLen, format, data.word, score );
}
} /* scoreLastMove */

View file

@ -238,7 +238,8 @@ void model_countAllTrayTiles( ModelCtxt* model, XP_U16* counts,
/********************* scoring ********************/
typedef XP_Bool (*WordNotifierProc)( XP_UCHAR* word, void* closure );
typedef XP_Bool (*WordNotifierProc)( const XP_UCHAR* word, XP_Bool isLegal,
void* closure );
typedef struct WordNotifierInfo {
WordNotifierProc proc;
void* closure;
@ -265,8 +266,7 @@ void model_figureFinalScores( ModelCtxt* model, ScoresArray* scores,
/* figureMoveScore is meant only for the engine's use */
XP_U16 figureMoveScore( const ModelCtxt* model, XP_U16 turn, MoveInfo* mvInfo,
EngineCtxt* engine, XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo, XP_UCHAR* mainWord,
XP_U16 mainWordLen );
WordNotifierInfo* notifyInfo );
/********************* persistence ********************/
#ifdef INCLUDE_IO_SUPPORT

View file

@ -42,8 +42,7 @@ static XP_S16 checkScoreMove( ModelCtxt* model, XP_S16 turn,
XP_Bool silent, WordNotifierInfo* notifyInfo );
static XP_U16 scoreWord( const ModelCtxt* model, XP_U16 turn, MoveInfo* movei,
EngineCtxt* engine, XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo, XP_UCHAR* mainWord,
XP_U16 mainWordLen );
WordNotifierInfo* notifyInfo );
/* for formatting when caller wants an explanation of the score. These live
in separate function called only when stream != NULL so that they'll have
@ -64,8 +63,7 @@ static void wordScoreFormatterAddTile( WordScoreFormatter* fmtr, Tile tile,
XP_U16 tileMultiplier,
XP_Bool isBlank );
static void wordScoreFormatterFinish( WordScoreFormatter* fmtr, Tile* word,
XWStreamCtxt* stream, XP_UCHAR* mainWord,
XP_U16 mainWordLen );
XWStreamCtxt* stream );
static void formatWordScore( XWStreamCtxt* stream, XP_U16 wordScore,
XP_U16 moveMultiplier );
static void formatSummary( XWStreamCtxt* stream, const ModelCtxt* model,
@ -104,7 +102,7 @@ adjustScoreForUndone( ModelCtxt* model, MoveInfo* mi, XP_U16 turn )
} else {
moveScore = figureMoveScore( model, turn, mi, (EngineCtxt*)NULL,
(XWStreamCtxt*)NULL,
(WordNotifierInfo*)NULL, NULL, 0 );
(WordNotifierInfo*)NULL );
}
player->score -= moveScore;
player->curMoveScore = 0;
@ -241,7 +239,7 @@ checkScoreMove( ModelCtxt* model, XP_S16 turn, EngineCtxt* engine,
if ( isLegalMove( model, &moveInfo, silent ) ) {
score = figureMoveScore( model, turn, &moveInfo, engine, stream,
notifyInfo, NULL, 0 );
notifyInfo );
}
} else if ( !silent ) { /* tiles out of line */
util_userError( model->vol.util, ERR_TILES_NOT_IN_LINE );
@ -450,8 +448,7 @@ isLegalMove( ModelCtxt* model, MoveInfo* mInfo, XP_Bool silent )
XP_U16
figureMoveScore( const ModelCtxt* model, XP_U16 turn, MoveInfo* moveInfo,
EngineCtxt* engine, XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo, XP_UCHAR* mainWord,
XP_U16 mainWordLen )
WordNotifierInfo* notifyInfo )
{
XP_U16 col, row;
XP_U16* incr;
@ -480,7 +477,7 @@ figureMoveScore( const ModelCtxt* model, XP_U16 turn, MoveInfo* moveInfo,
}
oneScore = scoreWord( model, turn, moveInfo, (EngineCtxt*)NULL, stream,
notifyInfo, mainWord, mainWordLen );
notifyInfo );
if ( !!stream ) {
formatWordScore( stream, oneScore, moveMultiplier );
}
@ -494,19 +491,10 @@ figureMoveScore( const ModelCtxt* model, XP_U16 turn, MoveInfo* moveInfo,
for ( i = 0, tiles = moveInfo->tiles; i < nTiles; ++i, ++tiles ) {
/* Moves using only one tile will sometimes score only in the
crosscheck direction. Score may still be 0 after the call to
scoreWord above. Keep trying to get some text in mainWord until
something's been scored. */
if ( score > 0 ) {
mainWord = NULL;
}
tmpMI.commonCoord = tiles->varCoord;
tmpMI.tiles[0].tile = tiles->tile;
oneScore = scoreWord( model, turn, &tmpMI, engine, stream,
notifyInfo, mainWord, mainWordLen );
oneScore = scoreWord( model, turn, &tmpMI, engine, stream, notifyInfo );
if ( !!stream ) {
formatWordScore( stream, oneScore, multipliers[i] );
}
@ -566,8 +554,7 @@ scoreWord( const ModelCtxt* model, XP_U16 turn,
MoveInfo* movei, /* new tiles */
EngineCtxt* engine,/* for crosswise caching */
XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo,
XP_UCHAR* mainWord, XP_U16 mainWordLen )
WordNotifierInfo* notifyInfo )
{
XP_U16 tileMultiplier;
XP_U16 restScore = 0;
@ -599,7 +586,7 @@ scoreWord( const ModelCtxt* model, XP_U16 turn,
if ( (end - start) >= 1 ) { /* one-letter word: score 0 */
WordScoreFormatter fmtr;
if ( !!stream || !!mainWord ) {
if ( !!stream ) {
wordScoreFormatterInit( &fmtr, dict );
}
@ -658,7 +645,7 @@ scoreWord( const ModelCtxt* model, XP_U16 turn,
*curTile++ = tile; /* save in case we're checking phonies */
if ( !!stream || !!mainWord ) {
if ( !!stream ) {
wordScoreFormatterAddTile( &fmtr, tile, tileMultiplier,
isBlank );
}
@ -679,17 +666,14 @@ scoreWord( const ModelCtxt* model, XP_U16 turn,
XP_U16 len = curTile - checkWordBuf;
XP_Bool legal = engine_check( dict, checkWordBuf, len );
if ( !legal ) {
XP_UCHAR buf[(MAX_ROWS*2)+1];
dict_tilesToString( dict, checkWordBuf, len, buf,
sizeof(buf) );
(*notifyInfo->proc)( buf, notifyInfo->closure );
}
XP_UCHAR buf[(MAX_ROWS*2)+1];
dict_tilesToString( dict, checkWordBuf, len, buf,
sizeof(buf) );
(void)(*notifyInfo->proc)( buf, legal, notifyInfo->closure );
}
if ( !!stream || !!mainWord ) {
wordScoreFormatterFinish( &fmtr, checkWordBuf, stream,
mainWord, mainWordLen );
if ( !!stream ) {
wordScoreFormatterFinish( &fmtr, checkWordBuf, stream );
}
#ifdef DEBUG
@ -804,8 +788,7 @@ wordScoreFormatterAddTile( WordScoreFormatter* fmtr, Tile tile,
static void
wordScoreFormatterFinish( WordScoreFormatter* fmtr, Tile* word,
XWStreamCtxt* stream, XP_UCHAR* mainWord,
XP_U16 mainWordLen )
XWStreamCtxt* stream )
{
XP_UCHAR buf[(MAX_ROWS*2)+1];
XP_U16 len = dict_tilesToString( fmtr->dict, word, fmtr->nTiles,
@ -817,11 +800,6 @@ wordScoreFormatterFinish( WordScoreFormatter* fmtr, Tile* word,
stream_putBytes( stream, fmtr->fullBuf, fmtr->bufLen );
stream_putU8( stream, ']' );
}
if ( !!mainWord ) {
XP_STRNCPY( mainWord, fmtr->wordBuf, mainWordLen );
}
} /* wordScoreFormatterFinish */
static void

View file

@ -1713,15 +1713,16 @@ server_setGameOverListener( ServerCtxt* server, GameOverListener gol,
} /* server_setGameOverListener */
static XP_Bool
storeBadWords( XP_UCHAR* word, void* closure )
storeBadWords( const XP_UCHAR* word, XP_Bool isLegal, void* closure )
{
ServerCtxt* server = (ServerCtxt*)closure;
if ( !isLegal ) {
ServerCtxt* server = (ServerCtxt*)closure;
XP_STATUSF( "storeBadWords called with \"%s\"", word );
server->illegalWordInfo.words[server->illegalWordInfo.nWords++]
= copyString( server->mpool, word );
XP_STATUSF( "storeBadWords called with \"%s\"", word );
server->illegalWordInfo.words[server->illegalWordInfo.nWords++]
= copyString( server->mpool, word );
}
return XP_TRUE;
} /* storeBadWords */

View file

@ -52,7 +52,6 @@ typedef enum {
ERR_REG_SERVER_SANS_REMOTE,
STR_NEED_BT_HOST_ADDR,
#endif
ERR_CANT_TRADE_MID_MOVE,
ERR_NO_EMPTY_TRADE,
/* ERR_CANT_ENGINE_MID_MOVE, */
/* ERR_NOT_YOUR_TURN_TO_TRADE, */
@ -160,7 +159,7 @@ typedef struct UtilVtable {
#ifndef XWFEATURE_MINIWIN
void (*m_util_bonusSquareHeld)( XW_UtilCtxt* uc, XWBonusType bonus );
void (*m_util_playerScoreHeld)( XW_UtilCtxt* uc, const XP_UCHAR* txt );
void (*m_util_playerScoreHeld)( XW_UtilCtxt* uc, XP_U16 player );
#endif
#ifndef XWFEATURE_STANDALONE_ONLY
@ -266,8 +265,8 @@ struct XW_UtilCtxt {
#ifndef XWFEATURE_MINIWIN
# define util_bonusSquareHeld( uc, b ) \
(uc)->vtable->m_util_bonusSquareHeld( (uc), (b) )
# define util_playerScoreHeld( uc, txt ) \
(uc)->vtable->m_util_playerScoreHeld( (uc), (txt) )
# define util_playerScoreHeld( uc, player ) \
(uc)->vtable->m_util_playerScoreHeld( (uc), (player) )
#endif
#ifndef XWFEATURE_STANDALONE_ONLY

View file

@ -897,6 +897,15 @@ handle_trayEditToggle_off( GtkWidget* widget, GtkAppGlobals* globals )
}
#endif
static void
handle_trade_cancel( GtkWidget* XP_UNUSED(widget), GtkAppGlobals* globals )
{
BoardCtxt* board = globals->cGlobals.game.board;
if ( board_endTrade( board ) ) {
board_draw( board );
}
}
#ifndef XWFEATURE_STANDALONE_ONLY
static void
handle_resend( GtkWidget* XP_UNUSED(widget), GtkAppGlobals* globals )
@ -992,6 +1001,9 @@ makeMenus( GtkAppGlobals* globals, int XP_UNUSED(argc),
(void)createAddItem( fileMenu, "Load dictionary",
GTK_SIGNAL_FUNC(load_dictionary), globals );
(void)createAddItem( fileMenu, "Cancel trade",
GTK_SIGNAL_FUNC(handle_trade_cancel), globals );
fileMenu = makeAddSubmenu( menubar, "Edit" );
(void)createAddItem( fileMenu, "Undo",
@ -1005,7 +1017,6 @@ makeMenus( GtkAppGlobals* globals, int XP_UNUSED(argc),
(void)createAddItem( fileMenu, "Dis-allow tray edit",
GTK_SIGNAL_FUNC(handle_trayEditToggle_off), globals );
#endif
fileMenu = makeAddSubmenu( menubar, "Network" );
#ifndef XWFEATURE_STANDALONE_ONLY
@ -1683,15 +1694,6 @@ gtk_util_getTraySearchLimits( XW_UtilCtxt* XP_UNUSED(uc),
#endif
#ifndef XWFEATURE_MINIWIN
static void
gtk_util_setInTrade( XW_UtilCtxt* uc, XP_U16 turn, XP_Bool entering )
{
XP_LOGF( "%s(turn=%d; entering=%d)", __func__, turn, entering );
XP_USE( uc );
XP_USE( turn );
XP_USE( entering );
}
static void
gtk_util_bonusSquareHeld( XW_UtilCtxt* uc, XWBonusType bonus )
{
@ -1701,11 +1703,19 @@ gtk_util_bonusSquareHeld( XW_UtilCtxt* uc, XWBonusType bonus )
}
static void
gtk_util_playerScoreHeld( XW_UtilCtxt* uc, const XP_UCHAR* txt )
gtk_util_playerScoreHeld( XW_UtilCtxt* uc, XP_U16 player )
{
LOG_FUNC();
XP_USE( uc );
XP_USE( txt );
GtkAppGlobals* globals = (GtkAppGlobals*)uc->closure;
XP_UCHAR scoreExpl[48];
XP_U16 explLen = sizeof(scoreExpl);
if ( model_getPlayersLastScore( globals->cGlobals.game.model,
player, scoreExpl, &explLen ) ) {
XP_LOGF( "got: %s", scoreExpl );
}
}
#endif
@ -1928,7 +1938,6 @@ setupGtkUtilCallbacks( GtkAppGlobals* globals, XW_UtilCtxt* util )
#endif
#ifndef XWFEATURE_MINIWIN
util->vtable->m_util_setInTrade = gtk_util_setInTrade;
util->vtable->m_util_bonusSquareHeld = gtk_util_bonusSquareHeld;
util->vtable->m_util_playerScoreHeld = gtk_util_playerScoreHeld;
#endif

View file

@ -332,10 +332,6 @@ linux_getErrString( UtilErrID id, XP_Bool* silent )
break;
#endif
case ERR_CANT_TRADE_MID_MOVE:
message = "Remove played tiles before trading.";
break;
case ERR_NO_EMPTY_TRADE:
message = "No tiles selected; trade cancelled.";
break;