mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-27 09:58:45 +01:00
add support for trays with up to 9 tiles
This commit is contained in:
parent
8f83a390f1
commit
694953c820
39 changed files with 483 additions and 205 deletions
|
@ -847,7 +847,7 @@ public class BoardDelegate extends DelegateBase
|
|||
case R.id.board_menu_done:
|
||||
int nTiles = XwJNI.model_getNumTilesInTray( m_jniGamePtr,
|
||||
m_view.getCurPlayer() );
|
||||
if ( XWApp.MAX_TRAY_TILES > nTiles ) {
|
||||
if ( m_gi.traySize > nTiles ) {
|
||||
makeNotAgainBuilder( R.string.not_again_done,
|
||||
R.string.key_notagain_done,
|
||||
Action.COMMIT_ACTION )
|
||||
|
|
|
@ -51,14 +51,12 @@ public class EnableSMSAlert extends DlgDelegateAlert {
|
|||
View layout = LocUtils.inflate( context, R.layout.confirm_sms );
|
||||
mSpinner = (Spinner)layout.findViewById( R.id.confirm_sms_reasons );
|
||||
|
||||
OnItemSelectedListener onItemSel = new OnItemSelectedListener() {
|
||||
OnItemSelectedListener onItemSel = new Utils.OnNothingSelDoesNothing() {
|
||||
@Override
|
||||
public void onItemSelected( AdapterView<?> parent, View view,
|
||||
int position, long id ) {
|
||||
checkEnableButton( (AlertDialog)getDialog() );
|
||||
}
|
||||
@Override
|
||||
public void onNothingSelected( AdapterView<?> parent ) {}
|
||||
};
|
||||
mSpinner.setOnItemSelectedListener( onItemSel );
|
||||
|
||||
|
|
|
@ -100,6 +100,7 @@ public class GameConfigDelegate extends DelegateBase
|
|||
// private Spinner m_connectSpinner;
|
||||
private Spinner m_phoniesSpinner;
|
||||
private Spinner m_boardsizeSpinner;
|
||||
private Spinner m_traysizeSpinner;
|
||||
private Spinner m_langSpinner;
|
||||
private Spinner m_smartnessSpinner;
|
||||
private TextView m_connLabel;
|
||||
|
@ -126,6 +127,7 @@ public class GameConfigDelegate extends DelegateBase
|
|||
R.id.duplicate_check,
|
||||
R.id.pick_faceup,
|
||||
R.id.boardsize_spinner,
|
||||
R.id.traysize_spinner,
|
||||
R.id.use_timer,
|
||||
R.id.timer_minutes_edit,
|
||||
R.id.smart_robot,
|
||||
|
@ -524,6 +526,8 @@ public class GameConfigDelegate extends DelegateBase
|
|||
.getSpinner();
|
||||
m_boardsizeSpinner = ((LabeledSpinner)findViewById( R.id.boardsize_spinner ))
|
||||
.getSpinner();
|
||||
m_traysizeSpinner = ((LabeledSpinner)findViewById( R.id.traysize_spinner ))
|
||||
.getSpinner();
|
||||
m_smartnessSpinner = ((LabeledSpinner)findViewById( R.id.smart_robot ))
|
||||
.getSpinner();
|
||||
|
||||
|
@ -680,6 +684,31 @@ public class GameConfigDelegate extends DelegateBase
|
|||
setChecked( R.id.pick_faceup, m_gi.allowPickTiles );
|
||||
|
||||
setBoardsizeSpinner();
|
||||
|
||||
final int[] curSel = {-1};
|
||||
String val = String.format( "%d", m_gi.traySize );
|
||||
SpinnerAdapter adapter = m_traysizeSpinner.getAdapter();
|
||||
for ( int ii = 0; ii < adapter.getCount(); ++ii ) {
|
||||
if ( val.equals( adapter.getItem(ii) ) ) {
|
||||
m_traysizeSpinner.setSelection( ii );
|
||||
curSel[0] = ii;
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_traysizeSpinner
|
||||
.setOnItemSelectedListener( new Utils.OnNothingSelDoesNothing() {
|
||||
@Override
|
||||
public void onItemSelected( AdapterView<?> parent, View spinner,
|
||||
int position, long id ) {
|
||||
if ( curSel[0] != position ) {
|
||||
curSel[0] = position;
|
||||
makeNotAgainBuilder( R.string.not_again_traysize,
|
||||
R.string.key_na_traysize )
|
||||
.show();
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
}
|
||||
} // loadGame
|
||||
|
||||
|
@ -1014,8 +1043,7 @@ public class GameConfigDelegate extends DelegateBase
|
|||
dictsSpinner.setPrompt( getString( R.string.dicts_list_prompt_fmt,
|
||||
langName ) );
|
||||
|
||||
OnItemSelectedListener onSel =
|
||||
new OnItemSelectedListener() {
|
||||
OnItemSelectedListener onSel = new Utils.OnNothingSelDoesNothing() {
|
||||
@Override
|
||||
public void onItemSelected( AdapterView<?> parentView,
|
||||
View selectedItemView,
|
||||
|
@ -1029,9 +1057,6 @@ public class GameConfigDelegate extends DelegateBase
|
|||
m_gi.dictLang );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parentView) {}
|
||||
};
|
||||
|
||||
ArrayAdapter<String> adapter =
|
||||
|
@ -1048,8 +1073,7 @@ public class GameConfigDelegate extends DelegateBase
|
|||
|
||||
final LangsArrayAdapter adapter = DictLangCache.getLangsAdapter( m_activity );
|
||||
|
||||
OnItemSelectedListener onSel =
|
||||
new OnItemSelectedListener() {
|
||||
OnItemSelectedListener onSel = new Utils.OnNothingSelDoesNothing() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parentView,
|
||||
View selectedItemView,
|
||||
|
@ -1067,9 +1091,6 @@ public class GameConfigDelegate extends DelegateBase
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parentView) {}
|
||||
};
|
||||
|
||||
String lang = DictLangCache.getLangName( m_activity, m_gi.dictLang );
|
||||
|
@ -1306,6 +1327,7 @@ public class GameConfigDelegate extends DelegateBase
|
|||
|
||||
position = m_boardsizeSpinner.getSelectedItemPosition();
|
||||
m_gi.boardSize = positionToSize( position );
|
||||
m_gi.traySize = Integer.parseInt( m_traysizeSpinner.getSelectedItem().toString() );
|
||||
|
||||
if ( m_conTypes.contains( CommsConnType.COMMS_CONN_RELAY ) ) {
|
||||
m_car.ip_relay_seeksPublicRoom = m_joinPublicCheck.isChecked();
|
||||
|
|
|
@ -360,7 +360,8 @@ abstract class InviteDelegate extends DelegateBase
|
|||
}
|
||||
spinner.setAdapter( adapter );
|
||||
spinner.setVisibility( View.VISIBLE );
|
||||
spinner.setOnItemSelectedListener( new OnItemSelectedListener() {
|
||||
spinner.setOnItemSelectedListener( new Utils.OnNothingSelDoesNothing() {
|
||||
@Override
|
||||
public void onItemSelected( AdapterView<?> parent,
|
||||
View view, int pos,
|
||||
long id )
|
||||
|
@ -368,8 +369,6 @@ abstract class InviteDelegate extends DelegateBase
|
|||
m_counts.put( item, 1 + pos );
|
||||
tryEnable();
|
||||
}
|
||||
|
||||
public void onNothingSelected( AdapterView<?> parent ) {}
|
||||
} );
|
||||
}
|
||||
|
||||
|
|
|
@ -226,6 +226,7 @@ public class StudyListDelegate extends ListDelegateBase
|
|||
//////////////////////////////////////////////////
|
||||
// AdapterView.OnItemSelectedListener interface
|
||||
//////////////////////////////////////////////////
|
||||
@Override
|
||||
public void onItemSelected( AdapterView<?> parent, View view,
|
||||
int position, long id )
|
||||
{
|
||||
|
@ -234,6 +235,7 @@ public class StudyListDelegate extends ListDelegateBase
|
|||
loadList(); // because language has changed
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected( AdapterView<?> parent )
|
||||
{
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ import android.view.Menu;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
|
@ -820,4 +821,10 @@ public class Utils {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class OnNothingSelDoesNothing
|
||||
implements AdapterView.OnItemSelectedListener {
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parentView) {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ public class XWApp extends Application
|
|||
public static final boolean OFFER_DUALPANE = false;
|
||||
|
||||
public static final String SMS_PUBLIC_HEADER = "-XW4";
|
||||
public static final int MAX_TRAY_TILES = 7; // comtypes.h
|
||||
public static final int MIN_TRAY_TILES = 7; // comtypes.h
|
||||
public static final int SEL_COLOR = Color.argb( 0xFF, 0x09, 0x70, 0x93 );
|
||||
|
||||
public static final int GREEN = 0xFF00AF00;
|
||||
|
|
|
@ -543,6 +543,11 @@ public class XWPrefs {
|
|||
return result;
|
||||
}
|
||||
|
||||
public static int getDefaultTraySize( Context context )
|
||||
{
|
||||
return getPrefsInt( context, R.string.key_tray_size, XWApp.MIN_TRAY_TILES );
|
||||
}
|
||||
|
||||
public static void setAddrTypes( Context context, CommsConnTypeSet set )
|
||||
{
|
||||
int flags = set.toInt();
|
||||
|
|
|
@ -27,7 +27,7 @@ public class BoardDims {
|
|||
public int width, height; // of the bitmap
|
||||
public int scoreLeft, scoreWidth, scoreHt;
|
||||
public int boardWidth, boardHt;
|
||||
public int trayLeft, trayTop, trayWidth, trayHt;
|
||||
public int trayLeft, trayTop, trayWidth, trayHt, traySize;
|
||||
public int cellSize, maxCellSize;
|
||||
public int timerWidth;
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@ import org.eehouse.android.xw4.DictUtils;
|
|||
import org.eehouse.android.xw4.Log;
|
||||
import org.eehouse.android.xw4.R;
|
||||
import org.eehouse.android.xw4.Utils;
|
||||
import org.eehouse.android.xw4.XWApp;
|
||||
import org.eehouse.android.xw4.XWPrefs;
|
||||
import org.eehouse.android.xw4.loc.LocUtils;
|
||||
|
||||
public class CurGameInfo implements Serializable {
|
||||
|
@ -45,6 +47,8 @@ public class CurGameInfo implements Serializable {
|
|||
public static final int MAX_NUM_PLAYERS = 4;
|
||||
|
||||
private static final String BOARD_SIZE = "BOARD_SIZE";
|
||||
private static final String TRAY_SIZE = "TRAY_SIZE";
|
||||
private static final String BINGO_MIN = "BINGO_MIN";
|
||||
private static final String NO_HINTS = "NO_HINTS";
|
||||
private static final String TIMER = "TIMER";
|
||||
private static final String ALLOW_PICK = "ALLOW_PICK";
|
||||
|
@ -61,6 +65,8 @@ public class CurGameInfo implements Serializable {
|
|||
public int gameSeconds;
|
||||
public int nPlayers;
|
||||
public int boardSize;
|
||||
public int traySize;
|
||||
public int bingoMin;
|
||||
public int forceChannel;
|
||||
public DeviceRole serverRole;
|
||||
|
||||
|
@ -89,6 +95,8 @@ public class CurGameInfo implements Serializable {
|
|||
gameSeconds = inDuplicateMode ? (5 * 60)
|
||||
: 60 * nPlayers * CommonPrefs.getDefaultPlayerMinutes( context );
|
||||
boardSize = CommonPrefs.getDefaultBoardSize( context );
|
||||
traySize = XWPrefs.getDefaultTraySize( context );
|
||||
bingoMin = XWApp.MIN_TRAY_TILES;
|
||||
players = new LocalPlayer[MAX_NUM_PLAYERS];
|
||||
serverRole = isNetworked ? DeviceRole.SERVER_ISCLIENT
|
||||
: DeviceRole.SERVER_STANDALONE;
|
||||
|
@ -140,6 +148,8 @@ public class CurGameInfo implements Serializable {
|
|||
nPlayers = src.nPlayers;
|
||||
gameSeconds = src.gameSeconds;
|
||||
boardSize = src.boardSize;
|
||||
traySize = src.traySize;
|
||||
bingoMin = src.bingoMin;
|
||||
players = new LocalPlayer[MAX_NUM_PLAYERS];
|
||||
serverRole = src.serverRole;
|
||||
dictName = src.dictName;
|
||||
|
@ -190,6 +200,8 @@ public class CurGameInfo implements Serializable {
|
|||
try {
|
||||
JSONObject obj = new JSONObject()
|
||||
.put( BOARD_SIZE, boardSize )
|
||||
.put( TRAY_SIZE, traySize )
|
||||
.put( BINGO_MIN, bingoMin )
|
||||
.put( NO_HINTS, hintsNotAllowed )
|
||||
.put( DUP, inDuplicateMode )
|
||||
.put( TIMER, timerEnabled )
|
||||
|
@ -210,6 +222,8 @@ public class CurGameInfo implements Serializable {
|
|||
try {
|
||||
JSONObject obj = new JSONObject( jsonData );
|
||||
boardSize = obj.optInt( BOARD_SIZE, boardSize );
|
||||
traySize = obj.optInt( TRAY_SIZE, traySize );
|
||||
bingoMin = obj.optInt( BINGO_MIN, bingoMin );
|
||||
hintsNotAllowed = obj.optBoolean( NO_HINTS, hintsNotAllowed );
|
||||
inDuplicateMode = obj.optBoolean( DUP, inDuplicateMode );
|
||||
timerEnabled = obj.optBoolean( TIMER, timerEnabled );
|
||||
|
@ -287,6 +301,8 @@ public class CurGameInfo implements Serializable {
|
|||
|| serverRole != other.serverRole
|
||||
|| dictLang != other.dictLang
|
||||
|| boardSize != other.boardSize
|
||||
|| traySize != other.traySize
|
||||
|| bingoMin != other.bingoMin
|
||||
|| hintsNotAllowed != other.hintsNotAllowed
|
||||
|| inDuplicateMode != other.inDuplicateMode
|
||||
|| allowPickTiles != other.allowPickTiles
|
||||
|
@ -320,6 +336,8 @@ public class CurGameInfo implements Serializable {
|
|||
&& gameSeconds == other.gameSeconds
|
||||
&& nPlayers == other.nPlayers
|
||||
&& boardSize == other.boardSize
|
||||
&& traySize == other.traySize
|
||||
&& bingoMin == other.bingoMin
|
||||
&& forceChannel == other.forceChannel
|
||||
&& hintsNotAllowed == other.hintsNotAllowed
|
||||
&& inDuplicateMode == other.inDuplicateMode
|
||||
|
|
|
@ -128,6 +128,7 @@ public class DUtilCtxt {
|
|||
private static final int STRD_DUP_TRADED = 28;
|
||||
private static final int STRSD_DUP_ONESCORE = 29;
|
||||
private static final int STR_PENDING_PLAYER = 30;
|
||||
private static final int STR_BONUS_ALL_SUB = 31;
|
||||
|
||||
public String getUserString( final int stringCode )
|
||||
{
|
||||
|
@ -184,6 +185,9 @@ public class DUtilCtxt {
|
|||
case STR_BONUS_ALL:
|
||||
id = R.string.str_bonus_all;
|
||||
break;
|
||||
case STR_BONUS_ALL_SUB:
|
||||
id = R.string.str_bonus_all_fmt;
|
||||
break;
|
||||
case STRD_TURN_SCORE:
|
||||
id = R.string.strd_turn_score_fmt;
|
||||
break;
|
||||
|
|
|
@ -117,6 +117,7 @@ public class LocDelegate extends ListDelegateBase
|
|||
//////////////////////////////////////////////////
|
||||
// AdapterView.OnItemSelectedListener interface
|
||||
//////////////////////////////////////////////////
|
||||
@Override
|
||||
public void onItemSelected( AdapterView<?> parent, View view,
|
||||
int position, long id )
|
||||
{
|
||||
|
@ -124,7 +125,6 @@ public class LocDelegate extends ListDelegateBase
|
|||
makeNewAdapter();
|
||||
}
|
||||
|
||||
public void onNothingSelected( AdapterView<?> parent )
|
||||
{
|
||||
}
|
||||
@Override
|
||||
public void onNothingSelected( AdapterView<?> parent ) {}
|
||||
}
|
||||
|
|
|
@ -263,11 +263,18 @@
|
|||
/>
|
||||
</org.eehouse.android.xw4.LabeledSpinner>
|
||||
|
||||
<CheckBox android:id="@+id/pick_faceup"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/pick_faceup"
|
||||
/>
|
||||
<org.eehouse.android.xw4.LabeledSpinner
|
||||
style="@style/config_spinner_container"
|
||||
android:id="@+id/traysize_spinner"
|
||||
>
|
||||
<TextView style="@style/config_spinner_label"
|
||||
android:text="@string/tray_size"
|
||||
/>
|
||||
<Spinner style="@style/config_spinner_spinner"
|
||||
android:prompt="@string/tray_size"
|
||||
android:entries="@array/tray_sizes"
|
||||
/>
|
||||
</org.eehouse.android.xw4.LabeledSpinner>
|
||||
|
||||
<org.eehouse.android.xw4.LabeledSpinner
|
||||
style="@style/config_spinner_container"
|
||||
|
@ -282,6 +289,12 @@
|
|||
/>
|
||||
</org.eehouse.android.xw4.LabeledSpinner>
|
||||
|
||||
<CheckBox android:id="@+id/pick_faceup"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/pick_faceup"
|
||||
/>
|
||||
|
||||
<LinearLayout android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
<string name="key_init_nethintsallowed">key_init_nethintsallowed</string>
|
||||
<string name="key_init_autojuggle">key_init_autojuggle</string>
|
||||
<string name="key_board_size">key_board_size</string>
|
||||
<string name="key_tray_size">key_tray_size</string>
|
||||
<string name="key_initial_player_minutes">key_initial_player_minutes</string>
|
||||
<string name="key_default_language">key_default_language</string>
|
||||
<string name="key_default_dict">key_default_dict</string>
|
||||
|
@ -157,6 +158,7 @@
|
|||
<string name="key_na_perms_phonestate">key_na_perms_phonestate</string>
|
||||
<string name="key_na_perms_storage_dicts">key_na_perms_storage_dicts</string>
|
||||
<string name="key_na_newFeatureFilter">key_na_newFeatureFilter</string>
|
||||
<string name="key_na_traysize">key_na_traysize</string>
|
||||
|
||||
<string name="key_na_dupstatus_host">key_na_dupstatus_host</string>
|
||||
<string name="key_na_dupstatus_guest">key_na_dupstatus_guest</string>
|
||||
|
@ -186,6 +188,12 @@
|
|||
<item>11x11</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="tray_sizes">
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
<item>9</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="phony_names">
|
||||
<item>@string/phonies_ignore</item>
|
||||
<item>@string/phonies_warn</item>
|
||||
|
|
|
@ -702,6 +702,8 @@
|
|||
<string name="vs_join">\u0020vs.\u0020</string>
|
||||
<!-- Used in formatting moves and history -->
|
||||
<string name="str_bonus_all">Bonus for using all tiles: 50\n</string>
|
||||
<!-- Used instead of above when fewer than a full tray is required for bingo -->
|
||||
<string name="str_bonus_all_fmt">Bonus for using %1$d tiles: 50\n</string>
|
||||
<!-- Used in formatting moves and history. The total score for
|
||||
one turn is substituted for %1$d.-->
|
||||
<string name="strd_turn_score_fmt">Score for turn: %1$d\n</string>
|
||||
|
@ -811,6 +813,7 @@
|
|||
<string name="initial_player_minutes">Timer minutes per player</string>
|
||||
<!-- preference for board size (15x15, 13x13 etc.) -->
|
||||
<string name="board_size">Board size</string>
|
||||
<string name="tray_size">Tiles in rack</string>
|
||||
<!--
|
||||
############################################################
|
||||
# :Screens:
|
||||
|
@ -1657,6 +1660,13 @@
|
|||
by tapping the Expander Arrow at the upper-right corner of the
|
||||
window.\n\nRead more in the FAQ by tapping the button
|
||||
below.</string>
|
||||
|
||||
<!-- Shown when user changes the new traysize config -->
|
||||
<string name="not_again_traysize">This new setting changes the
|
||||
number of tiles in the rack.\n\nNote: if anyone in your networked
|
||||
game is using an older version of CrossWords this setting will
|
||||
revert to 7 for everyone in the game.</string>
|
||||
|
||||
<string name="board_menu_file_email">Email author…</string>
|
||||
<!-- -->
|
||||
<string name="email_author_subject">Comment about CrossWords</string>
|
||||
|
|
|
@ -65,6 +65,13 @@
|
|||
android:numeric="decimal"
|
||||
/>
|
||||
|
||||
<org.eehouse.android.xw4.XWListPreference
|
||||
android:key="@string/key_tray_size"
|
||||
android:title="@string/tray_size"
|
||||
android:entries="@array/tray_sizes"
|
||||
android:entryValues="@array/tray_sizes"
|
||||
android:defaultValue="7"
|
||||
/>
|
||||
<org.eehouse.android.xw4.XWListPreference
|
||||
android:key="@string/key_board_size"
|
||||
android:title="@string/board_size"
|
||||
|
|
|
@ -34,5 +34,6 @@
|
|||
# define STRD_DUP_TRADED 28
|
||||
# define STRSD_DUP_ONESCORE 29
|
||||
# define STR_PENDING_PLAYER 30
|
||||
# define N_AND_USER_STRINGS 30
|
||||
# define STR_BONUS_ALL_SUB 31
|
||||
# define N_AND_USER_STRINGS 31
|
||||
#endif
|
||||
|
|
|
@ -421,6 +421,8 @@ static const SetInfo gi_ints[] = {
|
|||
ARR_MEMBER( CurGameInfo, nPlayers )
|
||||
,ARR_MEMBER( CurGameInfo, gameSeconds )
|
||||
,ARR_MEMBER( CurGameInfo, boardSize )
|
||||
,ARR_MEMBER( CurGameInfo, traySize )
|
||||
,ARR_MEMBER( CurGameInfo, bingoMin )
|
||||
,ARR_MEMBER( CurGameInfo, gameID )
|
||||
,ARR_MEMBER( CurGameInfo, dictLang )
|
||||
,ARR_MEMBER( CurGameInfo, forceChannel )
|
||||
|
@ -541,23 +543,23 @@ setJGI( JNIEnv* env, jobject jgi, const CurGameInfo* gi )
|
|||
} /* setJGI */
|
||||
|
||||
#ifdef COMMON_LAYOUT
|
||||
static const SetInfo bd_ints[] = {
|
||||
ARR_MEMBER( BoardDims, left )
|
||||
,ARR_MEMBER( BoardDims, top )
|
||||
,ARR_MEMBER( BoardDims, width )
|
||||
,ARR_MEMBER( BoardDims, height )
|
||||
,ARR_MEMBER( BoardDims, scoreLeft )
|
||||
,ARR_MEMBER( BoardDims, scoreHt )
|
||||
,ARR_MEMBER( BoardDims, scoreWidth )
|
||||
,ARR_MEMBER( BoardDims, boardWidth )
|
||||
,ARR_MEMBER( BoardDims, boardHt )
|
||||
,ARR_MEMBER( BoardDims, trayLeft )
|
||||
,ARR_MEMBER( BoardDims, trayTop )
|
||||
,ARR_MEMBER( BoardDims, trayWidth )
|
||||
,ARR_MEMBER( BoardDims, trayHt )
|
||||
,ARR_MEMBER( BoardDims, cellSize )
|
||||
,ARR_MEMBER( BoardDims, maxCellSize )
|
||||
,ARR_MEMBER( BoardDims, timerWidth )
|
||||
static const SetInfo bd_ints[] = { ARR_MEMBER( BoardDims, left ),
|
||||
ARR_MEMBER( BoardDims, top ),
|
||||
ARR_MEMBER( BoardDims, width ),
|
||||
ARR_MEMBER( BoardDims, height ),
|
||||
ARR_MEMBER( BoardDims, scoreLeft ),
|
||||
ARR_MEMBER( BoardDims, scoreHt ),
|
||||
ARR_MEMBER( BoardDims, scoreWidth ),
|
||||
ARR_MEMBER( BoardDims, boardWidth ),
|
||||
ARR_MEMBER( BoardDims, boardHt ),
|
||||
ARR_MEMBER( BoardDims, trayLeft ),
|
||||
ARR_MEMBER( BoardDims, trayTop ),
|
||||
ARR_MEMBER( BoardDims, trayWidth ),
|
||||
ARR_MEMBER( BoardDims, trayHt ),
|
||||
ARR_MEMBER( BoardDims, traySize ),
|
||||
ARR_MEMBER( BoardDims, cellSize ),
|
||||
ARR_MEMBER( BoardDims, maxCellSize ),
|
||||
ARR_MEMBER( BoardDims, timerWidth ),
|
||||
};
|
||||
|
||||
static void
|
||||
|
|
|
@ -258,10 +258,10 @@ board_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream, ModelCtxt* model
|
|||
arrow->visible = (XP_Bool)stream_getBits( stream, 1 );
|
||||
|
||||
if ( STREAM_VERS_MODELDIVIDER > version ) {
|
||||
(void)stream_getBits( stream, NTILES_NBITS );
|
||||
(void)stream_getBits( stream, NTILES_NBITS_7 );
|
||||
}
|
||||
pti->traySelBits = (TileBit)stream_getBits( stream,
|
||||
MAX_TRAY_TILES );
|
||||
XP_U16 nBits = STREAM_VERS_NINETILES <= version ? MAX_TRAY_TILES : 7;
|
||||
pti->traySelBits = (TileBit)stream_getBits( stream, nBits );
|
||||
pti->tradeInProgress = (XP_Bool)stream_getBits( stream, 1 );
|
||||
|
||||
if ( version >= STREAM_VERS_KEYNAV ) {
|
||||
|
@ -287,7 +287,6 @@ board_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream, ModelCtxt* model
|
|||
pti->limits.bottom = stream_getBits( stream, 4 );
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
board->selPlayer = (XP_U8)stream_getBits( stream, PLAYERNUM_NBITS );
|
||||
|
@ -351,6 +350,7 @@ board_writeToStream( const BoardCtxt* board, XWStreamCtxt* stream )
|
|||
stream_putBits( stream, 1, arrow->vert );
|
||||
stream_putBits( stream, 1, arrow->visible );
|
||||
|
||||
XP_ASSERT( CUR_STREAM_VERS == stream_getVersion(stream) );
|
||||
stream_putBits( stream, MAX_TRAY_TILES, pti->traySelBits );
|
||||
stream_putBits( stream, 1, pti->tradeInProgress );
|
||||
|
||||
|
@ -464,8 +464,7 @@ board_figureLayout( BoardCtxt* board, XWEnv xwe, const CurGameInfo* gi,
|
|||
XP_U16 scoreWidth, XP_U16 fontWidth, XP_U16 fontHt,
|
||||
XP_Bool squareTiles, BoardDims* dimsp )
|
||||
{
|
||||
BoardDims ldims;
|
||||
XP_MEMSET( &ldims, 0, sizeof(ldims) );
|
||||
BoardDims ldims = {0};
|
||||
|
||||
XP_U16 nCells = gi->boardSize;
|
||||
XP_U16 maxCellSize = 8 * fontHt;
|
||||
|
@ -569,6 +568,7 @@ board_figureLayout( BoardCtxt* board, XWEnv xwe, const CurGameInfo* gi,
|
|||
|
||||
ldims.boardHt = cellSize * nCells;
|
||||
ldims.trayTop = ldims.top + scoreHt + (cellSize * (nCells-nToScroll));
|
||||
ldims.traySize = gi->traySize;
|
||||
ldims.height =
|
||||
#ifdef FORCE_SQUARE
|
||||
ldims.width
|
||||
|
@ -629,7 +629,7 @@ board_applyLayout( BoardCtxt* board, XWEnv xwe, const BoardDims* dims )
|
|||
dims->top, dims->timerWidth, dims->scoreHt );
|
||||
|
||||
board_setTrayLoc( board, xwe, dims->trayLeft, dims->trayTop,
|
||||
dims->trayWidth, dims->trayHt );
|
||||
dims->trayWidth, dims->trayHt, dims->traySize );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1692,7 +1692,7 @@ onBorderCanScroll( const BoardCtxt* board, SDIndex indx,
|
|||
|
||||
void
|
||||
board_setTrayLoc( BoardCtxt* board, XWEnv xwe, XP_U16 trayLeft, XP_U16 trayTop,
|
||||
XP_U16 trayWidth, XP_U16 trayHeight )
|
||||
XP_U16 trayWidth, XP_U16 trayHeight, XP_U16 nTiles )
|
||||
{
|
||||
/* XP_LOGF( "%s(%d,%d,%d,%d)", __func__, trayLeft, trayTop, */
|
||||
/* trayWidth, trayHeight ); */
|
||||
|
@ -1709,7 +1709,7 @@ board_setTrayLoc( BoardCtxt* board, XWEnv xwe, XP_U16 trayLeft, XP_U16 trayTop,
|
|||
dividerWidth = dividerWidth +
|
||||
((trayWidth - dividerWidth) % MAX_TRAY_TILES);
|
||||
|
||||
board->trayScaleH = (trayWidth - dividerWidth) / MAX_TRAY_TILES;
|
||||
board->trayScaleH = (trayWidth - dividerWidth) / nTiles;
|
||||
board->trayScaleV = trayHeight;
|
||||
|
||||
board->dividerWidth = dividerWidth;
|
||||
|
|
|
@ -91,6 +91,7 @@ typedef struct _BoardDims {
|
|||
|
||||
/* tray */
|
||||
XP_U16 trayLeft, trayTop, trayWidth, trayHt;
|
||||
XP_U16 traySize;
|
||||
|
||||
/* other */
|
||||
XP_U16 cellSize, maxCellSize;
|
||||
|
@ -116,7 +117,7 @@ void board_setScoreboardLoc( BoardCtxt* board,
|
|||
XP_Bool divideHorizontally );
|
||||
void board_setTrayLoc( BoardCtxt* board, XWEnv xwe,
|
||||
XP_U16 trayLeft, XP_U16 trayTop,
|
||||
XP_U16 trayWidth, XP_U16 trayHeight );
|
||||
XP_U16 trayWidth, XP_U16 trayHeight, XP_U16 nTiles );
|
||||
|
||||
/* Vertical scroll support; offset is in rows, not pixels */
|
||||
XP_Bool board_setYOffset( BoardCtxt* board, XWEnv xwe, XP_U16 newOffset );
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#endif
|
||||
#define MAX_COLS MAX_ROWS
|
||||
|
||||
#define STREAM_VERS_NINETILES 0x1E
|
||||
#define STREAM_VERS_NOEMPTYDICT 0x1D
|
||||
#define STREAM_VERS_GICREATED 0x1C /* game struct gets created timestamp */
|
||||
#define STREAM_VERS_DUPLICATE 0x1B
|
||||
|
@ -91,7 +92,7 @@
|
|||
#define STREAM_VERS_405 0x01
|
||||
|
||||
/* search for FIX_NEXT_VERSION_CHANGE next time this is changed */
|
||||
#define CUR_STREAM_VERS STREAM_VERS_NOEMPTYDICT
|
||||
#define CUR_STREAM_VERS STREAM_VERS_NINETILES
|
||||
|
||||
typedef struct XP_Rect {
|
||||
XP_S16 left;
|
||||
|
@ -189,15 +190,12 @@ typedef enum {
|
|||
} XWTimerReason;
|
||||
|
||||
#define MAX_NUM_PLAYERS 4
|
||||
#ifdef EIGHT_TILES
|
||||
# define MAX_TRAY_TILES 8
|
||||
#else
|
||||
# define MAX_TRAY_TILES 7
|
||||
#endif
|
||||
#define MIN_TRAY_TILES 7
|
||||
#define MAX_TRAY_TILES 9
|
||||
#define PLAYERNUM_NBITS 2
|
||||
#define NDEVICES_NBITS 2 /* 1-4, but reduced by 1 fits in 2 bits */
|
||||
#define NPLAYERS_NBITS 3
|
||||
#define EMPTIED_TRAY_BONUS 50
|
||||
#define BINGO_BONUS 50
|
||||
|
||||
#if MAX_ROWS <= 16
|
||||
typedef XP_U16 RowFlags;
|
||||
|
@ -293,7 +291,7 @@ typedef struct _MoveInfoTile {
|
|||
Tile tile; /* 6 bits will do */
|
||||
} MoveInfoTile;
|
||||
|
||||
typedef struct MoveInfo {
|
||||
typedef struct _MoveInfo {
|
||||
XP_U8 nTiles; /* 4 bits: 0-7 */
|
||||
XP_U8 commonCoord; /* 5 bits: 0-16 if 17x17 possible */
|
||||
XP_Bool isHorizontal; /* 1 bit */
|
||||
|
|
|
@ -576,8 +576,7 @@ static void
|
|||
findMovesOneRow( EngineCtxt* engine, XWEnv xwe )
|
||||
{
|
||||
XP_U16 lastCol = engine->numCols - 1;
|
||||
XP_U16 col, row = engine->curRow;
|
||||
XP_S16 prevAnchor;
|
||||
XP_U16 row = engine->curRow;
|
||||
XP_U16 firstSearchCol, lastSearchCol;
|
||||
#ifdef XWFEATURE_SEARCHLIMIT
|
||||
const BdHintLimits* searchLimits = engine->searchLimits;
|
||||
|
@ -600,7 +599,7 @@ findMovesOneRow( EngineCtxt* engine, XWEnv xwe )
|
|||
}
|
||||
|
||||
XP_MEMSET( &engine->rowChecks, 0, sizeof(engine->rowChecks) ); /* clear */
|
||||
for ( col = 0; col <= lastCol; ++col ) {
|
||||
for ( XP_U16 col = 0; col <= lastCol; ++col ) {
|
||||
if ( col < firstSearchCol || col > lastSearchCol ) {
|
||||
engine->scoreCache[col] = 0;
|
||||
} else {
|
||||
|
@ -610,8 +609,8 @@ findMovesOneRow( EngineCtxt* engine, XWEnv xwe )
|
|||
}
|
||||
}
|
||||
|
||||
prevAnchor = firstSearchCol - 1;
|
||||
for ( col = firstSearchCol; col <= lastSearchCol && !engine->returnNOW;
|
||||
XP_S16 prevAnchor = firstSearchCol - 1;
|
||||
for ( XP_U16 col = firstSearchCol; col <= lastSearchCol && !engine->returnNOW;
|
||||
++col ) {
|
||||
if ( isAnchorSquare( engine, col, row ) ) {
|
||||
findMovesForAnchor( engine, xwe, &prevAnchor, col, row );
|
||||
|
|
|
@ -649,6 +649,8 @@ gi_copy( MPFORMAL CurGameInfo* destGI, const CurGameInfo* srcGI )
|
|||
destGI->nPlayers = (XP_U8)srcGI->nPlayers;
|
||||
nPlayers = srcGI->nPlayers;
|
||||
destGI->boardSize = (XP_U8)srcGI->boardSize;
|
||||
destGI->traySize = srcGI->traySize;
|
||||
destGI->bingoMin = srcGI->bingoMin;
|
||||
destGI->serverRole = srcGI->serverRole;
|
||||
|
||||
destGI->hintsNotAllowed = srcGI->hintsNotAllowed;
|
||||
|
@ -748,6 +750,12 @@ gi_readFromStream( MPFORMAL XWStreamCtxt* stream, CurGameInfo* gi )
|
|||
|
||||
gi->nPlayers = (XP_U8)stream_getBits( stream, NPLAYERS_NBITS );
|
||||
gi->boardSize = (XP_U8)stream_getBits( stream, nColsNBits );
|
||||
if ( STREAM_VERS_NINETILES <= strVersion ) {
|
||||
gi->traySize = (XP_U8)stream_getBits( stream, NTILES_NBITS_9 );
|
||||
gi->bingoMin = (XP_U8)stream_getBits( stream, NTILES_NBITS_9 );
|
||||
} else {
|
||||
gi->traySize = gi->bingoMin = 7;
|
||||
}
|
||||
gi->serverRole = (DeviceRole)stream_getBits( stream, 2 );
|
||||
/* XP_LOGF( "%s: read serverRole of %d", __func__, gi->serverRole ); */
|
||||
gi->hintsNotAllowed = stream_getBits( stream, 1 );
|
||||
|
@ -830,6 +838,14 @@ gi_writeToStream( XWStreamCtxt* stream, const CurGameInfo* gi )
|
|||
|
||||
stream_putBits( stream, NPLAYERS_NBITS, gi->nPlayers );
|
||||
stream_putBits( stream, nColsNBits, gi->boardSize );
|
||||
|
||||
if ( STREAM_VERS_NINETILES <= strVersion ) {
|
||||
XP_ASSERT( 0 < gi->traySize );
|
||||
stream_putBits( stream, NTILES_NBITS_9, gi->traySize );
|
||||
stream_putBits( stream, NTILES_NBITS_9, gi->bingoMin );
|
||||
} else {
|
||||
XP_LOGFF( "strVersion: %d so not writing traySize", strVersion );
|
||||
}
|
||||
stream_putBits( stream, 2, gi->serverRole );
|
||||
stream_putBits( stream, 1, gi->hintsNotAllowed );
|
||||
stream_putBits( stream, 2, gi->phoniesAction );
|
||||
|
|
|
@ -51,6 +51,8 @@ typedef struct CurGameInfo {
|
|||
XP_LangCode dictLang;
|
||||
XP_U8 nPlayers;
|
||||
XP_U8 boardSize;
|
||||
XP_U8 traySize;
|
||||
XP_U8 bingoMin;
|
||||
XP_U8 forceChannel;
|
||||
DeviceRole serverRole;
|
||||
|
||||
|
|
|
@ -123,7 +123,6 @@ model_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream,
|
|||
{
|
||||
ModelCtxt* model;
|
||||
XP_U16 nCols;
|
||||
XP_U16 nPlayers;
|
||||
XP_U16 version = stream_getVersion( stream );
|
||||
|
||||
XP_ASSERT( !!dict || !!dicts );
|
||||
|
@ -139,7 +138,7 @@ model_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream,
|
|||
}
|
||||
XP_ASSERT( MAX_COLS >= nCols );
|
||||
|
||||
nPlayers = (XP_U16)stream_getBits( stream, NPLAYERS_NBITS );
|
||||
XP_U16 nPlayers = (XP_U16)stream_getBits( stream, NPLAYERS_NBITS );
|
||||
|
||||
model = model_make( MPPARM(mpool) xwe, dict, dicts, util, nCols );
|
||||
model->nPlayers = nPlayers;
|
||||
|
@ -161,7 +160,6 @@ model_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream,
|
|||
stack_loadFromStream( model->vol.stack, stream );
|
||||
|
||||
MovePrintFuncPre pre = NULL;
|
||||
MovePrintFuncPost post = NULL;
|
||||
void* closure = NULL;
|
||||
#ifdef DEBUG
|
||||
pre = assertDiffTurn;
|
||||
|
@ -171,7 +169,7 @@ model_makeFromStream( MPFORMAL XWEnv xwe, XWStreamCtxt* stream,
|
|||
|
||||
buildModelFromStack( model, xwe, model->vol.stack, XP_FALSE, 0,
|
||||
(XWStreamCtxt*)NULL, (WordNotifierInfo*)NULL,
|
||||
pre, post, closure );
|
||||
pre, (MovePrintFuncPost)NULL, closure );
|
||||
|
||||
for ( int ii = 0; ii < model->nPlayers; ++ii ) {
|
||||
loadPlayerCtxt( model, stream, version, &model->players[ii] );
|
||||
|
@ -284,6 +282,12 @@ model_setSize( ModelCtxt* model, XP_U16 nCols )
|
|||
}
|
||||
} /* model_setSize */
|
||||
|
||||
void
|
||||
model_forceStack7Tiles( ModelCtxt* model )
|
||||
{
|
||||
stack_set7Tiles( model->vol.stack );
|
||||
}
|
||||
|
||||
void
|
||||
model_destroy( ModelCtxt* model, XWEnv xwe )
|
||||
{
|
||||
|
@ -1139,7 +1143,7 @@ model_currentMoveToStream( ModelCtxt* model, XP_S16 turn,
|
|||
XP_ASSERT( turn >= 0 );
|
||||
XP_S16 numTiles = model->players[turn].nPending;
|
||||
|
||||
stream_putBits( stream, NTILES_NBITS, numTiles );
|
||||
stream_putBits( stream, tilesNBits(stream), numTiles );
|
||||
|
||||
while ( numTiles-- ) {
|
||||
Tile tile;
|
||||
|
@ -1177,8 +1181,8 @@ model_makeTurnFromStream( ModelCtxt* model, XWEnv xwe, XP_U16 playerNum,
|
|||
|
||||
model_resetCurrentTurn( model, xwe, playerNum );
|
||||
|
||||
XP_U16 numTiles = (XP_U16)stream_getBits( stream, NTILES_NBITS );
|
||||
XP_LOGF( "%s: numTiles=%d", __func__, numTiles );
|
||||
XP_U16 numTiles = (XP_U16)stream_getBits( stream, tilesNBits(stream) );
|
||||
XP_LOGFF( "numTiles=%d", numTiles );
|
||||
|
||||
Tile tileFaces[numTiles];
|
||||
XP_U16 cols[numTiles];
|
||||
|
@ -2141,17 +2145,17 @@ model_getNumTilesInTray( ModelCtxt* model, XP_S16 turn )
|
|||
XP_ASSERT( turn >= 0 );
|
||||
player = &model->players[turn];
|
||||
XP_U16 result = player->trayTiles.nTiles;
|
||||
// XP_LOGF( "%s(turn=%d) => %d", __func__, turn, result );
|
||||
// XP_LOGFF( "(turn=%d) => %d", turn, result );
|
||||
return result;
|
||||
} /* model_getNumTilesInTray */
|
||||
|
||||
XP_U16
|
||||
model_getNumTilesTotal( ModelCtxt* model, XP_S16 turn )
|
||||
{
|
||||
PlayerCtxt* player;
|
||||
XP_ASSERT( turn >= 0 );
|
||||
player = &model->players[turn];
|
||||
return player->trayTiles.nTiles + player->nPending;
|
||||
PlayerCtxt* player = &model->players[turn];
|
||||
XP_U16 result = player->trayTiles.nTiles + player->nPending;
|
||||
return result;
|
||||
} /* model_getNumTilesTotal */
|
||||
|
||||
XP_U16
|
||||
|
@ -2423,8 +2427,10 @@ copyStack( const ModelCtxt* model, XWEnv xwe, StackCtxt* destStack,
|
|||
mem_stream_make_raw( MPPARM(model->vol.mpool)
|
||||
dutil_getVTManager(model->vol.dutil) );
|
||||
|
||||
stack_writeToStream( (StackCtxt*)srcStack, stream );
|
||||
stream_setVersion( stream, stack_getVersion(srcStack) );
|
||||
stack_writeToStream( srcStack, stream );
|
||||
stack_loadFromStream( destStack, stream );
|
||||
XP_ASSERT( stack_getVersion(destStack) == stack_getVersion( srcStack ) );
|
||||
|
||||
stream_destroy( stream, xwe );
|
||||
} /* copyStack */
|
||||
|
@ -2758,8 +2764,6 @@ static void
|
|||
loadPlayerCtxt( const ModelCtxt* model, XWStreamCtxt* stream, XP_U16 version,
|
||||
PlayerCtxt* pc )
|
||||
{
|
||||
PendingTile* pt;
|
||||
XP_U16 nTiles;
|
||||
XP_U16 nColsNBits;
|
||||
#ifdef STREAM_VERS_BIGBOARD
|
||||
nColsNBits = 16 <= model_numCols( model ) ? NUMCOLS_NBITS_5
|
||||
|
@ -2772,25 +2776,25 @@ loadPlayerCtxt( const ModelCtxt* model, XWStreamCtxt* stream, XP_U16 version,
|
|||
pc->curMoveValid = stream_getBits( stream, 1 );
|
||||
|
||||
traySetFromStream( stream, &pc->trayTiles );
|
||||
|
||||
pc->nPending = (XP_U8)stream_getBits( stream, NTILES_NBITS );
|
||||
|
||||
const XP_U16 nTileBits = tilesNBits(stream);
|
||||
pc->nPending = (XP_U8)stream_getBits( stream, nTileBits );
|
||||
if ( STREAM_VERS_NUNDONE <= version ) {
|
||||
pc->nUndone = (XP_U8)stream_getBits( stream, NTILES_NBITS );
|
||||
pc->nUndone = (XP_U8)stream_getBits( stream, nTileBits );
|
||||
} else {
|
||||
XP_ASSERT( 0 == pc->nUndone );
|
||||
}
|
||||
XP_ASSERT( 0 == pc->dividerLoc );
|
||||
if ( STREAM_VERS_MODELDIVIDER <= version ) {
|
||||
pc->dividerLoc = stream_getBits( stream, NTILES_NBITS );
|
||||
pc->dividerLoc = stream_getBits( stream, nTileBits );
|
||||
}
|
||||
|
||||
nTiles = pc->nPending + pc->nUndone;
|
||||
for ( pt = pc->pendingTiles; nTiles-- > 0; ++pt ) {
|
||||
XP_U16 nBits;
|
||||
XP_U16 nTiles = pc->nPending + pc->nUndone;
|
||||
for ( PendingTile* pt = pc->pendingTiles; nTiles-- > 0; ++pt ) {
|
||||
pt->col = (XP_U8)stream_getBits( stream, nColsNBits );
|
||||
pt->row = (XP_U8)stream_getBits( stream, nColsNBits );
|
||||
|
||||
nBits = (version <= STREAM_VERS_RELAY) ? 6 : 7;
|
||||
XP_U16 nBits = (version <= STREAM_VERS_RELAY) ? 6 : 7;
|
||||
pt->tile = (Tile)stream_getBits( stream, nBits );
|
||||
}
|
||||
|
||||
|
@ -2814,10 +2818,11 @@ writePlayerCtxt( const ModelCtxt* model, XWStreamCtxt* stream,
|
|||
stream_putBits( stream, 1, pc->curMoveValid );
|
||||
|
||||
traySetToStream( stream, &pc->trayTiles );
|
||||
|
||||
stream_putBits( stream, NTILES_NBITS, pc->nPending );
|
||||
stream_putBits( stream, NTILES_NBITS, pc->nUndone );
|
||||
stream_putBits( stream, NTILES_NBITS, pc->dividerLoc );
|
||||
|
||||
XP_U16 nBits = tilesNBits( stream );
|
||||
stream_putBits( stream, nBits, pc->nPending );
|
||||
stream_putBits( stream, nBits, pc->nUndone );
|
||||
stream_putBits( stream, nBits, pc->dividerLoc );
|
||||
|
||||
nTiles = pc->nPending + pc->nUndone;
|
||||
for ( pt = pc->pendingTiles; nTiles-- > 0; ++pt ) {
|
||||
|
|
|
@ -35,11 +35,8 @@ extern "C" {
|
|||
# define NUMCOLS_NBITS_5 5
|
||||
#endif
|
||||
|
||||
#ifdef EIGHT_TILES
|
||||
# define NTILES_NBITS 4
|
||||
#else
|
||||
# define NTILES_NBITS 3
|
||||
#endif
|
||||
#define NTILES_NBITS_7 3
|
||||
#define NTILES_NBITS_9 4
|
||||
|
||||
/* apply to CellTile */
|
||||
#define TILE_VALUE_MASK 0x003F
|
||||
|
@ -63,7 +60,7 @@ typedef struct BlankQueue {
|
|||
XP_U8 row[MAX_NUM_BLANKS];
|
||||
} BlankQueue;
|
||||
|
||||
typedef XP_U8 TileBit; /* bits indicating selection of tiles in tray */
|
||||
typedef XP_U16 TileBit; /* bits indicating selection of tiles in tray */
|
||||
#define ALLTILES ((TileBit)~(0xFF<<(MAX_TRAY_TILES)))
|
||||
|
||||
#define ILLEGAL_MOVE_SCORE (-1)
|
||||
|
@ -88,6 +85,7 @@ void model_writeToTextStream( const ModelCtxt* model, XWStreamCtxt* stream );
|
|||
#endif
|
||||
|
||||
void model_setSize( ModelCtxt* model, XP_U16 boardSize );
|
||||
void model_forceStack7Tiles( ModelCtxt* model );
|
||||
void model_destroy( ModelCtxt* model, XWEnv xwe );
|
||||
XP_U32 model_getHash( const ModelCtxt* model );
|
||||
XP_Bool model_hashMatches( const ModelCtxt* model, XP_U32 hash );
|
||||
|
|
|
@ -34,7 +34,7 @@ typedef struct PendingTile {
|
|||
Tile tile; /* includes face and blank bit */
|
||||
} PendingTile;
|
||||
|
||||
typedef struct PlayerCtxt {
|
||||
typedef struct _PlayerCtxt {
|
||||
XP_S16 score;
|
||||
XP_S16 curMoveScore; /* negative means illegal */
|
||||
XP_Bool curMoveValid;
|
||||
|
|
|
@ -59,6 +59,7 @@ struct StackCtxt {
|
|||
};
|
||||
|
||||
#define HAVE_FLAGS_MASK ((XP_U16)0x8000)
|
||||
#define VERS_7TILES_BIT 0x01
|
||||
|
||||
static XP_Bool popEntryImpl( StackCtxt* stack, StackEntry* entry );
|
||||
|
||||
|
@ -74,6 +75,21 @@ stack_init( StackCtxt* stack, XP_U16 nPlayers, XP_Bool inDuplicateMode )
|
|||
shrunk to fit as soon as we serialize/deserialize anyway. */
|
||||
} /* stack_init */
|
||||
|
||||
|
||||
void
|
||||
stack_set7Tiles( StackCtxt* stack )
|
||||
{
|
||||
XP_ASSERT( !stack->data );
|
||||
stack->flags |= VERS_7TILES_BIT;
|
||||
}
|
||||
|
||||
XP_U16
|
||||
stack_getVersion( const StackCtxt* stack )
|
||||
{
|
||||
XP_ASSERT( !!stack->data );
|
||||
return stream_getVersion( stack->data );
|
||||
}
|
||||
|
||||
#ifdef STREAM_VERS_HASHSTREAM
|
||||
XP_U32
|
||||
stack_getHash( const StackCtxt* stack )
|
||||
|
@ -143,12 +159,18 @@ stack_loadFromStream( StackCtxt* stack, XWStreamCtxt* stream )
|
|||
nBytes &= ~HAVE_FLAGS_MASK;
|
||||
|
||||
if ( nBytes > 0 ) {
|
||||
XP_U8 stackVersion = STREAM_VERS_NINETILES - 1;
|
||||
if ( STREAM_VERS_NINETILES <= stream_getVersion(stream) ) {
|
||||
stackVersion = stream_getU8( stream );
|
||||
XP_LOGFF( "read stackVersion: %d from stream", stackVersion );
|
||||
}
|
||||
stack->highWaterMark = stream_getU16( stream );
|
||||
stack->nEntries = stream_getU16( stream );
|
||||
stack->top = stream_getU32( stream );
|
||||
stack->data = mem_stream_make_raw( MPPARM(stack->mpool) stack->vtmgr );
|
||||
|
||||
stream_getFromStream( stack->data, stream, nBytes );
|
||||
stream_setVersion( stack->data, stackVersion );
|
||||
} else {
|
||||
XP_ASSERT( stack->nEntries == 0 );
|
||||
XP_ASSERT( stack->top == 0 );
|
||||
|
@ -178,6 +200,9 @@ stack_writeToStream( const StackCtxt* stack, XWStreamCtxt* stream )
|
|||
}
|
||||
|
||||
if ( nBytes > 0 ) {
|
||||
if ( STREAM_VERS_NINETILES <= stream_getVersion(stream) ) {
|
||||
stream_putU8( stream, stream_getVersion(data) );
|
||||
}
|
||||
stream_putU16( stream, stack->highWaterMark );
|
||||
stream_putU16( stream, stack->nEntries );
|
||||
stream_putU32( stream, stack->top );
|
||||
|
@ -208,16 +233,18 @@ stack_copy( const StackCtxt* stack )
|
|||
static void
|
||||
pushEntryImpl( StackCtxt* stack, const StackEntry* entry )
|
||||
{
|
||||
XWStreamCtxt* stream = stack->data;
|
||||
|
||||
XP_LOGFF( "(typ=%s, player=%d)", StackMoveType_2str(entry->moveType),
|
||||
entry->playerNum );
|
||||
|
||||
XWStreamCtxt* stream = stack->data;
|
||||
if ( !stream ) {
|
||||
stream = mem_stream_make_raw( MPPARM(stack->mpool) stack->vtmgr );
|
||||
stack->data = stream;
|
||||
stream = stack->data =
|
||||
mem_stream_make_raw( MPPARM(stack->mpool) stack->vtmgr );
|
||||
XP_U16 version = 0 == (stack->flags & VERS_7TILES_BIT)
|
||||
? CUR_STREAM_VERS : STREAM_VERS_NINETILES - 1;
|
||||
stream_setVersion( stream, version );
|
||||
stack->typeBits = stack->inDuplicateMode ? 3 : 2; /* the new size */
|
||||
XP_ASSERT( 0 == stack->flags );
|
||||
XP_ASSERT( 0 == (~VERS_7TILES_BIT & stack->flags) );
|
||||
}
|
||||
|
||||
XWStreamPos oldLoc = stream_setPos( stream, POS_WRITE, stack->top );
|
||||
|
|
|
@ -65,7 +65,7 @@ typedef struct _PauseRec {
|
|||
const XP_UCHAR* msg; /* requires stack_freeEntry() */
|
||||
} PauseRec;
|
||||
|
||||
typedef union EntryData {
|
||||
typedef union _EntryData {
|
||||
AssignRec assign;
|
||||
TradeRec trade;
|
||||
MoveRec move;
|
||||
|
@ -73,7 +73,7 @@ typedef union EntryData {
|
|||
PauseRec pause;
|
||||
} EntryData;
|
||||
|
||||
typedef struct StackEntry {
|
||||
typedef struct _StackEntry {
|
||||
StackMoveType moveType;
|
||||
XP_U8 playerNum;
|
||||
XP_U8 moveNum;
|
||||
|
@ -86,6 +86,8 @@ StackCtxt* stack_make( MPFORMAL VTableMgr* vtmgr, XP_U16 nPlayers, XP_Bool inDup
|
|||
void stack_destroy( StackCtxt* stack );
|
||||
|
||||
void stack_init( StackCtxt* stack, XP_U16 nPlayers, XP_Bool inDuplicateMode );
|
||||
void stack_set7Tiles( StackCtxt* stack );
|
||||
XP_U16 stack_getVersion( const StackCtxt* stack );
|
||||
XP_U32 stack_getHash( const StackCtxt* stack );
|
||||
void stack_setBitsPerTile( StackCtxt* stack, XP_U16 bitsPerTile );
|
||||
|
||||
|
|
|
@ -527,9 +527,9 @@ isLegalMove( ModelCtxt* model, XWEnv xwe, MoveInfo* mInfo, XP_Bool silent )
|
|||
} /* isLegalMove */
|
||||
|
||||
XP_U16
|
||||
figureMoveScore( const ModelCtxt* model, XWEnv xwe, XP_U16 turn, const MoveInfo* moveInfo,
|
||||
EngineCtxt* engine, XWStreamCtxt* stream,
|
||||
WordNotifierInfo* notifyInfo )
|
||||
figureMoveScore( const ModelCtxt* model, XWEnv xwe, XP_U16 turn,
|
||||
const MoveInfo* moveInfo, EngineCtxt* engine,
|
||||
XWStreamCtxt* stream, WordNotifierInfo* notifyInfo )
|
||||
{
|
||||
XP_U16 col, row;
|
||||
XP_U16* incr;
|
||||
|
@ -584,13 +584,22 @@ figureMoveScore( const ModelCtxt* model, XWEnv xwe, XP_U16 turn, const MoveInfo*
|
|||
score += oneScore;
|
||||
}
|
||||
|
||||
const CurGameInfo* gi = model->vol.gi;
|
||||
|
||||
/* did he use all 7 tiles? */
|
||||
if ( nTiles == MAX_TRAY_TILES ) {
|
||||
score += EMPTIED_TRAY_BONUS;
|
||||
if ( gi->bingoMin <= nTiles ) {
|
||||
score += BINGO_BONUS;
|
||||
|
||||
if ( !!stream ) {
|
||||
const XP_UCHAR* bstr = dutil_getUserString( model->vol.dutil,
|
||||
xwe, STR_BONUS_ALL );
|
||||
const XP_UCHAR* bstr;
|
||||
XP_UCHAR buf[128];
|
||||
if ( gi->bingoMin == gi->traySize ) {
|
||||
bstr = dutil_getUserString( model->vol.dutil, xwe, STR_BONUS_ALL );
|
||||
} else {
|
||||
bstr = dutil_getUserString( model->vol.dutil, xwe, STR_BONUS_ALL_SUB );
|
||||
XP_SNPRINTF( buf, VSIZE(buf), bstr, gi->bingoMin );
|
||||
bstr = buf;
|
||||
}
|
||||
stream_catString( stream, bstr );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*- compile-command: "cd ../linux && make -j3 MEMDEBUG=TRUE"; -*- */
|
||||
/*
|
||||
* Copyright 1997 - 2020 by Eric House (xwords@eehouse.org). All rights
|
||||
* Copyright 1997 - 2021 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -912,6 +912,15 @@ setStreamVersion( ServerCtxt* server )
|
|||
}
|
||||
XP_LOGF( "%s: setting streamVersion: 0x%x", __func__, streamVersion );
|
||||
server->nv.streamVersion = streamVersion;
|
||||
|
||||
CurGameInfo* gi = server->vol.gi;
|
||||
if ( STREAM_VERS_NINETILES > streamVersion ) {
|
||||
if ( 7 < gi->traySize ) {
|
||||
XP_LOGFF( "reducing tray size from %d to 7", gi->traySize );
|
||||
gi->traySize = gi->bingoMin = 7;
|
||||
}
|
||||
model_forceStack7Tiles( server->vol.model );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1919,6 +1928,9 @@ client_readInitialMessage( ServerCtxt* server, XWEnv xwe, XWStreamCtxt* stream )
|
|||
XP_U8 streamVersion = stream_getU8( stream );
|
||||
XP_LOGF( "%s: set streamVersion to %d", __func__, streamVersion );
|
||||
stream_setVersion( stream, streamVersion );
|
||||
if ( STREAM_VERS_NINETILES > streamVersion ) {
|
||||
model_forceStack7Tiles( server->vol.model );
|
||||
}
|
||||
// XP_ASSERT( streamVersion <= CUR_STREAM_VERS ); /* else do what? */
|
||||
|
||||
gameID = stream_getU32( stream );
|
||||
|
@ -1934,8 +1946,6 @@ client_readInitialMessage( ServerCtxt* server, XWEnv xwe, XWStreamCtxt* stream )
|
|||
localGI.dictName = copyString( server->mpool, gi->dictName );
|
||||
gi_copy( MPPARM(server->mpool) gi, &localGI );
|
||||
|
||||
XP_U16 nCols = localGI.boardSize;
|
||||
|
||||
if ( streamVersion < STREAM_VERS_NOEMPTYDICT ) {
|
||||
XP_LOGFF( "loading and dropping empty dict" );
|
||||
DictionaryCtxt* empty = util_makeEmptyDict( server->vol.util, xwe );
|
||||
|
@ -1957,7 +1967,7 @@ client_readInitialMessage( ServerCtxt* server, XWEnv xwe, XWStreamCtxt* stream )
|
|||
server->nv.addresses[0].channelNo = channelNo;
|
||||
XP_LOGF( "%s: assigning channelNo %x for 0", __func__, channelNo );
|
||||
|
||||
model_setSize( model, nCols );
|
||||
model_setSize( model, localGI.boardSize );
|
||||
|
||||
XP_U16 nPlayers = localGI.nPlayers;
|
||||
XP_LOGF( "%s: reading in %d players", __func__, localGI.nPlayers );
|
||||
|
@ -2583,8 +2593,8 @@ assignTilesToAll( ServerCtxt* server, XWEnv xwe )
|
|||
model_setNPlayers( model, nPlayers );
|
||||
|
||||
numAssigned = pool_getNTilesLeft( server->pool ) / nPlayers;
|
||||
if ( numAssigned > MAX_TRAY_TILES ) {
|
||||
numAssigned = MAX_TRAY_TILES;
|
||||
if ( numAssigned > gi->traySize ) {
|
||||
numAssigned = gi->traySize;
|
||||
}
|
||||
|
||||
/* Loop through all the players. If picking tiles is on, stop for each
|
||||
|
|
|
@ -53,7 +53,7 @@ void
|
|||
traySetToStream( XWStreamCtxt* stream, const TrayTileSet* ts )
|
||||
{
|
||||
XP_U16 nTiles = ts->nTiles;
|
||||
stream_putBits( stream, NTILES_NBITS, nTiles );
|
||||
stream_putBits( stream, tilesNBits(stream), nTiles );
|
||||
tilesToStream( stream, ts->tiles, nTiles );
|
||||
} /* traySetFromStream */
|
||||
|
||||
|
@ -99,7 +99,7 @@ scoresFromStream( XWStreamCtxt* stream, XP_U16 nScores, XP_U16* scores )
|
|||
void
|
||||
traySetFromStream( XWStreamCtxt* stream, TrayTileSet* ts )
|
||||
{
|
||||
XP_U16 nTiles = (XP_U16)stream_getBits( stream, NTILES_NBITS );
|
||||
XP_U16 nTiles = (XP_U16)stream_getBits( stream, tilesNBits( stream ) );
|
||||
tilesFromStream( stream, ts->tiles, nTiles );
|
||||
ts->nTiles = (XP_U8)nTiles;
|
||||
} /* traySetFromStream */
|
||||
|
@ -123,7 +123,7 @@ moveInfoToStream( XWStreamCtxt* stream, const MoveInfo* mi, XP_U16 bitsPerTile )
|
|||
#endif
|
||||
assertSorted( mi );
|
||||
|
||||
stream_putBits( stream, NTILES_NBITS, mi->nTiles );
|
||||
stream_putBits( stream, tilesNBits( stream ), mi->nTiles );
|
||||
stream_putBits( stream, NUMCOLS_NBITS_5, mi->commonCoord );
|
||||
stream_putBits( stream, 1, mi->isHorizontal );
|
||||
|
||||
|
@ -148,7 +148,7 @@ moveInfoFromStream( XWStreamCtxt* stream, MoveInfo* mi, XP_U16 bitsPerTile )
|
|||
/* XP_UCHAR buf[64] = {0}; */
|
||||
/* XP_U16 offset = 0; */
|
||||
#endif
|
||||
mi->nTiles = stream_getBits( stream, NTILES_NBITS );
|
||||
mi->nTiles = stream_getBits( stream, tilesNBits( stream ) );
|
||||
XP_ASSERT( mi->nTiles <= MAX_TRAY_TILES );
|
||||
mi->commonCoord = stream_getBits( stream, NUMCOLS_NBITS_5 );
|
||||
mi->isHorizontal = stream_getBits( stream, 1 );
|
||||
|
@ -396,6 +396,19 @@ finishHash( XP_U32 hash )
|
|||
return hash;
|
||||
}
|
||||
|
||||
XP_U16
|
||||
tilesNBits( const XWStreamCtxt* stream )
|
||||
{
|
||||
XP_U16 version = stream_getVersion( stream );
|
||||
XP_ASSERT( 0 < version );
|
||||
if ( 0 == version ) {
|
||||
XP_LOGFF( "version is 0" );
|
||||
}
|
||||
XP_U16 result = STREAM_VERS_NINETILES <= version
|
||||
? NTILES_NBITS_9 : NTILES_NBITS_7;
|
||||
return result;
|
||||
}
|
||||
|
||||
const XP_UCHAR*
|
||||
lcToLocale( XP_LangCode lc )
|
||||
{
|
||||
|
|
|
@ -86,6 +86,8 @@ void insetRect( XP_Rect* rect, XP_S16 byWidth, XP_S16 byHeight );
|
|||
XP_U32 augmentHash( XP_U32 hash, const XP_U8* ptr, XP_U16 len );
|
||||
XP_U32 finishHash( XP_U32 hash );
|
||||
|
||||
XP_U16 tilesNBits( const XWStreamCtxt* stream );
|
||||
|
||||
const XP_UCHAR* lcToLocale( XP_LangCode lc );
|
||||
|
||||
void p_replaceStringIfDifferent( MPFORMAL XP_UCHAR** curLoc,
|
||||
|
|
|
@ -132,8 +132,6 @@ figureTrayTileRect( BoardCtxt* board, XP_U16 index, XP_Rect* rect )
|
|||
void
|
||||
drawTray( BoardCtxt* board, XWEnv xwe )
|
||||
{
|
||||
XP_Rect tileRect;
|
||||
|
||||
if ( (board->trayInvalBits != 0) || board->dividerInvalid ) {
|
||||
const XP_S16 turn = board->selPlayer;
|
||||
PerTurnInfo* pti = board->selInfo;
|
||||
|
@ -165,9 +163,9 @@ drawTray( BoardCtxt* board, XWEnv xwe )
|
|||
if ( dictionary != NULL ) {
|
||||
XP_Bool showFaces = board->trayVisState == TRAY_REVEALED;
|
||||
Tile blank = dict_getBlankTile( dictionary );
|
||||
const XP_U16 nTrayTiles = board->gi->traySize;
|
||||
|
||||
if ( turn >= 0 ) {
|
||||
XP_S16 ii; /* which tile slot are we drawing in */
|
||||
XP_U16 ddAddedIndx, ddRmvdIndx;
|
||||
XP_U16 numInTray = countTilesToShow( board );
|
||||
XP_Bool isBlank;
|
||||
|
@ -179,7 +177,7 @@ drawTray( BoardCtxt* board, XWEnv xwe )
|
|||
|
||||
/* draw in reverse order so drawing happens after
|
||||
erasing */
|
||||
for ( ii = MAX_TRAY_TILES - 1; ii >= 0; --ii ) {
|
||||
for ( int ii = nTrayTiles - 1; ii >= 0; --ii ) {
|
||||
CellFlags flags = baseFlags;
|
||||
XP_U16 mask = 1 << ii;
|
||||
|
||||
|
@ -191,6 +189,7 @@ drawTray( BoardCtxt* board, XWEnv xwe )
|
|||
flags |= CELL_ISCURSOR;
|
||||
}
|
||||
#endif
|
||||
XP_Rect tileRect;
|
||||
figureTrayTileRect( board, ii, &tileRect );
|
||||
|
||||
XP_Bool drew;
|
||||
|
@ -262,7 +261,7 @@ drawTray( BoardCtxt* board, XWEnv xwe )
|
|||
board->dividerInvalid = XP_FALSE;
|
||||
}
|
||||
drawPendingScore( board, xwe, turnScore,
|
||||
(cursorBits & (1<<(MAX_TRAY_TILES-1))) != 0);
|
||||
(cursorBits & (1<<(nTrayTiles - 1))) != 0);
|
||||
}
|
||||
|
||||
draw_objFinished( board->draw, xwe, OBJ_TRAY, &board->trayBounds,
|
||||
|
@ -336,12 +335,13 @@ static void
|
|||
drawPendingScore( BoardCtxt* board, XWEnv xwe, XP_S16 turnScore, XP_Bool hasCursor )
|
||||
{
|
||||
/* Draw the pending score down in the last tray's rect */
|
||||
if ( countTilesToShow( board ) < MAX_TRAY_TILES ) {
|
||||
XP_U16 traySize = board->gi->traySize;
|
||||
if ( countTilesToShow( board ) < traySize ) {
|
||||
XP_U16 selPlayer = board->selPlayer;
|
||||
XP_Bool curTurn = server_isPlayersTurn( board->server, selPlayer );
|
||||
XP_Rect lastTileR;
|
||||
|
||||
figureTrayTileRect( board, MAX_TRAY_TILES-1, &lastTileR );
|
||||
figureTrayTileRect( board, traySize - 1, &lastTileR );
|
||||
if ( 0 < lastTileR.width && 0 < lastTileR.height ) {
|
||||
draw_score_pendingScore( board->draw, xwe, &lastTileR, turnScore,
|
||||
selPlayer, curTurn,
|
||||
|
@ -368,10 +368,9 @@ invalTilesUnderRect( BoardCtxt* board, const XP_Rect* rect )
|
|||
it for now. If it needs to be faster, invalCellsUnderRect is the model
|
||||
to use. */
|
||||
|
||||
XP_U16 ii;
|
||||
XP_Rect locRect;
|
||||
|
||||
for ( ii = 0; ii < MAX_TRAY_TILES; ++ii ) {
|
||||
for ( int ii = 0; ii < board->gi->traySize; ++ii ) {
|
||||
figureTrayTileRect( board, ii, &locRect );
|
||||
if ( rectsIntersect( rect, &locRect ) ) {
|
||||
board_invalTrayTiles( board, (TileBit)(1 << ii) );
|
||||
|
@ -458,7 +457,7 @@ handleActionInTray( BoardCtxt* board, XWEnv xwe, XP_S16 index, XP_Bool onDivider
|
|||
result = XP_TRUE;
|
||||
}
|
||||
#endif
|
||||
} else if ( index == -(MAX_TRAY_TILES) ) { /* pending score tile */
|
||||
} else if ( index == -(board->gi->traySize) ) { /* pending score tile */
|
||||
result = board_commitTurn( board, xwe, XP_FALSE, XP_FALSE, NULL );
|
||||
#if defined XWFEATURE_TRAYUNDO_ALL
|
||||
} else if ( index < 0 ) { /* other empty area */
|
||||
|
@ -535,7 +534,8 @@ void
|
|||
invalTrayTilesAbove( BoardCtxt* board, XP_U16 tileIndex )
|
||||
{
|
||||
TileBit bits = 0;
|
||||
while ( tileIndex < MAX_TRAY_TILES ) {
|
||||
const XP_U16 traySize = board->gi->traySize;
|
||||
while ( tileIndex < traySize ) {
|
||||
bits |= 1 << tileIndex++;
|
||||
}
|
||||
board_invalTrayTiles( board, bits );
|
||||
|
@ -626,16 +626,17 @@ tray_moveCursor( BoardCtxt* board, XP_Key cursorKey, XP_Bool preflightOnly,
|
|||
PerTurnInfo* pti = board->selInfo;
|
||||
XP_S16 trayCursorLoc;
|
||||
XP_S16 newLoc;
|
||||
const XP_U16 traySize = board->gi->traySize;
|
||||
for ( ; ; ) {
|
||||
trayCursorLoc = pti->trayCursorLoc;
|
||||
newLoc = trayCursorLoc + delta;
|
||||
if ( newLoc < 0 || newLoc > MAX_TRAY_TILES ) {
|
||||
if ( newLoc < 0 || newLoc > traySize ) {
|
||||
up = XP_TRUE;
|
||||
} else if ( !preflightOnly ) {
|
||||
XP_S16 tileLoc = trayCursorLoc;
|
||||
XP_U16 nTiles = board->trayVisState == TRAY_REVEALED
|
||||
? model_getNumTilesInTray( board->model, selPlayer )
|
||||
: MAX_TRAY_TILES;
|
||||
: traySize;
|
||||
XP_U16 dividerLoc = getDividerLoc( board );
|
||||
XP_Bool cursorOnDivider = trayCursorLoc == dividerLoc;
|
||||
XP_Bool cursorObjSelected;
|
||||
|
@ -683,7 +684,7 @@ tray_moveCursor( BoardCtxt* board, XP_Key cursorKey, XP_Bool preflightOnly,
|
|||
|
||||
if ( (newTileLoc > nTiles)
|
||||
&& (newLoc != dividerLoc)
|
||||
&& (newTileLoc < MAX_TRAY_TILES-1) ) {
|
||||
&& (newTileLoc < traySize-1) ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -730,9 +731,10 @@ board_moveDivider( BoardCtxt* board, XP_Bool right )
|
|||
XP_Bool result = board->trayVisState == TRAY_REVEALED;
|
||||
if ( result ) {
|
||||
XP_U8 loc = getDividerLoc( board );
|
||||
loc += MAX_TRAY_TILES + 1;
|
||||
const XP_U16 traySize = board->gi->traySize;
|
||||
loc += traySize + 1;
|
||||
loc += right? 1:-1;
|
||||
loc %= MAX_TRAY_TILES + 1;
|
||||
loc %= traySize + 1;
|
||||
|
||||
(void)dividerMoved( board, loc );
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ enum {
|
|||
STRD_DUP_TRADED,
|
||||
STRSD_DUP_ONESCORE,
|
||||
|
||||
STR_BONUS_ALL_SUB,
|
||||
|
||||
/* These three aren't in Android */
|
||||
STR_LOCALPLAYERS,
|
||||
STR_TOTALPLAYERS,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
|
||||
/*
|
||||
* Copyright 2001-2013 by Eric House (xwords@eehouse.org). All rights
|
||||
* Copyright 2001 - 2021 by Eric House (xwords@eehouse.org). All rights
|
||||
* reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -28,9 +28,13 @@
|
|||
#include "nwgamest.h"
|
||||
#include "gtkconnsdlg.h"
|
||||
#include "gtkutils.h"
|
||||
#include "gtkask.h"
|
||||
|
||||
#define MAX_SIZE_CHOICES 32
|
||||
|
||||
#define BINGO_THRESHOLD "Bingo threshold"
|
||||
#define TRAY_SIZE "Tray size"
|
||||
|
||||
typedef struct GtkNewGameState {
|
||||
GtkGameGlobals* globals;
|
||||
CurGameInfo* gi;
|
||||
|
@ -46,6 +50,8 @@ typedef struct GtkNewGameState {
|
|||
XP_Bool fireConnDlg;
|
||||
gboolean isNewGame;
|
||||
short nCols; /* for board size */
|
||||
int nTrayTiles;
|
||||
int bingoMin;
|
||||
gchar* dict;
|
||||
|
||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||
|
@ -167,6 +173,26 @@ size_combo_changed( GtkComboBox* combo, gpointer gp )
|
|||
}
|
||||
} /* size_combo_changed */
|
||||
|
||||
static void
|
||||
tray_size_changed( GtkComboBox* combo, gpointer gp )
|
||||
{
|
||||
GtkNewGameState* state = (GtkNewGameState*)gp;
|
||||
gint index = gtk_combo_box_get_active( GTK_COMBO_BOX(combo) );
|
||||
if ( index >= 0 ) {
|
||||
state->nTrayTiles = 7 + index;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bingo_changed( GtkComboBox* combo, gpointer gp )
|
||||
{
|
||||
GtkNewGameState* state = (GtkNewGameState*)gp;
|
||||
gint index = gtk_combo_box_get_active( GTK_COMBO_BOX(combo) );
|
||||
if ( index >= 0 ) {
|
||||
state->bingoMin = 7 + index;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dict_combo_changed( GtkComboBox* combo, gpointer gp )
|
||||
{
|
||||
|
@ -278,6 +304,103 @@ addDuplicateCheckbox( GtkNewGameState* state, GtkWidget* parent )
|
|||
gtk_box_pack_start( GTK_BOX(parent), duplicateCheck, FALSE, TRUE, 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
addSizesRow( GtkNewGameState* state, GtkWidget* parent )
|
||||
{
|
||||
LOG_FUNC();
|
||||
GtkWidget* hbox = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 );
|
||||
|
||||
/* Tray size */
|
||||
gtk_box_pack_start( GTK_BOX(hbox), gtk_label_new(TRAY_SIZE ":"), FALSE, TRUE, 0 );
|
||||
GtkWidget* traySizeCombo = gtk_combo_box_text_new();
|
||||
for ( int ii = MIN_TRAY_TILES; ii <= MAX_TRAY_TILES; ++ii ) {
|
||||
char buf[10];
|
||||
snprintf( buf, sizeof(buf), "%d", ii );
|
||||
gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(traySizeCombo), buf );
|
||||
}
|
||||
gtk_combo_box_set_active( GTK_COMBO_BOX(traySizeCombo),
|
||||
state->nTrayTiles - MIN_TRAY_TILES );
|
||||
|
||||
g_signal_connect( traySizeCombo, "changed", G_CALLBACK(tray_size_changed), state );
|
||||
gtk_widget_show( traySizeCombo );
|
||||
gtk_box_pack_start( GTK_BOX(hbox), traySizeCombo, FALSE, TRUE, 0 );
|
||||
|
||||
/* Bingo threshold */
|
||||
gtk_box_pack_start( GTK_BOX(hbox), gtk_label_new(BINGO_THRESHOLD":"), FALSE, TRUE, 0 );
|
||||
GtkWidget* bingoCombo = gtk_combo_box_text_new();
|
||||
for ( int ii = MIN_TRAY_TILES; ii <= MAX_TRAY_TILES; ++ii ) {
|
||||
char buf[10];
|
||||
snprintf( buf, sizeof(buf), "%d", ii );
|
||||
gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(bingoCombo), buf );
|
||||
}
|
||||
gtk_combo_box_set_active( GTK_COMBO_BOX(bingoCombo), state->bingoMin - MIN_TRAY_TILES );
|
||||
|
||||
g_signal_connect( bingoCombo, "changed", G_CALLBACK(bingo_changed), state );
|
||||
gtk_widget_show( bingoCombo );
|
||||
gtk_box_pack_start( GTK_BOX(hbox), bingoCombo, FALSE, TRUE, 0 );
|
||||
|
||||
/* board size choices */
|
||||
gtk_box_pack_start( GTK_BOX(hbox), gtk_label_new("Board size:"),
|
||||
FALSE, TRUE, 0 );
|
||||
|
||||
GtkWidget* boardSizeCombo = gtk_combo_box_text_new();
|
||||
if ( !state->isNewGame ) {
|
||||
gtk_widget_set_sensitive( boardSizeCombo, FALSE );
|
||||
}
|
||||
|
||||
for ( int ii = 0; ii < MAX_SIZE_CHOICES; ++ii ) {
|
||||
char buf[10];
|
||||
XP_U16 siz = MAX_COLS - ii;
|
||||
snprintf( buf, sizeof(buf), "%dx%d", siz, siz );
|
||||
gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(boardSizeCombo), buf );
|
||||
if ( siz == state->nCols ) {
|
||||
gtk_combo_box_set_active( GTK_COMBO_BOX(boardSizeCombo), ii );
|
||||
}
|
||||
}
|
||||
|
||||
g_signal_connect( boardSizeCombo, "changed",
|
||||
G_CALLBACK(size_combo_changed), state );
|
||||
|
||||
gtk_widget_show( boardSizeCombo );
|
||||
gtk_box_pack_start( GTK_BOX(hbox), boardSizeCombo, FALSE, TRUE, 0 );
|
||||
|
||||
gtk_box_pack_start( GTK_BOX(parent), hbox, FALSE, TRUE, 0 );
|
||||
} /* addSizesRow */
|
||||
|
||||
static void
|
||||
addDictsRow( GtkNewGameState* state, GtkWidget* parent )
|
||||
{
|
||||
GtkWidget* hbox = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 );
|
||||
|
||||
/* Dictionary combo */
|
||||
gtk_box_pack_start( GTK_BOX(hbox), gtk_label_new("Dictionary: "),
|
||||
FALSE, TRUE, 0 );
|
||||
GtkWidget* dictCombo = gtk_combo_box_text_new();
|
||||
g_signal_connect( dictCombo, "changed",
|
||||
G_CALLBACK(dict_combo_changed), state );
|
||||
gtk_widget_show( dictCombo );
|
||||
gtk_box_pack_start( GTK_BOX(hbox), dictCombo, FALSE, TRUE, 0 );
|
||||
|
||||
GSList* dicts = listDicts( state->globals->cGlobals.params );
|
||||
GSList* iter = dicts;
|
||||
for ( int ii = 0; !!iter; iter = iter->next, ++ii ) {
|
||||
const gchar* name = iter->data;
|
||||
gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(dictCombo), name );
|
||||
if ( !!state->gi->dictName ) {
|
||||
if ( !strcmp( name, state->gi->dictName ) ) {
|
||||
gtk_combo_box_set_active( GTK_COMBO_BOX(dictCombo), ii );
|
||||
}
|
||||
} else if ( 0 == ii ) {
|
||||
gtk_combo_box_set_active( GTK_COMBO_BOX(dictCombo), ii );
|
||||
}
|
||||
}
|
||||
g_slist_free( dicts );
|
||||
|
||||
addPhoniesCombo( state, hbox );
|
||||
|
||||
gtk_box_pack_start( GTK_BOX(parent), hbox, FALSE, TRUE, 0 );
|
||||
} /* addDictsRow */
|
||||
|
||||
static GtkWidget*
|
||||
makeNewGameDialog( GtkNewGameState* state )
|
||||
{
|
||||
|
@ -288,11 +411,6 @@ makeNewGameDialog( GtkNewGameState* state )
|
|||
GtkWidget* roleCombo;
|
||||
char* roles[] = { "Standalone", "Host", "Guest" };
|
||||
#endif
|
||||
GtkWidget* nPlayersCombo;
|
||||
GtkWidget* boardSizeCombo;
|
||||
GtkWidget* dictCombo;
|
||||
CurGameInfo* gi;
|
||||
short ii;
|
||||
|
||||
dialog = gtk_dialog_new();
|
||||
gtk_window_set_modal( GTK_WINDOW( dialog ), TRUE );
|
||||
|
@ -306,7 +424,7 @@ makeNewGameDialog( GtkNewGameState* state )
|
|||
roleCombo = gtk_combo_box_text_new();
|
||||
state->roleCombo = roleCombo;
|
||||
|
||||
for ( ii = 0; ii < VSIZE(roles); ++ii ) {
|
||||
for ( int ii = 0; ii < VSIZE(roles); ++ii ) {
|
||||
gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(roleCombo),
|
||||
roles[ii] );
|
||||
}
|
||||
|
@ -327,12 +445,10 @@ makeNewGameDialog( GtkNewGameState* state )
|
|||
state->nPlayersLabel = gtk_label_new("");
|
||||
gtk_box_pack_start( GTK_BOX(hbox), state->nPlayersLabel, FALSE, TRUE, 0 );
|
||||
|
||||
nPlayersCombo = gtk_combo_box_text_new();
|
||||
GtkWidget* nPlayersCombo = gtk_combo_box_text_new();
|
||||
state->nPlayersCombo = nPlayersCombo;
|
||||
|
||||
gi = state->gi;
|
||||
|
||||
for ( ii = 0; ii < MAX_NUM_PLAYERS; ++ii ) {
|
||||
for ( int ii = 0; ii < MAX_NUM_PLAYERS; ++ii ) {
|
||||
char buf[2] = { ii + '1', '\0' };
|
||||
gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(nPlayersCombo),
|
||||
buf );
|
||||
|
@ -351,7 +467,7 @@ makeNewGameDialog( GtkNewGameState* state )
|
|||
|
||||
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
|
||||
|
||||
for ( ii = 0; ii < MAX_NUM_PLAYERS; ++ii ) {
|
||||
for ( int ii = 0; ii < MAX_NUM_PLAYERS; ++ii ) {
|
||||
GtkWidget* label = gtk_label_new("Name:");
|
||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||
GtkWidget* remoteCheck = gtk_check_button_new_with_label( "Remote" );
|
||||
|
@ -401,58 +517,8 @@ makeNewGameDialog( GtkNewGameState* state )
|
|||
gtk_widget_show( hbox );
|
||||
}
|
||||
|
||||
/* board size choices */
|
||||
hbox = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 0 );
|
||||
gtk_box_pack_start( GTK_BOX(hbox), gtk_label_new("Board size"),
|
||||
FALSE, TRUE, 0 );
|
||||
|
||||
boardSizeCombo = gtk_combo_box_text_new();
|
||||
if ( !state->isNewGame ) {
|
||||
gtk_widget_set_sensitive( boardSizeCombo, FALSE );
|
||||
}
|
||||
|
||||
for ( ii = 0; ii < MAX_SIZE_CHOICES; ++ii ) {
|
||||
char buf[10];
|
||||
XP_U16 siz = MAX_COLS - ii;
|
||||
snprintf( buf, sizeof(buf), "%dx%d", siz, siz );
|
||||
gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(boardSizeCombo), buf );
|
||||
if ( siz == state->nCols ) {
|
||||
gtk_combo_box_set_active( GTK_COMBO_BOX(boardSizeCombo), ii );
|
||||
}
|
||||
}
|
||||
|
||||
g_signal_connect( boardSizeCombo, "changed",
|
||||
G_CALLBACK(size_combo_changed), state );
|
||||
|
||||
gtk_widget_show( boardSizeCombo );
|
||||
gtk_box_pack_start( GTK_BOX(hbox), boardSizeCombo, FALSE, TRUE, 0 );
|
||||
|
||||
/* Dictionary combo */
|
||||
|
||||
gtk_box_pack_start( GTK_BOX(hbox), gtk_label_new("Dictionary: "),
|
||||
FALSE, TRUE, 0 );
|
||||
dictCombo = gtk_combo_box_text_new();
|
||||
g_signal_connect( dictCombo, "changed",
|
||||
G_CALLBACK(dict_combo_changed), state );
|
||||
gtk_widget_show( dictCombo );
|
||||
gtk_box_pack_start( GTK_BOX(hbox), dictCombo, FALSE, TRUE, 0 );
|
||||
|
||||
GSList* dicts = listDicts( state->globals->cGlobals.params );
|
||||
GSList* iter;
|
||||
for ( iter = dicts, ii = 0; !!iter; iter = iter->next, ++ii ) {
|
||||
const gchar* name = iter->data;
|
||||
gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(dictCombo), name );
|
||||
if ( !!gi->dictName ) {
|
||||
if ( !strcmp( name, gi->dictName ) ) {
|
||||
gtk_combo_box_set_active( GTK_COMBO_BOX(dictCombo), ii );
|
||||
}
|
||||
} else if ( 0 == ii ) {
|
||||
gtk_combo_box_set_active( GTK_COMBO_BOX(dictCombo), ii );
|
||||
}
|
||||
}
|
||||
g_slist_free( dicts );
|
||||
|
||||
addPhoniesCombo( state, hbox );
|
||||
addSizesRow( state, vbox );
|
||||
addDictsRow( state, vbox );
|
||||
|
||||
gtk_widget_show( hbox );
|
||||
gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 0 );
|
||||
|
@ -664,6 +730,18 @@ setDefaults( CurGameInfo* gi )
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
checkAndWarn( GtkNewGameState* state, GtkWidget* dialog )
|
||||
{
|
||||
if ( state->nTrayTiles < state->bingoMin ) {
|
||||
gchar buf[128];
|
||||
XP_SNPRINTF( buf, VSIZE(buf),"\"%s\" cannot be greater than \"%s\"",
|
||||
BINGO_THRESHOLD, TRAY_SIZE );
|
||||
gtktell( dialog, buf );
|
||||
state->revert = XP_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtkNewGameDialog( GtkGameGlobals* globals, CurGameInfo* gi, CommsAddrRec* addr,
|
||||
XP_Bool isNewGame, XP_Bool fireConnDlg )
|
||||
|
@ -694,6 +772,8 @@ gtkNewGameDialog( GtkGameGlobals* globals, CurGameInfo* gi, CommsAddrRec* addr,
|
|||
state.revert = FALSE;
|
||||
state.loaded = XP_FALSE;
|
||||
state.nCols = gi->boardSize;
|
||||
state.nTrayTiles = gi->traySize;
|
||||
state.bingoMin = gi->bingoMin;
|
||||
if ( 0 == state.nCols ) {
|
||||
state.nCols = globals->cGlobals.params->pgi.boardSize;
|
||||
}
|
||||
|
@ -707,9 +787,13 @@ gtkNewGameDialog( GtkGameGlobals* globals, CurGameInfo* gi, CommsAddrRec* addr,
|
|||
state.loaded = XP_TRUE;
|
||||
|
||||
gtk_main();
|
||||
|
||||
checkAndWarn( &state, dialog );
|
||||
if ( !state.cancelled && !state.revert ) {
|
||||
if ( newg_store( state.newGameCtxt, NULL_XWE, gi, XP_TRUE ) ) {
|
||||
gi->boardSize = state.nCols;
|
||||
gi->traySize = state.nTrayTiles;
|
||||
gi->bingoMin = state.bingoMin;
|
||||
replaceStringIfDifferent( globals->cGlobals.util->mpool,
|
||||
&gi->dictName, state.dict );
|
||||
gi->phoniesAction = state.phoniesAction;
|
||||
|
|
|
@ -222,6 +222,8 @@ linux_dutil_getUserString( XW_DUtilCtxt* XP_UNUSED(uc),
|
|||
return (XP_UCHAR*)"Score for turn: %d\n";
|
||||
case STR_BONUS_ALL:
|
||||
return (XP_UCHAR*)"Bonus for using all tiles: 50\n";
|
||||
case STR_BONUS_ALL_SUB:
|
||||
return (XP_UCHAR*)"Bonus for using at least %d tiles: 50\n";
|
||||
case STR_PENDING_PLAYER:
|
||||
return (XP_UCHAR*)"(remote)";
|
||||
case STRD_TIME_PENALTY_SUB:
|
||||
|
|
|
@ -838,6 +838,7 @@ typedef enum {
|
|||
,CMD_NOCLOSESTDIN
|
||||
,CMD_QUITAFTER
|
||||
,CMD_BOARDSIZE
|
||||
,CMD_TRAYSIZE
|
||||
,CMD_DUP_MODE
|
||||
,CMD_HIDEVALUES
|
||||
,CMD_SKIPCONFIRM
|
||||
|
@ -985,6 +986,7 @@ static CmdInfoRec CmdInfoRecs[] = {
|
|||
,{ CMD_NOCLOSESTDIN, false, "no-close-stdin", "do not close stdin on start" }
|
||||
,{ CMD_QUITAFTER, true, "quit-after", "exit <n> seconds after game's done" }
|
||||
,{ CMD_BOARDSIZE, true, "board-size", "board is <n> by <n> cells" }
|
||||
,{ CMD_TRAYSIZE, true, "tray-size", "<n> tiles per tray (7-9 are legal)" }
|
||||
,{ CMD_DUP_MODE, false, "duplicate-mode", "play in duplicate mode" }
|
||||
,{ CMD_HIDEVALUES, false, "hide-values", "show letters, not nums, on tiles" }
|
||||
,{ CMD_SKIPCONFIRM, false, "skip-confirm", "don't confirm before commit" }
|
||||
|
@ -2690,6 +2692,8 @@ main( int argc, char** argv )
|
|||
mainParams.connInfo.sms.port = 1;
|
||||
#endif
|
||||
mainParams.pgi.boardSize = 15;
|
||||
mainParams.pgi.traySize = 7;
|
||||
mainParams.pgi.bingoMin = 7;
|
||||
mainParams.quitAfter = -1;
|
||||
mainParams.sleepOnAnchor = XP_FALSE;
|
||||
mainParams.printHistory = XP_FALSE;
|
||||
|
@ -3044,6 +3048,11 @@ main( int argc, char** argv )
|
|||
case CMD_BOARDSIZE:
|
||||
mainParams.pgi.boardSize = atoi(optarg);
|
||||
break;
|
||||
case CMD_TRAYSIZE:
|
||||
mainParams.pgi.traySize = atoi(optarg);
|
||||
XP_ASSERT( MIN_TRAY_TILES <= mainParams.pgi.traySize
|
||||
&& mainParams.pgi.traySize <= MAX_TRAY_TILES );
|
||||
break;
|
||||
case CMD_DUP_MODE:
|
||||
mainParams.pgi.inDuplicateMode = XP_TRUE;
|
||||
break;
|
||||
|
|
|
@ -510,6 +510,7 @@ def build_cmds(args):
|
|||
if DEV == 1 or usePublic: PARAMS += ['--force-game']
|
||||
if DEV == 1:
|
||||
PARAMS += ['--server', '--phonies', phonies ]
|
||||
PARAMS += ['--tray-size', random.randint(7, 9)] # randint() is *inclusive*
|
||||
# IFF there are any non-1 player counts, tell inviter which
|
||||
if sum(LOCALS) > NDEVS:
|
||||
PARAMS += ['--invitee-counts', ":".join(str(n) for n in LOCALS[1:])]
|
||||
|
|
Loading…
Reference in a new issue