use of soc.game.SOCGameOption in project JSettlers2 by jdmonin.
the class TestBoardLayouts method testSingleLayout.
/**
* Test one scenario's layout for a given number of players.
* @param sc Scenario to test, or {@code null} for classic games
* @param pl Number of players (3, 4, 6, etc)
* @return True if OK, false if construction failed
*/
public final boolean testSingleLayout(final SOCScenario sc, final int pl) {
final Map<String, SOCGameOption> gaOpts = SOCGameOption.parseOptionsToMap("PL=" + pl + ((sc != null) ? ",SC=" + sc.key : ""));
if (gaOpts != null)
assertNull("Unexpected problems with scenario options", SOCGameOption.adjustOptionsToKnown(gaOpts, null, true));
// this same pre-check is done by TestScenarioOpts.testAllScenarios()
final String gaName = ((sc != null) ? sc.key : "classic") + ":" + pl;
gl.createGame(gaName, "test", "en_US", gaOpts, sgh);
final SOCGame ga = gl.getGameData(gaName);
assertNotNull("Game not created", ga);
// which has a reminder comment to keep sync'd with this test method
try {
ga.addPlayer("player", 1);
// SOCBoard/SOCBoardAtServer.makeNewBoard is called here
ga.startGame();
gl.deleteGame(gaName);
} catch (Exception e) {
System.err.println("Error at board setup: " + gaName + ", " + pl + " players:");
e.printStackTrace();
return false;
}
return true;
}
use of soc.game.SOCGameOption in project JSettlers2 by jdmonin.
the class TestScenarioOpts method testAllScenarios.
/**
* Test all {@link SOCScenario}s' game option consistency,
* as described in {@link TestScenarioOpts class javadoc}.
*/
@Test
public void testAllScenarios() {
// use TreeSet for sorted results
final TreeSet<String> badScens = new TreeSet<String>();
for (final SOCScenario sc : SOCScenario.getAllKnownScenarios().values()) {
if (sc.scOpts.equals("-"))
continue;
try {
final Map<String, SOCGameOption> parsedOpts = SOCGameOption.parseOptionsToMap(sc.scOpts);
// will be null if any opts failed parsing
StringBuilder sb = null;
// This same pre-check is done by TestBoardLayouts.testSingleLayout(..)
if (parsedOpts != null) {
sb = SOCGameOption.adjustOptionsToKnown(parsedOpts, null, true);
if (null != sb) {
badScens.add(sc.key + ": Bad game options found by SGO.adjustOptionsToKnown: " + sb);
continue;
}
}
sb = new StringBuilder();
// Check for bad or changed values from sc.scOpts name-value pairs (nvpairs)
for (String nvpair : sc.scOpts.split(SOCMessage.sep2)) {
if (nvpair.length() == 0) {
if (sb.length() > 0)
sb.append(", ");
sb.append("Adjacent commas in sc.scOpts");
continue;
}
int i = nvpair.indexOf("=");
if ((i <= 0) || (i == nvpair.length() - 1)) {
if (sb.length() > 0)
sb.append(", ");
sb.append("Malformed name=value in sc.scOpts: \"" + nvpair + '"');
continue;
}
if (parsedOpts == null) {
if (null == SOCGameOption.parseOptionNameValue(nvpair, false)) {
if (sb.length() > 0)
sb.append(", ");
sb.append("Cannot parse option: check type and syntax: \"" + nvpair + '"');
}
} else {
final String origKey = nvpair.substring(0, i);
if (!parsedOpts.containsKey(origKey)) {
if (sb.length() > 0)
sb.append(", ");
sb.append("sc.scOpts key not found in parsed opts: \"" + nvpair + '"');
continue;
}
final String repacked = parsedOpts.get(origKey).toString();
if (!repacked.equals(nvpair)) {
if (sb.length() > 0)
sb.append(", ");
sb.append("sc.scOpts value changed by SGO.adjustOptionsToKnown: \"" + nvpair + "\" -> \"" + repacked + '"');
}
}
}
if (sb.length() > 0) {
badScens.add(sc.key + ": " + sb);
sb.delete(0, sb.length());
}
// Check opt versions
if (parsedOpts != null) {
int optsVers = -1;
for (SOCGameOption opt : parsedOpts.values()) {
final int vers = opt.minVersion;
if (vers > optsVers)
optsVers = vers;
if (vers > sc.minVersion) {
if (sb.length() > 0)
sb.append(", ");
sb.append(opt.key);
}
}
if (sb.length() > 0)
badScens.add(sc.key + ": Game options minVersion (" + optsVers + ") too new for scenario minVersion (" + sc.minVersion + "): " + sb);
}
} catch (IllegalArgumentException e) {
badScens.add(sc.key + ": bad option name: " + e.getMessage());
}
}
if (!badScens.isEmpty())
System.out.println("SOCScenarios with inconsistent game options: " + badScens);
assertTrue("SOCScenario game option consistency", badScens.isEmpty());
}
use of soc.game.SOCGameOption in project JSettlers2 by jdmonin.
the class NewGameOptionsFrame method readOptsValuesFromControls.
/**
* Read option values from controls, as prep to request the new game.
* If there is a problem (out of range, bad character in integer field, etc),
* set {@link #msgText} and set focus on the field.
* @param checkOptionsMinVers Warn the user if the options will require a
* minimum client version? Won't do so if {@link #forPractice} is set,
* because this isn't a problem for local practice games.
* The warning is skipped if that minimum is an old version
* <= {@link Version#versionNumberMaximumNoWarn()}.
* @return true if all were read OK, false if a problem (such as NumberFormatException)
*/
private boolean readOptsValuesFromControls(final boolean checkOptionsMinVers) {
if (readOnly)
// shouldn't be called in that case
return false;
boolean allOK = true;
for (Component ctrl : controlsOpts.keySet()) {
if (ctrl instanceof Label)
continue;
SOCGameOption op = controlsOpts.get(ctrl);
if (op.key.equals("SC")) {
// Special case: AWT event listeners have already set its value from controls
if (!op.getBoolValue())
op.setStringValue("");
continue;
}
if (ctrl instanceof Checkbox) {
op.setBoolValue(((Checkbox) ctrl).getState());
} else if (ctrl instanceof TextField) {
String txt = ((TextField) ctrl).getText().trim();
if ((op.optType == SOCGameOption.OTYPE_STR) || (op.optType == SOCGameOption.OTYPE_STRHIDE)) {
try {
op.setStringValue(txt);
} catch (IllegalArgumentException ex) {
allOK = false;
// only a single line of text allowed
msgText.setText(strings.get("game.options.singleline"));
ctrl.requestFocusInWindow();
}
} else {
// OTYPE_INT, OTYPE_INTBOOL; defer setting until after all checkboxes have been read
}
} else if (ctrl instanceof Choice) {
// this works with OTYPE_INT, OTYPE_INTBOOL, OTYPE_ENUM, OTYPE_ENUMBOOL
// 0 to n-1
int chIdx = ((Choice) ctrl).getSelectedIndex();
if (chIdx != -1)
op.setIntValue(chIdx + op.minIntValue);
else
allOK = false;
}
}
// Use 0 if blank (still checks if in range).
for (Component ctrl : controlsOpts.keySet()) {
if (!(ctrl instanceof TextField))
continue;
SOCGameOption op = controlsOpts.get(ctrl);
if (op.optType == SOCGameOption.OTYPE_INTBOOL) {
if (!op.getBoolValue())
continue;
} else if (op.optType != SOCGameOption.OTYPE_INT) {
continue;
}
String txt = ((TextField) ctrl).getText().trim();
try {
int iv;
if (txt.length() > 0)
iv = Integer.parseInt(txt);
else
iv = 0;
op.setIntValue(iv);
if (iv != op.getIntValue()) {
allOK = false;
msgText.setText(// "out of range"
strings.get("game.options.outofrange", op.minIntValue, op.maxIntValue));
ctrl.requestFocusInWindow();
}
} catch (NumberFormatException ex) {
allOK = false;
// "please use only digits here"
msgText.setText(strings.get("game.options.onlydigits"));
ctrl.requestFocusInWindow();
}
}
if (allOK && checkOptionsMinVers && !forPractice) {
int optsVers = SOCVersionedItem.itemsMinimumVersion(controlsOpts);
if ((optsVers > -1) && (optsVers > Version.versionNumberMaximumNoWarn())) {
allOK = false;
new VersionConfirmDialog(this, optsVers).setVisible(true);
}
}
return allOK;
}
use of soc.game.SOCGameOption in project JSettlers2 by jdmonin.
the class NewGameOptionsFrame method fireOptionChangeListener.
/**
* Handle firing a game option's ChangeListener, and refreshing related
* gameopts' values on-screen if needed.
* If <tt>oldValue</tt>.equals(<tt>newValue</tt>), nothing happens and
* the ChangeListener is not called.
* @param cl The ChangeListener; must not be null
* @param opt The game option
* @param oldValue Old value, string or boxed primitive
* @param newValue New value, string or boxed primitive
* @since 1.1.13
*/
private void fireOptionChangeListener(SOCGameOption.ChangeListener cl, SOCGameOption opt, final Object oldValue, final Object newValue) {
if (oldValue.equals(newValue))
// <--- Early return: Value didn't change ---
return;
try {
cl.valueChanged(opt, oldValue, newValue, opts);
} catch (Throwable thr) {
System.err.println("-- Error caught in ChangeListener: " + thr.toString() + " --");
thr.printStackTrace();
while (thr.getCause() != null) {
thr = thr.getCause();
System.err.println(" --> Cause: " + thr + " --");
thr.printStackTrace();
}
System.err.println("-- Error stack trace end --");
System.err.println();
}
List<SOCGameOption> refresh = SOCGameOption.getAndClearRefreshList();
if (refresh == null)
// <--- Early return: Nothing else changed ---
return;
// Refresh each one now, depending on type:
if (optsControls == null)
// should only be null if readOnly, and thus no changes to values anyway
return;
for (int i = refresh.size() - 1; i >= 0; --i) {
final SOCGameOption op = refresh.get(i);
final Component opComp = optsControls.get(op.key);
switch(// OTYPE_*
op.optType) {
case SOCGameOption.OTYPE_BOOL:
((Checkbox) opComp).setState(op.getBoolValue());
break;
case SOCGameOption.OTYPE_INT:
case SOCGameOption.OTYPE_INTBOOL:
{
if (opComp instanceof TextField)
((TextField) opComp).setText(Integer.toString(op.getIntValue()));
else
((Choice) opComp).select(op.getIntValue() - op.minIntValue);
final boolean hasCheckbox = (op.optType == SOCGameOption.OTYPE_INTBOOL);
if (hasCheckbox) {
Checkbox cb = boolOptCheckboxes.get(op.key);
if (cb != null)
cb.setState(op.getBoolValue());
}
}
break;
case SOCGameOption.OTYPE_ENUM:
case SOCGameOption.OTYPE_ENUMBOOL:
{
((Choice) opComp).select(op.getIntValue() - op.minIntValue);
final boolean hasCheckbox = (op.optType == SOCGameOption.OTYPE_ENUMBOOL);
if (hasCheckbox) {
Checkbox cb = boolOptCheckboxes.get(op.key);
if (cb != null)
cb.setState(op.getBoolValue());
}
}
break;
case SOCGameOption.OTYPE_STR:
case SOCGameOption.OTYPE_STRHIDE:
((TextField) opComp).setText(op.getStringValue());
break;
}
}
}
use of soc.game.SOCGameOption in project JSettlers2 by jdmonin.
the class NewGameOptionsFrame method textValueChanged.
/**
* When gamename contents change, enable/disable buttons as appropriate. (TextListener)
* Also handles {@link SOCGameOption#OTYPE_INTBOOL} textfield/checkbox combos.
* Also sets {@link SOCGameOption#userChanged}.
* @param e textevent from {@link #gameName}, or from a TextField in {@link #controlsOpts}
*/
public void textValueChanged(TextEvent e) {
if (readOnly)
return;
Object srcObj = e.getSource();
if (!(srcObj instanceof TextField))
return;
final String newText = ((TextField) srcObj).getText().trim();
final boolean notEmpty = (newText.length() > 0);
if (srcObj == gameName) {
if (notEmpty != create.isEnabled())
// enable "create" btn only if game name filled in
create.setEnabled(notEmpty);
} else {
// Check for a ChangeListener for OTYPE_STR and OTYPE_STRHIDE,
// OTYPE_INT and OTYPE_INTBOOL.
// if source is OTYPE_INTBOOL, check its checkbox vs notEmpty.
SOCGameOption opt = controlsOpts.get(srcObj);
if (opt == null)
return;
final String oldText = opt.getStringValue();
boolean validChange = false;
boolean otypeIsInt;
int oldIntValue = 0;
if ((opt.optType == SOCGameOption.OTYPE_STR) || (opt.optType == SOCGameOption.OTYPE_STRHIDE)) {
otypeIsInt = false;
try {
opt.setStringValue(newText);
validChange = true;
} catch (IllegalArgumentException ex) {
}
} else {
otypeIsInt = true;
try // OTYPE_INT, OTYPE_INTBOOL
{
final int iv = Integer.parseInt(newText);
oldIntValue = opt.getIntValue();
// ignored if outside min,max range
opt.setIntValue(iv);
if (iv == opt.getIntValue())
validChange = true;
} catch (NumberFormatException ex) {
}
}
if (validChange && !opt.userChanged)
opt.userChanged = true;
// If this string or int option also has a bool checkbox,
// set or clear that based on string/int not empty.
boolean cbSet = false;
Checkbox cb = boolOptCheckboxes.get(opt.key);
if ((cb != null) && (notEmpty != cb.getState())) {
cb.setState(notEmpty);
opt.setBoolValue(notEmpty);
cbSet = true;
}
SOCGameOption.ChangeListener cl = opt.getChangeListener();
if (cl == null)
return;
// calling fireOptionChangeListener. Boolean is called before int.
if (cbSet) {
// ChangeListener for checkbox
final Boolean newValue = (notEmpty) ? Boolean.TRUE : Boolean.FALSE;
final Boolean oldValue = (notEmpty) ? Boolean.FALSE : Boolean.TRUE;
fireOptionChangeListener(cl, opt, oldValue, newValue);
}
// ChangeListener for text field
if (validChange) {
if (otypeIsInt)
fireOptionChangeListener(cl, opt, new Integer(oldIntValue), new Integer(opt.getIntValue()));
else
fireOptionChangeListener(cl, opt, oldText, newText);
}
}
}
Aggregations